Merge pull request #122 from LNIS-Projects/dev

Support Global Port Definition for Physical Tile Ports
This commit is contained in:
Laboratory for Nano Integrated Systems (LNIS) 2020-11-11 16:16:32 -07:00 committed by GitHub
commit 2af49c245f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 2136 additions and 248 deletions

View File

@ -106,4 +106,7 @@ python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/tile_organization/top
echo -e "Testing tiles with pins only on bottom and right sides";
python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/tile_organization/bottom_right_custom_pins --debug --show_thread_logs
echo -e "Testing global port definition from tiles";
python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/global_tile_ports/global_tile_clock --debug --show_thread_logs
end_section "OpenFPGA.TaskTun"

View File

@ -49,6 +49,43 @@ Similar to the Switch Boxes and Connection Blocks, the channel wire segments in
- ``circuit_model_name="<string>"`` should match a circuit model whose type is ``chan_wire`` defined in :ref:`circuit_library`.
Physical Tile Annotation
~~~~~~~~~~~~~~~~~~~~~~~~
Original VPR architecture description contains ``<tile>`` XML nodes to define physical tile pins.
OpenFPGA allows users to define pin/port of physical tiles as global ports.
Here is an example:
.. code-block:: xml
<tile_annotations>
<global_port name="<string>" tile_port="<string>" is_clock="<bool>" is_reset="<bool>" is_set="<bool>"/>
</tile_annotations>
- ``name="<string>"`` is the port name to appear in the top-level FPGA fabric.
- ``tile_port="<string>"`` is the port name of a physical tile, e.g., ``tile_port="clb.clk"``.
.. note:: The port of physical tile must be a valid port of the physical definition in VPR architecture!
.. note:: The linked port of physical tile must meet the following requirements:
- If the ``global_port`` is set as clock through ``is_clock="true"``, the port of the physical tile must also be a clock port.
- If not a clock, the port of the physical tile must be defined as non-clock global
- The port of the physical tile should have zero connectivity (``Fc=0``) in VPR architecture
- ``is_clock="<bool>"`` define if the global port is a clock port at the top-level FPGA fabric. An operating clock port will be driven by proper signals in auto-generated testbenches.
- ``is_reset="<bool>"`` define if the global port is a reset port at the top-level FPGA fabric. An operating reset port will be driven by proper signals in testbenches.
- ``is_set="<bool>"`` define if the global port is a set port at the top-level FPGA fabric. An operating set port will be driven by proper signals in testbenches.
.. note:: A port can only be defined as ``clock`` or ``set`` or ``reset``.
.. note:: All the global port from a physical tile port is only used in operating phase. Any ports for programmable use are not allowed!
Primitive Blocks inside Multi-mode Configurable Logic Blocks
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -9,6 +9,7 @@
#include "simulation_setting.h"
#include "config_protocol.h"
#include "arch_direct.h"
#include "tile_annotation.h"
#include "pb_type_annotation.h"
/* namespace openfpga begins */
@ -51,6 +52,11 @@ struct Arch {
*/
ArchDirect arch_direct;
/* Physical tile annotations:
* Global port definition for tile ports
*/
TileAnnotation tile_annotations;
/* Pb type annotations
* Bind from operating to physical
* Bind from physical to circuit model

View File

@ -21,6 +21,7 @@
#include "read_xml_simulation_setting.h"
#include "read_xml_config_protocol.h"
#include "read_xml_routing_circuit.h"
#include "read_xml_tile_annotation.h"
#include "read_xml_pb_type_annotation.h"
#include "read_xml_openfpga_arch.h"
#include "openfpga_arch_linker.h"
@ -103,6 +104,9 @@ openfpga::Arch read_xml_openfpga_arch(const char* arch_file_name) {
openfpga_arch.arch_direct = read_xml_direct_circuit(xml_openfpga_arch, loc_data,
openfpga_arch.circuit_lib);
/* Parse the pb_type annotation */
openfpga_arch.tile_annotations = read_xml_tile_annotations(xml_openfpga_arch, loc_data);
/* Parse the pb_type annotation */
openfpga_arch.pb_type_annotations = read_xml_pb_type_annotations(xml_openfpga_arch, loc_data);

View File

@ -0,0 +1,107 @@
/********************************************************************
* This file includes the top-level function of this library
* which reads an XML modeling OpenFPGA architecture to the associated
* data structures
*******************************************************************/
#include <string>
/* Headers from pugi XML library */
#include "pugixml.hpp"
#include "pugixml_util.hpp"
/* Headers from vtr util library */
#include "vtr_assert.h"
/* Headers from libarchfpga */
#include "arch_error.h"
#include "read_xml_util.h"
/* Headers from libopenfpgautil */
#include "openfpga_tokenizer.h"
#include "openfpga_port_parser.h"
#include "read_xml_tile_annotation.h"
/********************************************************************
* Parse XML description for an interconnection annotation
* under a <global_port> XML node
*******************************************************************/
static
void read_xml_tile_global_port_annotation(pugi::xml_node& xml_tile,
const pugiutil::loc_data& loc_data,
openfpga::TileAnnotation& tile_annotation) {
/* We have two mandatory XML attributes
* 1. name of the port
* 2. name of the tile and ports in the format of <tile_name>.<tile_port_name>
*/
const std::string& name_attr = get_attribute(xml_tile, "name", loc_data).as_string();
const std::string& tile_port_name_attr = get_attribute(xml_tile, "tile_port", loc_data).as_string();
/* Extract the tile name */
openfpga::StringToken tokenizer(tile_port_name_attr);
std::vector<std::string> tile_port_tokens = tokenizer.split('.');
if (2 != tile_port_tokens.size()) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_tile),
"Invalid tile_port attribute '%s'! Valid format is <tile_name>.<port_name>\n",
tile_port_name_attr.c_str());
}
/* Extract the tile port information */
openfpga::PortParser tile_port_parser(tile_port_tokens[1]);
TileGlobalPortId tile_global_port_id = tile_annotation.create_global_port(name_attr, tile_port_tokens[0], tile_port_parser.port());
/* Report any duplicated port names */
if (TileGlobalPortId::INVALID() == tile_global_port_id) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_tile),
"Invalid port name '%s' which is defined more than once in the global port list!\n",
name_attr.c_str());
}
/* Get is_clock attributes */
tile_annotation.set_global_port_is_clock(tile_global_port_id, get_attribute(xml_tile, "is_clock", loc_data, pugiutil::ReqOpt::OPTIONAL).as_bool(false));
/* Get is_set attributes */
tile_annotation.set_global_port_is_set(tile_global_port_id, get_attribute(xml_tile, "is_set", loc_data, pugiutil::ReqOpt::OPTIONAL).as_bool(false));
/* Get is_reset attributes */
tile_annotation.set_global_port_is_reset(tile_global_port_id, get_attribute(xml_tile, "is_reset", loc_data, pugiutil::ReqOpt::OPTIONAL).as_bool(false));
/* Get default_value attributes */
tile_annotation.set_global_port_default_value(tile_global_port_id, get_attribute(xml_tile, "default_value", loc_data, pugiutil::ReqOpt::OPTIONAL).as_int(0));
/* Ensure valid port attributes */
if (false == tile_annotation.valid_global_port_attributes(tile_global_port_id)) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_tile),
"Invalid port attributes for '%s'! A port can only be clock or set or reset.\n",
name_attr.c_str());
}
}
/********************************************************************
* Top function to parse XML description about tile annotation
*******************************************************************/
openfpga::TileAnnotation read_xml_tile_annotations(pugi::xml_node& Node,
const pugiutil::loc_data& loc_data) {
openfpga::TileAnnotation tile_annotations;
/* Parse configuration protocol root node */
pugi::xml_node xml_annotations = get_single_child(Node, "tile_annotations", loc_data, pugiutil::ReqOpt::OPTIONAL);
/* Not found, we can return */
if (!xml_annotations) {
return tile_annotations;
}
/* Iterate over the children under this node,
* each child should be named after <pb_type>
*/
for (pugi::xml_node xml_tile_global_port : xml_annotations.children()) {
/* Error out if the XML child has an invalid name! */
if (xml_tile_global_port.name() != std::string("global_port")) {
bad_tag(xml_tile_global_port, loc_data, xml_annotations, {"global_port"});
}
read_xml_tile_global_port_annotation(xml_tile_global_port, loc_data, tile_annotations);
}
return tile_annotations;
}

View File

@ -0,0 +1,17 @@
#ifndef READ_XML_TILE_ANNOTATION_H
#define READ_XML_TILE_ANNOTATION_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include "pugixml_util.hpp"
#include "pugixml.hpp"
#include "tile_annotation.h"
/********************************************************************
* Function declaration
*******************************************************************/
openfpga::TileAnnotation read_xml_tile_annotations(pugi::xml_node& Node,
const pugiutil::loc_data& loc_data);
#endif

View File

@ -0,0 +1,144 @@
/************************************************************************
* Member functions for class TileAnnotation
***********************************************************************/
#include "vtr_assert.h"
#include "tile_annotation.h"
/* namespace openfpga begins */
namespace openfpga {
/************************************************************************
* Constructors
***********************************************************************/
TileAnnotation::TileAnnotation() {
return;
}
/************************************************************************
* Public Accessors : aggregates
***********************************************************************/
TileAnnotation::global_port_range TileAnnotation::global_ports() const {
return vtr::make_range(global_port_ids_.begin(), global_port_ids_.end());
}
/************************************************************************
* Public Accessors
***********************************************************************/
std::string TileAnnotation::global_port_name(const TileGlobalPortId& global_port_id) const {
VTR_ASSERT(valid_global_port_id(global_port_id));
return global_port_names_[global_port_id];
}
std::string TileAnnotation::global_port_tile_name(const TileGlobalPortId& global_port_id) const {
VTR_ASSERT(valid_global_port_id(global_port_id));
return global_port_tile_names_[global_port_id];
}
BasicPort TileAnnotation::global_port_tile_port(const TileGlobalPortId& global_port_id) const {
VTR_ASSERT(valid_global_port_id(global_port_id));
return global_port_tile_ports_[global_port_id];
}
bool TileAnnotation::global_port_is_clock(const TileGlobalPortId& global_port_id) const {
VTR_ASSERT(valid_global_port_id(global_port_id));
return global_port_is_clock_[global_port_id];
}
bool TileAnnotation::global_port_is_set(const TileGlobalPortId& global_port_id) const {
VTR_ASSERT(valid_global_port_id(global_port_id));
return global_port_is_set_[global_port_id];
}
bool TileAnnotation::global_port_is_reset(const TileGlobalPortId& global_port_id) const {
VTR_ASSERT(valid_global_port_id(global_port_id));
return global_port_is_reset_[global_port_id];
}
size_t TileAnnotation::global_port_default_value(const TileGlobalPortId& global_port_id) const {
VTR_ASSERT(valid_global_port_id(global_port_id));
return global_port_default_values_[global_port_id];
}
/************************************************************************
* Public Mutators
***********************************************************************/
TileGlobalPortId TileAnnotation::create_global_port(const std::string& port_name,
const std::string& tile_name,
const BasicPort& tile_port) {
/* Ensure that the name is unique */
std::map<std::string, TileGlobalPortId>::iterator it = global_port_name2ids_.find(port_name);
if (it != global_port_name2ids_.end()) {
return TileGlobalPortId::INVALID();
}
/* This is a legal name. we can create a new id */
TileGlobalPortId port_id = TileGlobalPortId(global_port_ids_.size());
global_port_ids_.push_back(port_id);
global_port_names_.push_back(port_name);
global_port_tile_names_.push_back(tile_name);
global_port_tile_ports_.push_back(tile_port);
global_port_is_clock_.push_back(false);
global_port_is_set_.push_back(false);
global_port_is_reset_.push_back(false);
global_port_default_values_.push_back(0);
/* Register in the name-to-id map */
global_port_name2ids_[port_name] = port_id;
return port_id;
}
void TileAnnotation::set_global_port_is_clock(const TileGlobalPortId& global_port_id,
const bool& is_clock) {
VTR_ASSERT(valid_global_port_id(global_port_id));
global_port_is_clock_[global_port_id] = is_clock;
}
void TileAnnotation::set_global_port_is_set(const TileGlobalPortId& global_port_id,
const bool& is_set) {
VTR_ASSERT(valid_global_port_id(global_port_id));
global_port_is_set_[global_port_id] = is_set;
}
void TileAnnotation::set_global_port_is_reset(const TileGlobalPortId& global_port_id,
const bool& is_reset) {
VTR_ASSERT(valid_global_port_id(global_port_id));
global_port_is_reset_[global_port_id] = is_reset;
}
void TileAnnotation::set_global_port_default_value(const TileGlobalPortId& global_port_id,
const size_t& default_value) {
VTR_ASSERT(valid_global_port_id(global_port_id));
global_port_default_values_[global_port_id] = default_value;
}
/************************************************************************
* Internal invalidators/validators
***********************************************************************/
/* Validators */
bool TileAnnotation::valid_global_port_id(const TileGlobalPortId& global_port_id) const {
return ( size_t(global_port_id) < global_port_ids_.size() ) && ( global_port_id == global_port_ids_[global_port_id] );
}
bool TileAnnotation::valid_global_port_attributes(const TileGlobalPortId& global_port_id) const {
VTR_ASSERT(valid_global_port_id(global_port_id));
int attribute_counter = 0;
if (true == global_port_is_clock_[global_port_id]) {
attribute_counter++;
}
if (true == global_port_is_reset_[global_port_id]) {
attribute_counter++;
}
if (true == global_port_is_set_[global_port_id]) {
attribute_counter++;
}
return ((0 == attribute_counter) || (1 == attribute_counter));
}
} /* namespace openfpga ends */

View File

@ -0,0 +1,86 @@
#ifndef TILE_ANNOTATION_H
#define TILE_ANNOTATION_H
/********************************************************************
* Include header files required by the data structure definition
*******************************************************************/
#include <vector>
#include <map>
#include <array>
#include "vtr_vector.h"
#include "openfpga_port.h"
#include "tile_annotation_fwd.h"
/* namespace openfpga begins */
namespace openfpga {
/********************************************************************
* This file include the declaration of data structures
* to store physical tile annotation, including
* 1. global port definition where a tile port can be treated as a
* global port of the FPGA fabric
*
* Note:
* 1. Keep this data structure as general as possible. It is supposed
* to contain the raw data from architecture XML! If you want to link
* to other data structures, please create another one in other header files
*******************************************************************/
class TileAnnotation {
public: /* Types */
typedef vtr::vector<TileGlobalPortId, TileGlobalPortId>::const_iterator global_port_iterator;
/* Create range */
typedef vtr::Range<global_port_iterator> global_port_range;
public: /* Constructor */
TileAnnotation();
public: /* Public accessors: aggregators */
global_port_range global_ports() const;
public: /* Public accessors */
std::string global_port_name(const TileGlobalPortId& global_port_id) const;
std::string global_port_tile_name(const TileGlobalPortId& global_port_id) const;
BasicPort global_port_tile_port(const TileGlobalPortId& global_port_id) const;
bool global_port_is_clock(const TileGlobalPortId& global_port_id) const;
bool global_port_is_set(const TileGlobalPortId& global_port_id) const;
bool global_port_is_reset(const TileGlobalPortId& global_port_id) const;
size_t global_port_default_value(const TileGlobalPortId& global_port_id) const;
public: /* Public mutators */
/* By default, we do not set it as a clock.
* Users should set it through the set_global_port_is_clock() function
*/
TileGlobalPortId create_global_port(const std::string& port_name,
const std::string& tile_name,
const BasicPort& tile_port);
void set_global_port_is_clock(const TileGlobalPortId& global_port_id,
const bool& is_clock);
void set_global_port_is_set(const TileGlobalPortId& global_port_id,
const bool& is_set);
void set_global_port_is_reset(const TileGlobalPortId& global_port_id,
const bool& is_reset);
void set_global_port_default_value(const TileGlobalPortId& global_port_id,
const size_t& default_value);
public: /* Public validator */
bool valid_global_port_id(const TileGlobalPortId& global_port_id) const;
/* Validate attributes of a given global port
* - A port can only be defined as clock or set or reset
*/
bool valid_global_port_attributes(const TileGlobalPortId& global_port_id) const;
private: /* Internal data */
/* Global port information for tiles */
vtr::vector<TileGlobalPortId, TileGlobalPortId> global_port_ids_;
vtr::vector<TileGlobalPortId, std::string> global_port_names_;
vtr::vector<TileGlobalPortId, std::string> global_port_tile_names_;
vtr::vector<TileGlobalPortId, BasicPort> global_port_tile_ports_;
vtr::vector<TileGlobalPortId, bool> global_port_is_clock_;
vtr::vector<TileGlobalPortId, bool> global_port_is_reset_;
vtr::vector<TileGlobalPortId, bool> global_port_is_set_;
vtr::vector<TileGlobalPortId, size_t> global_port_default_values_;
/* A fast lookup for port names */
std::map<std::string, TileGlobalPortId> global_port_name2ids_;
};
} /* namespace openfpga ends */
#endif

View File

@ -0,0 +1,22 @@
/************************************************************************
* A header file for TileAnnotation class, including critical data declaration
* Please include this file only for using any TileAnnotation data structure
* Refer to tile_annotation.h for more details
***********************************************************************/
/************************************************************************
* Create strong id for tile global ports to avoid illegal type casting
***********************************************************************/
#ifndef TILE_ANNOTATION_FWD_H
#define TILE_ANNOTATION_FWD_H
#include "vtr_strong_id.h"
struct tile_global_port_id_tag;
typedef vtr::StrongId<tile_global_port_id_tag> TileGlobalPortId;
/* Short declaration of class */
class TileAnnotation;
#endif

View File

@ -16,6 +16,7 @@
#include "write_xml_simulation_setting.h"
#include "write_xml_config_protocol.h"
#include "write_xml_routing_circuit.h"
#include "write_xml_tile_annotation.h"
#include "write_xml_pb_type_annotation.h"
#include "write_xml_openfpga_arch.h"
@ -59,7 +60,10 @@ void write_xml_openfpga_arch(const char* fname,
write_xml_direct_circuit(fp, fname, openfpga_arch.circuit_lib, openfpga_arch.arch_direct);
/* Write the pb_type annotations */
openfpga::write_xml_pb_type_annotations(fp, fname, openfpga_arch. pb_type_annotations);
openfpga::write_xml_tile_annotations(fp, fname, openfpga_arch.tile_annotations);
/* Write the pb_type annotations */
openfpga::write_xml_pb_type_annotations(fp, fname, openfpga_arch.pb_type_annotations);
fp << "</openfpga_architecture>" << "\n";

View File

@ -66,6 +66,7 @@ std::string generate_physical_pb_type_hierarchy_name(const PbTypeAnnotation& pb_
}
/********************************************************************
* FIXME: Use a common function to output ports
* Generate the full hierarchy name for a operating pb_type
*******************************************************************/
static

View File

@ -0,0 +1,94 @@
/********************************************************************
* This file includes functions that outputs tile annotations to XML format
*******************************************************************/
/* Headers from system goes first */
#include <string>
#include <algorithm>
/* Headers from vtr util library */
#include "vtr_assert.h"
#include "vtr_log.h"
#include "openfpga_digest.h"
/* Headers from readarchopenfpga library */
#include "write_xml_utils.h"
#include "write_xml_tile_annotation.h"
/* namespace openfpga begins */
namespace openfpga {
/********************************************************************
* FIXME: Use a common function to output ports
* Generate the full hierarchy name for a operating pb_type
*******************************************************************/
static
std::string generate_tile_port_name(const BasicPort& pb_port) {
std::string port_name;
/* Output format: <port_name>[<LSB>:<MSB>] */
port_name += pb_port.get_name();
port_name += std::string("[");
port_name += std::to_string(pb_port.get_lsb());
port_name += std::string(":");
port_name += std::to_string(pb_port.get_msb());
port_name += std::string("]");
return port_name;
}
/********************************************************************
* A writer to output a device variation in a technology library to XML format
*******************************************************************/
static
void write_xml_tile_annotation_global_port(std::fstream& fp,
const char* fname,
const openfpga::TileAnnotation& tile_annotation,
const TileGlobalPortId& global_port_id) {
/* Validate the file stream */
openfpga::check_file_stream(fname, fp);
fp << "\t\t" << "<global_port ";
write_xml_attribute(fp, "name", tile_annotation.global_port_name(global_port_id).c_str());
std::string tile_port_attr = tile_annotation.global_port_tile_name(global_port_id)
+ "."
+ generate_tile_port_name(tile_annotation.global_port_tile_port(global_port_id));
write_xml_attribute(fp, "tile_port", tile_port_attr.c_str());
write_xml_attribute(fp, "is_clock", tile_annotation.global_port_is_clock(global_port_id));
write_xml_attribute(fp, "is_set", tile_annotation.global_port_is_set(global_port_id));
write_xml_attribute(fp, "is_reset", tile_annotation.global_port_is_reset(global_port_id));
write_xml_attribute(fp, "default_value", tile_annotation.global_port_default_value(global_port_id));
fp << "/>" << "\n";
}
/********************************************************************
* A writer to output tile annotations to XML format
*******************************************************************/
void write_xml_tile_annotations(std::fstream& fp,
const char* fname,
const TileAnnotation& tile_annotation) {
/* Validate the file stream */
openfpga::check_file_stream(fname, fp);
/* Write the root node for pb_type annotations,
* we apply a tab becuase pb_type annotations is just a subnode
* under the root node <openfpga_arch>
*/
fp << "\t" << "<tile_annotations>" << "\n";
/* Write device model one by one */
for (const TileGlobalPortId& global_port_id : tile_annotation.global_ports()) {
write_xml_tile_annotation_global_port(fp, fname, tile_annotation, global_port_id);
}
/* Write the root node for pb_type annotations */
fp << "\t" << "</tile_annotations>" << "\n";
}
} /* namespace openfpga ends */

View File

@ -0,0 +1,22 @@
#ifndef WRITE_XML_TILE_ANNOTATION_H
#define WRITE_XML_TILE_ANNOTATION_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include <fstream>
#include "tile_annotation.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* namespace openfpga begins */
namespace openfpga {
void write_xml_tile_annotations(std::fstream& fp,
const char* fname,
const TileAnnotation& tile_annotation);
} /* namespace openfpga ends */
#endif

View File

@ -17,6 +17,7 @@
#include "fabric_hierarchy_writer.h"
#include "fabric_key_writer.h"
#include "build_fabric_io_location_map.h"
#include "build_fabric_global_port_info.h"
#include "openfpga_build_fabric.h"
/* Include global variables of VPR */
@ -120,6 +121,11 @@ int build_fabric(OpenfpgaContext& openfpga_ctx,
openfpga_ctx.mutable_io_location_map() = build_fabric_io_location_map(openfpga_ctx.module_graph(),
g_vpr_ctx.device().grid);
/* Build fabric global port information */
openfpga_ctx.mutable_fabric_global_port_info() = build_fabric_global_port_info(openfpga_ctx.module_graph(),
openfpga_ctx.arch().tile_annotations,
openfpga_ctx.arch().circuit_lib);
/* Output fabric key if user requested */
if (true == cmd_context.option_enable(cmd, opt_write_fabric_key)) {
std::string fkey_fname = cmd_context.option_value(cmd, opt_write_fabric_key);

View File

@ -19,6 +19,7 @@
#include "fabric_bitstream.h"
#include "device_rr_gsb.h"
#include "io_location_map.h"
#include "fabric_global_port_info.h"
/********************************************************************
* This file includes the declaration of the date structure
@ -65,6 +66,7 @@ class OpenfpgaContext : public Context {
const openfpga::BitstreamManager& bitstream_manager() const { return bitstream_manager_; }
const openfpga::FabricBitstream& fabric_bitstream() const { return fabric_bitstream_; }
const openfpga::IoLocationMap& io_location_map() const { return io_location_map_; }
const openfpga::FabricGlobalPortInfo& fabric_global_port_info() const { return fabric_global_port_info_; }
const std::unordered_map<AtomNetId, t_net_power>& net_activity() const { return net_activity_; }
const openfpga::NetlistManager& verilog_netlists() const { return verilog_netlists_; }
const openfpga::NetlistManager& spice_netlists() const { return spice_netlists_; }
@ -85,6 +87,7 @@ class OpenfpgaContext : public Context {
openfpga::BitstreamManager& mutable_bitstream_manager() { return bitstream_manager_; }
openfpga::FabricBitstream& mutable_fabric_bitstream() { return fabric_bitstream_; }
openfpga::IoLocationMap& mutable_io_location_map() { return io_location_map_; }
openfpga::FabricGlobalPortInfo& mutable_fabric_global_port_info() { return fabric_global_port_info_; }
std::unordered_map<AtomNetId, t_net_power>& mutable_net_activity() { return net_activity_; }
openfpga::NetlistManager& mutable_verilog_netlists() { return verilog_netlists_; }
openfpga::NetlistManager& mutable_spice_netlists() { return spice_netlists_; }
@ -123,6 +126,7 @@ class OpenfpgaContext : public Context {
/* Fabric module graph */
openfpga::ModuleManager module_graph_;
openfpga::IoLocationMap io_location_map_;
openfpga::FabricGlobalPortInfo fabric_global_port_info_;
/* Bitstream database */
openfpga::BitstreamManager bitstream_manager_;

View File

@ -17,6 +17,7 @@
#include "openfpga_side_manager.h"
#include "pb_type_utils.h"
#include "openfpga_physical_tile_utils.h"
#include "openfpga_pb_pin_fixup.h"
/* Include global variables of VPR */
@ -25,28 +26,6 @@
/* begin namespace openfpga */
namespace openfpga {
/********************************************************************
* Give a given pin index, find the side where this pin is located
* on the physical tile
* Note:
* - Need to check if the pin_width_offset and pin_height_offset
* are properly set in VPR!!!
*******************************************************************/
static
std::vector<e_side> find_logic_tile_pin_side(t_physical_tile_type_ptr physical_tile,
const int& physical_pin) {
std::vector<e_side> pin_sides;
for (const e_side& side_cand : {TOP, RIGHT, BOTTOM, LEFT}) {
int pin_width_offset = physical_tile->pin_width_offset[physical_pin];
int pin_height_offset = physical_tile->pin_height_offset[physical_pin];
if (true == physical_tile->pinloc[pin_width_offset][pin_height_offset][side_cand][physical_pin]) {
pin_sides.push_back(side_cand);
}
}
return pin_sides;
}
/********************************************************************
* Fix up the pb pin mapping results for a given clustered block
* 1. For each input/output pin of a clustered pb,
@ -86,7 +65,7 @@ void update_cluster_pin_with_post_routing_results(const DeviceContext& device_ct
VTR_ASSERT(class_inf.type == RECEIVER);
rr_node_type = IPIN;
}
std::vector<e_side> pin_sides = find_logic_tile_pin_side(physical_tile, physical_pin);
std::vector<e_side> pin_sides = find_physical_tile_pin_side(physical_tile, physical_pin, border_side);
/* As some grid has height/width offset, we may not have the pin on any side */
if (0 == pin_sides.size()) {
continue;

View File

@ -12,10 +12,14 @@
#include "read_xml_openfpga_arch.h"
#include "check_circuit_library.h"
#include "circuit_library_utils.h"
#include "check_tile_annotation.h"
#include "write_xml_openfpga_arch.h"
#include "openfpga_read_arch.h"
/* Include global variables of VPR */
#include "globals.h"
/* begin namespace openfpga */
namespace openfpga {
@ -44,8 +48,9 @@ int read_arch(OpenfpgaContext& openfpga_context,
/* Check the architecture:
* 1. Circuit library
* 2. Technology library (TODO)
* 3. Simulation settings (TODO)
* 2. Tile annotation
* 3. Technology library (TODO)
* 4. Simulation settings (TODO)
*/
if (false == check_circuit_library(openfpga_context.arch().circuit_lib)) {
return CMD_EXEC_FATAL_ERROR;
@ -57,6 +62,12 @@ int read_arch(OpenfpgaContext& openfpga_context,
return CMD_EXEC_FATAL_ERROR;
}
if (false == check_tile_annotation(openfpga_context.arch().tile_annotations,
openfpga_context.arch().circuit_lib,
g_vpr_ctx.device().physical_tile_types)) {
return CMD_EXEC_FATAL_ERROR;
}
return CMD_EXEC_SUCCESS;
}

View File

@ -80,11 +80,6 @@ int write_pnr_sdc(const OpenfpgaContext& openfpga_ctx,
options.set_generate_sdc_pnr(true);
}
/* Collect global ports from the circuit library:
* TODO: should we place this in the OpenFPGA context?
*/
std::vector<CircuitPortId> global_ports = find_circuit_library_global_ports(openfpga_ctx.arch().circuit_lib);
/* Execute only when sdc is enabled */
if (true == options.generate_sdc_pnr()) {
print_pnr_sdc(options,
@ -96,7 +91,7 @@ int write_pnr_sdc(const OpenfpgaContext& openfpga_ctx,
openfpga_ctx.module_graph(),
openfpga_ctx.mux_lib(),
openfpga_ctx.arch().circuit_lib,
global_ports,
openfpga_ctx.fabric_global_port_info(),
openfpga_ctx.flow_manager().compress_routing());
}
@ -193,17 +188,11 @@ int write_analysis_sdc(const OpenfpgaContext& openfpga_ctx,
options.set_time_unit(string_to_time_unit(cmd_context.option_value(cmd, opt_time_unit)));
}
/* Collect global ports from the circuit library:
* TODO: should we place this in the OpenFPGA context?
*/
std::vector<CircuitPortId> global_ports = find_circuit_library_global_ports(openfpga_ctx.arch().circuit_lib);
if (true == options.generate_sdc_analysis()) {
print_analysis_sdc(options,
1./openfpga_ctx.simulation_setting().operating_clock_frequency(),
g_vpr_ctx,
openfpga_ctx,
global_ports,
openfpga_ctx.flow_manager().compress_routing());
}

View File

@ -96,6 +96,7 @@ int write_verilog_testbench(OpenfpgaContext& openfpga_ctx,
g_vpr_ctx.atom(),
g_vpr_ctx.placement(),
openfpga_ctx.io_location_map(),
openfpga_ctx.fabric_global_port_info(),
openfpga_ctx.vpr_netlist_annotation(),
openfpga_ctx.arch().circuit_lib,
openfpga_ctx.simulation_setting(),

View File

@ -114,6 +114,7 @@ int build_device_module_graph(ModuleManager& module_manager,
decoder_lib,
openfpga_ctx.arch().circuit_lib,
vpr_device_ctx.grid,
openfpga_ctx.arch().tile_annotations,
vpr_device_ctx.rr_graph,
openfpga_ctx.device_rr_gsb(),
openfpga_ctx.tile_direct(),

View File

@ -0,0 +1,90 @@
/********************************************************************
* This file includes functions that are used to build the global port
* information for the top-level module of the FPGA fabric
* It helps OpenFPGA to build testbenches with the attributes of the global ports
*******************************************************************/
#include <map>
#include <algorithm>
/* Headers from vtrutil library */
#include "vtr_assert.h"
#include "vtr_time.h"
#include "vtr_log.h"
#include "openfpga_naming.h"
#include "circuit_library_utils.h"
#include "build_fabric_global_port_info.h"
/* begin namespace openfpga */
namespace openfpga {
/********************************************************************
* Find all the GPIO ports in the grid module
* and cache their port/pin index in the top-level module
*******************************************************************/
FabricGlobalPortInfo build_fabric_global_port_info(const ModuleManager& module_manager,
const TileAnnotation& tile_annotation,
const CircuitLibrary& circuit_lib) {
vtr::ScopedStartFinishTimer timer("Create global port info for top module");
FabricGlobalPortInfo fabric_global_port_info;
/* Find top-level module */
std::string top_module_name = generate_fpga_top_module_name();
ModuleId top_module = module_manager.find_module(top_module_name);
if (true != module_manager.valid_module_id(top_module)) {
VTR_LOG_ERROR("Unable to find the top-level module '%s'!\n",
top_module_name.c_str());
exit(1);
}
/* Add the global ports from circuit library */
for (const CircuitPortId& global_port : find_circuit_library_global_ports(circuit_lib)) {
/* We should find a port in the top module */
ModulePortId module_port = module_manager.find_module_port(top_module, circuit_lib.port_prefix(global_port));
/* Only add those ports have been defined in top-level module */
if (false == module_manager.valid_module_port_id(top_module, module_port)) {
continue;
}
/* Add the port information */
FabricGlobalPortId fabric_port = fabric_global_port_info.create_global_port(module_port);
fabric_global_port_info.set_global_port_is_clock(fabric_port, CIRCUIT_MODEL_PORT_CLOCK == circuit_lib.port_type(global_port));
fabric_global_port_info.set_global_port_is_reset(fabric_port, circuit_lib.port_is_reset(global_port));
fabric_global_port_info.set_global_port_is_set(fabric_port, circuit_lib.port_is_set(global_port));
fabric_global_port_info.set_global_port_is_prog(fabric_port, circuit_lib.port_is_prog(global_port));
fabric_global_port_info.set_global_port_is_config_enable(fabric_port, circuit_lib.port_is_config_enable(global_port));
fabric_global_port_info.set_global_port_default_value(fabric_port, circuit_lib.port_default_value(global_port));
}
/* Add the global ports from tile annotation */
for (const TileGlobalPortId& global_port : tile_annotation.global_ports()) {
/* We should find a port in the top module */
ModulePortId module_port = module_manager.find_module_port(top_module, tile_annotation.global_port_name(global_port));
/* Only add those ports have been defined in top-level module */
if (false == module_manager.valid_module_port_id(top_module, module_port)) {
continue;
}
/* Avoid adding redundant ports */
bool already_in_list = false;
for (const FabricGlobalPortId& port : fabric_global_port_info.global_ports()) {
if (module_port == fabric_global_port_info.global_module_port(port)) {
already_in_list = true;
break;
}
}
if (true == already_in_list) {
continue;
}
/* Add the port information */
FabricGlobalPortId fabric_port = fabric_global_port_info.create_global_port(module_port);
fabric_global_port_info.set_global_port_is_clock(fabric_port, tile_annotation.global_port_is_clock(global_port));
fabric_global_port_info.set_global_port_is_reset(fabric_port, tile_annotation.global_port_is_reset(global_port));
fabric_global_port_info.set_global_port_is_set(fabric_port, tile_annotation.global_port_is_set(global_port));
fabric_global_port_info.set_global_port_default_value(fabric_port, tile_annotation.global_port_default_value(global_port));
}
return fabric_global_port_info;
}
} /* end namespace openfpga */

View File

@ -0,0 +1,27 @@
#ifndef BUILD_FABRIC_GLOBAL_PORT_INFO_H
#define BUILD_FABRIC_GLOBAL_PORT_INFO_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include <string>
#include "tile_annotation.h"
#include "circuit_library.h"
#include "fabric_global_port_info.h"
#include "module_manager.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* begin namespace openfpga */
namespace openfpga {
FabricGlobalPortInfo build_fabric_global_port_info(const ModuleManager& module_manager,
const TileAnnotation& tile_annotation,
const CircuitLibrary& circuit_lib);
} /* end namespace openfpga */
#endif

View File

@ -287,6 +287,7 @@ int build_top_module(ModuleManager& module_manager,
DecoderLibrary& decoder_lib,
const CircuitLibrary& circuit_lib,
const DeviceGrid& grids,
const TileAnnotation& tile_annotation,
const RRGraph& rr_graph,
const DeviceRRGSB& device_rr_gsb,
const TileDirect& tile_direct,
@ -345,6 +346,12 @@ int build_top_module(ModuleManager& module_manager,
*/
add_module_global_ports_from_child_modules(module_manager, top_module);
/* Add global ports from grid ports that are defined as global in tile annotation */
status = add_top_module_global_ports_from_grid_modules(module_manager, top_module, tile_annotation, grids, grid_instance_ids);
if (CMD_EXEC_FATAL_ERROR == status) {
return status;
}
/* Add GPIO ports from the sub-modules under this Verilog module
* This is a much easier job after adding sub modules (instances),
* we just need to find all the I/O ports from the child modules and build a list of it

View File

@ -8,6 +8,7 @@
#include <string>
#include "vtr_geometry.h"
#include "device_grid.h"
#include "tile_annotation.h"
#include "rr_graph_obj.h"
#include "device_rr_gsb.h"
#include "circuit_library.h"
@ -29,6 +30,7 @@ int build_top_module(ModuleManager& module_manager,
DecoderLibrary& decoder_lib,
const CircuitLibrary& circuit_lib,
const DeviceGrid& grids,
const TileAnnotation& tile_annotation,
const RRGraph& rr_graph,
const DeviceRRGSB& device_rr_gsb,
const TileDirect& tile_direct,

View File

@ -6,14 +6,21 @@
#include "vtr_assert.h"
#include "vtr_time.h"
/* Headers from openfpgashell library */
#include "command_exit_codes.h"
/* Headers from openfpgautil library */
#include "openfpga_side_manager.h"
/* Headers from vpr library */
#include "vpr_utils.h"
#include "openfpga_reserved_words.h"
#include "openfpga_naming.h"
#include "pb_type_utils.h"
#include "rr_gsb_utils.h"
#include "openfpga_physical_tile_utils.h"
#include "openfpga_device_grid_utils.h"
#include "module_manager_utils.h"
#include "build_top_module_utils.h"
@ -683,4 +690,166 @@ void add_top_module_nets_connect_grids_and_gsbs(ModuleManager& module_manager,
}
}
/********************************************************************
* Add global port connection for a given port of a physical tile
* that are defined as global in tile annotation
*******************************************************************/
static
void build_top_module_global_net_for_given_grid_module(ModuleManager& module_manager,
const ModuleId& top_module,
const ModulePortId& top_module_port,
const TileAnnotation& tile_annotation,
const TileGlobalPortId& tile_global_port,
const DeviceGrid& grids,
const vtr::Point<size_t>& grid_coordinate,
const e_side& border_side,
const vtr::Matrix<size_t>& grid_instance_ids) {
t_physical_tile_type_ptr physical_tile = grids[grid_coordinate.x()][grid_coordinate.y()].type;
/* Ensure physical tile matches the global port definition */
VTR_ASSERT(std::string(physical_tile->name) == tile_annotation.global_port_tile_name(tile_global_port));
/* Find the port of the grid module according to the tile annotation */
int grid_pin_index = physical_tile->num_pins;
for (const t_physical_tile_port& tile_port : physical_tile->ports) {
if (std::string(tile_port.name) == tile_annotation.global_port_tile_port(tile_global_port).get_name()) {
/* Port size must match!!! */
VTR_ASSERT(size_t(tile_port.num_pins) == tile_annotation.global_port_tile_port(tile_global_port).get_width());
/* TODO: Should check there is only port matching!!! */
grid_pin_index = tile_port.absolute_first_pin_index;
break;
}
}
/* Ensure the pin index is valid */
VTR_ASSERT(grid_pin_index < physical_tile->num_pins);
/* Find the module name for this type of grid */
std::string grid_module_name_prefix(GRID_MODULE_NAME_PREFIX);
std::string grid_module_name = generate_grid_block_module_name(grid_module_name_prefix, std::string(physical_tile->name), is_io_type(physical_tile), border_side);
ModuleId grid_module = module_manager.find_module(grid_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(grid_module));
size_t grid_instance = grid_instance_ids[grid_coordinate.x()][grid_coordinate.y()];
/* Find the module pin */
size_t grid_pin_width = physical_tile->pin_width_offset[grid_pin_index];
size_t grid_pin_height = physical_tile->pin_height_offset[grid_pin_index];
std::vector<e_side> pin_sides = find_physical_tile_pin_side(physical_tile, grid_pin_index, border_side);
for (const e_side& pin_side : pin_sides) {
std::string grid_port_name = generate_grid_port_name(grid_coordinate,
grid_pin_width, grid_pin_height,
pin_side,
grid_pin_index, false);
ModulePortId grid_port_id = module_manager.find_module_port(grid_module, grid_port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(grid_module, grid_port_id));
/* Build nets */
add_module_bus_nets(module_manager, top_module,
top_module, 0, top_module_port,
grid_module, grid_instance, grid_port_id);
}
}
/********************************************************************
* Add global ports from grid ports that are defined as global in tile annotation
*******************************************************************/
int add_top_module_global_ports_from_grid_modules(ModuleManager& module_manager,
const ModuleId& top_module,
const TileAnnotation& tile_annotation,
const DeviceGrid& grids,
const vtr::Matrix<size_t>& grid_instance_ids) {
/* Add the global ports which are yet added to the top-level module
* (in different names than the global ports defined in circuit library
*/
std::vector<BasicPort> global_ports_to_add;
for (const TileGlobalPortId& tile_global_port : tile_annotation.global_ports()) {
ModulePortId module_port = module_manager.find_module_port(top_module, tile_annotation.global_port_name(tile_global_port));
if (ModulePortId::INVALID() == module_port) {
BasicPort global_port_to_add;
global_port_to_add.set_name(tile_annotation.global_port_name(tile_global_port));
global_port_to_add.set_width(tile_annotation.global_port_tile_port(tile_global_port).get_width());
global_ports_to_add.push_back(global_port_to_add);
}
}
for (const BasicPort& global_port_to_add : global_ports_to_add) {
module_manager.add_port(top_module, global_port_to_add, ModuleManager::MODULE_GLOBAL_PORT);
}
/* Add module nets */
std::map<e_side, std::vector<vtr::Point<size_t>>> io_coordinates = generate_perimeter_grid_coordinates( grids);
for (const TileGlobalPortId& tile_global_port : tile_annotation.global_ports()) {
/* Must found one valid port! */
ModulePortId top_module_port = module_manager.find_module_port(top_module, tile_annotation.global_port_name(tile_global_port));
VTR_ASSERT(ModulePortId::INVALID() != top_module_port);
/* Spot the port from child modules from core grids */
for (size_t ix = 1; ix < grids.width() - 1; ++ix) {
for (size_t iy = 1; iy < grids.height() - 1; ++iy) {
/* Bypass EMPTY tiles */
if (true == is_empty_type(grids[ix][iy].type)) {
continue;
}
/* Skip width or height > 1 tiles (mostly heterogeneous blocks) */
if ( (0 < grids[ix][iy].width_offset)
|| (0 < grids[ix][iy].height_offset)) {
continue;
}
/* Bypass the tiles whose names do not match */
if (std::string(grids[ix][iy].type->name) != tile_annotation.global_port_tile_name(tile_global_port)) {
continue;
}
/* Create nets and finish connection build-up */
build_top_module_global_net_for_given_grid_module(module_manager,
top_module,
top_module_port,
tile_annotation,
tile_global_port,
grids,
vtr::Point<size_t>(ix, iy),
NUM_SIDES,
grid_instance_ids);
}
}
/* Walk through all the grids on the perimeter, which are I/O grids */
for (const e_side& io_side : FPGA_SIDES_CLOCKWISE) {
for (const vtr::Point<size_t>& io_coordinate : io_coordinates[io_side]) {
/* Bypass EMPTY grid */
if (true == is_empty_type(grids[io_coordinate.x()][io_coordinate.y()].type)) {
continue;
}
/* Skip width or height > 1 tiles (mostly heterogeneous blocks) */
if ( (0 < grids[io_coordinate.x()][io_coordinate.y()].width_offset)
|| (0 < grids[io_coordinate.x()][io_coordinate.y()].height_offset)) {
continue;
}
/* Bypass the tiles whose names do not match */
if (std::string(grids[io_coordinate.x()][io_coordinate.y()].type->name) != tile_annotation.global_port_tile_name(tile_global_port)) {
continue;
}
/* Create nets and finish connection build-up */
build_top_module_global_net_for_given_grid_module(module_manager,
top_module,
top_module_port,
tile_annotation,
tile_global_port,
grids,
io_coordinate,
io_side,
grid_instance_ids);
}
}
}
return CMD_EXEC_SUCCESS;
}
} /* end namespace openfpga */

View File

@ -10,6 +10,7 @@
#include "device_grid.h"
#include "rr_graph_obj.h"
#include "device_rr_gsb.h"
#include "tile_annotation.h"
#include "module_manager.h"
/********************************************************************
@ -30,6 +31,12 @@ void add_top_module_nets_connect_grids_and_gsbs(ModuleManager& module_manager,
const bool& compact_routing_hierarchy,
const bool& duplicate_grid_pin);
int add_top_module_global_ports_from_grid_modules(ModuleManager& module_manager,
const ModuleId& top_module,
const TileAnnotation& tile_annotation,
const DeviceGrid& grids,
const vtr::Matrix<size_t>& grid_instance_ids);
} /* end namespace openfpga */
#endif

View File

@ -0,0 +1,137 @@
/************************************************************************
* Member functions for class FabricGlobalPortInfo
***********************************************************************/
#include "vtr_assert.h"
#include "fabric_global_port_info.h"
/* namespace openfpga begins */
namespace openfpga {
/************************************************************************
* Constructors
***********************************************************************/
FabricGlobalPortInfo::FabricGlobalPortInfo() {
return;
}
/************************************************************************
* Public Accessors : aggregates
***********************************************************************/
FabricGlobalPortInfo::global_port_range FabricGlobalPortInfo::global_ports() const {
return vtr::make_range(global_port_ids_.begin(), global_port_ids_.end());
}
/************************************************************************
* Public Accessors
***********************************************************************/
ModulePortId FabricGlobalPortInfo::global_module_port(const FabricGlobalPortId& global_port_id) const {
VTR_ASSERT(valid_global_port_id(global_port_id));
return global_module_ports_[global_port_id];
}
bool FabricGlobalPortInfo::global_port_is_clock(const FabricGlobalPortId& global_port_id) const {
VTR_ASSERT(valid_global_port_id(global_port_id));
return global_port_is_clock_[global_port_id];
}
bool FabricGlobalPortInfo::global_port_is_set(const FabricGlobalPortId& global_port_id) const {
VTR_ASSERT(valid_global_port_id(global_port_id));
return global_port_is_set_[global_port_id];
}
bool FabricGlobalPortInfo::global_port_is_reset(const FabricGlobalPortId& global_port_id) const {
VTR_ASSERT(valid_global_port_id(global_port_id));
return global_port_is_reset_[global_port_id];
}
bool FabricGlobalPortInfo::global_port_is_prog(const FabricGlobalPortId& global_port_id) const {
VTR_ASSERT(valid_global_port_id(global_port_id));
return global_port_is_prog_[global_port_id];
}
bool FabricGlobalPortInfo::global_port_is_config_enable(const FabricGlobalPortId& global_port_id) const {
VTR_ASSERT(valid_global_port_id(global_port_id));
return global_port_is_config_enable_[global_port_id];
}
bool FabricGlobalPortInfo::global_port_is_io(const FabricGlobalPortId& global_port_id) const {
VTR_ASSERT(valid_global_port_id(global_port_id));
return global_port_is_io_[global_port_id];
}
size_t FabricGlobalPortInfo::global_port_default_value(const FabricGlobalPortId& global_port_id) const {
VTR_ASSERT(valid_global_port_id(global_port_id));
return global_port_default_values_[global_port_id];
}
/************************************************************************
* Public Mutators
***********************************************************************/
FabricGlobalPortId FabricGlobalPortInfo::create_global_port(const ModulePortId& module_port) {
/* This is a legal name. we can create a new id */
FabricGlobalPortId port_id = FabricGlobalPortId(global_port_ids_.size());
global_port_ids_.push_back(port_id);
global_module_ports_.push_back(module_port);
global_port_is_clock_.push_back(false);
global_port_is_set_.push_back(false);
global_port_is_reset_.push_back(false);
global_port_is_prog_.push_back(false);
global_port_is_io_.push_back(false);
global_port_is_config_enable_.push_back(false);
global_port_default_values_.push_back(0);
return port_id;
}
void FabricGlobalPortInfo::set_global_port_is_clock(const FabricGlobalPortId& global_port_id,
const bool& is_clock) {
VTR_ASSERT(valid_global_port_id(global_port_id));
global_port_is_clock_[global_port_id] = is_clock;
}
void FabricGlobalPortInfo::set_global_port_is_set(const FabricGlobalPortId& global_port_id,
const bool& is_set) {
VTR_ASSERT(valid_global_port_id(global_port_id));
global_port_is_set_[global_port_id] = is_set;
}
void FabricGlobalPortInfo::set_global_port_is_reset(const FabricGlobalPortId& global_port_id,
const bool& is_reset) {
VTR_ASSERT(valid_global_port_id(global_port_id));
global_port_is_reset_[global_port_id] = is_reset;
}
void FabricGlobalPortInfo::set_global_port_is_prog(const FabricGlobalPortId& global_port_id,
const bool& is_prog) {
VTR_ASSERT(valid_global_port_id(global_port_id));
global_port_is_prog_[global_port_id] = is_prog;
}
void FabricGlobalPortInfo::set_global_port_is_config_enable(const FabricGlobalPortId& global_port_id,
const bool& is_config_enable) {
VTR_ASSERT(valid_global_port_id(global_port_id));
global_port_is_config_enable_[global_port_id] = is_config_enable;
}
void FabricGlobalPortInfo::set_global_port_is_io(const FabricGlobalPortId& global_port_id,
const bool& is_io) {
VTR_ASSERT(valid_global_port_id(global_port_id));
global_port_is_io_[global_port_id] = is_io;
}
void FabricGlobalPortInfo::set_global_port_default_value(const FabricGlobalPortId& global_port_id,
const size_t& default_value) {
VTR_ASSERT(valid_global_port_id(global_port_id));
global_port_default_values_[global_port_id] = default_value;
}
/************************************************************************
* Internal invalidators/validators
***********************************************************************/
/* Validators */
bool FabricGlobalPortInfo::valid_global_port_id(const FabricGlobalPortId& global_port_id) const {
return ( size_t(global_port_id) < global_port_ids_.size() ) && ( global_port_id == global_port_ids_[global_port_id] );
}
} /* namespace openfpga ends */

View File

@ -0,0 +1,79 @@
#ifndef FABRIC_GLOBAL_PORT_INFO_H
#define FABRIC_GLOBAL_PORT_INFO_H
/********************************************************************
* Include header files required by the data structure definition
*******************************************************************/
#include <vector>
#include <string>
#include "vtr_vector.h"
#include "module_manager_fwd.h"
#include "fabric_global_port_info_fwd.h"
/* namespace openfpga begins */
namespace openfpga {
/********************************************************************
* A data structure to store necessary information for the global
* ports that have been defined for the FPGA fabric
*
* Currently the global port information is mainly used for testbench generation
*******************************************************************/
class FabricGlobalPortInfo {
public: /* Types */
typedef vtr::vector<FabricGlobalPortId, FabricGlobalPortId>::const_iterator global_port_iterator;
/* Create range */
typedef vtr::Range<global_port_iterator> global_port_range;
public: /* Constructor */
FabricGlobalPortInfo();
public: /* Public accessors: aggregators */
global_port_range global_ports() const;
public: /* Public accessors */
ModulePortId global_module_port(const FabricGlobalPortId& global_port_id) const;
bool global_port_is_clock(const FabricGlobalPortId& global_port_id) const;
bool global_port_is_set(const FabricGlobalPortId& global_port_id) const;
bool global_port_is_reset(const FabricGlobalPortId& global_port_id) const;
bool global_port_is_prog(const FabricGlobalPortId& global_port_id) const;
bool global_port_is_config_enable(const FabricGlobalPortId& global_port_id) const;
bool global_port_is_io(const FabricGlobalPortId& global_port_id) const;
size_t global_port_default_value(const FabricGlobalPortId& global_port_id) const;
public: /* Public mutators */
/* By default, we do not set it as a clock.
* Users should set it through the set_global_port_is_clock() function
*/
FabricGlobalPortId create_global_port(const ModulePortId& module_port);
void set_global_port_is_clock(const FabricGlobalPortId& global_port_id,
const bool& is_clock);
void set_global_port_is_set(const FabricGlobalPortId& global_port_id,
const bool& is_set);
void set_global_port_is_reset(const FabricGlobalPortId& global_port_id,
const bool& is_reset);
void set_global_port_is_prog(const FabricGlobalPortId& global_port_id,
const bool& is_prog);
void set_global_port_is_config_enable(const FabricGlobalPortId& global_port_id,
const bool& is_config_enable);
void set_global_port_is_io(const FabricGlobalPortId& global_port_id,
const bool& is_io);
void set_global_port_default_value(const FabricGlobalPortId& global_port_id,
const size_t& default_value);
public: /* Public validator */
bool valid_global_port_id(const FabricGlobalPortId& global_port_id) const;
private: /* Internal data */
/* Global port information for tiles */
vtr::vector<FabricGlobalPortId, FabricGlobalPortId> global_port_ids_;
vtr::vector<FabricGlobalPortId, ModulePortId> global_module_ports_;
vtr::vector<FabricGlobalPortId, bool> global_port_is_clock_;
vtr::vector<FabricGlobalPortId, bool> global_port_is_reset_;
vtr::vector<FabricGlobalPortId, bool> global_port_is_set_;
vtr::vector<FabricGlobalPortId, bool> global_port_is_prog_;
vtr::vector<FabricGlobalPortId, bool> global_port_is_config_enable_;
vtr::vector<FabricGlobalPortId, bool> global_port_is_io_;
vtr::vector<FabricGlobalPortId, size_t> global_port_default_values_;
};
} /* namespace openfpga ends */
#endif

View File

@ -0,0 +1,22 @@
/************************************************************************
* A header file for FabricGlobalPortList class, including critical data declaration
* Please include this file only for using any FabricGlobalPortList data structure
* Refer to fabric_global_port_list.h for more details
***********************************************************************/
/************************************************************************
* Create strong id for fabric global ports to avoid illegal type casting
***********************************************************************/
#ifndef FABRIC_GLOBAL_PORT_INFO_FWD_H
#define FABRIC_GLOBAL_PORT_INFO_FWD_H
#include "vtr_strong_id.h"
struct fabric_global_port_id_tag;
typedef vtr::StrongId<fabric_global_port_id_tag> FabricGlobalPortId;
/* Short declaration of class */
class FabricGlobalPortInfo;
#endif

View File

@ -44,8 +44,7 @@ void print_analysis_sdc_io_delays(std::fstream& fp,
const IoLocationMap& io_location_map,
const ModuleManager& module_manager,
const ModuleId& top_module,
const CircuitLibrary& circuit_lib,
const std::vector<CircuitPortId>& global_ports,
const FabricGlobalPortInfo& fabric_global_port_info,
const float& critical_path_delay) {
/* Validate the file stream */
valid_file_stream(fp);
@ -57,17 +56,17 @@ void print_analysis_sdc_io_delays(std::fstream& fp,
/* Get clock port from the global port */
std::vector<BasicPort> operating_clock_ports;
for (const CircuitPortId& clock_port : global_ports) {
if (CIRCUIT_MODEL_PORT_CLOCK != circuit_lib.port_type(clock_port)) {
for (const FabricGlobalPortId& clock_port : fabric_global_port_info.global_ports()) {
if (false == fabric_global_port_info.global_port_is_clock(clock_port)) {
continue;
}
/* We only constrain operating clock here! */
if (true == circuit_lib.port_is_prog(clock_port)) {
if (true == fabric_global_port_info.global_port_is_prog(clock_port)) {
continue;
}
/* Find the module port and Update the operating port list */
ModulePortId module_port = module_manager.find_module_port(top_module, circuit_lib.port_prefix(clock_port));
ModulePortId module_port = fabric_global_port_info.global_module_port(clock_port);
operating_clock_ports.push_back(module_manager.module_port(top_module, module_port));
}
@ -181,8 +180,7 @@ static
void print_analysis_sdc_disable_global_ports(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& top_module,
const CircuitLibrary& circuit_lib,
const std::vector<CircuitPortId>& global_ports) {
const FabricGlobalPortInfo& fabric_global_port_info) {
/* Validate file stream */
valid_file_stream(fp);
@ -191,31 +189,19 @@ void print_analysis_sdc_disable_global_ports(std::fstream& fp,
fp << "# Disable timing for global ports " << std::endl;
fp << "##################################################" << std::endl;
for (const CircuitPortId& global_port : global_ports) {
for (const FabricGlobalPortId& global_port : fabric_global_port_info.global_ports()) {
/* Skip operating clock here! */
if ( (CIRCUIT_MODEL_PORT_CLOCK == circuit_lib.port_type(global_port))
&& (false == circuit_lib.port_is_prog(global_port)) ) {
if ( (true == fabric_global_port_info.global_port_is_clock(global_port))
&& (false == fabric_global_port_info.global_port_is_prog(global_port)) ) {
continue;
}
/* Skip any gpio port here! */
if ( (CIRCUIT_MODEL_PORT_INPUT == circuit_lib.port_type(global_port))
&& (true == circuit_lib.port_is_io(global_port)) ) {
if (true == fabric_global_port_info.global_port_is_io(global_port)) {
continue;
}
/* Skip any gpio port here! */
if (CIRCUIT_MODEL_PORT_OUTPUT == circuit_lib.port_type(global_port)) {
continue;
}
/* Skip any gpio port here! */
if ( (CIRCUIT_MODEL_PORT_INOUT == circuit_lib.port_type(global_port))
&& (true == circuit_lib.port_is_io(global_port)) ) {
continue;
}
ModulePortId module_port = module_manager.find_module_port(top_module, circuit_lib.port_prefix(global_port));
ModulePortId module_port = fabric_global_port_info.global_module_port(global_port);
BasicPort port_to_disable = module_manager.module_port(top_module, module_port);
print_sdc_disable_port_timing(fp, port_to_disable);
@ -230,7 +216,6 @@ void print_analysis_sdc(const AnalysisSdcOption& option,
const float& critical_path_delay,
const VprContext& vpr_ctx,
const OpenfpgaContext& openfpga_ctx,
const std::vector<CircuitPortId>& global_ports,
const bool& compact_routing_hierarchy) {
/* Create the file name for Verilog netlist */
std::string sdc_fname(option.sdc_dir() + generate_analysis_sdc_file_name(vpr_ctx.atom().nlist.netlist_name(), std::string(SDC_ANALYSIS_FILE_NAME)));
@ -261,13 +246,13 @@ void print_analysis_sdc(const AnalysisSdcOption& option,
vpr_ctx.atom(), vpr_ctx.placement(),
openfpga_ctx.vpr_netlist_annotation(), openfpga_ctx.io_location_map(),
openfpga_ctx.module_graph(), top_module,
openfpga_ctx.arch().circuit_lib, global_ports,
openfpga_ctx.fabric_global_port_info(),
critical_path_delay);
/* Disable the timing for global ports */
print_analysis_sdc_disable_global_ports(fp,
openfpga_ctx.module_graph(), top_module,
openfpga_ctx.arch().circuit_lib, global_ports);
openfpga_ctx.fabric_global_port_info());
/* Disable the timing for configuration cells */
rec_print_pnr_sdc_disable_configurable_memory_module_output(fp, option.flatten_names(),

View File

@ -21,7 +21,6 @@ void print_analysis_sdc(const AnalysisSdcOption& option,
const float& critical_path_delay,
const VprContext& vpr_ctx,
const OpenfpgaContext& openfpga_ctx,
const std::vector<CircuitPortId>& global_ports,
const bool& compact_routing_hierarchy);
} /* end namespace openfpga */

View File

@ -61,21 +61,22 @@ static
void print_pnr_sdc_global_clock_ports(std::fstream& fp,
const float& programming_critical_path_delay,
const float& operating_critical_path_delay,
const CircuitLibrary& circuit_lib,
const std::vector<CircuitPortId>& global_ports) {
const ModuleManager& module_manager,
const ModuleId& top_module,
const FabricGlobalPortInfo& fabric_global_port_info) {
valid_file_stream(fp);
/* Get clock port from the global port */
for (const CircuitPortId& clock_port : global_ports) {
if (CIRCUIT_MODEL_PORT_CLOCK != circuit_lib.port_type(clock_port)) {
for (const FabricGlobalPortId& global_port : fabric_global_port_info.global_ports()) {
if (false == fabric_global_port_info.global_port_is_clock(global_port)) {
continue;
}
/* Reach here, it means a clock port and we need print constraints */
float clock_period = operating_critical_path_delay;
/* For programming clock, we give a fixed period */
if (true == circuit_lib.port_is_prog(clock_port)) {
if (true == fabric_global_port_info.global_port_is_prog(global_port)) {
clock_period = programming_critical_path_delay;
/* Print comments */
fp << "##################################################" << std::endl;
@ -88,8 +89,9 @@ void print_pnr_sdc_global_clock_ports(std::fstream& fp,
fp << "##################################################" << std::endl;
}
for (const size_t& pin : circuit_lib.pins(clock_port)) {
BasicPort port_to_constrain(circuit_lib.port_prefix(clock_port), pin, pin);
BasicPort clock_port = module_manager.module_port(top_module, fabric_global_port_info.global_module_port(global_port));
for (const size_t& pin : clock_port.pins()) {
BasicPort port_to_constrain(clock_port.get_name(), pin, pin);
print_pnr_sdc_clock_port(fp,
port_to_constrain,
@ -109,14 +111,15 @@ void print_pnr_sdc_global_clock_ports(std::fstream& fp,
static
void print_pnr_sdc_global_non_clock_ports(std::fstream& fp,
const float& operating_critical_path_delay,
const CircuitLibrary& circuit_lib,
const std::vector<CircuitPortId>& global_ports) {
const ModuleManager& module_manager,
const ModuleId& top_module,
const FabricGlobalPortInfo& fabric_global_port_info) {
valid_file_stream(fp);
/* For non-clock port from the global port: give a fixed period */
for (const CircuitPortId& global_port : global_ports) {
if (CIRCUIT_MODEL_PORT_CLOCK == circuit_lib.port_type(global_port)) {
for (const FabricGlobalPortId& global_port : fabric_global_port_info.global_ports()) {
if (true == fabric_global_port_info.global_port_is_clock(global_port)) {
continue;
}
@ -127,8 +130,9 @@ void print_pnr_sdc_global_non_clock_ports(std::fstream& fp,
/* Reach here, it means a non-clock global port and we need print constraints */
float clock_period = operating_critical_path_delay;
for (const size_t& pin : circuit_lib.pins(global_port)) {
BasicPort port_to_constrain(circuit_lib.port_prefix(global_port), pin, pin);
BasicPort non_clock_port = module_manager.module_port(top_module, fabric_global_port_info.global_module_port(global_port));
for (const size_t& pin : non_clock_port.pins()) {
BasicPort port_to_constrain(non_clock_port.get_name(), pin, pin);
print_pnr_sdc_clock_port(fp,
port_to_constrain,
@ -151,8 +155,9 @@ void print_pnr_sdc_global_non_clock_ports(std::fstream& fp,
void print_pnr_sdc_global_ports(const std::string& sdc_dir,
const float& programming_critical_path_delay,
const float& operating_critical_path_delay,
const CircuitLibrary& circuit_lib,
const std::vector<CircuitPortId>& global_ports,
const ModuleManager& module_manager,
const ModuleId& top_module,
const FabricGlobalPortInfo& global_ports,
const bool& constrain_non_clock_port) {
/* Create the file name for Verilog netlist */
@ -174,13 +179,13 @@ void print_pnr_sdc_global_ports(const std::string& sdc_dir,
print_pnr_sdc_global_clock_ports(fp,
programming_critical_path_delay,
operating_critical_path_delay,
circuit_lib,
module_manager, top_module,
global_ports);
if (true == constrain_non_clock_port) {
print_pnr_sdc_global_non_clock_ports(fp,
operating_critical_path_delay,
circuit_lib,
module_manager, top_module,
global_ports);
}

View File

@ -6,7 +6,8 @@
*******************************************************************/
#include <string>
#include <vector>
#include "circuit_library.h"
#include "module_manager.h"
#include "fabric_global_port_info.h"
/********************************************************************
* Function declaration
@ -18,8 +19,9 @@ namespace openfpga {
void print_pnr_sdc_global_ports(const std::string& sdc_dir,
const float& programming_critical_path_delay,
const float& operating_critical_path_delay,
const CircuitLibrary& circuit_lib,
const std::vector<CircuitPortId>& global_ports,
const ModuleManager& module_manager,
const ModuleId& top_module,
const FabricGlobalPortInfo& global_ports,
const bool& constrain_non_clock_port);
} /* end namespace openfpga */

View File

@ -327,22 +327,22 @@ void print_pnr_sdc(const PnrSdcOption& sdc_options,
const ModuleManager& module_manager,
const MuxLibrary& mux_lib,
const CircuitLibrary& circuit_lib,
const std::vector<CircuitPortId>& global_ports,
const FabricGlobalPortInfo& global_ports,
const bool& compact_routing_hierarchy) {
std::string top_module_name = generate_fpga_top_module_name();
ModuleId top_module = module_manager.find_module(top_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(top_module));
/* Constrain global ports */
if (true == sdc_options.constrain_global_port()) {
print_pnr_sdc_global_ports(sdc_options.sdc_dir(),
programming_critical_path_delay,
operating_critical_path_delay,
circuit_lib, global_ports,
module_manager, top_module, global_ports,
sdc_options.constrain_non_clock_global_port());
}
std::string top_module_name = generate_fpga_top_module_name();
ModuleId top_module = module_manager.find_module(top_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(top_module));
/* Output Design Constraints to disable outputs of memory cells */
if (true == sdc_options.constrain_configurable_memory_outputs()) {
print_pnr_sdc_constrain_configurable_memory_outputs(sdc_options.sdc_dir(),

View File

@ -12,6 +12,7 @@
#include "module_manager.h"
#include "mux_library.h"
#include "circuit_library.h"
#include "fabric_global_port_info.h"
#include "pnr_sdc_option.h"
/********************************************************************
@ -30,7 +31,7 @@ void print_pnr_sdc(const PnrSdcOption& sdc_options,
const ModuleManager& module_manager,
const MuxLibrary& mux_lib,
const CircuitLibrary& circuit_lib,
const std::vector<CircuitPortId>& global_ports,
const FabricGlobalPortInfo& global_ports,
const bool& compact_routing_hierarchy);
} /* end namespace openfpga */

View File

@ -153,6 +153,7 @@ void fpga_verilog_testbench(const ModuleManager &module_manager,
const AtomContext &atom_ctx,
const PlacementContext &place_ctx,
const IoLocationMap &io_location_map,
const FabricGlobalPortInfo &fabric_global_port_info,
const VprNetlistAnnotation &netlist_annotation,
const CircuitLibrary &circuit_lib,
const SimulationSetting &simulation_setting,
@ -172,17 +173,12 @@ void fpga_verilog_testbench(const ModuleManager &module_manager,
print_verilog_simulation_preprocessing_flags(std::string(src_dir_path),
options);
/* Collect global ports from the circuit library:
* TODO: should we place this in the OpenFPGA context?
*/
std::vector<CircuitPortId> global_ports = find_circuit_library_global_ports(circuit_lib);
/* Generate wrapper module for FPGA fabric (mapped by the input benchmark and pre-configured testbench for verification */
if (true == options.print_formal_verification_top_netlist()) {
std::string formal_verification_top_netlist_file_path = src_dir_path + netlist_name + std::string(FORMAL_VERIFICATION_VERILOG_FILE_POSTFIX);
print_verilog_preconfig_top_module(module_manager, bitstream_manager,
config_protocol,
circuit_lib, global_ports,
circuit_lib, fabric_global_port_info,
atom_ctx, place_ctx, io_location_map,
netlist_annotation,
netlist_name,
@ -207,7 +203,7 @@ void fpga_verilog_testbench(const ModuleManager &module_manager,
print_verilog_top_testbench(module_manager,
bitstream_manager, fabric_bitstream,
config_protocol,
circuit_lib, global_ports,
fabric_global_port_info,
atom_ctx, place_ctx, io_location_map,
netlist_annotation,
netlist_name,

View File

@ -20,6 +20,7 @@
#include "fabric_bitstream.h"
#include "simulation_setting.h"
#include "io_location_map.h"
#include "fabric_global_port_info.h"
#include "vpr_netlist_annotation.h"
#include "fabric_verilog_options.h"
#include "verilog_testbench_options.h"
@ -47,6 +48,7 @@ void fpga_verilog_testbench(const ModuleManager& module_manager,
const AtomContext& atom_ctx,
const PlacementContext& place_ctx,
const IoLocationMap& io_location_map,
const FabricGlobalPortInfo &fabric_global_port_info,
const VprNetlistAnnotation& netlist_annotation,
const CircuitLibrary& circuit_lib,
const SimulationSetting& simulation_parameters,

View File

@ -118,8 +118,7 @@ namespace openfpga
static void print_verilog_preconfig_top_module_connect_global_ports(std::fstream &fp,
const ModuleManager &module_manager,
const ModuleId &top_module,
const CircuitLibrary &circuit_lib,
const std::vector<CircuitPortId> &global_ports,
const FabricGlobalPortInfo &fabric_global_ports,
const std::vector<std::string> &benchmark_clock_port_names)
{
/* Validate the file stream */
@ -127,40 +126,16 @@ namespace openfpga
print_verilog_comment(fp, std::string("----- Begin Connect Global ports of FPGA top module -----"));
/* Global ports of the top module in module manager do not carry any attributes,
* such as is_clock, is_set, etc.
* Therefore, for each global port in the top module, we find the circuit port in the circuit library
* which share the same name. We can access to the attributes.
* To gurantee the correct link between global ports in module manager and those in circuit library
* We have performed some critical check in check_circuit_library() for global ports,
* where we guarantee all the global ports share the same name must have the same attributes.
* So that each global port with the same name is unique!
*/
for (const BasicPort &module_global_port : module_manager.module_ports_by_type(top_module, ModuleManager::MODULE_GLOBAL_PORT))
{
CircuitPortId linked_circuit_port_id = CircuitPortId::INVALID();
/* Find the circuit port with the same name */
for (const CircuitPortId &circuit_port_id : global_ports)
{
if (0 != module_global_port.get_name().compare(circuit_lib.port_prefix(circuit_port_id)))
{
continue;
}
linked_circuit_port_id = circuit_port_id;
break;
}
/* Must find one valid circuit port */
VTR_ASSERT(CircuitPortId::INVALID() != linked_circuit_port_id);
/* Port size should match! */
VTR_ASSERT(module_global_port.get_width() == circuit_lib.port_size(linked_circuit_port_id));
for (const FabricGlobalPortId& global_port_id : fabric_global_ports.global_ports()) {
ModulePortId module_global_port_id = fabric_global_ports.global_module_port(global_port_id);
VTR_ASSERT(ModuleManager::MODULE_GLOBAL_PORT == module_manager.port_type(top_module, module_global_port_id));
BasicPort module_global_port = module_manager.module_port(top_module, module_global_port_id);
/* Now, for operating clock port, we should wire it to the clock of benchmark! */
if ((CIRCUIT_MODEL_PORT_CLOCK == circuit_lib.port_type(linked_circuit_port_id)) && (false == circuit_lib.port_is_prog(linked_circuit_port_id)))
{
if ((true == fabric_global_ports.global_port_is_clock(global_port_id))
&& (false == fabric_global_ports.global_port_is_prog(global_port_id))) {
/* Wiring to each pin of the global port: benchmark clock is always 1-bit */
for (const size_t &pin : module_global_port.pins())
{
for (const std::string &clock_port_name : benchmark_clock_port_names)
{
for (const size_t &pin : module_global_port.pins()) {
for (const std::string &clock_port_name : benchmark_clock_port_names) {
BasicPort module_clock_pin(module_global_port.get_name(), pin, pin);
BasicPort benchmark_clock_pin(clock_port_name + std::string(FORMAL_VERIFICATION_TOP_MODULE_PORT_POSTFIX), 1);
print_verilog_wire_connection(fp, module_clock_pin, benchmark_clock_pin, false);
@ -171,7 +146,7 @@ namespace openfpga
}
/* For other ports, give an default value */
std::vector<size_t> default_values(module_global_port.get_width(), circuit_lib.port_default_value(linked_circuit_port_id));
std::vector<size_t> default_values(module_global_port.get_width(), fabric_global_ports.global_port_default_value(global_port_id));
print_verilog_wire_constant_values(fp, module_global_port, default_values);
}
@ -430,7 +405,7 @@ namespace openfpga
const BitstreamManager &bitstream_manager,
const ConfigProtocol &config_protocol,
const CircuitLibrary &circuit_lib,
const std::vector<CircuitPortId> &global_ports,
const FabricGlobalPortInfo &global_ports,
const AtomContext &atom_ctx,
const PlacementContext &place_ctx,
const IoLocationMap &io_location_map,
@ -475,7 +450,7 @@ namespace openfpga
/* Connect FPGA top module global ports to constant or benchmark global signals! */
print_verilog_preconfig_top_module_connect_global_ports(fp, module_manager, top_module,
circuit_lib, global_ports,
global_ports,
benchmark_clock_port_names);
/* Connect I/Os to benchmark I/Os or constant driver */

View File

@ -11,6 +11,7 @@
#include "module_manager.h"
#include "bitstream_manager.h"
#include "io_location_map.h"
#include "fabric_global_port_info.h"
#include "config_protocol.h"
#include "vpr_netlist_annotation.h"
@ -25,7 +26,7 @@ void print_verilog_preconfig_top_module(const ModuleManager& module_manager,
const BitstreamManager& bitstream_manager,
const ConfigProtocol &config_protocol,
const CircuitLibrary& circuit_lib,
const std::vector<CircuitPortId>& global_ports,
const FabricGlobalPortInfo &global_ports,
const AtomContext& atom_ctx,
const PlacementContext& place_ctx,
const IoLocationMap& io_location_map,

View File

@ -6,7 +6,6 @@
#include <iomanip>
#include <algorithm>
/* Headers from vtrutil library */
#include "vtr_log.h"
#include "vtr_assert.h"
@ -24,6 +23,7 @@
#include "openfpga_atom_netlist_utils.h"
#include "fabric_bitstream_utils.h"
#include "fabric_global_port_info_utils.h"
#include "verilog_constants.h"
#include "verilog_writer_utils.h"
@ -62,54 +62,6 @@ constexpr char* TOP_TB_CLOCK_REG_POSTFIX = "_reg";
constexpr char* AUTOCHECK_TOP_TESTBENCH_VERILOG_MODULE_POSTFIX = "_autocheck_top_tb";
/********************************************************************
* Identify global reset ports for programming
*******************************************************************/
static
std::vector<CircuitPortId> find_global_programming_reset_ports(const CircuitLibrary& circuit_lib,
const std::vector<CircuitPortId>& global_ports) {
/* Try to find global reset ports for programming */
std::vector<CircuitPortId> global_prog_reset_ports;
for (const CircuitPortId& global_port : global_ports) {
VTR_ASSERT(true == circuit_lib.port_is_global(global_port));
if (false == circuit_lib.port_is_prog(global_port)) {
continue;
}
VTR_ASSERT(true == circuit_lib.port_is_prog(global_port));
VTR_ASSERT( (false == circuit_lib.port_is_reset(global_port))
|| (false == circuit_lib.port_is_set(global_port)));
if (true == circuit_lib.port_is_reset(global_port)) {
global_prog_reset_ports.push_back(global_port);
}
}
return global_prog_reset_ports;
}
/********************************************************************
* Identify global set ports for programming
*******************************************************************/
static
std::vector<CircuitPortId> find_global_programming_set_ports(const CircuitLibrary& circuit_lib,
const std::vector<CircuitPortId>& global_ports) {
/* Try to find global set ports for programming */
std::vector<CircuitPortId> global_prog_set_ports;
for (const CircuitPortId& global_port : global_ports) {
VTR_ASSERT(true == circuit_lib.port_is_global(global_port));
if (false == circuit_lib.port_is_prog(global_port)) {
continue;
}
VTR_ASSERT(true == circuit_lib.port_is_prog(global_port));
VTR_ASSERT( (false == circuit_lib.port_is_reset(global_port))
|| (false == circuit_lib.port_is_set(global_port)));
if (true == circuit_lib.port_is_set(global_port)) {
global_prog_set_ports.push_back(global_port);
}
}
return global_prog_set_ports;
}
/********************************************************************
* Print local wires for flatten memory (standalone) configuration protocols
*******************************************************************/
@ -300,8 +252,7 @@ static
void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& top_module,
const CircuitLibrary& circuit_lib,
const std::vector<CircuitPortId>& global_ports,
const FabricGlobalPortInfo& fabric_global_port_info,
const bool& active_global_prog_reset,
const bool& active_global_prog_set) {
/* Validate the file stream */
@ -310,8 +261,8 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp,
print_verilog_comment(fp, std::string("----- Begin connecting global ports of FPGA fabric to stimuli -----"));
/* Connect global clock ports to operating or programming clock signal */
for (const CircuitPortId& model_global_port : global_ports) {
if (CIRCUIT_MODEL_PORT_CLOCK != circuit_lib.port_type(model_global_port)) {
for (const FabricGlobalPortId& fabric_global_port : fabric_global_port_info.global_ports()) {
if (false == fabric_global_port_info.global_port_is_clock(fabric_global_port)) {
continue;
}
/* Reach here, it means we have a global clock to deal with:
@ -321,15 +272,15 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp,
* connect it to the local wire of operating clock
*/
/* Find the module port */
ModulePortId module_global_port = module_manager.find_module_port(top_module, circuit_lib.port_prefix(model_global_port));
ModulePortId module_global_port = fabric_global_port_info.global_module_port(fabric_global_port);
VTR_ASSERT(true == module_manager.valid_module_port_id(top_module, module_global_port));
BasicPort stimuli_clock_port;
if (true == circuit_lib.port_is_prog(model_global_port)) {
if (true == fabric_global_port_info.global_port_is_prog(fabric_global_port)) {
stimuli_clock_port.set_name(std::string(TOP_TB_PROG_CLOCK_PORT_NAME));
stimuli_clock_port.set_width(1);
} else {
VTR_ASSERT_SAFE(false == circuit_lib.port_is_prog(model_global_port));
VTR_ASSERT_SAFE(false == fabric_global_port_info.global_port_is_prog(fabric_global_port));
stimuli_clock_port.set_name(std::string(TOP_TB_OP_CLOCK_PORT_NAME));
stimuli_clock_port.set_width(1);
}
@ -339,21 +290,21 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp,
*/
print_verilog_wire_connection(fp, module_manager.module_port(top_module, module_global_port),
stimuli_clock_port,
1 == circuit_lib.port_default_value(model_global_port));
1 == fabric_global_port_info.global_port_default_value(fabric_global_port));
}
/* Connect global configuration done ports to configuration done signal */
for (const CircuitPortId& model_global_port : global_ports) {
for (const FabricGlobalPortId& fabric_global_port : fabric_global_port_info.global_ports()) {
/* Bypass clock signals, they have been processed */
if (CIRCUIT_MODEL_PORT_CLOCK == circuit_lib.port_type(model_global_port)) {
if (true == fabric_global_port_info.global_port_is_clock(fabric_global_port)) {
continue;
}
if (false == circuit_lib.port_is_config_enable(model_global_port)) {
if (false == fabric_global_port_info.global_port_is_config_enable(fabric_global_port)) {
continue;
}
/* Reach here, it means we have a configuration done port to deal with */
/* Find the module port */
ModulePortId module_global_port = module_manager.find_module_port(top_module, circuit_lib.port_prefix(model_global_port));
ModulePortId module_global_port = fabric_global_port_info.global_module_port(fabric_global_port);
VTR_ASSERT(true == module_manager.valid_module_port_id(top_module, module_global_port));
BasicPort stimuli_config_done_port(std::string(TOP_TB_CONFIG_DONE_PORT_NAME), 1);
@ -363,37 +314,37 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp,
*/
print_verilog_wire_connection(fp, module_manager.module_port(top_module, module_global_port),
stimuli_config_done_port,
1 == circuit_lib.port_default_value(model_global_port));
1 == fabric_global_port_info.global_port_default_value(fabric_global_port));
}
/* Connect global reset ports to operating or programming reset signal */
for (const CircuitPortId& model_global_port : global_ports) {
for (const FabricGlobalPortId& fabric_global_port : fabric_global_port_info.global_ports()) {
/* Bypass clock signals, they have been processed */
if (CIRCUIT_MODEL_PORT_CLOCK == circuit_lib.port_type(model_global_port)) {
if (true == fabric_global_port_info.global_port_is_clock(fabric_global_port)) {
continue;
}
/* Bypass config_done signals, they have been processed */
if (true == circuit_lib.port_is_config_enable(model_global_port)) {
if (true == fabric_global_port_info.global_port_is_config_enable(fabric_global_port)) {
continue;
}
if (false == circuit_lib.port_is_reset(model_global_port)) {
if (false == fabric_global_port_info.global_port_is_reset(fabric_global_port)) {
continue;
}
/* Reach here, it means we have a reset port to deal with */
/* Find the module port */
ModulePortId module_global_port = module_manager.find_module_port(top_module, circuit_lib.port_prefix(model_global_port));
ModulePortId module_global_port = fabric_global_port_info.global_module_port(fabric_global_port);
VTR_ASSERT(true == module_manager.valid_module_port_id(top_module, module_global_port));
/* For global programming reset port, we will active only when specified */
BasicPort stimuli_reset_port;
bool activate = true;
if (true == circuit_lib.port_is_prog(model_global_port)) {
if (true == fabric_global_port_info.global_port_is_prog(fabric_global_port)) {
stimuli_reset_port.set_name(std::string(TOP_TB_PROG_RESET_PORT_NAME));
stimuli_reset_port.set_width(1);
activate = active_global_prog_reset;
} else {
VTR_ASSERT_SAFE(false == circuit_lib.port_is_prog(model_global_port));
VTR_ASSERT_SAFE(false == fabric_global_port_info.global_port_is_prog(fabric_global_port));
stimuli_reset_port.set_name(std::string(TOP_TB_RESET_PORT_NAME));
stimuli_reset_port.set_width(1);
}
@ -404,47 +355,47 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp,
if (true == activate) {
print_verilog_wire_connection(fp, module_manager.module_port(top_module, module_global_port),
stimuli_reset_port,
1 == circuit_lib.port_default_value(model_global_port));
1 == fabric_global_port_info.global_port_default_value(fabric_global_port));
} else {
VTR_ASSERT_SAFE(false == activate);
print_verilog_wire_constant_values(fp, module_manager.module_port(top_module, module_global_port),
std::vector<size_t>(1, circuit_lib.port_default_value(model_global_port)));
std::vector<size_t>(1, fabric_global_port_info.global_port_default_value(fabric_global_port)));
}
}
/* Connect global set ports to operating or programming set signal */
for (const CircuitPortId& model_global_port : global_ports) {
for (const FabricGlobalPortId& fabric_global_port : fabric_global_port_info.global_ports()) {
/* Bypass clock signals, they have been processed */
if (CIRCUIT_MODEL_PORT_CLOCK == circuit_lib.port_type(model_global_port)) {
if (true == fabric_global_port_info.global_port_is_clock(fabric_global_port)) {
continue;
}
/* Bypass config_done signals, they have been processed */
if (true == circuit_lib.port_is_config_enable(model_global_port)) {
if (true == fabric_global_port_info.global_port_is_config_enable(fabric_global_port)) {
continue;
}
/* Bypass reset signals, they have been processed */
if (true == circuit_lib.port_is_reset(model_global_port)) {
if (true == fabric_global_port_info.global_port_is_reset(fabric_global_port)) {
continue;
}
if (false == circuit_lib.port_is_set(model_global_port)) {
if (false == fabric_global_port_info.global_port_is_set(fabric_global_port)) {
continue;
}
/* Reach here, it means we have a set port to deal with */
/* Find the module port */
ModulePortId module_global_port = module_manager.find_module_port(top_module, circuit_lib.port_prefix(model_global_port));
ModulePortId module_global_port = fabric_global_port_info.global_module_port(fabric_global_port);
VTR_ASSERT(true == module_manager.valid_module_port_id(top_module, module_global_port));
/* For global programming set port, we will active only when specified */
BasicPort stimuli_set_port;
bool activate = true;
if (true == circuit_lib.port_is_prog(model_global_port)) {
if (true == fabric_global_port_info.global_port_is_prog(fabric_global_port)) {
stimuli_set_port.set_name(std::string(TOP_TB_PROG_SET_PORT_NAME));
stimuli_set_port.set_width(1);
activate = active_global_prog_set;
} else {
VTR_ASSERT_SAFE(false == circuit_lib.port_is_prog(model_global_port));
VTR_ASSERT_SAFE(false == fabric_global_port_info.global_port_is_prog(fabric_global_port));
stimuli_set_port.set_name(std::string(TOP_TB_SET_PORT_NAME));
stimuli_set_port.set_width(1);
}
@ -455,56 +406,51 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp,
if (true == activate) {
print_verilog_wire_connection(fp, module_manager.module_port(top_module, module_global_port),
stimuli_set_port,
1 == circuit_lib.port_default_value(model_global_port));
1 == fabric_global_port_info.global_port_default_value(fabric_global_port));
} else {
VTR_ASSERT_SAFE(false == activate);
print_verilog_wire_constant_values(fp, module_manager.module_port(top_module, module_global_port),
std::vector<size_t>(1, circuit_lib.port_default_value(model_global_port)));
std::vector<size_t>(1, fabric_global_port_info.global_port_default_value(fabric_global_port)));
}
}
/* For the rest of global ports, wire them to constant signals */
for (const CircuitPortId& model_global_port : global_ports) {
for (const FabricGlobalPortId& fabric_global_port : fabric_global_port_info.global_ports()) {
/* Bypass clock signals, they have been processed */
if (CIRCUIT_MODEL_PORT_CLOCK == circuit_lib.port_type(model_global_port)) {
if (true == fabric_global_port_info.global_port_is_clock(fabric_global_port)) {
continue;
}
/* Bypass config_done signals, they have been processed */
if (true == circuit_lib.port_is_config_enable(model_global_port)) {
if (true == fabric_global_port_info.global_port_is_config_enable(fabric_global_port)) {
continue;
}
/* Bypass reset signals, they have been processed */
if (true == circuit_lib.port_is_reset(model_global_port)) {
if (true == fabric_global_port_info.global_port_is_reset(fabric_global_port)) {
continue;
}
/* Bypass set signals, they have been processed */
if (true == circuit_lib.port_is_set(model_global_port)) {
if (true == fabric_global_port_info.global_port_is_set(fabric_global_port)) {
continue;
}
/* Bypass io signals, they do not need any drivers */
if (true == circuit_lib.port_is_io(model_global_port)) {
if (true == fabric_global_port_info.global_port_is_io(fabric_global_port)) {
continue;
}
/* Find the port name, gpio port has special names */
std::string port_name;
if (true == circuit_lib.port_is_io(model_global_port)) {
port_name = generate_fpga_global_io_port_name(std::string(GIO_INOUT_PREFIX), circuit_lib, circuit_lib.port_parent_model(model_global_port), model_global_port);
} else {
VTR_ASSERT_SAFE(false == circuit_lib.port_is_io(model_global_port));
port_name = circuit_lib.port_prefix(model_global_port);
}
VTR_ASSERT_SAFE(false == fabric_global_port_info.global_port_is_io(fabric_global_port));
/* Reach here, it means we have a port to deal with */
/* Find the module port and wire it to constant values */
ModulePortId module_global_port = module_manager.find_module_port(top_module, port_name);
ModulePortId module_global_port = fabric_global_port_info.global_module_port(fabric_global_port);
VTR_ASSERT(true == module_manager.valid_module_port_id(top_module, module_global_port));
BasicPort module_port = module_manager.module_port(top_module, module_global_port);
std::vector<size_t> default_values(module_port.get_width(), circuit_lib.port_default_value(model_global_port));
std::vector<size_t> default_values(module_port.get_width(), fabric_global_port_info.global_port_default_value(fabric_global_port));
print_verilog_wire_constant_values(fp, module_port, default_values);
}
@ -1279,8 +1225,8 @@ void print_verilog_top_testbench_vanilla_bitstream(std::fstream& fp,
static
bool find_bit_value_to_skip_for_fast_configuration(const e_config_protocol_type& config_protocol_type,
const bool& fast_configuration,
const std::vector<CircuitPortId>& global_prog_reset_ports,
const std::vector<CircuitPortId>& global_prog_set_ports,
const std::vector<FabricGlobalPortId>& global_prog_reset_ports,
const std::vector<FabricGlobalPortId>& global_prog_set_ports,
const BitstreamManager& bitstream_manager,
const FabricBitstream& fabric_bitstream) {
@ -1824,8 +1770,7 @@ void print_verilog_top_testbench(const ModuleManager& module_manager,
const BitstreamManager& bitstream_manager,
const FabricBitstream& fabric_bitstream,
const ConfigProtocol& config_protocol,
const CircuitLibrary& circuit_lib,
const std::vector<CircuitPortId>& global_ports,
const FabricGlobalPortInfo& global_ports,
const AtomContext& atom_ctx,
const PlacementContext& place_ctx,
const IoLocationMap& io_location_map,
@ -1860,8 +1805,8 @@ void print_verilog_top_testbench(const ModuleManager& module_manager,
std::vector<std::string> clock_port_names = find_atom_netlist_clock_port_names(atom_ctx.nlist, netlist_annotation);
/* Preparation: find all the reset/set ports for programming usage */
std::vector<CircuitPortId> global_prog_reset_ports = find_global_programming_reset_ports(circuit_lib, global_ports);
std::vector<CircuitPortId> global_prog_set_ports = find_global_programming_set_ports(circuit_lib, global_ports);
std::vector<FabricGlobalPortId> global_prog_reset_ports = find_fabric_global_programming_reset_ports(global_ports);
std::vector<FabricGlobalPortId> global_prog_set_ports = find_fabric_global_programming_set_ports(global_ports);
/* Identify if we can apply fast configuration */
bool apply_fast_configuration = fast_configuration;
@ -1935,7 +1880,7 @@ void print_verilog_top_testbench(const ModuleManager& module_manager,
/* Generate stimuli for global ports or connect them to existed signals */
print_verilog_top_testbench_global_ports_stimuli(fp,
module_manager, top_module,
circuit_lib, global_ports,
global_ports,
active_global_prog_reset,
active_global_prog_set);

View File

@ -9,10 +9,10 @@
#include "module_manager.h"
#include "bitstream_manager.h"
#include "fabric_bitstream.h"
#include "circuit_library.h"
#include "config_protocol.h"
#include "vpr_context.h"
#include "io_location_map.h"
#include "fabric_global_port_info.h"
#include "vpr_netlist_annotation.h"
#include "simulation_setting.h"
@ -27,8 +27,7 @@ void print_verilog_top_testbench(const ModuleManager& module_manager,
const BitstreamManager& bitstream_manager,
const FabricBitstream& fabric_bitstream,
const ConfigProtocol& config_protocol,
const CircuitLibrary& circuit_lib,
const std::vector<CircuitPortId>& global_ports,
const FabricGlobalPortInfo& global_ports,
const AtomContext& atom_ctx,
const PlacementContext& place_ctx,
const IoLocationMap& io_location_map,

View File

@ -0,0 +1,229 @@
/************************************************************************
* Check functions for the content of tile annotation to avoid conflicts with
* other data structures
* These functions are not universal methods for the TileAnnotation class
* They are made to ease the development in some specific purposes
* Please classify such functions in this file
***********************************************************************/
#include <algorithm>
/* Headers from vtrutil library */
#include "vtr_assert.h"
#include "vtr_log.h"
#include "openfpga_physical_tile_utils.h"
#include "circuit_library_utils.h"
#include "check_tile_annotation.h"
/* begin namespace openfpga */
namespace openfpga {
/********************************************************************
* Check if the tile annotation is valid without any conflict with
* circuit library content.
* Items to check:
* - The global port defined in tile annotation has no conflicts with
* the global ports which are defined in circuit library:
* - If a port has the same name, must ensure that its attributes are the same
* i.e., is_clock, is_reset, is_set
* - Otherwise, error out
*******************************************************************/
static
int check_tile_annotation_conflicts_with_circuit_library(const TileAnnotation& tile_annotation,
const CircuitLibrary& circuit_lib) {
int num_err = 0;
std::vector<CircuitPortId> ckt_global_ports = find_circuit_library_global_ports(circuit_lib);
for (const TileGlobalPortId& tile_global_port : tile_annotation.global_ports()) {
for (const CircuitPortId& ckt_global_port : ckt_global_ports) {
if (tile_annotation.global_port_name(tile_global_port) != circuit_lib.port_prefix(ckt_global_port)) {
continue;
}
/* All the global clock port here must be operating clock */
bool is_both_op_signal = !circuit_lib.port_is_prog(ckt_global_port);
if (false == is_both_op_signal) {
VTR_LOGF_ERROR(__FILE__, __LINE__,
"Global port '%s' in tile annotation share the same name as global port '%s' in circuit library, which is defined for programming usage!\n",
tile_annotation.global_port_name(tile_global_port).c_str(),
circuit_lib.port_prefix(ckt_global_port).c_str());
num_err++;
}
/* Error out if one is defined as clock while another is not */
bool is_clock_attr_same = (tile_annotation.global_port_is_clock(tile_global_port) != (CIRCUIT_MODEL_PORT_CLOCK == circuit_lib.port_type(ckt_global_port)));
if (false == is_clock_attr_same) {
VTR_LOGF_ERROR(__FILE__, __LINE__,
"Global port '%s' in tile annotation share the same name as global port '%s' in circuit library but has different definition as clock!\n",
tile_annotation.global_port_name(tile_global_port).c_str(),
circuit_lib.port_prefix(ckt_global_port).c_str());
num_err++;
}
/* Error out if one is defined as reset while another is not */
bool is_reset_attr_same = (tile_annotation.global_port_is_reset(tile_global_port) != circuit_lib.port_is_reset(ckt_global_port));
if (false == is_reset_attr_same) {
VTR_LOGF_ERROR(__FILE__, __LINE__,
"Global port '%s' in tile annotation share the same name as global port '%s' in circuit library but has different definition as reset!\n",
tile_annotation.global_port_name(tile_global_port).c_str(),
circuit_lib.port_prefix(ckt_global_port).c_str());
num_err++;
}
/* Error out if one is defined as set while another is not */
bool is_set_attr_same = (tile_annotation.global_port_is_set(tile_global_port) != circuit_lib.port_is_set(ckt_global_port));
if (false == is_set_attr_same) {
VTR_LOGF_ERROR(__FILE__, __LINE__,
"Global port '%s' in tile annotation share the same name as global port '%s' in circuit library but has different definition as set!\n",
tile_annotation.global_port_name(tile_global_port).c_str(),
circuit_lib.port_prefix(ckt_global_port).c_str());
num_err++;
}
}
}
return num_err;
}
/********************************************************************
* Check if the tile annotation is valid without any conflict with
* physical tile definition.
* Items to check:
* - The global port defined in tile annotation is a valid port/pin in
* the physical tile definition.
* - If the port properties match:
* - the port in physical tile should have Fc = 0
* - a clock port should be also a clock port in physical tile
* - a non-clock port should be defined as a non-clock global port in physical tile
*******************************************************************/
static
int check_tile_annotation_conflicts_with_physical_tile(const TileAnnotation& tile_annotation,
const std::vector<t_physical_tile_type>& physical_tile_types) {
int num_err = 0;
for (const TileGlobalPortId& tile_global_port : tile_annotation.global_ports()) {
/* Must find a valid physical tile in the same name */
size_t found_matched_physical_tile = 0;
size_t found_matched_physical_tile_port = 0;
for (const t_physical_tile_type& physical_tile : physical_tile_types) {
if (std::string(physical_tile.name) != tile_annotation.global_port_tile_name(tile_global_port)) {
continue;
}
/* Found a match, increment the counter */
found_matched_physical_tile++;
/* Must found a valid port where both port name and port size must match!!! */
for (const t_physical_tile_port& tile_port : physical_tile.ports) {
if (std::string(tile_port.name) != tile_annotation.global_port_tile_port(tile_global_port).get_name()) {
continue;
}
if (size_t(tile_port.num_pins) != tile_annotation.global_port_tile_port(tile_global_port).get_width()) {
continue;
}
/* Check if port property matches */
int grid_pin_index = tile_port.absolute_first_pin_index;
if (tile_port.is_clock != tile_annotation.global_port_is_clock(tile_global_port)) {
VTR_LOGF_ERROR(__FILE__, __LINE__,
"Tile port '%s.%s[%ld:%ld]' in tile annotation '%s' does not match physical tile port %s.%s in clock property (one is defined as clock while the other is not)!\n",
tile_annotation.global_port_tile_name(tile_global_port).c_str(),
tile_annotation.global_port_tile_port(tile_global_port).get_name().c_str(),
tile_annotation.global_port_tile_port(tile_global_port).get_lsb(),
tile_annotation.global_port_tile_port(tile_global_port).get_msb(),
tile_annotation.global_port_name(tile_global_port).c_str(),
physical_tile.name, tile_port.name);
num_err++;
}
if ((false == tile_port.is_clock)
&& (false == tile_port.is_non_clock_global)) {
VTR_LOGF_ERROR(__FILE__, __LINE__,
"Tile port '%s.%s[%ld:%ld]' in tile annotation '%s' match physical tile port %s.%s but is not defined as a non-clock global port!\n",
tile_annotation.global_port_tile_name(tile_global_port).c_str(),
tile_annotation.global_port_tile_port(tile_global_port).get_name().c_str(),
tile_annotation.global_port_tile_port(tile_global_port).get_lsb(),
tile_annotation.global_port_tile_port(tile_global_port).get_msb(),
tile_annotation.global_port_name(tile_global_port).c_str(),
physical_tile.name, tile_port.name);
num_err++;
}
float pin_Fc = find_physical_tile_pin_Fc(&physical_tile, grid_pin_index);
if (0. != pin_Fc) {
VTR_LOGF_ERROR(__FILE__, __LINE__,
"Tile port '%s.%s[%ld:%ld]' in tile annotation '%s' match physical tile port %s.%s but its Fc is not zero '%g' !\n",
tile_annotation.global_port_tile_name(tile_global_port).c_str(),
tile_annotation.global_port_tile_port(tile_global_port).get_name().c_str(),
tile_annotation.global_port_tile_port(tile_global_port).get_lsb(),
tile_annotation.global_port_tile_port(tile_global_port).get_msb(),
tile_annotation.global_port_name(tile_global_port).c_str(),
physical_tile.name, tile_port.name, pin_Fc);
}
found_matched_physical_tile_port++;
}
}
/* If we found no match, error out */
if (0 == found_matched_physical_tile) {
VTR_LOGF_ERROR(__FILE__, __LINE__,
"Tile name '%s' in tile annotation '%s' does not match any physical tile!\n",
tile_annotation.global_port_tile_name(tile_global_port).c_str(),
tile_annotation.global_port_name(tile_global_port).c_str());
num_err++;
}
if (0 == found_matched_physical_tile_port) {
VTR_LOGF_ERROR(__FILE__, __LINE__,
"Tile port '%s.%s[%ld:%ld]' in tile annotation '%s' does not match any physical tile port!\n",
tile_annotation.global_port_tile_name(tile_global_port).c_str(),
tile_annotation.global_port_tile_port(tile_global_port).get_name().c_str(),
tile_annotation.global_port_tile_port(tile_global_port).get_lsb(),
tile_annotation.global_port_tile_port(tile_global_port).get_msb(),
tile_annotation.global_port_name(tile_global_port).c_str());
num_err++;
}
/* If we found more than 1 match, error out */
if (1 < found_matched_physical_tile) {
VTR_LOGF_ERROR(__FILE__, __LINE__,
"Tile name '%s' in tile annotation '%s' match more than 1 physical tile!\n",
tile_annotation.global_port_tile_name(tile_global_port).c_str(),
tile_annotation.global_port_name(tile_global_port).c_str());
num_err++;
}
if (1 < found_matched_physical_tile_port) {
VTR_LOGF_ERROR(__FILE__, __LINE__,
"Tile port '%s.%s[%ld:%ld]' in tile annotation '%s' match more than 1physical tile port!\n",
tile_annotation.global_port_tile_name(tile_global_port).c_str(),
tile_annotation.global_port_tile_port(tile_global_port).get_name().c_str(),
tile_annotation.global_port_tile_port(tile_global_port).get_lsb(),
tile_annotation.global_port_tile_port(tile_global_port).get_msb(),
tile_annotation.global_port_name(tile_global_port).c_str());
num_err++;
}
}
return num_err;
}
/********************************************************************
* Check if the tile annotation is valid without any conflict with
* circuit library content and physical tiles.
*******************************************************************/
bool check_tile_annotation(const TileAnnotation& tile_annotation,
const CircuitLibrary& circuit_lib,
const std::vector<t_physical_tile_type>& physical_tile_types) {
int num_err = 0;
num_err += check_tile_annotation_conflicts_with_circuit_library(tile_annotation, circuit_lib);
num_err += check_tile_annotation_conflicts_with_physical_tile(tile_annotation, physical_tile_types);
VTR_LOG("Found %ld errors when checking tile annotation!\n",
num_err);
return (0 == num_err);
}
} /* end namespace openfpga */

View File

@ -0,0 +1,25 @@
#ifndef CHECK_TILE_ANNOTATION_H
#define CHECK_TILE_ANNOTATION_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include <vector>
#include "tile_annotation.h"
#include "circuit_library.h"
#include "physical_types.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* begin namespace openfpga */
namespace openfpga {
bool check_tile_annotation(const TileAnnotation& tile_annotations,
const CircuitLibrary& circuit_lib,
const std::vector<t_physical_tile_type>& physical_tile_types);
} /* end namespace openfpga */
#endif

View File

@ -0,0 +1,61 @@
/************************************************************************
* Function to perform fundamental operation for the fabric global ports
* These functions are not universal methods for the FabricGlobalPortInfo class
* They are made to ease the development in some specific purposes
* Please classify such functions in this file
***********************************************************************/
#include <algorithm>
/* Headers from vtrutil library */
#include "vtr_assert.h"
#include "vtr_log.h"
#include "fabric_global_port_info_utils.h"
/* begin namespace openfpga */
namespace openfpga {
/********************************************************************
* Identify global reset ports for programming
*******************************************************************/
std::vector<FabricGlobalPortId> find_fabric_global_programming_reset_ports(const FabricGlobalPortInfo& fabric_global_port_info) {
/* Try to find global reset ports for programming */
std::vector<FabricGlobalPortId> global_prog_reset_ports;
for (const FabricGlobalPortId& global_port : fabric_global_port_info.global_ports()) {
if (false == fabric_global_port_info.global_port_is_prog(global_port)) {
continue;
}
VTR_ASSERT(true == fabric_global_port_info.global_port_is_prog(global_port));
VTR_ASSERT( (false == fabric_global_port_info.global_port_is_reset(global_port))
|| (false == fabric_global_port_info.global_port_is_set(global_port)));
if (true == fabric_global_port_info.global_port_is_reset(global_port)) {
global_prog_reset_ports.push_back(global_port);
}
}
return global_prog_reset_ports;
}
/********************************************************************
* Identify global set ports for programming
*******************************************************************/
std::vector<FabricGlobalPortId> find_fabric_global_programming_set_ports(const FabricGlobalPortInfo& fabric_global_port_info) {
/* Try to find global set ports for programming */
std::vector<FabricGlobalPortId> global_prog_set_ports;
for (const FabricGlobalPortId& global_port : fabric_global_port_info.global_ports()) {
if (false == fabric_global_port_info.global_port_is_prog(global_port)) {
continue;
}
VTR_ASSERT(true == fabric_global_port_info.global_port_is_prog(global_port));
VTR_ASSERT( (false == fabric_global_port_info.global_port_is_reset(global_port))
|| (false == fabric_global_port_info.global_port_is_set(global_port)));
if (true == fabric_global_port_info.global_port_is_set(global_port)) {
global_prog_set_ports.push_back(global_port);
}
}
return global_prog_set_ports;
}
} /* end namespace openfpga */

View File

@ -0,0 +1,23 @@
#ifndef FABRIC_GLOBAL_PORT_INFO_UTILS_H
#define FABRIC_GLOBAL_PORT_INFO_UTILS_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include <vector>
#include "fabric_global_port_info.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* begin namespace openfpga */
namespace openfpga {
std::vector<FabricGlobalPortId> find_fabric_global_programming_reset_ports(const FabricGlobalPortInfo& fabric_global_port_info);
std::vector<FabricGlobalPortId> find_fabric_global_programming_set_ports(const FabricGlobalPortInfo& fabric_global_port_info);
} /* end namespace openfpga */
#endif

View File

@ -564,7 +564,6 @@ void add_primitive_pb_type_module_nets(ModuleManager& module_manager,
BasicPort des_port = module_manager.module_port(child_module, des_module_port_id);
/* Port size must match */
if (src_port.get_width() != des_port.get_width())
VTR_ASSERT(src_port.get_width() == des_port.get_width());
/* For each pin, generate the nets.
@ -588,9 +587,9 @@ void add_primitive_pb_type_module_nets(ModuleManager& module_manager,
for (size_t pin_id = 0; pin_id < src_port.pins().size(); ++pin_id) {
ModuleNetId net = module_manager.create_module_net(pb_type_module);
/* Add net source */
module_manager.add_module_net_sink(pb_type_module, net, pb_type_module, 0, src_module_port_id, src_port.pins()[pin_id]);
/* Add net sink */
module_manager.add_module_net_source(pb_type_module, net, child_module, child_instance_id, des_module_port_id, des_port.pins()[pin_id]);
/* Add net sink */
module_manager.add_module_net_sink(pb_type_module, net, pb_type_module, 0, src_module_port_id, src_port.pins()[pin_id]);
}
break;
default:

View File

@ -8,12 +8,50 @@
#include "vtr_assert.h"
#include "vtr_time.h"
/* Headers from openfpgautil library */
#include "openfpga_side_manager.h"
#include "openfpga_device_grid_utils.h"
#include "openfpga_physical_tile_utils.h"
/* begin namespace openfpga */
namespace openfpga {
/********************************************************************
* Give a given pin index, find the side where this pin is located
* on the physical tile
* Note:
* - Need to check if the pin_width_offset and pin_height_offset
* are properly set in VPR!!!
*******************************************************************/
std::vector<e_side> find_physical_tile_pin_side(t_physical_tile_type_ptr physical_tile,
const int& physical_pin,
const e_side& border_side) {
std::vector<e_side> pin_sides;
for (const e_side& side_cand : {TOP, RIGHT, BOTTOM, LEFT}) {
int pin_width_offset = physical_tile->pin_width_offset[physical_pin];
int pin_height_offset = physical_tile->pin_height_offset[physical_pin];
if (true == physical_tile->pinloc[pin_width_offset][pin_height_offset][side_cand][physical_pin]) {
pin_sides.push_back(side_cand);
}
}
/* For regular grid, we should have pin only one side!
* I/O grids: VPR creates the grid with duplicated pins on every side
* but the expected side (only used side) will be opposite side of the border side!
*/
if (NUM_SIDES == border_side) {
VTR_ASSERT(1 == pin_sides.size());
} else {
SideManager side_manager(border_side);
VTR_ASSERT(pin_sides.end() != std::find(pin_sides.begin(), pin_sides.end(), side_manager.get_opposite()));
pin_sides.clear();
pin_sides.push_back(side_manager.get_opposite());
}
return pin_sides;
}
/********************************************************************
* Find the Fc of a pin in physical tile
*******************************************************************/

View File

@ -17,6 +17,10 @@
/* begin namespace openfpga */
namespace openfpga {
std::vector<e_side> find_physical_tile_pin_side(t_physical_tile_type_ptr physical_tile,
const int& physical_pin,
const e_side& border_side);
float find_physical_tile_pin_Fc(t_physical_tile_type_ptr type,
const int& pin);

View File

@ -0,0 +1,192 @@
<!-- Architecture annotation for OpenFPGA framework
This annotation supports the k6_N10_40nm.xml
- General purpose logic block
- K = 6, N = 10, I = 40
- Single mode
- Routing architecture
- L = 4, fc_in = 0.15, fc_out = 0.1
-->
<openfpga_architecture>
<technology_library>
<device_library>
<device_model name="logic" type="transistor">
<lib type="industry" corner="TOP_TT" ref="M" path="${OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.pm"/>
<design vdd="0.9" pn_ratio="2"/>
<pmos name="pch" chan_length="40e-9" min_width="140e-9" variation="logic_transistor_var"/>
<nmos name="nch" chan_length="40e-9" min_width="140e-9" variation="logic_transistor_var"/>
</device_model>
<device_model name="io" type="transistor">
<lib type="academia" ref="M" path="${OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.pm"/>
<design vdd="2.5" pn_ratio="3"/>
<pmos name="pch_25" chan_length="270e-9" min_width="320e-9" variation="io_transistor_var"/>
<nmos name="nch_25" chan_length="270e-9" min_width="320e-9" variation="io_transistor_var"/>
</device_model>
</device_library>
<variation_library>
<variation name="logic_transistor_var" abs_deviation="0.1" num_sigma="3"/>
<variation name="io_transistor_var" abs_deviation="0.1" num_sigma="3"/>
</variation_library>
</technology_library>
<circuit_library>
<circuit_model type="inv_buf" name="INVTX1" prefix="INVTX1" is_default="true">
<design_technology type="cmos" topology="inverter" size="1"/>
<device_technology device_model_name="logic"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<delay_matrix type="rise" in_port="in" out_port="out">
10e-12
</delay_matrix>
<delay_matrix type="fall" in_port="in" out_port="out">
10e-12
</delay_matrix>
</circuit_model>
<circuit_model type="inv_buf" name="buf4" prefix="buf4" is_default="false">
<design_technology type="cmos" topology="buffer" size="1" num_level="2" f_per_stage="4"/>
<device_technology device_model_name="logic"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<delay_matrix type="rise" in_port="in" out_port="out">
10e-12
</delay_matrix>
<delay_matrix type="fall" in_port="in" out_port="out">
10e-12
</delay_matrix>
</circuit_model>
<circuit_model type="inv_buf" name="tap_buf4" prefix="tap_buf4" is_default="false">
<design_technology type="cmos" topology="buffer" size="1" num_level="3" f_per_stage="4"/>
<device_technology device_model_name="logic"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<delay_matrix type="rise" in_port="in" out_port="out">
10e-12
</delay_matrix>
<delay_matrix type="fall" in_port="in" out_port="out">
10e-12
</delay_matrix>
</circuit_model>
<circuit_model type="pass_gate" name="TGATE" prefix="TGATE" is_default="true">
<design_technology type="cmos" topology="transmission_gate" nmos_size="1" pmos_size="2"/>
<device_technology device_model_name="logic"/>
<input_buffer exist="false"/>
<output_buffer exist="false"/>
<port type="input" prefix="in" size="1"/>
<port type="input" prefix="sel" size="1"/>
<port type="input" prefix="selb" size="1"/>
<port type="output" prefix="out" size="1"/>
<delay_matrix type="rise" in_port="in sel selb" out_port="out">
10e-12 5e-12 5e-12
</delay_matrix>
<delay_matrix type="fall" in_port="in sel selb" out_port="out">
10e-12 5e-12 5e-12
</delay_matrix>
</circuit_model>
<circuit_model type="chan_wire" name="chan_segment" prefix="track_seg" is_default="true">
<design_technology type="cmos"/>
<input_buffer exist="false"/>
<output_buffer exist="false"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<wire_param model_type="pi" R="101" C="22.5e-15" num_level="1"/> <!-- model_type could be T, res_val and cap_val DON'T CARE -->
</circuit_model>
<circuit_model type="wire" name="direct_interc" prefix="direct_interc" is_default="true">
<design_technology type="cmos"/>
<input_buffer exist="false"/>
<output_buffer exist="false"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<wire_param model_type="pi" R="0" C="0" num_level="1"/> <!-- model_type could be T, res_val cap_val should be defined -->
</circuit_model>
<circuit_model type="mux" name="mux_tree" prefix="mux_tree" dump_structural_verilog="true">
<design_technology type="cmos" structure="tree" add_const_input="true" const_input_val="1"/>
<input_buffer exist="true" circuit_model_name="INVTX1"/>
<output_buffer exist="true" circuit_model_name="INVTX1"/>
<pass_gate_logic circuit_model_name="TGATE"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<port type="sram" prefix="sram" size="1"/>
</circuit_model>
<circuit_model type="mux" name="mux_tree_tapbuf" prefix="mux_tree_tapbuf" is_default="true" dump_structural_verilog="true">
<design_technology type="cmos" structure="tree" add_const_input="true" const_input_val="1"/>
<input_buffer exist="true" circuit_model_name="INVTX1"/>
<output_buffer exist="true" circuit_model_name="tap_buf4"/>
<pass_gate_logic circuit_model_name="TGATE"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<port type="sram" prefix="sram" size="1"/>
</circuit_model>
<!--DFF subckt ports should be defined as <D> <Q> <CLK> <RESET> <SET> -->
<circuit_model type="ff" name="DFFSRQ" prefix="DFFSRQ" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/spice/dff.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/verilog/dff.v">
<design_technology type="cmos"/>
<input_buffer exist="true" circuit_model_name="INVTX1"/>
<output_buffer exist="true" circuit_model_name="INVTX1"/>
<port type="input" prefix="D" size="1"/>
<port type="input" prefix="set" lib_name="SET" size="1" is_global="true" default_val="0" is_set="true"/>
<port type="input" prefix="reset" lib_name="RST" size="1" is_global="true" default_val="0" is_reset="true"/>
<port type="output" prefix="Q" size="1"/>
<port type="clock" prefix="clk" lib_name="CK" size="1" is_global="false" default_val="0"/>
</circuit_model>
<circuit_model type="lut" name="lut4" prefix="lut4" dump_structural_verilog="true">
<design_technology type="cmos"/>
<input_buffer exist="true" circuit_model_name="INVTX1"/>
<output_buffer exist="true" circuit_model_name="INVTX1"/>
<lut_input_inverter exist="true" circuit_model_name="INVTX1"/>
<lut_input_buffer exist="true" circuit_model_name="buf4"/>
<pass_gate_logic circuit_model_name="TGATE"/>
<port type="input" prefix="in" size="4"/>
<port type="output" prefix="out" size="1"/>
<port type="sram" prefix="sram" size="16"/>
</circuit_model>
<!--Scan-chain DFF subckt ports should be defined as <D> <Q> <Qb> <CLK> <RESET> <SET> -->
<circuit_model type="ccff" name="DFF" prefix="DFF" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/spice/dff.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/verilog/dff.v">
<design_technology type="cmos"/>
<input_buffer exist="true" circuit_model_name="INVTX1"/>
<output_buffer exist="true" circuit_model_name="INVTX1"/>
<port type="input" prefix="D" size="1"/>
<port type="output" prefix="Q" size="1"/>
<port type="output" prefix="QN" size="1"/>
<port type="clock" prefix="prog_clk" lib_name="CK" size="1" is_global="true" default_val="0" is_prog="true"/>
</circuit_model>
<circuit_model type="iopad" name="GPIO" prefix="GPIO" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/spice/gpio.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/verilog/gpio.v">
<design_technology type="cmos"/>
<input_buffer exist="true" circuit_model_name="INVTX1"/>
<output_buffer exist="true" circuit_model_name="INVTX1"/>
<port type="inout" prefix="PAD" size="1" is_global="true" is_io="true" is_data_io="true"/>
<port type="sram" prefix="DIR" size="1" mode_select="true" circuit_model_name="DFF" default_val="1"/>
<port type="input" prefix="outpad" lib_name="A" size="1"/>
<port type="output" prefix="inpad" lib_name="Y" size="1"/>
</circuit_model>
</circuit_library>
<configuration_protocol>
<organization type="scan_chain" circuit_model_name="DFF"/>
</configuration_protocol>
<connection_block>
<switch name="ipin_cblock" circuit_model_name="mux_tree_tapbuf"/>
</connection_block>
<switch_block>
<switch name="0" circuit_model_name="mux_tree_tapbuf"/>
</switch_block>
<routing_segment>
<segment name="L4" circuit_model_name="chan_segment"/>
</routing_segment>
<tile_annotations>
<global_port name="clk" tile_port="clb.clk" is_clock="true" default_val="0"/>
</tile_annotations>
<pb_type_annotations>
<!-- physical pb_type binding in complex block IO -->
<pb_type name="io" physical_mode_name="physical" idle_mode_name="inpad"/>
<pb_type name="io[physical].iopad" circuit_model_name="GPIO" mode_bits="1"/>
<pb_type name="io[inpad].inpad" physical_pb_type_name="io[physical].iopad" mode_bits="1"/>
<pb_type name="io[outpad].outpad" physical_pb_type_name="io[physical].iopad" mode_bits="0"/>
<!-- End physical pb_type binding in complex block IO -->
<!-- physical pb_type binding in complex block CLB -->
<!-- physical mode will be the default mode if not specified -->
<pb_type name="clb">
<!-- Binding interconnect to circuit models as their physical implementation, if not defined, we use the default model -->
<interconnect name="crossbar" circuit_model_name="mux_tree"/>
</pb_type>
<pb_type name="clb.fle[n1_lut4].ble4.lut4" circuit_model_name="lut4"/>
<pb_type name="clb.fle[n1_lut4].ble4.ff" circuit_model_name="DFFSRQ"/>
<!-- End physical pb_type binding in complex block IO -->
</pb_type_annotations>
</openfpga_architecture>

View File

@ -0,0 +1,34 @@
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# 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 = true
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/OpenFPGAShellScripts/configuration_chain_example_script.openfpga
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_GlobalTileClk_cc_openfpga.xml
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
[ARCHITECTURES]
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_GlobalTileClk_40nm.xml
[BENCHMARKS]
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.v
[SYNTHESIS_PARAM]
bench0_top = and2
bench0_chan_width = 300
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
end_flow_with_test=

View File

@ -0,0 +1,295 @@
<!--
Architecture with no fracturable LUTs
- 40 nm technology
- General purpose logic block:
K = 4, N = 4
- Routing architecture: L = 4, fc_in = 0.15, Fc_out = 0.1
Details on Modelling:
Based on flagship k6_frac_N10_mem32K_40nm.xml architecture. This architecture has no fracturable LUTs nor any heterogeneous blocks.
Authors: Jason Luu, Jeff Goeders, Vaughn Betz
-->
<architecture>
<!--
ODIN II specific config begins
Describes the types of user-specified netlist blocks (in blif, this corresponds to
".model [type_of_block]") that this architecture supports.
Note: Basic LUTs, I/Os, and flip-flops are not included here as there are
already special structures in blif (.names, .input, .output, and .latch)
that describe them.
-->
<models>
<!-- A virtual model for I/O to be used in the physical mode of io block -->
<model name="io">
<input_ports>
<port name="outpad"/>
</input_ports>
<output_ports>
<port name="inpad"/>
</output_ports>
</model>
</models>
<tiles>
<tile name="io" capacity="8" area="0">
<equivalent_sites>
<site pb_type="io"/>
</equivalent_sites>
<input name="outpad" num_pins="1"/>
<output name="inpad" num_pins="1"/>
<fc in_type="frac" in_val="0.15" out_type="frac" out_val="0.10"/>
<pinlocations pattern="custom">
<loc side="left">io.outpad io.inpad</loc>
<loc side="top">io.outpad io.inpad</loc>
<loc side="right">io.outpad io.inpad</loc>
<loc side="bottom">io.outpad io.inpad</loc>
</pinlocations>
</tile>
<tile name="clb" area="53894">
<equivalent_sites>
<site pb_type="clb"/>
</equivalent_sites>
<input name="I" num_pins="10" equivalent="full"/>
<output name="O" num_pins="4" equivalent="none"/>
<clock name="clk" num_pins="1"/>
<fc in_type="frac" in_val="0.15" out_type="frac" out_val="0.10">
<fc_override port_name="clk" fc_type="frac" fc_val="0"/>
</fc>
<pinlocations pattern="spread"/>
</tile>
</tiles>
<!-- ODIN II specific config ends -->
<!-- Physical descriptions begin -->
<layout tileable="true">
<auto_layout aspect_ratio="1.0">
<!--Perimeter of 'io' blocks with 'EMPTY' blocks at corners-->
<perimeter type="io" priority="100"/>
<corners type="EMPTY" priority="101"/>
<!--Fill with 'clb'-->
<fill type="clb" priority="10"/>
</auto_layout>
<fixed_layout name="2x2" width="4" height="4">
<!--Perimeter of 'io' blocks with 'EMPTY' blocks at corners-->
<perimeter type="io" priority="100"/>
<corners type="EMPTY" priority="101"/>
<!--Fill with 'clb'-->
<fill type="clb" priority="10"/>
</fixed_layout>
</layout>
<device>
<!-- VB & JL: Using Ian Kuon's transistor sizing and drive strength data for routing, at 40 nm. Ian used BPTM
models. We are modifying the delay values however, to include metal C and R, which allows more architecture
experimentation. We are also modifying the relative resistance of PMOS to be 1.8x that of NMOS
(vs. Ian's 3x) as 1.8x lines up with Jeff G's data from a 45 nm process (and is more typical of
45 nm in general). I'm upping the Rmin_nmos from Ian's just over 6k to nearly 9k, and dropping
RminW_pmos from 18k to 16k to hit this 1.8x ratio, while keeping the delays of buffers approximately
lined up with Stratix IV.
We are using Jeff G.'s capacitance data for 45 nm (in tech/ptm_45nm).
Jeff's tables list C in for transistors with widths in multiples of the minimum feature size (45 nm).
The minimum contactable transistor is 2.5 * 45 nm, so I need to multiply drive strength sizes in this file
by 2.5x when looking up in Jeff's tables.
The delay values are lined up with Stratix IV, which has an architecture similar to this
proposed FPGA, and which is also 40 nm
C_ipin_cblock: input capacitance of a track buffer, which VPR assumes is a single-stage
4x minimum drive strength buffer. -->
<sizing R_minW_nmos="8926" R_minW_pmos="16067"/>
<!-- The grid_logic_tile_area below will be used for all blocks that do not explicitly set their own (non-routing)
area; set to 0 since we explicitly set the area of all blocks currently in this architecture file.
-->
<area grid_logic_tile_area="0"/>
<chan_width_distr>
<x distr="uniform" peak="1.000000"/>
<y distr="uniform" peak="1.000000"/>
</chan_width_distr>
<switch_block type="wilton" fs="3"/>
<connection_block input_switch_name="ipin_cblock"/>
</device>
<switchlist>
<!-- VB: the mux_trans_size and buf_size data below is in minimum width transistor *areas*, assuming the purple
book area formula. This means the mux transistors are about 5x minimum drive strength.
We assume the first stage of the buffer is 3x min drive strength to be reasonable given the large
mux transistors, and this gives a reasonable stage ratio of a bit over 5x to the second stage. We assume
the n and p transistors in the first stage are equal-sized to lower the buffer trip point, since it's fed
by a pass transistor mux. We can then reverse engineer the buffer second stage to hit the specified
buf_size (really buffer area) - 16.2x minimum drive nmos and 1.8*16.2 = 29.2x minimum drive.
I then took the data from Jeff G.'s PTM modeling of 45 nm to get the Cin (gate of first stage) and Cout
(diff of second stage) listed below. Jeff's models are in tech/ptm_45nm, and are in min feature multiples.
The minimum contactable transistor is 2.5 * 45 nm, so I need to multiply the drive strength sizes above by
2.5x when looking up in Jeff's tables.
Finally, we choose a switch delay (58 ps) that leads to length 4 wires having a delay equal to that of SIV of 126 ps.
This also leads to the switch being 46% of the total wire delay, which is reasonable. -->
<switch type="mux" name="0" R="551" Cin=".77e-15" Cout="4e-15" Tdel="58e-12" mux_trans_size="2.630740" buf_size="27.645901"/>
<!--switch ipin_cblock resistance set to yeild for 4x minimum drive strength buffer-->
<switch type="mux" name="ipin_cblock" R="2231.5" Cout="0." Cin="1.47e-15" Tdel="7.247000e-11" mux_trans_size="1.222260" buf_size="auto"/>
</switchlist>
<segmentlist>
<!--- VB & JL: using ITRS metal stack data, 96 nm half pitch wires, which are intermediate metal width/space.
With the 96 nm half pitch, such wires would take 60 um of height, vs. a 90 nm high (approximated as square) Stratix IV tile so this seems
reasonable. Using a tile length of 90 nm, corresponding to the length of a Stratix IV tile if it were square. -->
<segment name="L4" freq="1.000000" length="4" type="unidir" Rmetal="101" Cmetal="22.5e-15">
<mux name="0"/>
<sb type="pattern">1 1 1 1 1</sb>
<cb type="pattern">1 1 1 1</cb>
</segment>
</segmentlist>
<complexblocklist>
<!-- Define I/O pads begin -->
<!-- Capacity is a unique property of I/Os, it is the maximum number of I/Os that can be placed at the same (X,Y) location on the FPGA -->
<!-- Not sure of the area of an I/O (varies widely), and it's not relevant to the design of the FPGA core, so we're setting it to 0. -->
<pb_type name="io">
<input name="outpad" num_pins="1"/>
<output name="inpad" num_pins="1"/>
<!-- A mode denotes the physical implementation of an I/O
This mode will be not packable but is mainly used for fabric verilog generation
-->
<mode name="physical" packable="false">
<pb_type name="iopad" blif_model=".subckt io" num_pb="1">
<input name="outpad" num_pins="1"/>
<output name="inpad" num_pins="1"/>
</pb_type>
<interconnect>
<direct name="outpad" input="io.outpad" output="iopad.outpad">
<delay_constant max="1.394e-11" in_port="io.outpad" out_port="iopad.outpad"/>
</direct>
<direct name="inpad" input="iopad.inpad" output="io.inpad">
<delay_constant max="4.243e-11" in_port="iopad.inpad" out_port="io.inpad"/>
</direct>
</interconnect>
</mode>
<!-- IOs can operate as either inputs or outputs.
Delays below come from Ian Kuon. They are small, so they should be interpreted as
the delays to and from registers in the I/O (and generally I/Os are registered
today and that is when you timing analyze them.
-->
<mode name="inpad">
<pb_type name="inpad" blif_model=".input" num_pb="1">
<output name="inpad" num_pins="1"/>
</pb_type>
<interconnect>
<direct name="inpad" input="inpad.inpad" output="io.inpad">
<delay_constant max="4.243e-11" in_port="inpad.inpad" out_port="io.inpad"/>
</direct>
</interconnect>
</mode>
<mode name="outpad">
<pb_type name="outpad" blif_model=".output" num_pb="1">
<input name="outpad" num_pins="1"/>
</pb_type>
<interconnect>
<direct name="outpad" input="io.outpad" output="outpad.outpad">
<delay_constant max="1.394e-11" in_port="io.outpad" out_port="outpad.outpad"/>
</direct>
</interconnect>
</mode>
<!-- Every input pin is driven by 15% of the tracks in a channel, every output pin is driven by 10% of the tracks in a channel -->
<!-- IOs go on the periphery of the FPGA, for consistency,
make it physically equivalent on all sides so that only one definition of I/Os is needed.
If I do not make a physically equivalent definition, then I need to define 4 different I/Os, one for each side of the FPGA
-->
<!-- Place I/Os on the sides of the FPGA -->
<power method="ignore"/>
</pb_type>
<!-- Define I/O pads ends -->
<!-- Define general purpose logic block (CLB) begin -->
<!--- Area calculation: Total Stratix IV tile area is about 8100 um^2, and a minimum width transistor
area is 60 L^2 yields a tile area of 84375 MWTAs.
Routing at W=300 is 30481 MWTAs, leaving us with a total of 53000 MWTAs for logic block area
This means that only 37% of our area is in the general routing, and 63% is inside the logic
block. Note that the crossbar / local interconnect is considered part of the logic block
area in this analysis. That is a lower proportion of of routing area than most academics
assume, but note that the total routing area really includes the crossbar, which would push
routing area up significantly, we estimate into the ~70% range.
-->
<pb_type name="clb">
<input name="I" num_pins="10" equivalent="full"/>
<output name="O" num_pins="4" equivalent="none"/>
<clock name="clk" num_pins="1"/>
<!-- Describe basic logic element.
Each basic logic element has a 4-LUT that can be optionally registered
-->
<pb_type name="fle" num_pb="4">
<input name="in" num_pins="4"/>
<output name="out" num_pins="1"/>
<clock name="clk" num_pins="1"/>
<!-- 4-LUT mode definition begin -->
<mode name="n1_lut4">
<!-- Define 4-LUT mode -->
<pb_type name="ble4" num_pb="1">
<input name="in" num_pins="4"/>
<output name="out" num_pins="1"/>
<clock name="clk" num_pins="1"/>
<!-- Define LUT -->
<pb_type name="lut4" blif_model=".names" num_pb="1" class="lut">
<input name="in" num_pins="4" port_class="lut_in"/>
<output name="out" num_pins="1" port_class="lut_out"/>
<!-- LUT timing using delay matrix -->
<delay_matrix type="max" in_port="lut4.in" out_port="lut4.out">
261e-12
261e-12
261e-12
261e-12
</delay_matrix>
</pb_type>
<!-- Define flip-flop -->
<pb_type name="ff" blif_model=".latch" num_pb="1" class="flipflop">
<input name="D" num_pins="1" port_class="D"/>
<output name="Q" num_pins="1" port_class="Q"/>
<clock name="clk" num_pins="1" port_class="clock"/>
<T_setup value="66e-12" port="ff.D" clock="clk"/>
<T_clock_to_Q max="124e-12" port="ff.Q" clock="clk"/>
</pb_type>
<interconnect>
<direct name="direct1" input="ble4.in" output="lut4[0:0].in"/>
<direct name="direct2" input="lut4.out" output="ff.D">
<!-- Advanced user option that tells CAD tool to find LUT+FF pairs in netlist -->
<pack_pattern name="ble4" in_port="lut4.out" out_port="ff.D"/>
</direct>
<direct name="direct3" input="ble4.clk" output="ff.clk"/>
<mux name="mux1" input="ff.Q lut4.out" output="ble4.out">
<!-- LUT to output is faster than FF to output on a Stratix IV -->
<delay_constant max="25e-12" in_port="lut4.out" out_port="ble4.out"/>
<delay_constant max="45e-12" in_port="ff.Q" out_port="ble4.out"/>
</mux>
</interconnect>
</pb_type>
<interconnect>
<direct name="direct1" input="fle.in" output="ble4.in"/>
<direct name="direct2" input="ble4.out" output="fle.out[0:0]"/>
<direct name="direct3" input="fle.clk" output="ble4.clk"/>
</interconnect>
</mode>
<!-- 6-LUT mode definition end -->
</pb_type>
<interconnect>
<!-- We use a full crossbar to get logical equivalence at inputs of CLB
The delays below come from Stratix IV. the delay through a connection block
input mux + the crossbar in Stratix IV is 167 ps. We already have a 72 ps
delay on the connection block input mux (modeled by Ian Kuon), so the remaining
delay within the crossbar is 95 ps.
The delays of cluster feedbacks in Stratix IV is 100 ps, when driven by a LUT.
Since all our outputs LUT outputs go to a BLE output, and have a delay of
25 ps to do so, we subtract 25 ps from the 100 ps delay of a feedback
to get the part that should be marked on the crossbar. -->
<complete name="crossbar" input="clb.I fle[3:0].out" output="fle[3:0].in">
<delay_constant max="95e-12" in_port="clb.I" out_port="fle[3:0].in"/>
<delay_constant max="75e-12" in_port="fle[3:0].out" out_port="fle[3:0].in"/>
</complete>
<complete name="clks" input="clb.clk" output="fle[3:0].clk">
</complete>
<!-- This way of specifying direct connection to clb outputs is important because this architecture uses automatic spreading of opins.
By grouping to output pins in this fashion, if a logic block is completely filled by 6-LUTs,
then the outputs those 6-LUTs take get evenly distributed across all four sides of the CLB instead of clumped on two sides (which is what happens with a more
naive specification).
-->
<direct name="clbouts1" input="fle[3:0].out" output="clb.O"/>
</interconnect>
<!-- Every input pin is driven by 15% of the tracks in a channel, every output pin is driven by 10% of the tracks in a channel -->
<!-- Place this general purpose logic block in any unspecified column -->
</pb_type>
<!-- Define general purpose logic block (CLB) ends -->
</complexblocklist>
</architecture>