diff --git a/docs/source/manual/file_formats/bus_group_file.rst b/docs/source/manual/file_formats/bus_group_file.rst new file mode 100644 index 000000000..bf14fec4e --- /dev/null +++ b/docs/source/manual/file_formats/bus_group_file.rst @@ -0,0 +1,40 @@ +.. _file_format_bus_group_file: + +Bus Group File (.xml) +===================== + +The bus group file aims to show + +- How bus ports are flatten by EDA engines, e.g., synthesis. +- What are the pins in post-routing corresponding to the bus ports before synthesis + +An example of file is shown as follows. + +.. code-block:: xml + + + + + + + + + + +Bus-related Syntax +------------------ + +.. option:: name="" + + The bus port defined before synthesis, e.g., addr[0:3] + +Pin-related Syntax +------------------ + +.. option:: id="" + + The index of the current pin in a bus port. The index must be the range of **[LSB, MSB-1]** that are defined in the bus. + +.. option:: name="" + + The pin name after bus flatten in synthesis results diff --git a/docs/source/manual/file_formats/index.rst b/docs/source/manual/file_formats/index.rst index 7ed213012..c00f46b6b 100644 --- a/docs/source/manual/file_formats/index.rst +++ b/docs/source/manual/file_formats/index.rst @@ -25,3 +25,5 @@ OpenFPGA widely uses XML format for interchangable files io_mapping_file bitstream_distribution_file + + bus_group_file diff --git a/docs/source/manual/openfpga_shell/openfpga_commands/fpga_verilog_commands.rst b/docs/source/manual/openfpga_shell/openfpga_commands/fpga_verilog_commands.rst index 9f39f8250..6a872a1d1 100644 --- a/docs/source/manual/openfpga_shell/openfpga_commands/fpga_verilog_commands.rst +++ b/docs/source/manual/openfpga_shell/openfpga_commands/fpga_verilog_commands.rst @@ -68,6 +68,11 @@ write_full_testbench Specify the *Pin Constraints File* (PCF) if you want to custom stimulus in testbenches. For example, ``-pin_constraints_file pin_constraints.xml`` Strongly recommend for multi-clock simulations. See detailed file format about :ref:`file_format_pin_constraints_file`. + .. option:: --bus_group_file or -bgf + + Specify the *Bus Group File* (BGF) if you want to group pins to buses. For example, ``-bgf bus_group.xml`` + Strongly recommend when input HDL contains bus ports. See detailed file format about :ref:`file_format_bus_group_file`. + .. option:: --fast_configuration Enable fast configuration phase for the top-level testbench in order to reduce runtime of simulations. It is applicable to configuration chain, memory bank and frame-based configuration protocols. For configuration chain, when enabled, the zeros at the head of the bitstream will be skipped. For memory bank and frame-based, when enabled, all the zero configuration bits will be skipped. So ensure that your memory cells can be correctly reset to zero with a reset signal. @@ -120,6 +125,11 @@ write_preconfigured_fabric_wrapper Specify the *Pin Constraints File* (PCF) if you want to custom stimulus in testbenches. For example, ``-pin_constraints_file pin_constraints.xml`` Strongly recommend for multi-clock simulations. See detailed file format about :ref:`file_format_pin_constraints_file`. + .. option:: --bus_group_file or -bgf + + Specify the *Bus Group File* (BGF) if you want to group pins to buses. For example, ``-bgf bus_group.xml`` + Strongly recommend when input HDL contains bus ports. See detailed file format about :ref:`file_format_bus_group_file`. + .. option:: --explicit_port_mapping Use explicit port mapping when writing the Verilog netlists @@ -180,6 +190,11 @@ write_preconfigured_testbench Specify the *Pin Constraints File* (PCF) if you want to custom stimulus in testbenches. For example, ``-pin_constraints_file pin_constraints.xml`` Strongly recommend for multi-clock simulations. See detailed file format about :ref:`file_format_pin_constraints_file`. + .. option:: --bus_group_file or -bgf + + Specify the *Bus Group File* (BGF) if you want to group pins to buses. For example, ``-bgf bus_group.xml`` + Strongly recommend when input HDL contains bus ports. See detailed file format about :ref:`file_format_bus_group_file`. + .. option:: --explicit_port_mapping Use explicit port mapping when writing the Verilog netlists diff --git a/docs/source/tutorials/getting_started/tools.rst b/docs/source/tutorials/getting_started/tools.rst index 7f1b7f850..ebff3c77c 100644 --- a/docs/source/tutorials/getting_started/tools.rst +++ b/docs/source/tutorials/getting_started/tools.rst @@ -11,7 +11,7 @@ To enable various design purposes, OpenFPGA integrates several tools to i.e., FP .. _fig_openfpga_tools: .. figure:: figures/openfpga_tools.svg - :scale: 25% + :width: 100% :alt: map to buried treasure OpenFPGA tool suites and design flows diff --git a/libopenfpga/CMakeLists.txt b/libopenfpga/CMakeLists.txt index 62dc6d596..36bce10b6 100644 --- a/libopenfpga/CMakeLists.txt +++ b/libopenfpga/CMakeLists.txt @@ -7,3 +7,4 @@ add_subdirectory(libfabrickey) add_subdirectory(librepackdc) add_subdirectory(libfpgabitstream) add_subdirectory(libpcf) +add_subdirectory(libbusgroup) diff --git a/libopenfpga/libbusgroup/CMakeLists.txt b/libopenfpga/libbusgroup/CMakeLists.txt new file mode 100644 index 000000000..a2cbea164 --- /dev/null +++ b/libopenfpga/libbusgroup/CMakeLists.txt @@ -0,0 +1,35 @@ +cmake_minimum_required(VERSION 3.9) + +project("libbusgroup") + +file(GLOB_RECURSE EXEC_SOURCES test/*.cpp) +file(GLOB_RECURSE LIB_SOURCES src/*.cpp) +file(GLOB_RECURSE LIB_HEADERS src/*.h) +files_to_dirs(LIB_HEADERS LIB_INCLUDE_DIRS) + +#Remove test executable from library +list(REMOVE_ITEM LIB_SOURCES ${EXEC_SOURCES}) + +#Create the library +add_library(libbusgroup STATIC + ${LIB_HEADERS} + ${LIB_SOURCES}) +target_include_directories(libbusgroup PUBLIC ${LIB_INCLUDE_DIRS}) +set_target_properties(libbusgroup PROPERTIES PREFIX "") #Avoid extra 'lib' prefix + +#Specify link-time dependancies +target_link_libraries(libbusgroup + libopenfpgautil + libarchopenfpga + libvtrutil + libpugixml + libpugiutil) + +#Create the test executable +foreach(testsourcefile ${EXEC_SOURCES}) + # Use a simple string replace, to cut off .cpp. + get_filename_component(testname ${testsourcefile} NAME_WE) + add_executable(${testname} ${testsourcefile}) + # Make sure the library is linked to each test executable + target_link_libraries(${testname} libbusgroup) +endforeach(testsourcefile ${EXEC_SOURCES}) diff --git a/libopenfpga/libbusgroup/example/bus_group_example.xml b/libopenfpga/libbusgroup/example/bus_group_example.xml new file mode 100644 index 000000000..2d31fb76a --- /dev/null +++ b/libopenfpga/libbusgroup/example/bus_group_example.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/libopenfpga/libbusgroup/src/bus_group.cpp b/libopenfpga/libbusgroup/src/bus_group.cpp new file mode 100644 index 000000000..7aed69215 --- /dev/null +++ b/libopenfpga/libbusgroup/src/bus_group.cpp @@ -0,0 +1,170 @@ +#include + +#include "vtr_assert.h" +#include "vtr_log.h" + +#include "bus_group.h" + +namespace openfpga { // Begin namespace openfpga + +/************************************************************************ + * Member functions for class BusGroup + ***********************************************************************/ + +/************************************************************************ + * Constructors + ***********************************************************************/ +BusGroup::BusGroup() { + return; +} + +/************************************************************************ + * Public Accessors : aggregates + ***********************************************************************/ +BusGroup::bus_group_range BusGroup::buses() const { + return vtr::make_range(bus_ids_.begin(), bus_ids_.end()); +} + +/************************************************************************ + * Public Accessors : Basic data query + ***********************************************************************/ +openfpga::BasicPort BusGroup::bus_port(const BusGroupId& bus_id) const { + VTR_ASSERT(valid_bus_id(bus_id)); + return bus_ports_[bus_id]; +} + +std::vector BusGroup::bus_pins(const BusGroupId& bus_id) const { + VTR_ASSERT(valid_bus_id(bus_id)); + return bus_pin_ids_[bus_id]; +} + +int BusGroup::pin_index(const BusPinId& pin_id) const { + VTR_ASSERT(valid_pin_id(pin_id)); + return pin_indices_[pin_id]; +} + +std::string BusGroup::pin_name(const BusPinId& pin_id) const { + VTR_ASSERT(valid_pin_id(pin_id)); + return pin_names_[pin_id]; +} + +BusGroupId BusGroup::find_pin_bus(const std::string& pin_name) const { + std::map::const_iterator result = pin_name2id_map_.find(pin_name); + if (result == pin_name2id_map_.end()) { + /* Not found, return an invalid id */ + return BusGroupId::INVALID(); + } + /* Found, we should get the parent bus */ + BusPinId pin_id = result->second; + return pin_parent_bus_ids_[pin_id]; +} + +BusGroupId BusGroup::find_bus(const std::string& bus_name) const { + std::map::const_iterator result = bus_name2id_map_.find(bus_name); + if (result == bus_name2id_map_.end()) { + /* Not found, return an invalid id */ + return BusGroupId::INVALID(); + } + /* Found, we should get the parent bus */ + return result->second; +} + +BusPinId BusGroup::find_pin(const std::string& pin_name) const { + std::map::const_iterator result = pin_name2id_map_.find(pin_name); + if (result == pin_name2id_map_.end()) { + /* Not found, return an invalid id */ + return BusPinId::INVALID(); + } + /* Found, we should get the parent bus */ + return result->second; +} + +bool BusGroup::empty() const { + return 0 == bus_ids_.size(); +} + +/************************************************************************ + * Public Mutators + ***********************************************************************/ +void BusGroup::reserve_buses(const size_t& num_buses) { + bus_ids_.reserve(num_buses); + bus_ports_.reserve(num_buses); + bus_pin_ids_.reserve(num_buses); +} + +void BusGroup::reserve_pins(const size_t& num_pins) { + pin_ids_.reserve(num_pins); + pin_indices_.reserve(num_pins); + pin_names_.reserve(num_pins); + pin_parent_bus_ids_.reserve(num_pins); +} + +BusGroupId BusGroup::create_bus(const openfpga::BasicPort& bus_port) { + /* Create a new id */ + BusGroupId bus_id = BusGroupId(bus_ids_.size()); + + bus_ids_.push_back(bus_id); + bus_ports_.push_back(bus_port); + bus_pin_ids_.emplace_back(); + + /* Register to fast look-up */ + auto result = bus_name2id_map_.find(bus_port.get_name()); + if (result == bus_name2id_map_.end()) { + bus_name2id_map_[bus_port.get_name()] = bus_id; + } else { + VTR_LOG_ERROR("Duplicated bus name '%s' in bus group", bus_port.get_name().c_str()); + exit(1); + } + + return bus_id; +} + +BusPinId BusGroup::create_pin(const BusGroupId& bus_id, const int& index) { + /* Create a new id */ + BusPinId pin_id = BusPinId(pin_ids_.size()); + + pin_ids_.push_back(pin_id); + + pin_indices_.push_back(index); + pin_names_.emplace_back(); + + /* Register the pin to the bus */ + VTR_ASSERT(valid_bus_id(bus_id)); + pin_parent_bus_ids_.push_back(bus_id); + + /* If the pin index is beyond the range of the bus_pin_ids, resize it */ + if (size_t(index) >= bus_pin_ids_[bus_id].size()) { + bus_pin_ids_[bus_id].resize(index + 1); + } + bus_pin_ids_[bus_id][index] = pin_id; + + return pin_id; +} + + +void BusGroup::set_pin_name(const BusPinId& pin_id, const std::string& name) { + VTR_ASSERT(valid_pin_id(pin_id)); + pin_names_[pin_id] = name; + + /* Register to fast look-up */ + auto result = pin_name2id_map_.find(name); + if (result == pin_name2id_map_.end()) { + pin_name2id_map_[name] = pin_id; + } else { + VTR_LOG_ERROR("Duplicated pin name '%s' in bus group", name.c_str()); + exit(1); + } +} + +/************************************************************************ + * Internal invalidators/validators + ***********************************************************************/ +bool BusGroup::valid_bus_id(const BusGroupId& bus_id) const { + return ( size_t(bus_id) < bus_ids_.size() ) && ( bus_id == bus_ids_[bus_id] ); +} + +bool BusGroup::valid_pin_id(const BusPinId& pin_id) const { + return ( size_t(pin_id) < pin_ids_.size() ) && ( pin_id == pin_ids_[pin_id] ); +} + +} // End of namespace openfpga diff --git a/libopenfpga/libbusgroup/src/bus_group.h b/libopenfpga/libbusgroup/src/bus_group.h new file mode 100644 index 000000000..da63fb210 --- /dev/null +++ b/libopenfpga/libbusgroup/src/bus_group.h @@ -0,0 +1,125 @@ +#ifndef BUS_GROUP_H +#define BUS_GROUP_H + +/******************************************************************** + * This file include the declaration of pin constraints + *******************************************************************/ +#include +#include +#include + +/* Headers from vtrutil library */ +#include "vtr_vector.h" + +/* Headers from openfpgautil library */ +#include "openfpga_port.h" + +#include "bus_group_fwd.h" + +namespace openfpga { // Begin namespace openfpga + +/******************************************************************** + * A data structure to describe the bus-to-pin mapping + * This data structure may include a number of buses + * each of which has: + * - a unique id and name + * - a number of pins with names and index which are flatten from the bus + * + * Typical usage: + * -------------- + * // Create an object of bus group + * BusGroup bus_group; + * // Create a new port + * BasicPort bus_a("BusA", 0, 3) + * // Add a bus + * BusGroupId bus_group_id = bus_group.create_bus(bus_a); + * + *******************************************************************/ +class BusGroup { + public: /* Types */ + typedef vtr::vector::const_iterator bus_group_iterator; + typedef vtr::vector::const_iterator bus_pin_iterator; + /* Create range */ + typedef vtr::Range bus_group_range; + typedef vtr::Range bus_pin_range; + public: /* Constructors */ + BusGroup(); + public: /* Accessors: aggregates */ + bus_group_range buses() const; + public: /* Public Accessors: Basic data query */ + /** Get port information of a bus with a given id */ + BasicPort bus_port(const BusGroupId& bus_id) const; + + /* Get the pins under a specific bus */ + std::vector bus_pins(const BusGroupId& bus_id) const; + + /* Get the index of a pin */ + int pin_index(const BusPinId& pin_id) const; + + /* Get the name of a pin */ + std::string pin_name(const BusPinId& pin_id) const; + + /* Find the bus that a pin belongs to */ + BusGroupId find_pin_bus(const std::string& pin_name) const; + + /* Find the bus id with a given name */ + BusGroupId find_bus(const std::string& bus_name) const; + + /* Find the pin id with a given name */ + BusPinId find_pin(const std::string& pin_name) const; + + /* Check if there are any buses */ + bool empty() const; + + public: /* Public Mutators */ + /* Reserve a number of buses to be memory efficent */ + void reserve_buses(const size_t& num_buses); + + /* Reserve a number of pins to be memory efficent */ + void reserve_pins(const size_t& num_pins); + + /* Add a bus to storage */ + BusGroupId create_bus(const openfpga::BasicPort& bus_port); + + /* Add a pin to a bus, with a given index in the bus, e.g., A[1] in A[0:2] */ + BusPinId create_pin(const BusGroupId& bus_id, const int& index); + + /* Set the name for a pin */ + void set_pin_name(const BusPinId& pin_id, const std::string& name); + + public: /* Public invalidators/validators */ + /* Show if the bus id is a valid for data queries */ + bool valid_bus_id(const BusGroupId& bus_id) const; + + /* Show if the pin id is a valid for data queries */ + bool valid_pin_id(const BusPinId& pin_id) const; + + private: /* Internal data */ + /* Unique ids for each bus */ + vtr::vector bus_ids_; + + /* Port information of each bus */ + vtr::vector bus_ports_; + + /* Indices of each pin under each bus */ + vtr::vector> bus_pin_ids_; + + /* Unique ids for each pin */ + vtr::vector pin_ids_; + + /* Index for each pin */ + vtr::vector pin_indices_; + + /* Name of each pin under each bus */ + vtr::vector pin_names_; + + /* Parent bus of each pin */ + vtr::vector pin_parent_bus_ids_; + + /* Fast look-up */ + std::map bus_name2id_map_; + std::map pin_name2id_map_; +}; + +} // End of namespace openfpga +#endif diff --git a/libopenfpga/libbusgroup/src/bus_group_fwd.h b/libopenfpga/libbusgroup/src/bus_group_fwd.h new file mode 100644 index 000000000..d6cfea772 --- /dev/null +++ b/libopenfpga/libbusgroup/src/bus_group_fwd.h @@ -0,0 +1,28 @@ +/************************************************************************ + * A header file for BusGroup class, including critical data declaration + * Please include this file only for using any PinConstraints data structure + * Refer to bus_group.h for more details + ***********************************************************************/ + +/************************************************************************ + * Create strong id for BusGroup to avoid illegal type casting + ***********************************************************************/ +#ifndef BUS_GROUP_FWD_H +#define BUS_GROUP_FWD_H + +#include "vtr_strong_id.h" + +namespace openfpga { // Begin namespace openfpga + +struct bus_group_id_tag; +struct bus_pin_id_tag; + +typedef vtr::StrongId BusGroupId; +typedef vtr::StrongId BusPinId; + +/* Short declaration of class */ +class BusGroup; + +} // End of namespace openfpga + +#endif diff --git a/libopenfpga/libbusgroup/src/bus_group_xml_constants.h b/libopenfpga/libbusgroup/src/bus_group_xml_constants.h new file mode 100644 index 000000000..9f27ae978 --- /dev/null +++ b/libopenfpga/libbusgroup/src/bus_group_xml_constants.h @@ -0,0 +1,13 @@ +#ifndef BUS_GROUP_XML_CONSTANTS_H +#define BUS_GROUP_XML_CONSTANTS_H + +/* Constants required by XML parser */ + +constexpr char* XML_BUS_GROUP_NODE_NAME = "bus_group"; +constexpr char* XML_BUS_NODE_NAME = "bus"; +constexpr char* XML_BUS_PORT_ATTRIBUTE_NAME = "name"; +constexpr char* XML_PIN_NODE_NAME = "pin"; +constexpr char* XML_PIN_INDEX_ATTRIBUTE_NAME = "id"; +constexpr char* XML_PIN_NAME_ATTRIBUTE_NAME = "name"; + +#endif diff --git a/libopenfpga/libbusgroup/src/read_xml_bus_group.cpp b/libopenfpga/libbusgroup/src/read_xml_bus_group.cpp new file mode 100644 index 000000000..020aa224b --- /dev/null +++ b/libopenfpga/libbusgroup/src/read_xml_bus_group.cpp @@ -0,0 +1,134 @@ +/******************************************************************** + * This file includes the top-level function of this library + * which reads an XML of bus group file to the associated + * data structures + *******************************************************************/ +#include + +/* Headers from pugi XML library */ +#include "pugixml.hpp" +#include "pugixml_util.hpp" + +/* Headers from vtr util library */ +#include "vtr_assert.h" +#include "vtr_time.h" + +/* Headers from libopenfpga util library */ +#include "openfpga_port_parser.h" + +/* Headers from libarchfpga */ +#include "arch_error.h" +#include "read_xml_util.h" + +#include "bus_group_xml_constants.h" +#include "read_xml_bus_group.h" + +namespace openfpga { // Begin namespace openfpga + +/******************************************************************** + * Parse XML codes of a to an object of BusGroup + *******************************************************************/ +static +void read_xml_pin(pugi::xml_node& xml_pin, + const pugiutil::loc_data& loc_data, + BusGroup& bus_group, + const BusGroupId& bus_id) { + if (false == bus_group.valid_bus_id(bus_id)) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_pin), + "Invalid id of a bus group!\n"); + } + + int pin_index = get_attribute(xml_pin, XML_PIN_INDEX_ATTRIBUTE_NAME, loc_data).as_int(); + std::string pin_name = get_attribute(xml_pin, XML_PIN_NAME_ATTRIBUTE_NAME, loc_data).as_string(); + + /* Before update storage, check if the pin index is in the range */ + BasicPort pin_port(bus_group.bus_port(bus_id).get_name(), pin_index, pin_index); + if (!bus_group.bus_port(bus_id).contained(pin_port)) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_pin), + "Pin index is out of range of the bus port width!\n"); + } + + BusPinId pin_id = bus_group.create_pin(bus_id, pin_index); + bus_group.set_pin_name(pin_id, pin_name); +} + +/******************************************************************** + * Parse XML codes of a to an object of BusGroup + *******************************************************************/ +static +void read_xml_bus(pugi::xml_node& xml_bus, + const pugiutil::loc_data& loc_data, + BusGroup& bus_group) { + + openfpga::PortParser port_parser(get_attribute(xml_bus, XML_BUS_PORT_ATTRIBUTE_NAME, loc_data).as_string()); + + /* Create a new bus in the storage */ + BusGroupId bus_id = bus_group.create_bus(port_parser.port()); + + if (false == bus_group.valid_bus_id(bus_id)) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_bus), + "Fail to create a bus group!\n"); + } + + /* Ensure the bus port is valid */ + if (!bus_group.bus_port(bus_id).is_valid()) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_bus), + "Bus port is invalid, check LSB and MSB!\n"); + } + + for (pugi::xml_node xml_pin : xml_bus.children()) { + /* Error out if the XML child has an invalid name! */ + if (xml_pin.name() != std::string(XML_PIN_NODE_NAME)) { + bad_tag(xml_pin, loc_data, xml_bus, {XML_PIN_NODE_NAME}); + } + read_xml_pin(xml_pin, loc_data, bus_group, bus_id); + } +} + +/******************************************************************** + * Parse XML codes about to an object of BusGroup + *******************************************************************/ +BusGroup read_xml_bus_group(const char* fname) { + + vtr::ScopedStartFinishTimer timer("Read Bus Group"); + + BusGroup bus_group; + + /* Parse the file */ + pugi::xml_document doc; + pugiutil::loc_data loc_data; + + try { + loc_data = pugiutil::load_xml(doc, fname); + + pugi::xml_node xml_root = get_single_child(doc, XML_BUS_GROUP_NODE_NAME, loc_data); + + size_t num_buses = std::distance(xml_root.children().begin(), xml_root.children().end()); + + /* Count the total number of pins */ + size_t num_pins = 0; + for (pugi::xml_node xml_bus : xml_root.children()) { + num_pins += std::distance(xml_bus.children().begin(), xml_bus.children().end()); + } + + /* Reserve memory space for the buses */ + bus_group.reserve_buses(num_buses); + /* Reserve memory space for the pins */ + bus_group.reserve_pins(num_pins); + + for (pugi::xml_node xml_bus : xml_root.children()) { + /* Error out if the XML child has an invalid name! */ + if (xml_bus.name() != std::string(XML_BUS_NODE_NAME)) { + bad_tag(xml_bus, loc_data, xml_root, {XML_BUS_NODE_NAME}); + } + read_xml_bus(xml_bus, loc_data, bus_group); + } + } catch (pugiutil::XmlError& e) { + archfpga_throw(fname, e.line(), + "%s", e.what()); + } + + return bus_group; +} + +} // End of namespace openfpga diff --git a/libopenfpga/libbusgroup/src/read_xml_bus_group.h b/libopenfpga/libbusgroup/src/read_xml_bus_group.h new file mode 100644 index 000000000..7b1c89a06 --- /dev/null +++ b/libopenfpga/libbusgroup/src/read_xml_bus_group.h @@ -0,0 +1,21 @@ +#ifndef READ_XML_BUS_GROUP_H +#define READ_XML_BUS_GROUP_H + +/******************************************************************** + * Include header files that are required by function declaration + *******************************************************************/ +#include "pugixml_util.hpp" +#include "pugixml.hpp" +#include "bus_group.h" + +/******************************************************************** + * Function declaration + *******************************************************************/ + +namespace openfpga { // Begin namespace openfpga + +BusGroup read_xml_bus_group(const char* fname); + +} // End of namespace openfpga + +#endif diff --git a/libopenfpga/libbusgroup/src/write_xml_bus_group.cpp b/libopenfpga/libbusgroup/src/write_xml_bus_group.cpp new file mode 100644 index 000000000..9d9fdb005 --- /dev/null +++ b/libopenfpga/libbusgroup/src/write_xml_bus_group.cpp @@ -0,0 +1,112 @@ +/******************************************************************** + * This file includes functions that outputs a bus group object to XML format + *******************************************************************/ +/* Headers from system goes first */ +#include +#include + +/* Headers from vtr util library */ +#include "vtr_assert.h" +#include "vtr_log.h" +#include "vtr_time.h" + +/* Headers from openfpga util library */ +#include "openfpga_digest.h" + +/* Headers from arch openfpga library */ +#include "write_xml_utils.h" + +/* Headers from pin constraint library */ +#include "bus_group_xml_constants.h" +#include "write_xml_bus_group.h" + +namespace openfpga { // Begin namespace openfpga + +/******************************************************************** + * A writer to output a bus to XML format + * + * Return 0 if successful + * Return 1 if there are more serious bugs in the architecture + * Return 2 if fail when creating files + *******************************************************************/ +static +int write_xml_bus(std::fstream& fp, + const BusGroup& bus_group, + const BusGroupId& bus_id) { + /* Validate the file stream */ + if (false == openfpga::valid_file_stream(fp)) { + return 2; + } + + openfpga::write_tab_to_file(fp, 1); + fp << "<" << XML_BUS_NODE_NAME << ""; + + if (false == bus_group.valid_bus_id(bus_id)) { + return 1; + } + + write_xml_attribute(fp, XML_BUS_PORT_ATTRIBUTE_NAME, generate_xml_port_name(bus_group.bus_port(bus_id)).c_str()); + fp << ">" << "\n"; + + /* Output all the pins under this bus */ + for (const BusPinId& pin_id : bus_group.bus_pins(bus_id)) { + openfpga::write_tab_to_file(fp, 2); + fp << "<" << XML_PIN_NODE_NAME << ""; + + write_xml_attribute(fp, XML_PIN_INDEX_ATTRIBUTE_NAME, bus_group.pin_index(pin_id)); + write_xml_attribute(fp, XML_PIN_NAME_ATTRIBUTE_NAME, bus_group.pin_name(pin_id).c_str()); + + fp << "/>" << "\n"; + } + + openfpga::write_tab_to_file(fp, 1); + fp << "" << "\n"; + + return 0; +} + +/******************************************************************** + * A writer to output a bus group object to XML format + * + * Return 0 if successful + * Return 1 if there are more serious bugs in the architecture + * Return 2 if fail when creating files + *******************************************************************/ +int write_xml_bus_group(const char* fname, + const BusGroup& bus_group) { + + vtr::ScopedStartFinishTimer timer("Write Bus Group"); + + /* Create a file handler */ + std::fstream fp; + /* Open the file stream */ + fp.open(std::string(fname), std::fstream::out | std::fstream::trunc); + + /* Validate the file stream */ + openfpga::check_file_stream(fname, fp); + + /* Write the root node */ + fp << "<" << XML_BUS_GROUP_NODE_NAME << ">" << "\n"; + + int err_code = 0; + + /* Write each bus */ + for (const BusGroupId& bus : bus_group.buses()) { + /* Write bus */ + err_code = write_xml_bus(fp, bus_group, bus); + if (0 != err_code) { + return err_code; + } + } + + /* Finish writing the root node */ + fp << "" << "\n"; + + /* Close the file stream */ + fp.close(); + + return err_code; +} + +} // End of namespace openfpga diff --git a/libopenfpga/libbusgroup/src/write_xml_bus_group.h b/libopenfpga/libbusgroup/src/write_xml_bus_group.h new file mode 100644 index 000000000..09a51673f --- /dev/null +++ b/libopenfpga/libbusgroup/src/write_xml_bus_group.h @@ -0,0 +1,20 @@ +#ifndef WRITE_XML_BUS_GROUP_H +#define WRITE_XML_BUS_GROUP_H + +/******************************************************************** + * Include header files that are required by function declaration + *******************************************************************/ +#include +#include "bus_group.h" + +/******************************************************************** + * Function declaration + *******************************************************************/ +namespace openfpga { // Begin namespace openfpga + +int write_xml_bus_group(const char* fname, + const BusGroup& bus_group); + +} // End of namespace openfpga + +#endif diff --git a/libopenfpga/libbusgroup/test/xml_io_bus_group.cpp b/libopenfpga/libbusgroup/test/xml_io_bus_group.cpp new file mode 100644 index 000000000..1f372c311 --- /dev/null +++ b/libopenfpga/libbusgroup/test/xml_io_bus_group.cpp @@ -0,0 +1,33 @@ +/******************************************************************** + * Unit test functions to validate the correctness of + * 1. parser of data structures + * 2. writer of data structures + *******************************************************************/ +/* Headers from vtrutils */ +#include "vtr_assert.h" +#include "vtr_log.h" + +/* Headers from readarchopenfpga */ +#include "read_xml_bus_group.h" +#include "write_xml_bus_group.h" + +int main(int argc, const char** argv) { + /* Ensure we have only one or two argument */ + VTR_ASSERT((2 == argc) || (3 == argc)); + + /* Parse the circuit library from an XML file */ + const openfpga::BusGroup& bus_group = openfpga::read_xml_bus_group(argv[1]); + VTR_LOG("Parsed %lu bus(es) from XML into bus group.\n", + bus_group.buses().size()); + + /* Output the bus group to an XML file + * This is optional only used when there is a second argument + */ + if (3 <= argc) { + openfpga::write_xml_bus_group(argv[2], bus_group); + VTR_LOG("Write the bus group to an XML file: %s.\n", + argv[2]); + } +} + + diff --git a/openfpga/CMakeLists.txt b/openfpga/CMakeLists.txt index 88b790d89..70b00fa7b 100644 --- a/openfpga/CMakeLists.txt +++ b/openfpga/CMakeLists.txt @@ -28,6 +28,7 @@ target_link_libraries(libopenfpga libini libpcf libvtrutil + libbusgroup libvpr) #Create the test executable diff --git a/openfpga/src/base/openfpga_verilog.cpp b/openfpga/src/base/openfpga_verilog.cpp index 7569a14bf..ae154435f 100644 --- a/openfpga/src/base/openfpga_verilog.cpp +++ b/openfpga/src/base/openfpga_verilog.cpp @@ -17,6 +17,9 @@ /* Headers from pcf library */ #include "read_xml_pin_constraints.h" +/* Headers from bgf library */ +#include "read_xml_bus_group.h" + /* Include global variables of VPR */ #include "globals.h" @@ -79,6 +82,7 @@ int write_full_testbench(const OpenfpgaContext& openfpga_ctx, CommandOptionId opt_bitstream = cmd.option("bitstream"); CommandOptionId opt_fabric_netlist = cmd.option("fabric_netlist_file_path"); CommandOptionId opt_pcf = cmd.option("pin_constraints_file"); + CommandOptionId opt_bgf = cmd.option("bus_group_file"); CommandOptionId opt_reference_benchmark = cmd.option("reference_benchmark_file_path"); CommandOptionId opt_fast_configuration = cmd.option("fast_configuration"); CommandOptionId opt_explicit_port_mapping = cmd.option("explicit_port_mapping"); @@ -111,6 +115,12 @@ int write_full_testbench(const OpenfpgaContext& openfpga_ctx, if (true == cmd_context.option_enable(cmd, opt_pcf)) { pin_constraints = read_xml_pin_constraints(cmd_context.option_value(cmd, opt_pcf).c_str()); } + + /* If bug group file are enabled by command options, read the file */ + BusGroup bus_group; + if (true == cmd_context.option_enable(cmd, opt_bgf)) { + bus_group = read_xml_bus_group(cmd_context.option_value(cmd, opt_bgf).c_str()); + } return fpga_verilog_full_testbench(openfpga_ctx.module_graph(), openfpga_ctx.bitstream_manager(), @@ -119,6 +129,7 @@ int write_full_testbench(const OpenfpgaContext& openfpga_ctx, g_vpr_ctx.atom(), g_vpr_ctx.placement(), pin_constraints, + bus_group, cmd_context.option_value(cmd, opt_bitstream), openfpga_ctx.io_location_map(), openfpga_ctx.fabric_global_port_info(), @@ -138,6 +149,7 @@ int write_preconfigured_fabric_wrapper(const OpenfpgaContext& openfpga_ctx, CommandOptionId opt_output_dir = cmd.option("file"); CommandOptionId opt_fabric_netlist = cmd.option("fabric_netlist_file_path"); CommandOptionId opt_pcf = cmd.option("pin_constraints_file"); + CommandOptionId opt_bgf = cmd.option("bus_group_file"); CommandOptionId opt_explicit_port_mapping = cmd.option("explicit_port_mapping"); CommandOptionId opt_default_net_type = cmd.option("default_net_type"); CommandOptionId opt_include_signal_init = cmd.option("include_signal_init"); @@ -170,12 +182,19 @@ int write_preconfigured_fabric_wrapper(const OpenfpgaContext& openfpga_ctx, if (true == cmd_context.option_enable(cmd, opt_pcf)) { pin_constraints = read_xml_pin_constraints(cmd_context.option_value(cmd, opt_pcf).c_str()); } + + /* If bug group file are enabled by command options, read the file */ + BusGroup bus_group; + if (true == cmd_context.option_enable(cmd, opt_bgf)) { + bus_group = read_xml_bus_group(cmd_context.option_value(cmd, opt_bgf).c_str()); + } return fpga_verilog_preconfigured_fabric_wrapper(openfpga_ctx.module_graph(), openfpga_ctx.bitstream_manager(), g_vpr_ctx.atom(), g_vpr_ctx.placement(), pin_constraints, + bus_group, openfpga_ctx.io_location_map(), openfpga_ctx.fabric_global_port_info(), openfpga_ctx.vpr_netlist_annotation(), @@ -192,6 +211,7 @@ int write_preconfigured_testbench(const OpenfpgaContext& openfpga_ctx, CommandOptionId opt_output_dir = cmd.option("file"); CommandOptionId opt_pcf = cmd.option("pin_constraints_file"); + CommandOptionId opt_bgf = cmd.option("bus_group_file"); CommandOptionId opt_fabric_netlist = cmd.option("fabric_netlist_file_path"); CommandOptionId opt_reference_benchmark = cmd.option("reference_benchmark_file_path"); CommandOptionId opt_explicit_port_mapping = cmd.option("explicit_port_mapping"); @@ -221,10 +241,17 @@ int write_preconfigured_testbench(const OpenfpgaContext& openfpga_ctx, if (true == cmd_context.option_enable(cmd, opt_pcf)) { pin_constraints = read_xml_pin_constraints(cmd_context.option_value(cmd, opt_pcf).c_str()); } + + /* If bug group file are enabled by command options, read the file */ + BusGroup bus_group; + if (true == cmd_context.option_enable(cmd, opt_bgf)) { + bus_group = read_xml_bus_group(cmd_context.option_value(cmd, opt_bgf).c_str()); + } return fpga_verilog_preconfigured_testbench(openfpga_ctx.module_graph(), g_vpr_ctx.atom(), pin_constraints, + bus_group, openfpga_ctx.fabric_global_port_info(), openfpga_ctx.vpr_netlist_annotation(), openfpga_ctx.simulation_setting(), diff --git a/openfpga/src/base/openfpga_verilog_command.cpp b/openfpga/src/base/openfpga_verilog_command.cpp index 9d0f58eef..1cc85333a 100644 --- a/openfpga/src/base/openfpga_verilog_command.cpp +++ b/openfpga/src/base/openfpga_verilog_command.cpp @@ -89,6 +89,11 @@ ShellCommandId add_openfpga_write_full_testbench_command(openfpga::Shell prefix_to_remove; - prefix_to_remove.push_back(std::string(VPR_BENCHMARK_OUT_PORT_PREFIX)); - prefix_to_remove.push_back(std::string(OPENFPGA_BENCHMARK_OUT_PORT_PREFIX)); print_verilog_testbench_benchmark_instance(fp, reference_verilog_top_name, std::string(BENCHMARK_INSTANCE_NAME), std::string(), std::string(), std::string(), - prefix_to_remove, std::string(BENCHMARK_PORT_POSTFIX), std::vector(), atom_ctx, netlist_annotation, pin_constraints, + bus_group, explicit_port_mapping); print_verilog_comment(fp, std::string("----- End reference Benchmark Instanication -------")); @@ -149,29 +144,24 @@ void print_verilog_random_testbench_fpga_instance(std::fstream& fp, const AtomContext& atom_ctx, const VprNetlistAnnotation& netlist_annotation, const PinConstraints& pin_constraints, + const BusGroup& bus_group, const bool& explicit_port_mapping) { /* Validate the file stream */ valid_file_stream(fp); print_verilog_comment(fp, std::string("----- FPGA fabric instanciation -------")); - /* VPR added a prefix of "out_" to the output ports of input benchmark */ - std::vector prefix_to_remove; - prefix_to_remove.push_back(std::string(VPR_BENCHMARK_OUT_PORT_PREFIX)); - prefix_to_remove.push_back(std::string(OPENFPGA_BENCHMARK_OUT_PORT_PREFIX)); - - /* Always use explicit port mapping */ print_verilog_testbench_benchmark_instance(fp, std::string(circuit_name + std::string(FORMAL_VERIFICATION_TOP_MODULE_POSTFIX)), std::string(FPGA_INSTANCE_NAME), std::string(), std::string(), std::string(), - prefix_to_remove, std::string(FPGA_PORT_POSTFIX), std::vector(), atom_ctx, netlist_annotation, pin_constraints, + bus_group, explicit_port_mapping); print_verilog_comment(fp, std::string("----- End FPGA Fabric Instanication -------")); @@ -288,6 +278,7 @@ void print_verilog_random_top_testbench(const std::string& circuit_name, const ModuleManager& module_manager, const FabricGlobalPortInfo& global_ports, const PinConstraints& pin_constraints, + const BusGroup& bus_group, const SimulationSetting& simulation_parameters, const VerilogTestbenchOption &options) { std::string timer_message = std::string("Write configuration-skip testbench for FPGA top-level Verilog netlist implemented by '") + circuit_name.c_str() + std::string("'"); @@ -316,6 +307,7 @@ void print_verilog_random_top_testbench(const std::string& circuit_name, print_verilog_random_testbench_fpga_instance(fp, circuit_name, atom_ctx, netlist_annotation, pin_constraints, + bus_group, options.explicit_port_mapping()); /* Call defined benchmark */ @@ -323,6 +315,7 @@ void print_verilog_random_top_testbench(const std::string& circuit_name, print_verilog_top_random_testbench_benchmark_instance(fp, circuit_name, atom_ctx, netlist_annotation, pin_constraints, + bus_group, options.explicit_port_mapping()); } diff --git a/openfpga/src/fpga_verilog/verilog_formal_random_top_testbench.h b/openfpga/src/fpga_verilog/verilog_formal_random_top_testbench.h index d58bae969..e3b092e1c 100644 --- a/openfpga/src/fpga_verilog/verilog_formal_random_top_testbench.h +++ b/openfpga/src/fpga_verilog/verilog_formal_random_top_testbench.h @@ -11,6 +11,7 @@ #include "fabric_global_port_info.h" #include "simulation_setting.h" #include "verilog_testbench_options.h" +#include "bus_group.h" /******************************************************************** * Function declaration @@ -26,6 +27,7 @@ void print_verilog_random_top_testbench(const std::string& circuit_name, const ModuleManager& module_manager, const FabricGlobalPortInfo& global_ports, const PinConstraints& pin_constraints, + const BusGroup& bus_group, const SimulationSetting& simulation_parameters, const VerilogTestbenchOption &options); diff --git a/openfpga/src/fpga_verilog/verilog_preconfig_top_module.cpp b/openfpga/src/fpga_verilog/verilog_preconfig_top_module.cpp index fc4ebd626..26ce11c2f 100644 --- a/openfpga/src/fpga_verilog/verilog_preconfig_top_module.cpp +++ b/openfpga/src/fpga_verilog/verilog_preconfig_top_module.cpp @@ -38,7 +38,8 @@ static void print_verilog_preconfig_top_module_ports(std::fstream &fp, const std::string &circuit_name, const AtomContext &atom_ctx, - const VprNetlistAnnotation &netlist_annotation) { + const VprNetlistAnnotation &netlist_annotation, + const BusGroup& bus_group) { /* Validate the file stream */ valid_file_stream(fp); @@ -47,14 +48,15 @@ void print_verilog_preconfig_top_module_ports(std::fstream &fp, fp << "module " << circuit_name << std::string(FORMAL_VERIFICATION_TOP_MODULE_POSTFIX); fp << " (" << std::endl; - /* Add module ports */ - size_t port_counter = 0; - /* Port type-to-type mapping */ std::map port_type2type_map; port_type2type_map[AtomBlockType::INPAD] = VERILOG_PORT_INPUT; port_type2type_map[AtomBlockType::OUTPAD] = VERILOG_PORT_OUTPUT; + /* Ports to be added, this is to avoid any bus port */ + std::vector port_list; + std::vector port_types; + /* Print all the I/Os of the circuit implementation to be tested*/ for (const AtomBlockId &atom_blk : atom_ctx.nlist.blocks()) { /* We only care I/O logical blocks !*/ @@ -62,8 +64,8 @@ void print_verilog_preconfig_top_module_ports(std::fstream &fp, continue; } - /* The block may be renamed as it contains special characters which violate Verilog syntax */ std::string block_name = atom_ctx.nlist.block_name(atom_blk); + /* The block may be renamed as it contains special characters which violate Verilog syntax */ if (true == netlist_annotation.is_block_renamed(atom_blk)) { block_name = netlist_annotation.block_name(atom_blk); } @@ -82,12 +84,38 @@ void print_verilog_preconfig_top_module_ports(std::fstream &fp, } } + /* If the pin is part of a bus, + * - Check if the bus is already in the list + * - If not, add it to the port list + * - If yes, do nothing and move onto the next port + * If the pin does not belong to any bus + * - Add it to the bus port + */ + BusGroupId bus_id = bus_group.find_pin_bus(block_name); + if (bus_id) { + if (port_list.end() == std::find(port_list.begin(), port_list.end(), bus_group.bus_port(bus_id))) { + port_list.push_back(bus_group.bus_port(bus_id)); + port_types.push_back(atom_ctx.nlist.block_type(atom_blk)); + } + continue; + } + + /* Both input and output ports have only size of 1 */ + BasicPort module_port(std::string(block_name), 1); + port_list.push_back(module_port); + port_types.push_back(atom_ctx.nlist.block_type(atom_blk)); + } + + /* After collecting all the ports, now print the port mapping */ + size_t port_counter = 0; + for (size_t iport = 0; iport < port_list.size(); ++iport) { + BasicPort module_port = port_list[iport]; + AtomBlockType port_type = port_types[iport]; if (0 < port_counter) { fp << "," << std::endl; } - /* Both input and output ports have only size of 1 */ - BasicPort module_port(std::string(block_name), 1); - fp << generate_verilog_port(port_type2type_map[atom_ctx.nlist.block_type(atom_blk)], module_port); + + fp << generate_verilog_port(port_type2type_map[port_type], module_port); /* Update port counter */ port_counter++; @@ -434,6 +462,7 @@ int print_verilog_preconfig_top_module(const ModuleManager &module_manager, const AtomContext &atom_ctx, const PlacementContext &place_ctx, const PinConstraints& pin_constraints, + const BusGroup& bus_group, const IoLocationMap &io_location_map, const VprNetlistAnnotation &netlist_annotation, const std::string &circuit_name, @@ -461,7 +490,7 @@ int print_verilog_preconfig_top_module(const ModuleManager &module_manager, options.default_net_type()); /* Print module declaration and ports */ - print_verilog_preconfig_top_module_ports(fp, circuit_name, atom_ctx, netlist_annotation); + print_verilog_preconfig_top_module_ports(fp, circuit_name, atom_ctx, netlist_annotation, bus_group); /* Find the top_module */ ModuleId top_module = module_manager.find_module(generate_fpga_top_module_name()); @@ -488,16 +517,13 @@ int print_verilog_preconfig_top_module(const ModuleManager &module_manager, } /* Connect I/Os to benchmark I/Os or constant driver */ - std::vector prefix_to_remove; - prefix_to_remove.push_back(std::string(VPR_BENCHMARK_OUT_PORT_PREFIX)); - prefix_to_remove.push_back(std::string(OPENFPGA_BENCHMARK_OUT_PORT_PREFIX)); print_verilog_testbench_connect_fpga_ios(fp, module_manager, top_module, atom_ctx, place_ctx, io_location_map, netlist_annotation, + bus_group, std::string(FORMAL_VERIFICATION_TOP_MODULE_PORT_POSTFIX), std::string(), std::string(), - prefix_to_remove, std::vector(), (size_t)VERILOG_DEFAULT_SIGNAL_INIT_VALUE); diff --git a/openfpga/src/fpga_verilog/verilog_preconfig_top_module.h b/openfpga/src/fpga_verilog/verilog_preconfig_top_module.h index 01bb12f08..39e1d9f28 100644 --- a/openfpga/src/fpga_verilog/verilog_preconfig_top_module.h +++ b/openfpga/src/fpga_verilog/verilog_preconfig_top_module.h @@ -14,6 +14,7 @@ #include "io_location_map.h" #include "fabric_global_port_info.h" #include "config_protocol.h" +#include "bus_group.h" #include "vpr_netlist_annotation.h" #include "verilog_testbench_options.h" @@ -32,6 +33,7 @@ int print_verilog_preconfig_top_module(const ModuleManager& module_manager, const AtomContext& atom_ctx, const PlacementContext& place_ctx, const PinConstraints& pin_constraints, + const BusGroup& bus_group, const IoLocationMap& io_location_map, const VprNetlistAnnotation& netlist_annotation, const std::string& circuit_name, diff --git a/openfpga/src/fpga_verilog/verilog_testbench_utils.cpp b/openfpga/src/fpga_verilog/verilog_testbench_utils.cpp index 899d6b014..4d19b5e96 100644 --- a/openfpga/src/fpga_verilog/verilog_testbench_utils.cpp +++ b/openfpga/src/fpga_verilog/verilog_testbench_utils.cpp @@ -22,6 +22,7 @@ #include "module_manager_utils.h" #include "fabric_global_port_info_utils.h" +#include "openfpga_atom_netlist_utils.h" #include "verilog_constants.h" #include "verilog_writer_utils.h" @@ -79,19 +80,22 @@ void print_verilog_testbench_benchmark_instance(std::fstream& fp, const std::string& module_input_port_postfix, const std::string& module_output_port_postfix, const std::string& input_port_postfix, - const std::vector& output_port_prefix_to_remove, const std::string& output_port_postfix, const std::vector& clock_port_names, const AtomContext& atom_ctx, const VprNetlistAnnotation& netlist_annotation, const PinConstraints& pin_constraints, + const BusGroup& bus_group, const bool& use_explicit_port_map) { /* Validate the file stream */ valid_file_stream(fp); fp << "\t" << module_name << " " << instance_name << "(" << std::endl; - size_t port_counter = 0; + /* Consider all the unique port names */ + std::vector port_names; + std::vector port_types; + for (const AtomBlockId& atom_blk : atom_ctx.nlist.blocks()) { /* Bypass non-I/O atom blocks ! */ if ( (AtomBlockType::INPAD != atom_ctx.nlist.block_type(atom_blk)) @@ -105,62 +109,129 @@ void print_verilog_testbench_benchmark_instance(std::fstream& fp, block_name = netlist_annotation.block_name(atom_blk); } + /* Note that VPR added a prefix "out_" or "out:" to the name of output blocks + * We can remove this when specified through input argument + */ + if (AtomBlockType::OUTPAD == atom_ctx.nlist.block_type(atom_blk)) { + block_name = remove_atom_block_name_prefix(block_name); + } + + /* If the pin is part of a bus, + * - Check if the bus is already in the list + * - If not, add it to the port list + * - If yes, do nothing and move onto the next port + * If the pin does not belong to any bus + * - Add it to the bus port + */ + BusGroupId bus_id = bus_group.find_pin_bus(block_name); + if (bus_id) { + if (port_names.end() == std::find(port_names.begin(), port_names.end(), bus_group.bus_port(bus_id).get_name())) { + port_names.push_back(bus_group.bus_port(bus_id).get_name()); + port_types.push_back(atom_ctx.nlist.block_type(atom_blk)); + } + continue; + } + + /* Input port follows the logical block name while output port requires a special postfix */ + port_names.push_back(block_name); + port_types.push_back(atom_ctx.nlist.block_type(atom_blk)); + } + + /* Print out the instance with port mapping */ + size_t port_counter = 0; + for (size_t iport = 0; iport < port_names.size(); ++iport) { /* The first port does not need a comma */ - if(0 < port_counter){ + if (0 < port_counter){ fp << "," << std::endl; } - /* Input port follows the logical block name while output port requires a special postfix */ - if (AtomBlockType::INPAD == atom_ctx.nlist.block_type(atom_blk)) { - fp << "\t\t"; + + fp << "\t\t"; + if (AtomBlockType::INPAD == port_types[iport]) { if (true == use_explicit_port_map) { - fp << "." << block_name << module_input_port_postfix << "("; + fp << "." << port_names[iport] << module_input_port_postfix << "("; } - /* Polarity of some input may have to be inverted, as defined in pin constraints - * For example, the reset signal of the benchmark is active low - * while the reset signal of the FPGA fabric is active high (inside FPGA, the reset signal will be inverted) - * However, to ensure correct stimuli to the benchmark, we have to invert the signal - */ - if (PinConstraints::LOGIC_HIGH == pin_constraints.net_default_value(block_name)) { - fp << "~"; - } - /* For clock ports, skip postfix */ - if (clock_port_names.end() != std::find(clock_port_names.begin(), clock_port_names.end(), block_name)) { - fp << block_name; - } else { - fp << block_name << input_port_postfix; - } - if (true == use_explicit_port_map) { - fp << ")"; - } - } else { - VTR_ASSERT_SAFE(AtomBlockType::OUTPAD == atom_ctx.nlist.block_type(atom_blk)); - fp << "\t\t"; - /* Note that VPR added a prefix "out_" or "out:" to the name of output blocks - * We can remove this when specified through input argument - */ - std::string output_block_name = block_name; - for (const std::string& prefix_to_remove : output_port_prefix_to_remove) { - if (!prefix_to_remove.empty()) { - if (0 == output_block_name.find(prefix_to_remove)) { - output_block_name.erase(0, prefix_to_remove.length()); - break; + /* For bus ports, include a complete list of pins */ + BusGroupId bus_id = bus_group.find_bus(port_names[iport]); + if (bus_id) { + fp << "{"; + int pin_counter = 0; + /* Include all the pins */ + for (const BusPinId& pin : bus_group.bus_pins(bus_id)) { + if (0 < pin_counter) { + fp << ", "; } + /* Polarity of some input may have to be inverted, as defined in pin constraints + * For example, the reset signal of the benchmark is active low + * while the reset signal of the FPGA fabric is active high (inside FPGA, the reset signal will be inverted) + * However, to ensure correct stimuli to the benchmark, we have to invert the signal + */ + if (PinConstraints::LOGIC_HIGH == pin_constraints.net_default_value(bus_group.pin_name(pin))) { + fp << "~"; + } + + fp << bus_group.pin_name(pin); + + /* For clock ports, skip postfix */ + if (clock_port_names.end() == std::find(clock_port_names.begin(), clock_port_names.end(), port_names[iport])) { + fp << input_port_postfix; + } + + pin_counter++; + } + fp << "}"; + } else { + /* Polarity of some input may have to be inverted, as defined in pin constraints + * For example, the reset signal of the benchmark is active low + * while the reset signal of the FPGA fabric is active high (inside FPGA, the reset signal will be inverted) + * However, to ensure correct stimuli to the benchmark, we have to invert the signal + */ + if (PinConstraints::LOGIC_HIGH == pin_constraints.net_default_value(port_names[iport])) { + fp << "~"; + } + + fp << port_names[iport]; + /* For clock ports, skip postfix */ + if (clock_port_names.end() == std::find(clock_port_names.begin(), clock_port_names.end(), port_names[iport])) { + fp << input_port_postfix; } } if (true == use_explicit_port_map) { - fp << "." << output_block_name << module_output_port_postfix << "("; + fp << ")"; + } + } else { + VTR_ASSERT_SAFE(AtomBlockType::OUTPAD == port_types[iport]); + if (true == use_explicit_port_map) { + fp << "." << port_names[iport] << module_output_port_postfix << "("; + } + + /* For bus ports, include a complete list of pins */ + BusGroupId bus_id = bus_group.find_bus(port_names[iport]); + if (bus_id) { + fp << "{"; + int pin_counter = 0; + /* Include all the pins */ + for (const BusPinId& pin : bus_group.bus_pins(bus_id)) { + if (0 < pin_counter) { + fp << ", "; + } + fp << bus_group.pin_name(pin) << output_port_postfix; + pin_counter++; + } + fp << "}"; + } else { + fp << port_names[iport] << output_port_postfix; } - fp << block_name << output_port_postfix; if (true == use_explicit_port_map) { fp << ")"; } - } + } + /* Update the counter */ port_counter++; } - fp << "\t);" << std::endl; + fp << "\n\t);" << std::endl; } /******************************************************************** @@ -177,10 +248,10 @@ void print_verilog_testbench_connect_fpga_ios(std::fstream& fp, const PlacementContext& place_ctx, const IoLocationMap& io_location_map, const VprNetlistAnnotation& netlist_annotation, + const BusGroup& bus_group, const std::string& net_name_postfix, const std::string& io_input_port_name_postfix, const std::string& io_output_port_name_postfix, - const std::vector& output_port_prefix_to_remove, const std::vector& clock_port_names, const size_t& unused_io_value) { /* Validate the file stream */ @@ -276,13 +347,8 @@ void print_verilog_testbench_connect_fpga_ios(std::fstream& fp, /* Note that VPR added a prefix to the name of output blocks * We can remove this when specified through input argument */ - for (const std::string& prefix_to_remove : output_port_prefix_to_remove) { - if (!prefix_to_remove.empty()) { - if (0 == block_name.find(prefix_to_remove)) { - block_name.erase(0, prefix_to_remove.length()); - break; - } - } + if (AtomBlockType::OUTPAD == atom_ctx.nlist.block_type(atom_blk)) { + block_name = remove_atom_block_name_prefix(block_name); } /* Create the port for benchmark I/O, due to BLIF benchmark, each I/O always has a size of 1 @@ -290,6 +356,18 @@ void print_verilog_testbench_connect_fpga_ios(std::fstream& fp, * due to verification context! Here, we give full customization on naming */ BasicPort benchmark_io_port; + + /* If this benchmark pin belongs to any bus group, use the bus pin instead */ + BusGroupId bus_id = bus_group.find_pin_bus(block_name); + BusPinId bus_pin_id = bus_group.find_pin(block_name); + if (bus_id) { + block_name = bus_group.bus_port(bus_id).get_name(); + VTR_ASSERT_SAFE(bus_pin_id); + benchmark_io_port.set_width(bus_group.pin_index(bus_pin_id), bus_group.pin_index(bus_pin_id)); + } else { + benchmark_io_port.set_width(1); + } + if (AtomBlockType::INPAD == atom_ctx.nlist.block_type(atom_blk)) { /* If the port is a clock, do not add a postfix */ if (clock_port_names.end() != std::find(clock_port_names.begin(), clock_port_names.end(), block_name)) { @@ -297,13 +375,11 @@ void print_verilog_testbench_connect_fpga_ios(std::fstream& fp, } else { benchmark_io_port.set_name(std::string(block_name + io_input_port_name_postfix)); } - benchmark_io_port.set_width(1); print_verilog_comment(fp, std::string("----- Blif Benchmark input " + block_name + " is mapped to FPGA IOPAD " + module_mapped_io_port.get_name() + "[" + std::to_string(io_index) + "] -----")); print_verilog_wire_connection(fp, module_mapped_io_port, benchmark_io_port, false); } else { VTR_ASSERT(AtomBlockType::OUTPAD == atom_ctx.nlist.block_type(atom_blk)); benchmark_io_port.set_name(std::string(block_name + io_output_port_name_postfix)); - benchmark_io_port.set_width(1); print_verilog_comment(fp, std::string("----- Blif Benchmark output " + block_name + " is mapped to FPGA IOPAD " + module_mapped_io_port.get_name() + "[" + std::to_string(io_index) + "] -----")); print_verilog_wire_connection(fp, benchmark_io_port, module_mapped_io_port, false); } @@ -487,6 +563,7 @@ void print_verilog_testbench_check(std::fstream& fp, } if (AtomBlockType::OUTPAD == atom_ctx.nlist.block_type(atom_blk)) { + block_name = remove_atom_block_name_prefix(block_name); fp << "\t\t\tif(!(" << block_name << fpga_port_postfix; fp << " === " << block_name << benchmark_port_postfix; fp << ") && !(" << block_name << benchmark_port_postfix; @@ -514,6 +591,7 @@ void print_verilog_testbench_check(std::fstream& fp, if (true == netlist_annotation.is_block_renamed(atom_blk)) { block_name = netlist_annotation.block_name(atom_blk); } + block_name = remove_atom_block_name_prefix(block_name); fp << "\talways@(posedge " << block_name << check_flag_port_postfix << ") begin" << std::endl; fp << "\t\tif(" << block_name << check_flag_port_postfix << ") begin" << std::endl; @@ -621,6 +699,9 @@ void print_verilog_testbench_random_stimuli(std::fstream& fp, if (true == netlist_annotation.is_block_renamed(atom_blk)) { block_name = netlist_annotation.block_name(atom_blk); } + if (AtomBlockType::OUTPAD == atom_ctx.nlist.block_type(atom_blk)) { + block_name = remove_atom_block_name_prefix(block_name); + } /* Bypass clock ports because their stimulus cannot be random */ if (clock_port_names.end() != std::find(clock_port_names.begin(), clock_port_names.end(), block_name)) { @@ -656,6 +737,7 @@ void print_verilog_testbench_random_stimuli(std::fstream& fp, if (true == netlist_annotation.is_block_renamed(atom_blk)) { block_name = netlist_annotation.block_name(atom_blk); } + block_name = remove_atom_block_name_prefix(block_name); /* Each logical block assumes a single-width port */ BasicPort output_port(std::string(block_name + check_flag_port_postfix), 1); @@ -690,6 +772,9 @@ void print_verilog_testbench_random_stimuli(std::fstream& fp, if (true == netlist_annotation.is_block_renamed(atom_blk)) { block_name = netlist_annotation.block_name(atom_blk); } + if (AtomBlockType::OUTPAD == atom_ctx.nlist.block_type(atom_blk)) { + block_name = remove_atom_block_name_prefix(block_name); + } /* Bypass clock ports because their stimulus cannot be random */ if (clock_port_names.end() != std::find(clock_port_names.begin(), clock_port_names.end(), block_name)) { @@ -785,6 +870,7 @@ void print_verilog_testbench_shared_ports(std::fstream& fp, if (true == netlist_annotation.is_block_renamed(atom_blk)) { block_name = netlist_annotation.block_name(atom_blk); } + block_name = remove_atom_block_name_prefix(block_name); /* Each logical block assumes a single-width port */ BasicPort output_port(std::string(block_name + fpga_output_port_postfix), 1); @@ -811,6 +897,7 @@ void print_verilog_testbench_shared_ports(std::fstream& fp, if (true == netlist_annotation.is_block_renamed(atom_blk)) { block_name = netlist_annotation.block_name(atom_blk); } + block_name = remove_atom_block_name_prefix(block_name); /* Each logical block assumes a single-width port */ BasicPort output_port(std::string(block_name + benchmark_output_port_postfix), 1); @@ -833,6 +920,7 @@ void print_verilog_testbench_shared_ports(std::fstream& fp, if (true == netlist_annotation.is_block_renamed(atom_blk)) { block_name = netlist_annotation.block_name(atom_blk); } + block_name = remove_atom_block_name_prefix(block_name); /* Each logical block assumes a single-width port */ BasicPort output_port(std::string(block_name + check_flag_port_postfix), 1); diff --git a/openfpga/src/fpga_verilog/verilog_testbench_utils.h b/openfpga/src/fpga_verilog/verilog_testbench_utils.h index 44816e85b..7803be4d0 100644 --- a/openfpga/src/fpga_verilog/verilog_testbench_utils.h +++ b/openfpga/src/fpga_verilog/verilog_testbench_utils.h @@ -17,6 +17,7 @@ #include "simulation_setting.h" #include "fabric_global_port_info.h" #include "pin_constraints.h" +#include "bus_group.h" /******************************************************************** * Function declaration @@ -38,12 +39,12 @@ void print_verilog_testbench_benchmark_instance(std::fstream& fp, const std::string& module_input_port_postfix, const std::string& module_output_port_postfix, const std::string& input_port_postfix, - const std::vector& output_port_prefix_to_remove, const std::string& output_port_postfix, const std::vector& clock_port_names, const AtomContext& atom_ctx, const VprNetlistAnnotation& netlist_annotation, const PinConstraints& pin_constraints, + const BusGroup& bus_group, const bool& use_explicit_port_map); void print_verilog_testbench_connect_fpga_ios(std::fstream& fp, @@ -53,10 +54,10 @@ void print_verilog_testbench_connect_fpga_ios(std::fstream& fp, const PlacementContext& place_ctx, const IoLocationMap& io_location_map, const VprNetlistAnnotation& netlist_annotation, + const BusGroup& bus_group, const std::string& net_name_postfix, const std::string& io_input_port_name_postfix, const std::string& io_output_port_name_postfix, - const std::vector& output_port_prefix_to_remove, const std::vector& clock_port_names, const size_t& unused_io_value); diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp index d668cb997..689b7f569 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp +++ b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp @@ -937,6 +937,7 @@ void print_verilog_top_testbench_benchmark_instance(std::fstream& fp, const AtomContext& atom_ctx, const VprNetlistAnnotation& netlist_annotation, const PinConstraints& pin_constraints, + const BusGroup& bus_group, const std::vector& clock_port_names, const bool& explicit_port_mapping) { /* Validate the file stream */ @@ -945,22 +946,16 @@ void print_verilog_top_testbench_benchmark_instance(std::fstream& fp, /* Instanciate benchmark */ print_verilog_comment(fp, std::string("----- Reference Benchmark Instanication -------")); - /* Do NOT use explicit port mapping here: - * VPR added a prefix of "out_" to the output ports of input benchmark - */ - std::vector prefix_to_remove; - prefix_to_remove.push_back(std::string(VPR_BENCHMARK_OUT_PORT_PREFIX)); - prefix_to_remove.push_back(std::string(OPENFPGA_BENCHMARK_OUT_PORT_PREFIX)); print_verilog_testbench_benchmark_instance(fp, reference_verilog_top_name, std::string(TOP_TESTBENCH_REFERENCE_INSTANCE_NAME), std::string(), std::string(), std::string(TOP_TESTBENCH_SHARED_INPUT_POSTFIX), - prefix_to_remove, std::string(TOP_TESTBENCH_REFERENCE_OUTPUT_POSTFIX), clock_port_names, atom_ctx, netlist_annotation, pin_constraints, + bus_group, explicit_port_mapping); print_verilog_comment(fp, std::string("----- End reference Benchmark Instanication -------")); @@ -1924,6 +1919,7 @@ int print_verilog_full_testbench(const ModuleManager& module_manager, const AtomContext& atom_ctx, const PlacementContext& place_ctx, const PinConstraints& pin_constraints, + const BusGroup& bus_group, const std::string& bitstream_file, const IoLocationMap& io_location_map, const VprNetlistAnnotation& netlist_annotation, @@ -2064,10 +2060,10 @@ int print_verilog_full_testbench(const ModuleManager& module_manager, print_verilog_testbench_connect_fpga_ios(fp, module_manager, top_module, atom_ctx, place_ctx, io_location_map, netlist_annotation, + BusGroup(), std::string(), std::string(TOP_TESTBENCH_SHARED_INPUT_POSTFIX), std::string(TOP_TESTBENCH_FPGA_OUTPUT_POSTFIX), - std::vector(), clock_port_names, (size_t)VERILOG_DEFAULT_SIGNAL_INIT_VALUE); @@ -2078,6 +2074,7 @@ int print_verilog_full_testbench(const ModuleManager& module_manager, atom_ctx, netlist_annotation, pin_constraints, + bus_group, clock_port_names, explicit_port_mapping); } diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench.h b/openfpga/src/fpga_verilog/verilog_top_testbench.h index bbad08125..51f71fee7 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench.h +++ b/openfpga/src/fpga_verilog/verilog_top_testbench.h @@ -19,6 +19,7 @@ #include "simulation_setting.h" #include "memory_bank_shift_register_banks.h" #include "verilog_testbench_options.h" +#include "bus_group.h" /******************************************************************** * Function declaration @@ -37,6 +38,7 @@ int print_verilog_full_testbench(const ModuleManager& module_manager, const AtomContext& atom_ctx, const PlacementContext& place_ctx, const PinConstraints& pin_constraints, + const BusGroup& bus_group, const std::string& bitstream_file, const IoLocationMap& io_location_map, const VprNetlistAnnotation& netlist_annotation, diff --git a/openfpga/src/utils/openfpga_atom_netlist_utils.cpp b/openfpga/src/utils/openfpga_atom_netlist_utils.cpp index 8d1876f90..9539a7c91 100644 --- a/openfpga/src/utils/openfpga_atom_netlist_utils.cpp +++ b/openfpga/src/utils/openfpga_atom_netlist_utils.cpp @@ -11,6 +11,7 @@ /* Headers from vtrutil library */ #include "atom_netlist_utils.h" +#include "openfpga_reserved_words.h" #include "openfpga_atom_netlist_utils.h" /* begin namespace openfpga */ @@ -38,4 +39,27 @@ std::vector find_atom_netlist_clock_port_names(const AtomNetlist& a return clock_names; } +/******************************************************************** + * Remove the prefix that is added to the name of a output block (by VPR) + *******************************************************************/ +std::string remove_atom_block_name_prefix(const std::string& block_name) { + /* VPR added a prefix of "out_" to the output ports of input benchmark */ + std::vector prefix_to_remove; + prefix_to_remove.push_back(std::string(VPR_BENCHMARK_OUT_PORT_PREFIX)); + prefix_to_remove.push_back(std::string(OPENFPGA_BENCHMARK_OUT_PORT_PREFIX)); + + std::string ret_block_name = block_name; + + for (const std::string& cur_prefix_to_remove : prefix_to_remove) { + if (!cur_prefix_to_remove.empty()) { + if (0 == ret_block_name.find(cur_prefix_to_remove)) { + ret_block_name.erase(0, cur_prefix_to_remove.length()); + break; + } + } + } + + return ret_block_name; +} + } /* end namespace openfpga */ diff --git a/openfpga/src/utils/openfpga_atom_netlist_utils.h b/openfpga/src/utils/openfpga_atom_netlist_utils.h index dfa5743a2..3ddad6a93 100644 --- a/openfpga/src/utils/openfpga_atom_netlist_utils.h +++ b/openfpga/src/utils/openfpga_atom_netlist_utils.h @@ -19,6 +19,8 @@ namespace openfpga { std::vector find_atom_netlist_clock_port_names(const AtomNetlist& atom_nlist, const VprNetlistAnnotation& netlist_annotation); +std::string remove_atom_block_name_prefix(const std::string& block_name); + } /* end namespace openfpga */ #endif diff --git a/openfpga_flow/misc/ys_tmpl_yosys_vpr_flow_with_rewrite.ys b/openfpga_flow/misc/ys_tmpl_yosys_vpr_flow_with_rewrite.ys index 2dd4ab695..9083f7344 100644 --- a/openfpga_flow/misc/ys_tmpl_yosys_vpr_flow_with_rewrite.ys +++ b/openfpga_flow/misc/ys_tmpl_yosys_vpr_flow_with_rewrite.ys @@ -39,3 +39,4 @@ synth -run check # Clean and output blif opt_clean -purge write_blif rewritten_${OUTPUT_BLIF} +write_verilog ${OUTPUT_VERILOG} diff --git a/openfpga_flow/openfpga_shell_scripts/full_testbench_bus_group_example_script.openfpga b/openfpga_flow/openfpga_shell_scripts/full_testbench_bus_group_example_script.openfpga new file mode 100644 index 000000000..b44f1a3bd --- /dev/null +++ b/openfpga_flow/openfpga_shell_scripts/full_testbench_bus_group_example_script.openfpga @@ -0,0 +1,64 @@ +# Run VPR for the 'and' design +#--write_rr_graph example_rr_graph.xml +vpr ${VPR_ARCH_FILE} ${VPR_TESTBENCH_BLIF} --clock_modeling ideal + +# Read OpenFPGA architecture definition +read_openfpga_arch -f ${OPENFPGA_ARCH_FILE} + +# Read OpenFPGA simulation settings +read_openfpga_simulation_setting -f ${OPENFPGA_SIM_SETTING_FILE} + +# Annotate the OpenFPGA architecture to VPR data base +# to debug use --verbose options +link_openfpga_arch --sort_gsb_chan_node_in_edges + +# Check and correct any naming conflicts in the BLIF netlist +check_netlist_naming_conflict --fix --report ./netlist_renaming.xml + +# Apply fix-up to clustering nets based on routing results +pb_pin_fixup --verbose + +# Apply fix-up to Look-Up Table truth tables based on packing results +lut_truth_table_fixup + +# Build the module graph +# - Enabled compression on routing architecture modules +# - Enable pin duplication on grid modules +build_fabric --compress_routing #--verbose + +# Write the fabric hierarchy of module graph to a file +# This is used by hierarchical PnR flows +write_fabric_hierarchy --file ./fabric_hierarchy.txt + +# Repack the netlist to physical pbs +# This must be done before bitstream generator and testbench generation +# Strongly recommend it is done after all the fix-up have been applied +repack #--verbose + +# Build the bitstream +# - Output the fabric-independent bitstream to a file +build_architecture_bitstream --verbose --write_file fabric_independent_bitstream.xml + +# Build fabric-dependent bitstream +build_fabric_bitstream --verbose + +# Write fabric-dependent bitstream +write_fabric_bitstream --file fabric_bitstream.bit --format plain_text + +# Write the Verilog netlist for FPGA fabric +# - Enable the use of explicit port mapping in Verilog netlist +write_fabric_verilog --file ./SRC --explicit_port_mapping --include_timing --verbose + +# Write the Verilog testbench for FPGA fabric +# - 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_full_testbench --file ./SRC --reference_benchmark_file_path ${REFERENCE_VERILOG_TESTBENCH} ${OPENFPGA_VERILOG_PORT_MAPPING} --include_signal_init --bitstream fabric_bitstream.bit --pin_constraints_file ${OPENFPGA_PIN_CONSTRAINTS_FILE} --bus_group_file ${OPENFPGA_BUS_GROUP_FILE} + +# Finish and exit OpenFPGA +exit + +# Note : +# To run verification at the end of the flow maintain source in ./SRC directory diff --git a/openfpga_flow/openfpga_shell_scripts/preconfigured_testbench_bus_group_example_script.openfpga b/openfpga_flow/openfpga_shell_scripts/preconfigured_testbench_bus_group_example_script.openfpga new file mode 100644 index 000000000..a85b8e24c --- /dev/null +++ b/openfpga_flow/openfpga_shell_scripts/preconfigured_testbench_bus_group_example_script.openfpga @@ -0,0 +1,65 @@ +# Run VPR for the 'and' design +#--write_rr_graph example_rr_graph.xml +vpr ${VPR_ARCH_FILE} ${VPR_TESTBENCH_BLIF} --clock_modeling ideal + +# Read OpenFPGA architecture definition +read_openfpga_arch -f ${OPENFPGA_ARCH_FILE} + +# Read OpenFPGA simulation settings +read_openfpga_simulation_setting -f ${OPENFPGA_SIM_SETTING_FILE} + +# Annotate the OpenFPGA architecture to VPR data base +# to debug use --verbose options +link_openfpga_arch --sort_gsb_chan_node_in_edges + +# Check and correct any naming conflicts in the BLIF netlist +check_netlist_naming_conflict --fix --report ./netlist_renaming.xml + +# Apply fix-up to clustering nets based on routing results +pb_pin_fixup --verbose + +# Apply fix-up to Look-Up Table truth tables based on packing results +lut_truth_table_fixup + +# Build the module graph +# - Enabled compression on routing architecture modules +# - Enable pin duplication on grid modules +build_fabric --compress_routing #--verbose + +# Write the fabric hierarchy of module graph to a file +# This is used by hierarchical PnR flows +write_fabric_hierarchy --file ./fabric_hierarchy.txt + +# Repack the netlist to physical pbs +# This must be done before bitstream generator and testbench generation +# Strongly recommend it is done after all the fix-up have been applied +repack #--verbose + +# Build the bitstream +# - Output the fabric-independent bitstream to a file +build_architecture_bitstream --verbose --write_file fabric_independent_bitstream.xml + +# Build fabric-dependent bitstream +build_fabric_bitstream --verbose + +# Write fabric-dependent bitstream +write_fabric_bitstream --file fabric_bitstream.bit --format plain_text + +# Write the Verilog netlist for FPGA fabric +# - Enable the use of explicit port mapping in Verilog netlist +write_fabric_verilog --file ./SRC --explicit_port_mapping --include_timing --verbose + +# Write the Verilog testbench for FPGA fabric +# - 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_preconfigured_fabric_wrapper --embed_bitstream iverilog --file ./SRC ${OPENFPGA_VERILOG_PORT_MAPPING} --pin_constraints_file ${OPENFPGA_PIN_CONSTRAINTS_FILE} --bus_group_file ${OPENFPGA_BUS_GROUP_FILE} +write_preconfigured_testbench --file ./SRC --reference_benchmark_file_path ${REFERENCE_VERILOG_TESTBENCH} ${OPENFPGA_VERILOG_PORT_MAPPING} --pin_constraints_file ${OPENFPGA_PIN_CONSTRAINTS_FILE} --bus_group_file ${OPENFPGA_BUS_GROUP_FILE} + +# Finish and exit OpenFPGA +exit + +# Note : +# To run verification at the end of the flow maintain source in ./SRC directory diff --git a/openfpga_flow/regression_test_scripts/basic_reg_test.sh b/openfpga_flow/regression_test_scripts/basic_reg_test.sh index b8261b501..bab6c6256 100755 --- a/openfpga_flow/regression_test_scripts/basic_reg_test.sh +++ b/openfpga_flow/regression_test_scripts/basic_reg_test.sh @@ -166,3 +166,9 @@ run-task basic_tests/write_gsb/write_gsb_to_xml --debug --show_thread_logs run-task basic_tests/write_gsb/write_gsb_to_xml_compress_routing --debug --show_thread_logs run-task basic_tests/write_gsb/write_unique_gsb_to_xml --debug --show_thread_logs run-task basic_tests/write_gsb/write_unique_gsb_to_xml_compress_routing --debug --show_thread_logs + +echo -e "Testing bus group features"; +run-task basic_tests/bus_group/preconfig_testbench_explicit_mapping --debug --show_thread_logs +run-task basic_tests/bus_group/preconfig_testbench_implicit_mapping --debug --show_thread_logs +run-task basic_tests/bus_group/full_testbench_explicit_mapping --debug --show_thread_logs +run-task basic_tests/bus_group/full_testbench_implicit_mapping --debug --show_thread_logs diff --git a/openfpga_flow/tasks/basic_tests/bus_group/full_testbench_explicit_mapping/config/counter8_bus_group.xml b/openfpga_flow/tasks/basic_tests/bus_group/full_testbench_explicit_mapping/config/counter8_bus_group.xml new file mode 100644 index 000000000..51dccca71 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/bus_group/full_testbench_explicit_mapping/config/counter8_bus_group.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/openfpga_flow/tasks/basic_tests/bus_group/full_testbench_explicit_mapping/config/pin_constraints_reset.xml b/openfpga_flow/tasks/basic_tests/bus_group/full_testbench_explicit_mapping/config/pin_constraints_reset.xml new file mode 100644 index 000000000..abcf209f6 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/bus_group/full_testbench_explicit_mapping/config/pin_constraints_reset.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/openfpga_flow/tasks/basic_tests/bus_group/full_testbench_explicit_mapping/config/task.conf b/openfpga_flow/tasks/basic_tests/bus_group/full_testbench_explicit_mapping/config/task.conf new file mode 100644 index 000000000..adfb12dc1 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/bus_group/full_testbench_explicit_mapping/config/task.conf @@ -0,0 +1,47 @@ +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# 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/full_testbench_bus_group_example_script.openfpga +openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_dpram8K_dsp36_fracff_40nm_openfpga.xml +openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/fixed_sim_openfpga.xml +openfpga_verilog_port_mapping=--explicit_port_mapping +openfpga_bus_group_file=${PATH:TASK_DIR}/config/counter8_bus_group.xml + +[ARCHITECTURES] +arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_fracff_40nm.xml + +[BENCHMARKS] +bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/counters/counter_8bit_async_reset/counter.v + +[SYNTHESIS_PARAM] +# Yosys script parameters +bench_yosys_cell_sim_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_fracff_40nm_cell_sim.v +bench_yosys_dff_map_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_fracff_40nm_dff_map.v +bench_yosys_bram_map_rules_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_40nm_bram.txt +bench_yosys_bram_map_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_40nm_bram_map.v +bench_yosys_dsp_map_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_40nm_dsp_map.v +bench_yosys_dsp_map_parameters_common=-D DSP_A_MAXWIDTH=36 -D DSP_B_MAXWIDTH=36 -D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 -D DSP_NAME=mult_36x36 +bench_read_verilog_options_common = -nolatches +bench_yosys_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_dff_flow.ys +bench_yosys_rewrite_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_flow_with_rewrite.ys + +bench0_top = counter +bench0_openfpga_pin_constraints_file=${PATH:TASK_DIR}/config/pin_constraints_reset.xml + +[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH] +end_flow_with_test= diff --git a/openfpga_flow/tasks/basic_tests/bus_group/full_testbench_implicit_mapping/config/counter8_bus_group.xml b/openfpga_flow/tasks/basic_tests/bus_group/full_testbench_implicit_mapping/config/counter8_bus_group.xml new file mode 100644 index 000000000..51dccca71 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/bus_group/full_testbench_implicit_mapping/config/counter8_bus_group.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/openfpga_flow/tasks/basic_tests/bus_group/full_testbench_implicit_mapping/config/pin_constraints_reset.xml b/openfpga_flow/tasks/basic_tests/bus_group/full_testbench_implicit_mapping/config/pin_constraints_reset.xml new file mode 100644 index 000000000..abcf209f6 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/bus_group/full_testbench_implicit_mapping/config/pin_constraints_reset.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/openfpga_flow/tasks/basic_tests/bus_group/full_testbench_implicit_mapping/config/task.conf b/openfpga_flow/tasks/basic_tests/bus_group/full_testbench_implicit_mapping/config/task.conf new file mode 100644 index 000000000..2ecda7275 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/bus_group/full_testbench_implicit_mapping/config/task.conf @@ -0,0 +1,47 @@ +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# 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/full_testbench_bus_group_example_script.openfpga +openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_dpram8K_dsp36_fracff_40nm_openfpga.xml +openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/fixed_sim_openfpga.xml +openfpga_verilog_port_mapping= +openfpga_bus_group_file=${PATH:TASK_DIR}/config/counter8_bus_group.xml + +[ARCHITECTURES] +arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_fracff_40nm.xml + +[BENCHMARKS] +bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/counters/counter_8bit_async_reset/counter.v + +[SYNTHESIS_PARAM] +# Yosys script parameters +bench_yosys_cell_sim_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_fracff_40nm_cell_sim.v +bench_yosys_dff_map_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_fracff_40nm_dff_map.v +bench_yosys_bram_map_rules_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_40nm_bram.txt +bench_yosys_bram_map_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_40nm_bram_map.v +bench_yosys_dsp_map_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_40nm_dsp_map.v +bench_yosys_dsp_map_parameters_common=-D DSP_A_MAXWIDTH=36 -D DSP_B_MAXWIDTH=36 -D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 -D DSP_NAME=mult_36x36 +bench_read_verilog_options_common = -nolatches +bench_yosys_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_dff_flow.ys +bench_yosys_rewrite_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_flow_with_rewrite.ys + +bench0_top = counter +bench0_openfpga_pin_constraints_file=${PATH:TASK_DIR}/config/pin_constraints_reset.xml + +[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH] +end_flow_with_test= diff --git a/openfpga_flow/tasks/basic_tests/bus_group/preconfig_testbench_explicit_mapping/config/counter8_bus_group.xml b/openfpga_flow/tasks/basic_tests/bus_group/preconfig_testbench_explicit_mapping/config/counter8_bus_group.xml new file mode 100644 index 000000000..51dccca71 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/bus_group/preconfig_testbench_explicit_mapping/config/counter8_bus_group.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/openfpga_flow/tasks/basic_tests/bus_group/preconfig_testbench_explicit_mapping/config/pin_constraints_reset.xml b/openfpga_flow/tasks/basic_tests/bus_group/preconfig_testbench_explicit_mapping/config/pin_constraints_reset.xml new file mode 100644 index 000000000..abcf209f6 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/bus_group/preconfig_testbench_explicit_mapping/config/pin_constraints_reset.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/openfpga_flow/tasks/basic_tests/bus_group/preconfig_testbench_explicit_mapping/config/task.conf b/openfpga_flow/tasks/basic_tests/bus_group/preconfig_testbench_explicit_mapping/config/task.conf new file mode 100644 index 000000000..92892a530 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/bus_group/preconfig_testbench_explicit_mapping/config/task.conf @@ -0,0 +1,48 @@ +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# 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/preconfigured_testbench_bus_group_example_script.openfpga +openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_dpram8K_dsp36_fracff_40nm_openfpga.xml +openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/fixed_sim_openfpga.xml +openfpga_verilog_port_mapping=--explicit_port_mapping +openfpga_bus_group_file=${PATH:TASK_DIR}/config/counter8_bus_group.xml + +[ARCHITECTURES] +arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_fracff_40nm.xml + +[BENCHMARKS] +bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/counters/counter_8bit_async_reset/counter.v + +[SYNTHESIS_PARAM] +# Yosys script parameters +bench_yosys_cell_sim_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_fracff_40nm_cell_sim.v +bench_yosys_dff_map_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_fracff_40nm_dff_map.v +bench_yosys_bram_map_rules_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_40nm_bram.txt +bench_yosys_bram_map_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_40nm_bram_map.v +bench_yosys_dsp_map_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_40nm_dsp_map.v +bench_yosys_dsp_map_parameters_common=-D DSP_A_MAXWIDTH=36 -D DSP_B_MAXWIDTH=36 -D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 -D DSP_NAME=mult_36x36 +bench_read_verilog_options_common = -nolatches +bench_yosys_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_dff_flow.ys +bench_yosys_rewrite_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_flow_with_rewrite.ys + +bench0_top = counter +bench0_openfpga_pin_constraints_file=${PATH:TASK_DIR}/config/pin_constraints_reset.xml + +[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH] +end_flow_with_test= +vpr_fpga_verilog_formal_verification_top_netlist= diff --git a/openfpga_flow/tasks/basic_tests/bus_group/preconfig_testbench_implicit_mapping/config/counter8_bus_group.xml b/openfpga_flow/tasks/basic_tests/bus_group/preconfig_testbench_implicit_mapping/config/counter8_bus_group.xml new file mode 100644 index 000000000..51dccca71 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/bus_group/preconfig_testbench_implicit_mapping/config/counter8_bus_group.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/openfpga_flow/tasks/basic_tests/bus_group/preconfig_testbench_implicit_mapping/config/pin_constraints_reset.xml b/openfpga_flow/tasks/basic_tests/bus_group/preconfig_testbench_implicit_mapping/config/pin_constraints_reset.xml new file mode 100644 index 000000000..abcf209f6 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/bus_group/preconfig_testbench_implicit_mapping/config/pin_constraints_reset.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/openfpga_flow/tasks/basic_tests/bus_group/preconfig_testbench_implicit_mapping/config/task.conf b/openfpga_flow/tasks/basic_tests/bus_group/preconfig_testbench_implicit_mapping/config/task.conf new file mode 100644 index 000000000..23af1199a --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/bus_group/preconfig_testbench_implicit_mapping/config/task.conf @@ -0,0 +1,48 @@ +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# 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/preconfigured_testbench_bus_group_example_script.openfpga +openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_dpram8K_dsp36_fracff_40nm_openfpga.xml +openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/fixed_sim_openfpga.xml +openfpga_verilog_port_mapping= +openfpga_bus_group_file=${PATH:TASK_DIR}/config/counter8_bus_group.xml + +[ARCHITECTURES] +arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_fracff_40nm.xml + +[BENCHMARKS] +bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/counters/counter_8bit_async_reset/counter.v + +[SYNTHESIS_PARAM] +# Yosys script parameters +bench_yosys_cell_sim_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_fracff_40nm_cell_sim.v +bench_yosys_dff_map_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_fracff_40nm_dff_map.v +bench_yosys_bram_map_rules_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_40nm_bram.txt +bench_yosys_bram_map_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_40nm_bram_map.v +bench_yosys_dsp_map_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_40nm_dsp_map.v +bench_yosys_dsp_map_parameters_common=-D DSP_A_MAXWIDTH=36 -D DSP_B_MAXWIDTH=36 -D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 -D DSP_NAME=mult_36x36 +bench_read_verilog_options_common = -nolatches +bench_yosys_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_dff_flow.ys +bench_yosys_rewrite_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_flow_with_rewrite.ys + +bench0_top = counter +bench0_openfpga_pin_constraints_file=${PATH:TASK_DIR}/config/pin_constraints_reset.xml + +[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH] +end_flow_with_test= +vpr_fpga_verilog_formal_verification_top_netlist=