blob: 6712196800bc647c9d43a490b8ddac7de450d5c2 [file] [log] [blame]
/*
* Author: Jason Luu
* Date: October 8, 2008
*
* Initializes and allocates the physical logic block grid for VPR.
*
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <regex>
#include <limits>
#include "vtr_assert.h"
#include "vtr_math.h"
#include "vtr_log.h"
#include "vpr_types.h"
#include "vpr_error.h"
#include "vpr_utils.h"
#include "globals.h"
#include "SetupGrid.h"
#include "expr_eval.h"
static DeviceGrid auto_size_device_grid(const std::vector<t_grid_def>& grid_layouts, const std::map<t_logical_block_type_ptr, size_t>& minimum_instance_counts, float maximum_device_utilization);
static std::vector<t_physical_tile_type_ptr> grid_overused_resources(const DeviceGrid& grid, std::map<t_logical_block_type_ptr, size_t> instance_counts);
static bool grid_satisfies_instance_counts(const DeviceGrid& grid, std::map<t_logical_block_type_ptr, size_t> instance_counts, float maximum_utilization);
static DeviceGrid build_device_grid(const t_grid_def& grid_def, size_t width, size_t height, bool warn_out_of_range = true, std::vector<t_physical_tile_type_ptr> limiting_resources = std::vector<t_physical_tile_type_ptr>());
static void CheckGrid(const DeviceGrid& grid);
static void set_grid_block_type(int priority, const t_physical_tile_type* type, size_t x_root, size_t y_root, vtr::Matrix<t_grid_tile>& grid, vtr::Matrix<int>& grid_priorities, const t_metadata_dict* meta);
//Create the device grid based on resource requirements
DeviceGrid create_device_grid(std::string layout_name, const std::vector<t_grid_def>& grid_layouts, const std::map<t_logical_block_type_ptr, size_t>& minimum_instance_counts, float target_device_utilization) {
if (layout_name == "auto") {
//Auto-size the device
//
//Note that we treat the target device utilization as a maximum
return auto_size_device_grid(grid_layouts, minimum_instance_counts, target_device_utilization);
} else {
//Use the specified device
//Find the matching grid definition
auto cmp = [&](const t_grid_def& grid_def) {
return grid_def.name == layout_name;
};
auto iter = std::find_if(grid_layouts.begin(), grid_layouts.end(), cmp);
if (iter == grid_layouts.end()) {
//Not found
std::string valid_names;
for (size_t i = 0; i < grid_layouts.size(); ++i) {
if (i != 0) {
valid_names += ", ";
}
valid_names += "'" + grid_layouts[i].name + "'";
}
VPR_FATAL_ERROR(VPR_ERROR_ARCH, "Failed to find grid layout named '%s' (valid grid layouts: %s)\n", layout_name.c_str(), valid_names.c_str());
}
return build_device_grid(*iter, iter->width, iter->height);
}
}
//Create the device grid based on dimensions
DeviceGrid create_device_grid(std::string layout_name, const std::vector<t_grid_def>& grid_layouts, size_t width, size_t height) {
if (layout_name == "auto") {
VTR_ASSERT(grid_layouts.size() > 0);
//Auto-size
if (grid_layouts[0].grid_type == GridDefType::AUTO) {
//Auto layout of the specified dimensions
return build_device_grid(grid_layouts[0], width, height);
} else {
//Find the fixed layout close to the target size
std::vector<const t_grid_def*> grid_layouts_view;
grid_layouts_view.reserve(grid_layouts.size());
for (const auto& layout : grid_layouts) {
grid_layouts_view.push_back(&layout);
}
auto sort_cmp = [](const t_grid_def* lhs, const t_grid_def* rhs) {
return lhs->width < rhs->width || lhs->height < rhs->width;
};
std::stable_sort(grid_layouts_view.begin(), grid_layouts_view.end(), sort_cmp);
auto find_cmp = [&](const t_grid_def* grid_def) {
return grid_def->width >= int(width) && grid_def->height >= int(height);
};
auto iter = std::find_if(grid_layouts_view.begin(), grid_layouts_view.end(), find_cmp);
if (iter == grid_layouts_view.end()) {
//No device larger than specified width/height, so choose largest possible
VTR_LOG_WARN(
"Specified device dimensions (%zux%zu) exceed those of the largest fixed-size device."
" Using the largest fixed-size device\n",
width, height);
--iter;
}
const t_grid_def* layout = *iter;
return build_device_grid(*layout, layout->width, layout->height);
}
} else {
//Use the specified device
auto cmp = [&](const t_grid_def& grid_def) {
return grid_def.name == layout_name;
};
auto iter = std::find_if(grid_layouts.begin(), grid_layouts.end(), cmp);
if (iter == grid_layouts.end()) {
//Not found
std::string valid_names;
for (size_t i = 0; i < grid_layouts.size(); ++i) {
if (i != 0) {
valid_names += ", ";
}
valid_names += "'" + grid_layouts[i].name + "'";
}
VPR_FATAL_ERROR(VPR_ERROR_ARCH, "Failed to find grid layout named '%s' (valid grid layouts: %s)\n", layout_name.c_str(), valid_names.c_str());
}
return build_device_grid(*iter, iter->width, iter->height);
}
}
//Create a device grid which satisfies the minimum block counts
// If a set of fixed grid layouts are specified, the smallest satisfying grid is picked
// If an auto grid layouts are specified, the smallest dynamicly sized grid is picked
static DeviceGrid auto_size_device_grid(const std::vector<t_grid_def>& grid_layouts, const std::map<t_logical_block_type_ptr, size_t>& minimum_instance_counts, float maximum_device_utilization) {
VTR_ASSERT(grid_layouts.size() > 0);
DeviceGrid grid;
auto is_auto_grid_def = [](const t_grid_def& grid_def) {
return grid_def.grid_type == GridDefType::AUTO;
};
auto auto_layout_itr = std::find_if(grid_layouts.begin(), grid_layouts.end(), is_auto_grid_def);
if (auto_layout_itr != grid_layouts.end()) {
//Automatic grid layout, find the smallest height/width
VTR_ASSERT_SAFE_MSG(std::find_if(auto_layout_itr + 1, grid_layouts.end(), is_auto_grid_def) == grid_layouts.end(), "Only one <auto_layout>");
const auto& grid_def = *auto_layout_itr;
VTR_ASSERT(grid_def.aspect_ratio >= 0.);
//Initial size is 3x3, the smallest possible while avoiding
//start before end location issues with <perimeter> location
//specifications
size_t width = 3;
size_t height = 3;
std::vector<t_physical_tile_type_ptr> limiting_resources;
do {
//Scale opposite dimension to match aspect ratio
height = vtr::nint(width / grid_def.aspect_ratio);
#ifdef VERBOSE
VTR_LOG("Grid size: %zu x %zu (AR: %.2f) \n", width, height, float(width) / height);
#endif
//Build the device
// Don't warn about out-of-range specifications since these can
// occur (harmlessly) at small device dimensions
grid = build_device_grid(grid_def, width, height, false, limiting_resources);
//Check if it satisfies the block counts
if (grid_satisfies_instance_counts(grid, minimum_instance_counts, maximum_device_utilization)) {
//Re-build the grid at the final size with out-of-range
//warnings turned on (so users are aware of out-of-range issues
//at the final device sizes)
grid = build_device_grid(grid_def, width, height, true, limiting_resources);
return grid;
}
limiting_resources = grid_overused_resources(grid, minimum_instance_counts);
//Increase the grid size
width++;
} while (true);
} else {
VTR_ASSERT(auto_layout_itr == grid_layouts.end());
//Fixed grid layouts, find the smallest of the fixed layouts
//Sort the grid layouts from smallest to largest
std::vector<const t_grid_def*> grid_layouts_view;
grid_layouts_view.reserve(grid_layouts.size());
for (const auto& layout : grid_layouts) {
grid_layouts_view.push_back(&layout);
}
auto area_cmp = [](const t_grid_def* lhs, const t_grid_def* rhs) {
VTR_ASSERT(lhs->grid_type == GridDefType::FIXED);
VTR_ASSERT(rhs->grid_type == GridDefType::FIXED);
int lhs_area = lhs->width * lhs->height;
int rhs_area = rhs->width * rhs->height;
return lhs_area < rhs_area;
};
std::stable_sort(grid_layouts_view.begin(), grid_layouts_view.end(), area_cmp);
std::vector<t_physical_tile_type_ptr> limiting_resources;
//Try all the fixed devices in order from smallest to largest
for (const auto* grid_def : grid_layouts_view) {
//Build the grid
grid = build_device_grid(*grid_def, grid_def->width, grid_def->height, true, limiting_resources);
if (grid_satisfies_instance_counts(grid, minimum_instance_counts, maximum_device_utilization)) {
return grid;
}
limiting_resources = grid_overused_resources(grid, minimum_instance_counts);
}
}
return grid; //Unreachable
}
static std::vector<t_physical_tile_type_ptr> grid_overused_resources(const DeviceGrid& grid, std::map<t_logical_block_type_ptr, size_t> instance_counts) {
std::vector<t_physical_tile_type_ptr> overused_resources;
//Are the resources satisified?
for (auto kv : instance_counts) {
t_physical_tile_type_ptr type;
size_t min_count;
std::tie(type, min_count) = std::make_pair(physical_tile_type(kv.first), kv.second);
size_t inst_cnt = grid.num_instances(type);
if (inst_cnt < min_count) {
overused_resources.push_back(type);
}
}
return overused_resources;
}
static bool grid_satisfies_instance_counts(const DeviceGrid& grid, std::map<t_logical_block_type_ptr, size_t> instance_counts, float maximum_utilization) {
//Are the resources satisified?
auto overused_resources = grid_overused_resources(grid, instance_counts);
if (!overused_resources.empty()) {
return false;
}
//Is the utilization below the maximum?
float utilization = calculate_device_utilization(grid, instance_counts);
if (utilization > maximum_utilization) {
return false;
}
return true; //OK
}
//Build the specified device grid
static DeviceGrid build_device_grid(const t_grid_def& grid_def, size_t grid_width, size_t grid_height, bool warn_out_of_range, const std::vector<t_physical_tile_type_ptr> limiting_resources) {
if (grid_def.grid_type == GridDefType::FIXED) {
if (grid_def.width != int(grid_width) || grid_def.height != int(grid_height)) {
VPR_FATAL_ERROR(VPR_ERROR_OTHER,
"Requested grid size (%zu%zu) does not match fixed device size (%dx%d)",
grid_width, grid_height, grid_def.width, grid_def.height);
}
}
auto& device_ctx = g_vpr_ctx.device();
//Track the current priority for each grid location
// Note that we initialize it to the lowest (i.e. most negative) possible value, so
// any user-specified priority will override the default empty grid
auto grid_priorities = vtr::Matrix<int>({grid_width, grid_height}, std::numeric_limits<int>::lowest());
auto grid = vtr::Matrix<t_grid_tile>({grid_width, grid_height});
//Initialize the device to all empty blocks
auto empty_type = find_block_type_by_name(EMPTY_BLOCK_NAME, device_ctx.physical_tile_types);
VTR_ASSERT(empty_type != nullptr);
for (size_t x = 0; x < grid_width; ++x) {
for (size_t y = 0; y < grid_height; ++y) {
set_grid_block_type(std::numeric_limits<int>::lowest() + 1, //+1 so it overrides without warning
empty_type, x, y, grid, grid_priorities, /*meta=*/nullptr);
}
}
std::set<t_physical_tile_type_ptr> seen_types;
for (const auto& grid_loc_def : grid_def.loc_defs) {
//Fill in the block types according to the specification
auto type = find_block_type_by_name(grid_loc_def.block_type, device_ctx.physical_tile_types);
if (!type) {
VPR_FATAL_ERROR(VPR_ERROR_ARCH,
"Failed to find block type '%s' for grid location specification",
grid_loc_def.block_type.c_str());
}
seen_types.insert(type);
t_formula_data vars;
vars.set_var_value("W", grid_width);
vars.set_var_value("H", grid_height);
vars.set_var_value("w", type->width);
vars.set_var_value("h", type->height);
//Load the x specification
auto& xspec = grid_loc_def.x;
VTR_ASSERT_MSG(!xspec.start_expr.empty(), "x start position must be specified");
VTR_ASSERT_MSG(!xspec.end_expr.empty(), "x end position must be specified");
VTR_ASSERT_MSG(!xspec.incr_expr.empty(), "x increment must be specified");
VTR_ASSERT_MSG(!xspec.repeat_expr.empty(), "x repeat must be specified");
size_t startx = parse_formula(xspec.start_expr, vars);
size_t endx = parse_formula(xspec.end_expr, vars);
size_t incrx = parse_formula(xspec.incr_expr, vars);
size_t repeatx = parse_formula(xspec.repeat_expr, vars);
//Load the y specification
auto& yspec = grid_loc_def.y;
VTR_ASSERT_MSG(!yspec.start_expr.empty(), "y start position must be specified");
VTR_ASSERT_MSG(!yspec.end_expr.empty(), "y end position must be specified");
VTR_ASSERT_MSG(!yspec.incr_expr.empty(), "y increment must be specified");
VTR_ASSERT_MSG(!yspec.repeat_expr.empty(), "y repeat must be specified");
size_t starty = parse_formula(yspec.start_expr, vars);
size_t endy = parse_formula(yspec.end_expr, vars);
size_t incry = parse_formula(yspec.incr_expr, vars);
size_t repeaty = parse_formula(yspec.repeat_expr, vars);
//Check start against the device dimensions
// Start locations outside the device will never create block instances
if (startx > grid_width - 1) {
if (warn_out_of_range) {
VTR_LOG_WARN("Block type '%s' grid location specification startx (%s = %d) falls outside device horizontal range [%d,%d]\n",
type->name, xspec.start_expr.c_str(), startx, 0, grid_width - 1);
}
continue; //No instances will be created
}
if (starty > grid_height - 1) {
if (warn_out_of_range) {
VTR_LOG_WARN("Block type '%s' grid location specification starty (%s = %d) falls outside device vertical range [%d,%d]\n",
type->name, yspec.start_expr.c_str(), starty, 0, grid_height - 1);
}
continue; //No instances will be created
}
//Check end against the device dimensions
if (endx > grid_width - 1) {
if (warn_out_of_range) {
VTR_LOG_WARN("Block type '%s' grid location specification endx (%s = %d) falls outside device horizontal range [%d,%d]\n",
type->name, xspec.end_expr.c_str(), endx, 0, grid_width - 1);
}
}
if (endy > grid_height - 1) {
if (warn_out_of_range) {
VTR_LOG_WARN("Block type '%s' grid location specification endy (%s = %d) falls outside device vertical range [%d,%d]\n",
type->name, yspec.end_expr.c_str(), endy, 0, grid_height - 1);
}
}
//The end must fall after (or equal) to the start
if (endx < startx) {
VPR_FATAL_ERROR(VPR_ERROR_ARCH,
"Grid location specification endx (%s = %d) can not come before startx (%s = %d) for block type '%s'",
xspec.end_expr.c_str(), endx, xspec.start_expr.c_str(), startx, type->name);
}
if (endy < starty) {
VPR_FATAL_ERROR(VPR_ERROR_ARCH,
"Grid location specification endy (%s = %d) can not come before starty (%s = %d) for block type '%s'",
yspec.end_expr.c_str(), endy, yspec.start_expr.c_str(), starty, type->name);
}
//The minimum increment is the block dimension
VTR_ASSERT(type->width > 0);
if (incrx < size_t(type->width)) {
VPR_FATAL_ERROR(VPR_ERROR_ARCH,
"Grid location specification incrx for block type '%s' must be at least"
" block width (%d) to avoid overlapping instances (was %s = %d)",
type->name, type->width, xspec.incr_expr.c_str(), incrx);
}
VTR_ASSERT(type->height > 0);
if (incry < size_t(type->height)) {
VPR_FATAL_ERROR(VPR_ERROR_ARCH,
"Grid location specification incry for block type '%s' must be at least"
" block height (%d) to avoid overlapping instances (was %s = %d)",
type->name, type->height, yspec.incr_expr.c_str(), incry);
}
//The minimum repeat is the region dimension
size_t region_width = endx - startx + 1; //+1 since start/end are both inclusive
if (repeatx < region_width) {
VPR_FATAL_ERROR(VPR_ERROR_ARCH,
"Grid location specification repeatx for block type '%s' must be at least"
" the region width (%d) to avoid overlapping instances (was %s = %d)",
type->name, region_width, xspec.repeat_expr.c_str(), repeatx);
}
size_t region_height = endy - starty + 1; //+1 since start/end are both inclusive
if (repeaty < region_height) {
VPR_FATAL_ERROR(VPR_ERROR_ARCH,
"Grid location specification repeaty for block type '%s' must be at least"
" the region height (%d) to avoid overlapping instances (was %s = %d)",
type->name, region_height, xspec.repeat_expr.c_str(), repeaty);
}
//VTR_LOG("Applying grid_loc_def for '%s' priority %d startx=%s=%zu, endx=%s=%zu, starty=%s=%zu, endx=%s=%zu,\n",
// type->name, grid_loc_def.priority,
// xspec.start_expr.c_str(), startx, xspec.end_expr.c_str(), endx,
// yspec.start_expr.c_str(), starty, yspec.end_expr.c_str(), endy);
size_t x_end = 0;
for (size_t kx = 0; x_end < grid_width; ++kx) { //Repeat in x direction
size_t x_start = startx + kx * repeatx;
x_end = endx + kx * repeatx;
size_t y_end = 0;
for (size_t ky = 0; y_end < grid_height; ++ky) { //Repeat in y direction
size_t y_start = starty + ky * repeaty;
y_end = endy + ky * repeaty;
size_t x_max = std::min(x_end, grid_width - 1);
size_t y_max = std::min(y_end, grid_height - 1);
//Fill in the region
for (size_t x = x_start; x + (type->width - 1) <= x_max; x += incrx) {
for (size_t y = y_start; y + (type->height - 1) <= y_max; y += incry) {
set_grid_block_type(grid_loc_def.priority, type, x, y, grid, grid_priorities, grid_loc_def.meta);
}
}
}
}
}
//Warn if any types were not specified in the grid layout
for (auto const& type : device_ctx.physical_tile_types) {
if (&type == empty_type) continue; //Don't worry if empty hasn't been specified
if (!seen_types.count(&type)) {
VTR_LOG_WARN("Block type '%s' was not specified in device grid layout\n",
type.name);
}
}
auto device_grid = DeviceGrid(grid_def.name, grid, limiting_resources);
CheckGrid(device_grid);
return device_grid;
}
static void set_grid_block_type(int priority, const t_physical_tile_type* type, size_t x_root, size_t y_root, vtr::Matrix<t_grid_tile>& grid, vtr::Matrix<int>& grid_priorities, const t_metadata_dict* meta) {
struct TypeLocation {
TypeLocation(size_t x_val, size_t y_val, const t_physical_tile_type* type_val, int priority_val)
: x(x_val)
, y(y_val)
, type(type_val)
, priority(priority_val) {}
size_t x;
size_t y;
const t_physical_tile_type* type;
int priority;
bool operator<(const TypeLocation& rhs) const {
return x < rhs.x || y < rhs.y || type < rhs.type;
}
};
//Collect locations effected by this block
std::set<TypeLocation> target_locations;
for (size_t x = x_root; x < x_root + type->width; ++x) {
for (size_t y = y_root; y < y_root + type->height; ++y) {
target_locations.insert(TypeLocation(x, y, grid[x][y].type, grid_priorities[x][y]));
}
}
//Record the highest priority of all effected locations
auto iter = target_locations.begin();
TypeLocation max_priority_type_loc = *iter;
for (; iter != target_locations.end(); ++iter) {
if (iter->priority > max_priority_type_loc.priority) {
max_priority_type_loc = *iter;
}
}
if (priority < max_priority_type_loc.priority) {
//Lower priority, do not override
#ifdef VERBOSE
VTR_LOG("Not creating block '%s' at (%zu,%zu) since overlaps block '%s' at (%zu,%zu) with higher priority (%d > %d)\n",
type->name, x_root, y_root, max_priority_type_loc.type->name, max_priority_type_loc.x, max_priority_type_loc.y,
max_priority_type_loc.priority, priority);
#endif
return;
}
if (priority == max_priority_type_loc.priority) {
//Ambiguous case where current grid block and new specification have equal priority
//
//We arbitrarily decide to take the 'last applied' wins approach, and warn the user
//about the potential ambiguity
VTR_LOG_WARN(
"Ambiguous block type specification at grid location (%zu,%zu)."
" Existing block type '%s' at (%zu,%zu) has the same priority (%d) as new overlapping type '%s'."
" The last specification will apply.\n",
x_root, y_root,
max_priority_type_loc.type->name, max_priority_type_loc.x, max_priority_type_loc.y,
priority, type->name);
}
//Mark all the grid tiles 'covered' by this block with the appropriate type
//and width/height offsets
std::set<TypeLocation> root_blocks_to_rip_up;
auto& device_ctx = g_vpr_ctx.device();
for (size_t x = x_root; x < x_root + type->width; ++x) {
VTR_ASSERT(x < grid.end_index(0));
size_t x_offset = x - x_root;
for (size_t y = y_root; y < y_root + type->height; ++y) {
VTR_ASSERT(y < grid.end_index(1));
size_t y_offset = y - y_root;
auto& grid_tile = grid[x][y];
VTR_ASSERT(grid_priorities[x][y] <= priority);
if (grid_tile.type != nullptr
&& grid_tile.type != device_ctx.EMPTY_TYPE) {
//We are overriding a non-empty block, we need to be careful
//to ensure we remove any blocks which will be invalidated when we
//overwrite part of their locations
size_t orig_root_x = x - grid[x][y].width_offset;
size_t orig_root_y = y - grid[x][y].height_offset;
root_blocks_to_rip_up.insert(TypeLocation(orig_root_x, orig_root_y, grid[x][y].type, grid_priorities[x][y]));
}
grid[x][y].type = type;
grid[x][y].width_offset = x_offset;
grid[x][y].height_offset = y_offset;
grid[x][y].meta = meta;
grid_priorities[x][y] = priority;
}
}
//Rip-up any invalidated blocks
for (auto invalidated_root : root_blocks_to_rip_up) {
//Mark all the grid locations used by this root block as empty
for (size_t x = invalidated_root.x; x < invalidated_root.x + invalidated_root.type->width; ++x) {
int x_offset = x - invalidated_root.x;
for (size_t y = invalidated_root.y; y < invalidated_root.y + invalidated_root.type->height; ++y) {
int y_offset = y - invalidated_root.y;
if (grid[x][y].type == invalidated_root.type
&& grid[x][y].width_offset == x_offset
&& grid[x][y].height_offset == y_offset) {
//This is a left-over invalidated block, mark as empty
// Note: that we explicitly check the type and offsets, since the original block
// may have been completely overwritten, and we don't want to change anything
// in that case
VTR_ASSERT(device_ctx.EMPTY_TYPE->width == 1);
VTR_ASSERT(device_ctx.EMPTY_TYPE->height == 1);
#ifdef VERBOSE
VTR_LOG("Ripping up block '%s' at (%d,%d) offset (%d,%d). Overlapped by '%s' at (%d,%d)\n",
invalidated_root.type->name, invalidated_root.x, invalidated_root.y,
x_offset, y_offset,
type->name, x_root, y_root);
#endif
grid[x][y].type = device_ctx.EMPTY_TYPE;
grid[x][y].width_offset = 0;
grid[x][y].height_offset = 0;
grid_priorities[x][y] = std::numeric_limits<int>::lowest();
}
}
}
}
}
static void CheckGrid(const DeviceGrid& grid) {
/* Check grid is valid */
for (size_t i = 0; i < grid.width(); ++i) {
for (size_t j = 0; j < grid.height(); ++j) {
auto type = grid[i][j].type;
if (nullptr == type) {
VPR_FATAL_ERROR(VPR_ERROR_OTHER, "Grid Location (%d,%d) has no type.\n", i, j);
}
if ((grid[i][j].width_offset < 0)
|| (grid[i][j].width_offset >= type->width)) {
VPR_FATAL_ERROR(VPR_ERROR_OTHER, "Grid Location (%d,%d) has invalid width offset (%d).\n", i, j, grid[i][j].width_offset);
}
if ((grid[i][j].height_offset < 0)
|| (grid[i][j].height_offset >= type->height)) {
VPR_FATAL_ERROR(VPR_ERROR_OTHER, "Grid Location (%d,%d) has invalid height offset (%d).\n", i, j, grid[i][j].height_offset);
}
//Verify that type and width/height offsets are correct (e.g. for dimension > 1 blocks)
if (grid[i][j].width_offset == 0 && grid[i][j].height_offset == 0) {
//From the root block check that all other blocks are correct
for (size_t x = i; x < i + type->width; ++x) {
int x_offset = x - i;
for (size_t y = j; y < j + type->height; ++y) {
int y_offset = y - j;
auto& tile = grid[x][y];
if (tile.type != type) {
VPR_FATAL_ERROR(VPR_ERROR_OTHER,
"Grid Location (%d,%d) should have type '%s' (based on root location) but has type '%s'\n",
i, j, type->name, tile.type->name);
}
if (tile.width_offset != x_offset) {
VPR_FATAL_ERROR(VPR_ERROR_OTHER,
"Grid Location (%d,%d) of type '%s' should have width offset '%d' (based on root location) but has '%d'\n",
i, j, type->name, x_offset, tile.width_offset);
}
if (tile.height_offset != y_offset) {
VPR_FATAL_ERROR(VPR_ERROR_OTHER,
"Grid Location (%d,%d) of type '%s' should have height offset '%d' (based on root location) but has '%d'\n",
i, j, type->name, y_offset, tile.height_offset);
}
}
}
}
}
}
}
float calculate_device_utilization(const DeviceGrid& grid, std::map<t_logical_block_type_ptr, size_t> instance_counts) {
//Record the resources of the grid
std::map<t_physical_tile_type_ptr, size_t> grid_resources;
for (size_t x = 0; x < grid.width(); ++x) {
for (size_t y = 0; y < grid.height(); ++y) {
const auto& grid_tile = grid[x][y];
if (grid_tile.width_offset == 0 && grid_tile.height_offset == 0) {
++grid_resources[grid_tile.type];
}
}
}
//Determine the area of grid in tile units
float grid_area = 0.;
for (auto& kv : grid_resources) {
t_physical_tile_type_ptr type = kv.first;
size_t count = kv.second;
float type_area = type->width * type->height;
grid_area += type_area * count;
}
//Determine the area of instances in tile units
float instance_area = 0.;
for (auto& kv : instance_counts) {
t_physical_tile_type_ptr type = physical_tile_type(kv.first);
size_t count = kv.second;
float type_area = type->width * type->height;
//Instances of multi-capaicty blocks take up less space
if (type->capacity != 0) {
type_area /= type->capacity;
}
instance_area += type_area * count;
}
float utilization = instance_area / grid_area;
return utilization;
}
size_t count_grid_tiles(const DeviceGrid& grid) {
return grid.width() * grid.height();
}