Merge pull request #170 from lnis-uofu/dev

Extended Support on Defining Global Ports from Physical Tile Ports
This commit is contained in:
tangxifan 2021-01-11 10:02:31 -07:00 committed by GitHub
commit a0b9f2b40d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 1117 additions and 234 deletions

View File

@ -49,6 +49,9 @@ python3 openfpga_flow/scripts/run_fpga_task.py fpga_verilog/io/embedded_io --deb
echo -e "Testing Verilog generation with SoC I/Os for an FPGA ";
python3 openfpga_flow/scripts/run_fpga_task.py fpga_verilog/io/soc_io --debug --show_thread_logs
echo -e "Testing Verilog generation with registerable I/Os for an FPGA ";
python3 openfpga_flow/scripts/run_fpga_task.py fpga_verilog/io/registerable_io --debug --show_thread_logs
echo -e "Testing Verilog generation with adder chain across an FPGA";
python3 openfpga_flow/scripts/run_fpga_task.py fpga_verilog/fabric_chain/adder_chain --debug --show_thread_logs

View File

@ -60,21 +60,14 @@ 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>" default_val="<int>"/>
<global_port name="<string>" is_clock="<bool>" is_reset="<bool>" is_set="<bool>" default_val="<int>">
<tile name="<string>" port="<string>" x="<int>" y="<int>"/>
...
</global_port>
</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.
@ -87,6 +80,26 @@ Here is an example:
- ``default_val="<int>"`` define if the default value for the global port when initialized in testbenches. Valid values are either ``0`` or ``1``. For example, the default value of an active-high reset pin is ``0``, while an active-low reset pin is ``1``.
.. note:: A global port could be connected from different tiles by defining multiple <tile> lines under a global port!!!
.. option:: <tile name="<string>" port="<string>" x="<int>" y="<int>"/>
- ``name="<string>"`` is the name of a physical tile, e.g., ``name="clb"``.
- ``port="<string>"`` is the port name of a physical tile, e.g., ``port="clk[0:3]"``.
- ``x="<int>"`` is the x coordinate of a physical tile, e.g., ``x="1"``. If the x coordinate is set to ``-1``, it means all the valid x coordinates of the selected physical tile in the FPGA device will be considered.
- ``y="<int>"`` is the y coordinate of a physical tile, e.g., ``y="1"``. If the y coordinate is set to ``-1``, it means all the valid y coordinates of the selected physical tile in the FPGA device will be considered.
.. note:: The port of physical tile must be a valid port of the physical definition in VPR architecture! If you define a multi-bit port, it must be explicitly defined in the port, e.g., clk[0:3], which must be in the range of the port definition in physical tiles of VPR architecture files!!!
.. 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
A more illustrative example:
:numref:`fig_global_tile_ports` illustrates the difference between the global ports defined through ``circuit_model`` and ``tile_annotation``.
@ -114,7 +127,9 @@ When a global port, e.g., ``clk``, is defined in ``tile_annotation`` using the f
.. code-block:: xml
<tile_annotations>
<global_port name="clk" tile_port="clb.clk" is_clock="true"/>
<global_port name="clk" is_clock="true">
<tile name="clb" port="clk"/>
</global_port>
</tile_annotations>
Clock port ``clk`` of each ``clb`` tile will be connected to a common clock port of the top module, while local clock network is customizable through VPR's architecture description language. For instance, the local clock network can be a programmable clock network.

View File

@ -30,25 +30,12 @@ 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>
/* We have mandatory XML attributes:
* - name of the port
*/
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());
TileGlobalPortId tile_global_port_id = tile_annotation.create_global_port(name_attr);
/* Report any duplicated port names */
if (TileGlobalPortId::INVALID() == tile_global_port_id) {
@ -57,6 +44,39 @@ void read_xml_tile_global_port_annotation(pugi::xml_node& xml_tile,
name_attr.c_str());
}
/* Iterate over the children under this node,
* each child should be named after <pb_type>
*/
for (pugi::xml_node xml_tile_port : xml_tile.children()) {
/* Error out if the XML child has an invalid name! */
if (xml_tile_port.name() != std::string("tile")) {
bad_tag(xml_tile_port, loc_data, xml_tile, {"tile"});
}
/* Parse the name of the tiles and ports */
const std::string& tile_name_attr = get_attribute(xml_tile_port, "name", loc_data).as_string();
const std::string& port_name_attr = get_attribute(xml_tile_port, "port", loc_data).as_string();
/* Extract the tile port information */
openfpga::PortParser tile_port_parser(port_name_attr);
/* Parse tile coordinates */
vtr::Point<size_t> tile_coord(get_attribute(xml_tile_port, "x", loc_data, pugiutil::ReqOpt::OPTIONAL).as_int(-1),
get_attribute(xml_tile_port, "y", loc_data, pugiutil::ReqOpt::OPTIONAL).as_int(-1));
/* Add tile port information */
tile_annotation.add_global_port_tile_information(tile_global_port_id,
tile_name_attr,
tile_port_parser.port(),
tile_coord);
}
/* Check: Must have at least one global port tile information */
if (true == tile_annotation.global_port_tile_names(tile_global_port_id).empty()) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_tile),
"Invalid tile annotation for global port '%s'! At least 1 tile port definition is expected!\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));
@ -81,7 +101,7 @@ void read_xml_tile_global_port_annotation(pugi::xml_node& xml_tile,
* 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) {
const pugiutil::loc_data& loc_data) {
openfpga::TileAnnotation tile_annotations;
/* Parse configuration protocol root node */

View File

@ -30,16 +30,21 @@ std::string TileAnnotation::global_port_name(const TileGlobalPortId& global_port
return global_port_names_[global_port_id];
}
std::string TileAnnotation::global_port_tile_name(const TileGlobalPortId& global_port_id) const {
std::vector<std::string> TileAnnotation::global_port_tile_names(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 {
std::vector<BasicPort> TileAnnotation::global_port_tile_ports(const TileGlobalPortId& global_port_id) const {
VTR_ASSERT(valid_global_port_id(global_port_id));
return global_port_tile_ports_[global_port_id];
}
std::vector<vtr::Point<size_t>> TileAnnotation::global_port_tile_coordinates(const TileGlobalPortId& global_port_id) const {
VTR_ASSERT(valid_global_port_id(global_port_id));
return global_port_tile_coordinates_[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];
@ -63,9 +68,7 @@ size_t TileAnnotation::global_port_default_value(const TileGlobalPortId& global_
/************************************************************************
* Public Mutators
***********************************************************************/
TileGlobalPortId TileAnnotation::create_global_port(const std::string& port_name,
const std::string& tile_name,
const BasicPort& tile_port) {
TileGlobalPortId TileAnnotation::create_global_port(const std::string& port_name) {
/* 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()) {
@ -76,8 +79,9 @@ TileGlobalPortId TileAnnotation::create_global_port(const std::string& port_name
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_tile_names_.emplace_back();
global_port_tile_ports_.emplace_back();
global_port_tile_coordinates_.emplace_back();
global_port_is_clock_.push_back(false);
global_port_is_set_.push_back(false);
global_port_is_reset_.push_back(false);
@ -89,6 +93,16 @@ TileGlobalPortId TileAnnotation::create_global_port(const std::string& port_name
return port_id;
}
void TileAnnotation::add_global_port_tile_information(const TileGlobalPortId& global_port_id,
const std::string& tile_name,
const BasicPort& tile_port,
const vtr::Point<size_t>& tile_coord) {
VTR_ASSERT(valid_global_port_id(global_port_id));
global_port_tile_names_[global_port_id].push_back(tile_name);
global_port_tile_ports_[global_port_id].push_back(tile_port);
global_port_tile_coordinates_[global_port_id].push_back(tile_coord);
}
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));

View File

@ -9,6 +9,7 @@
#include <array>
#include "vtr_vector.h"
#include "vtr_geometry.h"
#include "openfpga_port.h"
@ -39,8 +40,9 @@ class TileAnnotation {
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;
std::vector<std::string> global_port_tile_names(const TileGlobalPortId& global_port_id) const;
std::vector<BasicPort> global_port_tile_ports(const TileGlobalPortId& global_port_id) const;
std::vector<vtr::Point<size_t>> global_port_tile_coordinates(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;
@ -49,9 +51,12 @@ class TileAnnotation {
/* 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);
TileGlobalPortId create_global_port(const std::string& port_name);
/* Add tile port information */
void add_global_port_tile_information(const TileGlobalPortId& global_port_id,
const std::string& tile_name,
const BasicPort& tile_port,
const vtr::Point<size_t>& tile_coord);
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,
@ -70,8 +75,9 @@ class TileAnnotation {
/* 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, std::vector<std::string>> global_port_tile_names_;
vtr::vector<TileGlobalPortId, std::vector<vtr::Point<size_t>>> global_port_tile_coordinates_;
vtr::vector<TileGlobalPortId, std::vector<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_;

View File

@ -51,11 +51,6 @@ void write_xml_tile_annotation_global_port(std::fstream& fp,
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));
@ -64,7 +59,18 @@ void write_xml_tile_annotation_global_port(std::fstream& fp,
write_xml_attribute(fp, "default_value", tile_annotation.global_port_default_value(global_port_id));
fp << "/>" << "\n";
fp << ">" << "\n";
for (size_t tile_info_id = 0; tile_info_id < tile_annotation.global_port_tile_names(global_port_id).size(); ++tile_info_id) {
fp << "\t\t\t" << "<tile ";
write_xml_attribute(fp, "name", tile_annotation.global_port_tile_names(global_port_id)[tile_info_id].c_str());
write_xml_attribute(fp, "port", generate_tile_port_name(tile_annotation.global_port_tile_ports(global_port_id)[tile_info_id]).c_str());
write_xml_attribute(fp, "x", tile_annotation.global_port_tile_coordinates(global_port_id)[tile_info_id].x());
write_xml_attribute(fp, "y", tile_annotation.global_port_tile_coordinates(global_port_id)[tile_info_id].y());
fp << "/>";
}
fp << "\t\t" << "</global_port>";
}
/********************************************************************

View File

@ -695,33 +695,42 @@ void add_top_module_nets_connect_grids_and_gsbs(ModuleManager& module_manager,
* 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) {
int 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 BasicPort& tile_port_to_connect,
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;
int grid_pin_start_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()) {
if (std::string(tile_port.name) == tile_port_to_connect.get_name()) {
BasicPort ref_tile_port(tile_port.name, tile_port.num_pins);
/* 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;
if (false == ref_tile_port.contained(tile_port_to_connect)) {
VTR_LOG_ERROR("Tile annotation '%s' port '%s[%lu:%lu]' is out of the range of physical tile port '%s[%lu:%lu]'!",
tile_annotation.global_port_name(tile_global_port).c_str(),
tile_port_to_connect.get_name().c_str(),
tile_port_to_connect.get_lsb(),
tile_port_to_connect.get_msb(),
ref_tile_port.get_name().c_str(),
ref_tile_port.get_lsb(),
ref_tile_port.get_msb());
return CMD_EXEC_FATAL_ERROR;
}
grid_pin_start_index = tile_port.absolute_first_pin_index;
break;
}
}
/* Ensure the pin index is valid */
VTR_ASSERT(grid_pin_index < physical_tile->num_pins);
VTR_ASSERT(grid_pin_start_index < physical_tile->num_pins);
/* Find the module name for this type of grid */
std::string grid_module_name_prefix(GRID_MODULE_NAME_PREFIX);
@ -730,23 +739,39 @@ void build_top_module_global_net_for_given_grid_module(ModuleManager& module_man
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));
VTR_ASSERT(1 == physical_tile->equivalent_sites.size());
/* Build nets */
add_module_bus_nets(module_manager, top_module,
top_module, 0, top_module_port,
grid_module, grid_instance, grid_port_id);
/* A tile may consist of multiple subtile, connect to all the pins from sub tiles */
for (int iz = 0; iz < physical_tile->capacity; ++iz) {
/* TODO: This should be replaced by using a pin mapping data structure from physical tile! */
int grid_pin_index = grid_pin_start_index + iz * physical_tile->equivalent_sites[0]->pb_type->num_pins;
/* 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 */
BasicPort src_port = module_manager.module_port(top_module, top_module_port);
for (size_t pin_id = 0; pin_id < tile_port_to_connect.pins().size(); ++pin_id) {
ModuleNetId net = create_module_source_pin_net(module_manager, top_module,
top_module, 0,
top_module_port, src_port.pins()[pin_id]);
VTR_ASSERT(ModuleNetId::INVALID() != net);
/* Configure the net sink */
module_manager.add_module_net_sink(top_module, net, grid_module, grid_instance, grid_port_id, tile_port_to_connect.pins()[pin_id]);
}
}
}
return CMD_EXEC_SUCCESS;
}
/********************************************************************
@ -757,17 +782,23 @@ int add_top_module_global_ports_from_grid_modules(ModuleManager& module_manager,
const TileAnnotation& tile_annotation,
const DeviceGrid& grids,
const vtr::Matrix<size_t>& grid_instance_ids) {
int status = CMD_EXEC_SUCCESS;
/* Add the global ports which are yet added to the top-level module
/* Add the global ports which are NOT 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));
/* The global port size is derived from the maximum port size among all the tile port defintion */
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());
size_t max_port_size = 0;
for (const BasicPort& tile_port : tile_annotation.global_port_tile_ports(tile_global_port)) {
max_port_size = std::max(tile_port.get_width(), max_port_size);
}
global_port_to_add.set_width(max_port_size);
global_ports_to_add.push_back(global_port_to_add);
}
}
@ -784,72 +815,130 @@ int add_top_module_global_ports_from_grid_modules(ModuleManager& module_manager,
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;
}
for (size_t tile_info_id = 0; tile_info_id < tile_annotation.global_port_tile_names(tile_global_port).size(); ++tile_info_id) {
std::string tile_name = tile_annotation.global_port_tile_names(tile_global_port)[tile_info_id];
BasicPort tile_port = tile_annotation.global_port_tile_ports(tile_global_port)[tile_info_id];
/* Find the coordinates for the wanted tiles */
vtr::Point<size_t> start_coord(1, 1);
vtr::Point<size_t> end_coord(grids.width() - 1, grids.height() - 1);
vtr::Point<size_t> range = tile_annotation.global_port_tile_coordinates(tile_global_port)[tile_info_id];
bool out_of_range = false;
/* 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;
/* -1 means all the x should be considered */
if (size_t(-1) != range.x()) {
if ((range.x() < start_coord.x()) || (range.x() > end_coord.x())) {
out_of_range = true;
} else {
/* Set the range */
start_coord.set_x(range.x());
end_coord.set_x(range.x());
}
/* 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;
}
/* -1 means all the y should be considered */
if (size_t(-1) != range.y()) {
if ((range.y() < start_coord.y()) || (range.y() > end_coord.y())) {
out_of_range = true;
} else {
/* Set the range */
start_coord.set_y(range.y());
end_coord.set_y(range.y());
}
}
/* Error out immediately if the coordinate is not valid! */
if (true == out_of_range) {
VTR_LOG_ERROR("Coordinate (%lu, %lu) in tile annotation for tile '%s' is out of range (%lu:%lu, %lu:%lu)!",
range.x(), range.y(), tile_name.c_str(),
start_coord.x(), end_coord.x(), start_coord.y(), end_coord.y());
return CMD_EXEC_FATAL_ERROR;
}
/* Spot the port from child modules from core grids */
for (size_t ix = start_coord.x(); ix < end_coord.x(); ++ix) {
for (size_t iy = start_coord.y(); iy < end_coord.y(); ++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_name) {
continue;
}
/* Create nets and finish connection build-up */
status = build_top_module_global_net_for_given_grid_module(module_manager,
top_module,
top_module_port,
tile_annotation,
tile_global_port,
tile_port,
grids,
vtr::Point<size_t>(ix, iy),
NUM_SIDES,
grid_instance_ids);
if (CMD_EXEC_FATAL_ERROR == status) {
return status;
}
}
}
/* 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;
}
/* 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;
}
/* Bypass the tiles whose names do not match */
if (std::string(grids[io_coordinate.x()][io_coordinate.y()].type->name) != tile_name) {
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);
/* Check if the coordinate satisfy the tile coordinate defintion
* - Bypass if the x is a specific number (!= -1), and io_coordinate is different
* - Bypass if the y is a specific number (!= -1), and io_coordinate is different
*/
if ((size_t(-1) != range.x()) && (range.x() != io_coordinate.x())) {
continue;
}
if ((size_t(-1) != range.y()) && (range.y() != io_coordinate.y())) {
continue;
}
/* Create nets and finish connection build-up */
status = build_top_module_global_net_for_given_grid_module(module_manager,
top_module,
top_module_port,
tile_annotation,
tile_global_port,
tile_port,
grids,
io_coordinate,
io_side,
grid_instance_ids);
if (CMD_EXEC_FATAL_ERROR == status) {
return status;
}
}
}
}
}
return CMD_EXEC_SUCCESS;
return status;
}
} /* end namespace openfpga */

View File

@ -21,6 +21,9 @@ FabricBitstream::FabricBitstream() {
num_regions_ = 0;
invalid_region_ids_.clear();
use_address_ = false;
use_wl_address_ = false;
}
/**************************************************

View File

@ -102,107 +102,125 @@ int check_tile_annotation_conflicts_with_physical_tile(const TileAnnotation& til
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;
}
for (size_t tile_info_id = 0; tile_info_id < tile_annotation.global_port_tile_names(tile_global_port).size(); ++tile_info_id) {
/* 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;
/* Found a match, increment the counter */
found_matched_physical_tile++;
std::string required_tile_name = tile_annotation.global_port_tile_names(tile_global_port)[tile_info_id];
BasicPort required_tile_port = tile_annotation.global_port_tile_ports(tile_global_port)[tile_info_id];
/* 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()) {
for (const t_physical_tile_type& physical_tile : physical_tile_types) {
if (std::string(physical_tile.name) != required_tile_name) {
continue;
}
if (size_t(tile_port.num_pins) != tile_annotation.global_port_tile_port(tile_global_port).get_width()) {
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) != required_tile_port.get_name()) {
continue;
}
BasicPort ref_tile_port(tile_port.name, tile_port.num_pins);
/* Port size must be in range!!! */
if (false == ref_tile_port.contained(required_tile_port)) {
VTR_LOG_ERROR("Tile annotation port '%s[%lu:%lu]' is out of the range of physical tile port '%s[%lu:%lu]'!",
required_tile_port.get_name().c_str(),
required_tile_port.get_lsb(),
required_tile_port.get_msb(),
ref_tile_port.get_name().c_str(),
ref_tile_port.get_lsb(),
ref_tile_port.get_msb());
num_err++;
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",
required_tile_name.c_str(),
required_tile_port.get_name().c_str(),
required_tile_port.get_lsb(),
required_tile_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",
required_tile_name.c_str(),
required_tile_port.get_name().c_str(),
required_tile_port.get_lsb(),
required_tile_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",
required_tile_name.c_str(),
required_tile_port.get_name().c_str(),
required_tile_port.get_lsb(),
required_tile_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++;
}
/* 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 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",
required_tile_name.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",
required_tile_name.c_str(),
required_tile_port.get_name().c_str(),
required_tile_port.get_lsb(),
required_tile_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++;
/* 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",
required_tile_name.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 1 physical tile port!\n",
required_tile_name.c_str(),
required_tile_port.get_name().c_str(),
required_tile_port.get_lsb(),
required_tile_port.get_msb(),
tile_annotation.global_port_name(tile_global_port).c_str());
num_err++;
}
}
}

View File

@ -0,0 +1,9 @@
clk 0.500000 2.000000
a 0.502000 0.197200
b 0.485400 0.202800
c 0.248000 0.176800
a_reg 0.502000 0.197200
b_reg 0.485400 0.202800
n10 0.248000 0.043259
n13 0.502000 0.098994
n17 0.485400 0.098439

View File

@ -0,0 +1,16 @@
# Benchmark "and2_pipelined" written by ABC on Sun Jan 10 10:26:01 2021
.model and2_pipelined
.inputs clk a b
.outputs c
.latch n10 c 2
.latch n13 a_reg 2
.latch n17 b_reg 2
.names a_reg b_reg n10
11 1
.names a n13
1 1
.names b n17
1 1
.end

View File

@ -0,0 +1,34 @@
/////////////////////////////////////////
// Functionality: a pipelined 2-input AND
// where inputs and outputs are registered
// Author: Xifan Tang
////////////////////////////////////////
`timescale 1ns / 1ps
module and2_pipelined(
clk,
a,
b,
c);
input wire clk;
input wire a;
input wire b;
output wire c;
reg a_reg;
reg b_reg;
reg c_reg;
always @(posedge clk) begin
a_reg <= a;
b_reg <= b;
end
always @(posedge clk) begin
c_reg <= a_reg & b_reg;
end
assign c = c_reg;
endmodule

View File

@ -21,6 +21,7 @@ Note that an OpenFPGA architecture can be applied to multiple VPR architecture f
- behavioral: If behavioral Verilog modeling is specified
- local\_encoder: If local encoders are used in routing multiplexer design
- spyio/spypad: If spy I/Os are used
- registerable\_io: If I/Os are registerable (can be either combinational or sequential)
- stdcell: If circuit designs are built with standard cells only
- tree\_mux: If routing multiplexers are built with a tree-like structure
- <feature_size>: The technology node which the delay numbers are extracted from.

View File

@ -169,7 +169,9 @@
<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"/>
<global_port name="clk" is_clock="true" default_val="0">
<tile name="clb" port="clk" x="-1" y="-1"/>
</global_port>
</tile_annotations>
<pb_type_annotations>
<!-- physical pb_type binding in complex block IO -->

View File

@ -0,0 +1,198 @@
<!-- 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" is_clock="true" default_val="0">
<tile name="clb" port="clk" x="-1" y="-1"/>
<tile name="io" port="clk" x="-1" y="-1"/>
</global_port>
</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[physical].ff" circuit_model_name="DFFSRQ"/>
<pb_type name="io[inpad].inpad" physical_pb_type_name="io[physical].iopad" mode_bits="1"/>
<pb_type name="io[inpad_registered].inpad" physical_pb_type_name="io[physical].iopad" mode_bits="1"/>
<pb_type name="io[inpad_registered].ff" physical_pb_type_name="io[physical].ff"/>
<pb_type name="io[outpad].outpad" physical_pb_type_name="io[physical].iopad" mode_bits="0"/>
<!-- End physical pb_type binding in complex block IO -->
<!-- physical pb_type binding in complex block CLB -->
<!-- physical mode will be the default mode if not specified -->
<pb_type name="clb">
<!-- Binding interconnect to circuit models as their physical implementation, if not defined, we use the default model -->
<interconnect name="crossbar" circuit_model_name="mux_tree"/>
</pb_type>
<pb_type name="clb.fle[n1_lut4].ble4.lut4" circuit_model_name="lut4"/>
<pb_type name="clb.fle[n1_lut4].ble4.ff" circuit_model_name="DFFSRQ"/>
<!-- End physical pb_type binding in complex block IO -->
</pb_type_annotations>
</openfpga_architecture>

View File

@ -217,8 +217,12 @@
<direct name="scan_chain" circuit_model_name="direct_interc" type="column" x_dir="positive" y_dir="positive"/>
</direct_connection>
<tile_annotations>
<global_port name="clk" tile_port="clb.clk" is_clock="true" default_val="0"/>
<global_port name="reset" tile_port="clb.reset" is_reset="true" default_val="0"/>
<global_port name="clk" tile_port="clb.clk" is_clock="true" default_val="0">
<tile name="clb" port="clk"/>
</global_port>
<global_port name="reset" is_reset="true" default_val="0">
<tile name="clb" port="reset"/>
</global_port>
</tile_annotations>
<pb_type_annotations>
<!-- physical pb_type binding in complex block IO -->

View File

@ -0,0 +1,76 @@
# Run VPR for the 'and' design
# When the global clock is defined as a port of a tile, clock routing in VPR should be skipped
# This is due to the Fc_in of clock port is set to 0 for global wiring
#--write_rr_graph example_rr_graph.xml
vpr ${VPR_ARCH_FILE} ${VPR_TESTBENCH_BLIF} --device ${OPENFPGA_VPR_DEVICE_LAYOUT}
# Read OpenFPGA architecture definition
read_openfpga_arch -f ${OPENFPGA_ARCH_FILE}
# Read OpenFPGA simulation settings
read_openfpga_simulation_setting -f ${OPENFPGA_SIM_SETTING_FILE}
# Annotate the OpenFPGA architecture to VPR data base
# to debug use --verbose options
link_openfpga_arch --activity_file ${ACTIVITY_FILE} --sort_gsb_chan_node_in_edges
# Check and correct any naming conflicts in the BLIF netlist
check_netlist_naming_conflict --fix --report ./netlist_renaming.xml
# Apply fix-up to clustering nets based on routing results
pb_pin_fixup --verbose
# Apply fix-up to Look-Up Table truth tables based on packing results
lut_truth_table_fixup
# Build the module graph
# - Enabled compression on routing architecture modules
# - Enable pin duplication on grid modules
build_fabric --compress_routing #--verbose
# Write the fabric hierarchy of module graph to a file
# This is used by hierarchical PnR flows
write_fabric_hierarchy --file ./fabric_hierarchy.txt
# Repack the netlist to physical pbs
# This must be done before bitstream generator and testbench generation
# Strongly recommend it is done after all the fix-up have been applied
repack #--verbose
# Build the bitstream
# - Output the fabric-independent bitstream to a file
build_architecture_bitstream --verbose --write_file fabric_independent_bitstream.xml
# Build fabric-dependent bitstream
build_fabric_bitstream --verbose
# Write fabric-dependent bitstream
write_fabric_bitstream --file fabric_bitstream.xml --format xml
# Write the Verilog netlist for FPGA fabric
# - Enable the use of explicit port mapping in Verilog netlist
write_fabric_verilog --file ./SRC --explicit_port_mapping --include_timing --print_user_defined_template --verbose
# Write the Verilog testbench for FPGA fabric
# - We suggest the use of same output directory as fabric Verilog netlists
# - Must specify the reference benchmark file if you want to output any testbenches
# - Enable top-level testbench which is a full verification including programming circuit and core logic of FPGA
# - Enable pre-configured top-level testbench which is a fast verification skipping programming phase
# - Simulation ini file is optional and is needed only when you need to interface different HDL simulators using openfpga flow-run scripts
write_verilog_testbench --file ./SRC --reference_benchmark_file_path ${REFERENCE_VERILOG_TESTBENCH} --print_top_testbench --print_preconfig_top_testbench --print_simulation_ini ./SimulationDeck/simulation_deck.ini --include_signal_init --support_icarus_simulator --explicit_port_mapping
# Write the SDC files for PnR backend
# - Turn on every options here
write_pnr_sdc --file ./SDC
# Write SDC to disable timing for configure ports
write_sdc_disable_timing_configure_ports --file ./SDC/disable_configure_ports.sdc
# Write the SDC to run timing analysis for a mapped FPGA fabric
write_analysis_sdc --file ./SDC_analysis
# Finish and exit OpenFPGA
exit
# Note :
# To run verification at the end of the flow maintain source in ./SRC directory

View File

@ -26,6 +26,7 @@ arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_GlobalTileClk_
[BENCHMARKS]
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.v
bench1=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2_latch/and2_latch.v
bench2=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2_pipelined/and2_pipelined.v
[SYNTHESIS_PARAM]
bench0_top = and2
@ -34,5 +35,8 @@ bench0_chan_width = 300
bench1_top = and2_latch
bench1_chan_width = 300
bench2_top = and2_pipelined
bench2_chan_width = 300
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
end_flow_with_test=

View File

@ -0,0 +1,35 @@
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# 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/openfpga_shell_scripts/fix_device_global_tile_clock_example_script.openfpga
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_GlobalTileClk_registerable_io_cc_openfpga.xml
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
openfpga_vpr_device_layout=2x2
[ARCHITECTURES]
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_GlobalTileClk_registerable_io_40nm.xml
[BENCHMARKS]
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2_pipelined/and2_pipelined.v
[SYNTHESIS_PARAM]
bench0_top = and2_pipelined
bench0_chan_width = 300
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
end_flow_with_test=

View File

@ -15,6 +15,7 @@ Please reveal the following architecture features in the names to help quickly s
- aib: If the Advanced Interface Bus (AIB) is used in place of some I/Os.
- multi\_io\_capacity: If I/O capacity is different on each side of FPGAs.
- reduced\_io: If I/Os only appear a certain or multiple sides of FPGAs
- registerable\_io: If I/Os are registerable (can be either combinational or sequential)
- <feature\_size>: The technology node which the delay numbers are extracted from.
- TileOrgz<Type>: How tile is organized.
* Top-left (Tl): the pins of a tile are placed on the top side and left side only

View File

@ -0,0 +1,329 @@
<!--
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"/>
<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="custom">
<loc side="left">io.outpad io.inpad io.clk</loc>
<loc side="top">io.outpad io.inpad io.clk</loc>
<loc side="right">io.outpad io.inpad io.clk</loc>
<loc side="bottom">io.outpad io.inpad io.clk</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"/>
<clock name="clk" 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>
<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="clk" input="io.clk" output="ff.clk"/>
<direct name="outpad" input="io.outpad" output="iopad.outpad">
<delay_constant max="1.394e-11" in_port="io.outpad" out_port="iopad.outpad"/>
</direct>
<!-- Create a selector between registered/combinational I/O -->
<direct name="inpad" input="iopad.inpad" output="ff.D"/>
<mux name="mux1" input="iopad.inpad ff.Q" output="io.inpad">
<delay_constant max="4.5e-11" in_port="iopad.inpad" out_port="io.inpad"/>
<delay_constant max="4.243e-11" in_port="ff.Q" out_port="io.inpad"/>
</mux>
</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="inpad_registered">
<pb_type name="inpad" blif_model=".input" num_pb="1">
<output name="inpad" num_pins="1"/>
</pb_type>
<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="clk" input="io.clk" output="ff.clk"/>
<direct name="inpad" input="inpad.inpad" output="ff.D">
<pack_pattern name="registered_io" in_port="inpad.inpad" out_port="ff.D"/>
</direct>
<direct name="ff2inpad" input="ff.Q" output="io.inpad"/>
</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>