Skip to content

FPGA Interchange: improve arch reader #1937

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
e7f55d3
libs: arch: move common functions to util and check source files
acomodi Nov 29, 2021
bd20726
libs: arch: interchange: add logical blocks and physical tile parsing
acomodi Nov 29, 2021
3e969ea
vpr: tests: improve interchange tests
acomodi Nov 29, 2021
9037dca
libs: arch: interchange: improve bel to cell mapping
acomodi Nov 17, 2021
a9444cd
libs: arch: fix multiple sites and rr graph gen
acomodi Dec 3, 2021
b8a5a88
libs: arch: interchange: fix IO pads reading
acomodi Dec 3, 2021
a06b406
libs: arch: interchange: add workarounds for RR graph generation
acomodi Dec 3, 2021
98a1718
vpr: test: interchange: fix grid width and height
acomodi Dec 3, 2021
5dca717
vpr: base: remove cStr() casts from interchange netlist reader
mtdudek Dec 6, 2021
06c8abd
libs: arch: interchange: fix and enhance to start reading in xc7 arch
acomodi Dec 6, 2021
5d17366
libs: arch: interchange: allow cascading routing bels
acomodi Dec 7, 2021
749b402
vpr: pack: allow pins to have name starting with integer
acomodi Dec 7, 2021
9c7fb88
libs: arch: interchange : allow inout ports in bels connected to pads
acomodi Dec 10, 2021
b7c962d
vpr: base: interchange: netlist: add c-style init and fixed bug
acomodi Dec 13, 2021
a97a3e9
libs: arch: interchange: add pack pattern propagation
acomodi Dec 14, 2021
c513f9c
libs: arch: interchange: clean and add in-code comments
acomodi Dec 15, 2021
a017e53
vpr: test: adjust grid layout test as NULL tile is not in the grid
acomodi Dec 15, 2021
21ee47c
Added reading LUT elements from FPGA interchange
mkurc-ant Dec 8, 2021
857e7ce
libs: arch: interchange: fix luts that have additional pins
acomodi Dec 16, 2021
821bff9
interchange: address review comments
acomodi Jan 21, 2022
162ca07
libs: arch: add is_empty function to phys/log types
acomodi Jan 24, 2022
450540c
vpr: test: fix interchange test
acomodi Jan 24, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
211 changes: 207 additions & 4 deletions libs/libarchfpga/src/arch_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -555,9 +555,9 @@ t_port* findPortByName(const char* name, t_pb_type* pb_type, int* high_index, in
return port;
}

t_physical_tile_type SetupEmptyPhysicalType() {
t_physical_tile_type get_empty_physical_type(const char* name) {
t_physical_tile_type type;
type.name = vtr::strdup("EMPTY");
type.name = vtr::strdup(name);
type.num_pins = 0;
type.width = 1;
type.height = 1;
Expand All @@ -573,9 +573,9 @@ t_physical_tile_type SetupEmptyPhysicalType() {
return type;
}

t_logical_block_type SetupEmptyLogicalType() {
t_logical_block_type get_empty_logical_type(const char* name) {
t_logical_block_type type;
type.name = vtr::strdup("EMPTY");
type.name = vtr::strdup(name);
type.pb_type = nullptr;

return type;
Expand Down Expand Up @@ -1392,5 +1392,208 @@ const t_pin_to_pin_annotation* find_combinational_annotation(const t_pb_type* pb
}
}
}

return nullptr;
}

void link_physical_logical_types(std::vector<t_physical_tile_type>& PhysicalTileTypes,
std::vector<t_logical_block_type>& LogicalBlockTypes) {
for (auto& physical_tile : PhysicalTileTypes) {
if (physical_tile.index == EMPTY_TYPE_INDEX) continue;

auto eq_sites_set = get_equivalent_sites_set(&physical_tile);
auto equivalent_sites = std::vector<t_logical_block_type_ptr>(eq_sites_set.begin(), eq_sites_set.end());

auto criteria = [&physical_tile](const t_logical_block_type* lhs, const t_logical_block_type* rhs) {
int num_pins = physical_tile.num_inst_pins;

int lhs_num_logical_pins = lhs->pb_type->num_pins;
int rhs_num_logical_pins = rhs->pb_type->num_pins;

int lhs_diff_num_pins = num_pins - lhs_num_logical_pins;
int rhs_diff_num_pins = num_pins - rhs_num_logical_pins;

return lhs_diff_num_pins < rhs_diff_num_pins;
};

std::sort(equivalent_sites.begin(), equivalent_sites.end(), criteria);

for (auto& logical_block : LogicalBlockTypes) {
for (auto site : equivalent_sites) {
if (0 == strcmp(logical_block.name, site->pb_type->name)) {
logical_block.equivalent_tiles.push_back(&physical_tile);
break;
}
}
}
}

for (auto& logical_block : LogicalBlockTypes) {
if (logical_block.index == EMPTY_TYPE_INDEX) continue;

auto& equivalent_tiles = logical_block.equivalent_tiles;

if ((int)equivalent_tiles.size() <= 0) {
archfpga_throw(__FILE__, __LINE__,
"Logical Block %s does not have any equivalent tiles.\n", logical_block.name);
}

std::unordered_map<int, bool> ignored_pins_check_map;
std::unordered_map<int, bool> global_pins_check_map;

auto criteria = [&logical_block](const t_physical_tile_type* lhs, const t_physical_tile_type* rhs) {
int num_logical_pins = logical_block.pb_type->num_pins;

int lhs_num_pins = lhs->num_inst_pins;
int rhs_num_pins = rhs->num_inst_pins;

int lhs_diff_num_pins = lhs_num_pins - num_logical_pins;
int rhs_diff_num_pins = rhs_num_pins - num_logical_pins;

return lhs_diff_num_pins < rhs_diff_num_pins;
};

std::sort(equivalent_tiles.begin(), equivalent_tiles.end(), criteria);

for (int pin = 0; pin < logical_block.pb_type->num_pins; pin++) {
for (auto& tile : equivalent_tiles) {
auto direct_maps = tile->tile_block_pin_directs_map.at(logical_block.index);

for (auto& sub_tile : tile->sub_tiles) {
auto equiv_sites = sub_tile.equivalent_sites;
if (std::find(equiv_sites.begin(), equiv_sites.end(), &logical_block) == equiv_sites.end()) {
continue;
}

auto direct_map = direct_maps.at(sub_tile.index);

auto result = direct_map.find(t_logical_pin(pin));
if (result == direct_map.end()) {
archfpga_throw(__FILE__, __LINE__,
"Logical pin %d not present in pin mapping between Tile %s and Block %s.\n",
pin, tile->name, logical_block.name);
}

int sub_tile_pin_index = result->second.pin;
int phy_index = sub_tile.sub_tile_to_tile_pin_indices[sub_tile_pin_index];

bool is_ignored = tile->is_ignored_pin[phy_index];
bool is_global = tile->is_pin_global[phy_index];

auto ignored_result = ignored_pins_check_map.insert(std::pair<int, bool>(pin, is_ignored));
if (!ignored_result.second && ignored_result.first->second != is_ignored) {
archfpga_throw(__FILE__, __LINE__,
"Physical Tile %s has a different value for the ignored pin (physical pin: %d, logical pin: %d) "
"different from the corresponding pins of the other equivalent site %s\n.",
tile->name, phy_index, pin, logical_block.name);
}

auto global_result = global_pins_check_map.insert(std::pair<int, bool>(pin, is_global));
if (!global_result.second && global_result.first->second != is_global) {
archfpga_throw(__FILE__, __LINE__,
"Physical Tile %s has a different value for the global pin (physical pin: %d, logical pin: %d) "
"different from the corresponding pins of the other equivalent sites\n.",
tile->name, phy_index, pin);
}
}
}
}
}
}

/* Sets up the pin classes for the type. */
void setup_pin_classes(t_physical_tile_type* type) {
int i, k;
int pin_count;
int num_class;

for (i = 0; i < type->num_pins; i++) {
type->pin_class.push_back(OPEN);
type->is_ignored_pin.push_back(true);
type->is_pin_global.push_back(true);
}

pin_count = 0;

t_class_range class_range;

/* Equivalent pins share the same class, non-equivalent pins belong to different pin classes */
for (auto& sub_tile : type->sub_tiles) {
int capacity = sub_tile.capacity.total();
class_range.low = type->class_inf.size();
class_range.high = class_range.low - 1;
for (i = 0; i < capacity; ++i) {
for (const auto& port : sub_tile.ports) {
if (port.equivalent != PortEquivalence::NONE) {
t_class class_inf;
num_class = (int)type->class_inf.size();
class_inf.num_pins = port.num_pins;
class_inf.equivalence = port.equivalent;

if (port.type == IN_PORT) {
class_inf.type = RECEIVER;
} else {
VTR_ASSERT(port.type == OUT_PORT);
class_inf.type = DRIVER;
}

for (k = 0; k < port.num_pins; ++k) {
class_inf.pinlist.push_back(pin_count);
type->pin_class[pin_count] = num_class;
// clock pins and other specified global ports are initially specified
// as ignored pins (i.e. connections are not created in the rr_graph and
// nets connected to the port are ignored as well).
type->is_ignored_pin[pin_count] = port.is_clock || port.is_non_clock_global;
// clock pins and other specified global ports are flaged as global
type->is_pin_global[pin_count] = port.is_clock || port.is_non_clock_global;

if (port.is_clock) {
type->clock_pin_indices.push_back(pin_count);
}

pin_count++;
}

type->class_inf.push_back(class_inf);
class_range.high++;
} else if (port.equivalent == PortEquivalence::NONE) {
for (k = 0; k < port.num_pins; ++k) {
t_class class_inf;
num_class = (int)type->class_inf.size();
class_inf.num_pins = 1;
class_inf.pinlist.push_back(pin_count);
class_inf.equivalence = port.equivalent;

if (port.type == IN_PORT) {
class_inf.type = RECEIVER;
} else {
VTR_ASSERT(port.type == OUT_PORT);
class_inf.type = DRIVER;
}

type->pin_class[pin_count] = num_class;
// clock pins and other specified global ports are initially specified
// as ignored pins (i.e. connections are not created in the rr_graph and
// nets connected to the port are ignored as well).
type->is_ignored_pin[pin_count] = port.is_clock || port.is_non_clock_global;
// clock pins and other specified global ports are flaged as global
type->is_pin_global[pin_count] = port.is_clock || port.is_non_clock_global;

if (port.is_clock) {
type->clock_pin_indices.push_back(pin_count);
}

pin_count++;

type->class_inf.push_back(class_inf);
class_range.high++;
}
}
}
}

type->sub_tiles[sub_tile.index].class_range = class_range;
}

VTR_ASSERT(pin_count == type->num_pins);
}
26 changes: 24 additions & 2 deletions libs/libarchfpga/src/arch_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ void set_arch_file_name(const char* arch);
*/
const char* get_arch_file_name();

constexpr const char* EMPTY_BLOCK_NAME = "EMPTY";

class InstPort {
public:
static constexpr int UNSPECIFIED = -1;
Expand Down Expand Up @@ -60,8 +62,15 @@ void free_type_descriptors(std::vector<t_physical_tile_type>& type_descriptors);

t_port* findPortByName(const char* name, t_pb_type* pb_type, int* high_index, int* low_index);

t_physical_tile_type SetupEmptyPhysicalType();
t_logical_block_type SetupEmptyLogicalType();
/** @brief Returns and empty physical tile type, assigned with the given name argument.
* The default empty string is assigned if no name is provided
*/
t_physical_tile_type get_empty_physical_type(const char* name = EMPTY_BLOCK_NAME);

/** @brief Returns and empty logical block type, assigned with the given name argument.
* The default empty string is assigned if no name is provided
*/
t_logical_block_type get_empty_logical_type(const char* name = EMPTY_BLOCK_NAME);

std::unordered_set<t_logical_block_type_ptr> get_equivalent_sites_set(t_physical_tile_type_ptr type);

Expand Down Expand Up @@ -100,4 +109,17 @@ bool pb_type_contains_blif_model(const t_pb_type* pb_type, const std::string& bl
const t_pin_to_pin_annotation* find_sequential_annotation(const t_pb_type* pb_type, const t_model_ports* port, enum e_pin_to_pin_delay_annotations annot_type);
const t_pin_to_pin_annotation* find_combinational_annotation(const t_pb_type* pb_type, std::string in_port, std::string out_port);

/**
* @brief Updates the physical and logical types based on the equivalence between one and the other.
*
* This function is required to check and synchronize all the information to be able to use the logical block
* equivalence, and link all the logical block pins to the physical tile ones, given that multiple logical blocks (i.e. pb_types)
* can be placed at the same physical location if this is allowed in the architecture description.
*
* See https://docs.verilogtorouting.org/en/latest/tutorials/arch/equivalent_sites/ for reference
*/
void link_physical_logical_types(std::vector<t_physical_tile_type>& PhysicalTileTypes,
std::vector<t_logical_block_type>& LogicalBlockTypes);

void setup_pin_classes(t_physical_tile_type* type);
#endif
15 changes: 15 additions & 0 deletions libs/libarchfpga/src/physical_types.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#include "physical_types.h"
#include "vtr_math.h"
#include "vtr_util.h"
#include "vtr_log.h"

#include "arch_util.h"

static bool switch_type_is_buffered(SwitchType type);
static bool switch_type_is_configurable(SwitchType type);
Expand Down Expand Up @@ -129,6 +132,18 @@ int t_physical_tile_type::get_sub_tile_loc_from_pin(int pin_num) const {
return OPEN;
}

bool t_physical_tile_type::is_empty() const {
return std::string(name) == std::string(EMPTY_BLOCK_NAME);
}

/*
* t_logical_block_type
*/

bool t_logical_block_type::is_empty() const {
return std::string(name) == std::string(EMPTY_BLOCK_NAME);
}

/**
* t_pb_graph_node
*/
Expand Down
29 changes: 29 additions & 0 deletions libs/libarchfpga/src/physical_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,9 @@ struct t_physical_tile_type {

// Does this t_physical_tile_type contain an outpad?
bool is_output_type = false;

// Is this t_physical_tile_type an empty type?
bool is_empty() const;
};

/* Holds the capacity range of a certain sub_tile block within the parent physical tile type.
Expand Down Expand Up @@ -828,6 +831,9 @@ struct t_logical_block_type {

std::vector<t_physical_tile_type_ptr> equivalent_tiles; ///>List of physical tiles at which one could
///>place this type of netlist block.

// Is this t_logical_block_type empty?
bool is_empty() const;
};

/*************************************************************************************************
Expand Down Expand Up @@ -1738,9 +1744,31 @@ struct t_lut_cell {
std::vector<std::string> inputs;
};

struct t_lut_bel {
std::string name;

std::vector<std::string> input_pins;
std::string output_pin;

bool operator==(const t_lut_bel& other) const {
return name == other.name && input_pins == other.input_pins && output_pin == other.output_pin;
}
};

struct t_lut_element {
std::string site_type;
int width;
std::vector<t_lut_bel> lut_bels;

bool operator==(const t_lut_element& other) const {
return site_type == other.site_type && width == other.width && lut_bels == other.lut_bels;
}
};

/* Detailed routing architecture */
struct t_arch {
mutable vtr::string_internment strings;
std::vector<vtr::interned_string> interned_strings;

char* architecture_id; //Secure hash digest of the architecture file to uniquely identify this architecture

Expand Down Expand Up @@ -1787,6 +1815,7 @@ struct t_arch {

// Luts
std::vector<t_lut_cell> lut_cells;
std::unordered_map<std::string, std::vector<t_lut_element>> lut_elements;

//The name of the switch used for the input connection block (i.e. to
//connect routing tracks to block pins).
Expand Down
Loading