diff --git a/libopenfpga/libpcf/CMakeLists.txt b/libopenfpga/libpcf/CMakeLists.txt new file mode 100644 index 000000000..8287bb3bc --- /dev/null +++ b/libopenfpga/libpcf/CMakeLists.txt @@ -0,0 +1,35 @@ +cmake_minimum_required(VERSION 3.9) + +project("libpcf") + +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(libpcf STATIC + ${LIB_HEADERS} + ${LIB_SOURCES}) +target_include_directories(libpcf PUBLIC ${LIB_INCLUDE_DIRS}) +set_target_properties(libpcf PROPERTIES PREFIX "") #Avoid extra 'lib' prefix + +#Specify link-time dependancies +target_link_libraries(libpcf + 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} libpcf) +endforeach(testsourcefile ${EXEC_SOURCES}) diff --git a/libopenfpga/libpcf/example/fpga_io_nets.xml b/libopenfpga/libpcf/example/fpga_io_nets.xml new file mode 100644 index 000000000..90523a274 --- /dev/null +++ b/libopenfpga/libpcf/example/fpga_io_nets.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/libopenfpga/libpcf/src/pin_constraints.cpp b/libopenfpga/libpcf/src/pin_constraints.cpp new file mode 100644 index 000000000..4f7a701a7 --- /dev/null +++ b/libopenfpga/libpcf/src/pin_constraints.cpp @@ -0,0 +1,72 @@ +#include + +#include "vtr_assert.h" +#include "vtr_log.h" + +#include "pin_constraints.h" + +/************************************************************************ + * Member functions for class PinConstraints + ***********************************************************************/ + +/************************************************************************ + * Constructors + ***********************************************************************/ +PinConstraints::PinConstraints() { + return; +} + +/************************************************************************ + * Public Accessors : aggregates + ***********************************************************************/ +PinConstraints::pin_constraint_range PinConstraints::pin_constraints() const { + return vtr::make_range(pin_constraint_ids_.begin(), pin_constraint_ids_.end()); +} + +/************************************************************************ + * Public Accessors : Basic data query + ***********************************************************************/ +openfpga::BasicPort PinConstraints::pin(const PinConstraintId& pin_constraint_id) const { + /* validate the pin_constraint_id */ + VTR_ASSERT(valid_pin_constraint_id(pin_constraint_id)); + return pin_constraint_pins_[pin_constraint_id]; +} + +std::string PinConstraints::net(const PinConstraintId& pin_constraint_id) const { + /* validate the pin_constraint_id */ + VTR_ASSERT(valid_pin_constraint_id(pin_constraint_id)); + return pin_constraint_nets_[pin_constraint_id]; +} + +bool PinConstraints::empty() const { + return 0 == pin_constraint_ids_.size(); +} + +/************************************************************************ + * Public Mutators + ***********************************************************************/ +void PinConstraints::reserve_pin_constraints(const size_t& num_pin_constraints) { + pin_constraint_ids_.reserve(num_pin_constraints); + pin_constraint_pins_.reserve(num_pin_constraints); + pin_constraint_nets_.reserve(num_pin_constraints); +} + +PinConstraintId PinConstraints::create_pin_constraint(const openfpga::BasicPort& pin, + const std::string& net) { + /* Create a new id */ + PinConstraintId pin_constraint_id = PinConstraintId(pin_constraint_ids_.size()); + + pin_constraint_ids_.push_back(pin_constraint_id); + pin_constraint_pins_.push_back(pin); + pin_constraint_nets_.push_back(net); + + return pin_constraint_id; +} + +/************************************************************************ + * Internal invalidators/validators + ***********************************************************************/ +/* Validators */ +bool PinConstraints::valid_pin_constraint_id(const PinConstraintId& pin_constraint_id) const { + return ( size_t(pin_constraint_id) < pin_constraint_ids_.size() ) && ( pin_constraint_id == pin_constraint_ids_[pin_constraint_id] ); +} diff --git a/libopenfpga/libpcf/src/pin_constraints.h b/libopenfpga/libpcf/src/pin_constraints.h new file mode 100644 index 000000000..487eec22a --- /dev/null +++ b/libopenfpga/libpcf/src/pin_constraints.h @@ -0,0 +1,77 @@ +#ifndef PIN_CONSTRAINTS_H +#define PIN_CONSTRAINTS_H + +/******************************************************************** + * This file include the declaration of pin constraints + *******************************************************************/ +#include +#include +#include + +/* Headers from vtrutil library */ +#include "vtr_vector.h" +#include "vtr_geometry.h" + +/* Headers from openfpgautil library */ +#include "openfpga_port.h" + +#include "pin_constraints_fwd.h" + +/******************************************************************** + * A data structure to describe the pin constraints for FPGA fabrics + * This data structure may include a number of pin constraints + * each of which may constrain: + * - pin assignment, for instance, force a net to be mapped to specific pin + * + * Typical usage: + * -------------- + * // Create an object of pin constraints + * PinConstraints pin_constraints; + * // Add a pin assignment + * openfpga::BasicPort pin_info(clk, 1); + * std::string net_info("top_clock"); + * PinConstraintId pin_constraint_id = pin_constraints.create_pin_constraint(pin_info, net_info); + * + *******************************************************************/ +class PinConstraints { + public: /* Types */ + typedef vtr::vector::const_iterator pin_constraint_iterator; + /* Create range */ + typedef vtr::Range pin_constraint_range; + public: /* Constructors */ + PinConstraints(); + public: /* Accessors: aggregates */ + pin_constraint_range pin_constraints() const; + public: /* Public Accessors: Basic data query */ + /* Get the pin to be constrained */ + openfpga::BasicPort pin(const PinConstraintId& pin_constraint_id) const; + + /* Get the net to be constrained */ + std::string net(const PinConstraintId& pin_constraint_id) const; + + /* Check if there are any pin constraints */ + bool empty() const; + + public: /* Public Mutators */ + + /* Reserve a number of design constraints to be memory efficent */ + void reserve_pin_constraints(const size_t& num_pin_constraints); + + /* Add a pin constraint to storage */ + PinConstraintId create_pin_constraint(const openfpga::BasicPort& pin, + const std::string& net); + + public: /* Public invalidators/validators */ + bool valid_pin_constraint_id(const PinConstraintId& pin_constraint_id) const; + private: /* Internal data */ + /* Unique ids for each design constraint */ + vtr::vector pin_constraint_ids_; + + /* Pins to constraint */ + vtr::vector pin_constraint_pins_; + + /* Nets to constraint */ + vtr::vector pin_constraint_nets_; +}; + +#endif diff --git a/libopenfpga/libpcf/src/pin_constraints_fwd.h b/libopenfpga/libpcf/src/pin_constraints_fwd.h new file mode 100644 index 000000000..245e72ff3 --- /dev/null +++ b/libopenfpga/libpcf/src/pin_constraints_fwd.h @@ -0,0 +1,22 @@ +/************************************************************************ + * A header file for PinConstraints class, including critical data declaration + * Please include this file only for using any PinConstraints data structure + * Refer to pin_constraints.h for more details + ***********************************************************************/ + +/************************************************************************ + * Create strong id for PinConstraints to avoid illegal type casting + ***********************************************************************/ +#ifndef PIN_CONSTRAINTS_FWD_H +#define PIN_CONSTRAINTS_FWD_H + +#include "vtr_strong_id.h" + +struct pin_constraint_id_tag; + +typedef vtr::StrongId PinConstraintId; + +/* Short declaration of class */ +class PinConstraints; + +#endif diff --git a/libopenfpga/libpcf/src/read_xml_pin_constraints.cpp b/libopenfpga/libpcf/src/read_xml_pin_constraints.cpp new file mode 100644 index 000000000..b0c662da5 --- /dev/null +++ b/libopenfpga/libpcf/src/read_xml_pin_constraints.cpp @@ -0,0 +1,82 @@ +/******************************************************************** + * This file includes the top-level function of this library + * which reads an XML of pin constraints 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 "read_xml_pin_constraints.h" + +/******************************************************************** + * Parse XML codes of a to an object of PinConstraint + *******************************************************************/ +static +void read_xml_pin_constraint(pugi::xml_node& xml_pin_constraint, + const pugiutil::loc_data& loc_data, + PinConstraints& pin_constraints) { + + openfpga::PortParser port_parser(get_attribute(xml_pin_constraint, "pin", loc_data).as_string()); + + std::string net_name = get_attribute(xml_pin_constraint, "net", loc_data).as_string(); + + /* Create a new pin constraint in the storage */ + PinConstraintId pin_constraint_id = pin_constraints.create_pin_constraint(port_parser.port(), net_name); + + if (false == pin_constraints.valid_pin_constraint_id(pin_constraint_id)) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_pin_constraint), + "Fail to create pin constraint!\n"); + } +} + +/******************************************************************** + * Parse XML codes about to an object of PinConstraints + *******************************************************************/ +PinConstraints read_xml_pin_constraints(const char* pin_constraint_fname) { + + vtr::ScopedStartFinishTimer timer("Read Pin Constraints"); + + PinConstraints pin_constraints; + + /* Parse the file */ + pugi::xml_document doc; + pugiutil::loc_data loc_data; + + try { + loc_data = pugiutil::load_xml(doc, pin_constraint_fname); + + pugi::xml_node xml_root = get_single_child(doc, "pin_constraints", loc_data); + + size_t num_pin_constraints = std::distance(xml_root.children().begin(), xml_root.children().end()); + /* Reserve memory space for the region */ + pin_constraints.reserve_pin_constraints(num_pin_constraints); + + for (pugi::xml_node xml_pin_constraint : xml_root.children()) { + /* Error out if the XML child has an invalid name! */ + if (xml_pin_constraint.name() != std::string("set_io")) { + bad_tag(xml_pin_constraint, loc_data, xml_root, {"set_io"}); + } + read_xml_pin_constraint(xml_pin_constraint, loc_data, pin_constraints); + } + } catch (pugiutil::XmlError& e) { + archfpga_throw(pin_constraint_fname, e.line(), + "%s", e.what()); + } + + return pin_constraints; +} + diff --git a/libopenfpga/libpcf/src/read_xml_pin_constraints.h b/libopenfpga/libpcf/src/read_xml_pin_constraints.h new file mode 100644 index 000000000..45065be26 --- /dev/null +++ b/libopenfpga/libpcf/src/read_xml_pin_constraints.h @@ -0,0 +1,16 @@ +#ifndef READ_XML_PIN_CONSTRAINTS_H +#define READ_XML_PIN_CONSTRAINTS_H + +/******************************************************************** + * Include header files that are required by function declaration + *******************************************************************/ +#include "pugixml_util.hpp" +#include "pugixml.hpp" +#include "pin_constraints.h" + +/******************************************************************** + * Function declaration + *******************************************************************/ +PinConstraints read_xml_pin_constraints(const char* pin_constraint_fname); + +#endif diff --git a/libopenfpga/libpcf/src/write_xml_pin_constraints.cpp b/libopenfpga/libpcf/src/write_xml_pin_constraints.cpp new file mode 100644 index 000000000..ba471fb0c --- /dev/null +++ b/libopenfpga/libpcf/src/write_xml_pin_constraints.cpp @@ -0,0 +1,94 @@ +/******************************************************************** + * This file includes functions that outputs a pin constraint 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 "write_xml_pin_constraints.h" + +/******************************************************************** + * A writer to output a pin constraint 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_io_constraint(std::fstream& fp, + const PinConstraints& pin_constraints, + const PinConstraintId& pin_constraint) { + /* Validate the file stream */ + if (false == openfpga::valid_file_stream(fp)) { + return 2; + } + + openfpga::write_tab_to_file(fp, 1); + fp << "" << "\n"; + + return 0; +} + +/******************************************************************** + * A writer to output a repack pin constraint 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_pin_constraints(const char* fname, + const PinConstraints& pin_constraints) { + + vtr::ScopedStartFinishTimer timer("Write Pin Constraints"); + + /* 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 << "" << "\n"; + + int err_code = 0; + + /* Write region by region */ + for (const PinConstraintId& pin_constraint : pin_constraints.pin_constraints()) { + /* Write constraint by constraint */ + err_code = write_xml_pin_constraint(fp, pin_constraints, pin_constraint); + if (0 != err_code) { + return err_code; + } + } + + /* Finish writing the root node */ + fp << "" << "\n"; + + /* Close the file stream */ + fp.close(); + + return err_code; +} diff --git a/libopenfpga/libpcf/src/write_xml_pin_constraints.h b/libopenfpga/libpcf/src/write_xml_pin_constraints.h new file mode 100644 index 000000000..c68b072b9 --- /dev/null +++ b/libopenfpga/libpcf/src/write_xml_pin_constraints.h @@ -0,0 +1,16 @@ +#ifndef WRITE_XML_PIN_CONSTRAINTS_H +#define WRITE_XML_PIN_CONSTRAINTS_H + +/******************************************************************** + * Include header files that are required by function declaration + *******************************************************************/ +#include +#include "pin_constraints.h" + +/******************************************************************** + * Function declaration + *******************************************************************/ +int write_xml_pin_constraints(const char* fname, + const PinConstraints& pin_constraints); + +#endif diff --git a/libopenfpga/libpcf/test/test_xml_pcf.cpp b/libopenfpga/libpcf/test/test_xml_pcf.cpp new file mode 100644 index 000000000..da91ddbcc --- /dev/null +++ b/libopenfpga/libpcf/test/test_xml_pcf.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 fabric key */ +#include "read_xml_pin_constraints.h" +#include "write_xml_pin_constraints.h" + +int main(int argc, const char** argv) { + /* Ensure we have only one or two argument */ + VTR_ASSERT((2 == argc) || (3 == argc)); + + /* Parse the fabric key from an XML file */ + PinConstraints pin_constraints = read_xml_pin_constraints(argv[1]); + VTR_LOG("Read the pin constraints from an XML file: %s.\n", + argv[1]); + + /* Output pin constraints to an XML file + * This is optional only used when there is a second argument + */ + if (3 <= argc) { + write_xml_pin_constraints(argv[2], pin_constraints); + VTR_LOG("Echo the pin constraints to an XML file: %s.\n", + argv[2]); + } +} + +