Merge pull request #122 from LNIS-Projects/dev
Support Global Port Definition for Physical Tile Ports
This commit is contained in:
commit
2af49c245f
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
|
@ -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
|
|
@ -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";
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
|
@ -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
|
|
@ -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);
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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 */
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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(),
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
*******************************************************************/
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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>
|
|
@ -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=
|
|
@ -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>
|
Loading…
Reference in New Issue