-
Notifications
You must be signed in to change notification settings - Fork 415
Refactored read_place and read_user_block_loc functions into two new … #1490
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
Changes from 5 commits
c96a78a
926ac26
c512c70
7e4fb4a
d3a5046
257b53e
724f717
2102256
5192d2c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
#include <cstdio> | ||
#include <cstring> | ||
#include <fstream> | ||
#include <algorithm> | ||
|
||
#include "vtr_assert.h" | ||
#include "vtr_util.h" | ||
|
@@ -15,25 +16,78 @@ | |
#include "read_place.h" | ||
#include "read_xml_arch_file.h" | ||
|
||
void read_place(const char* net_file, | ||
const char* place_file, | ||
bool verify_file_digests, | ||
const DeviceGrid& grid) { | ||
void read_place_header( | ||
std::ifstream& placement_file, | ||
const char* net_file, | ||
const char* place_file, | ||
bool verify_file_hashes, | ||
const DeviceGrid& grid); | ||
|
||
void read_place_body( | ||
std::ifstream& placement_file, | ||
const char* place_file, | ||
bool is_place_file); | ||
|
||
void read_place( | ||
const char* net_file, | ||
const char* place_file, | ||
bool verify_file_digests, | ||
const DeviceGrid& grid, | ||
bool is_place_file) { | ||
std::ifstream fstream(place_file); | ||
if (!fstream) { | ||
VPR_FATAL_ERROR(VPR_ERROR_PLACE_F, | ||
"'%s' - Cannot open place file.\n", | ||
place_file); | ||
} | ||
|
||
VTR_LOG("Reading %s.\n", place_file); | ||
VTR_LOG("\n"); | ||
|
||
read_place_header(fstream, net_file, place_file, verify_file_digests, grid); | ||
read_place_body(fstream, place_file, is_place_file); | ||
|
||
VTR_LOG("Successfully read %s.\n", place_file); | ||
VTR_LOG("\n"); | ||
} | ||
|
||
void read_constraints(const char* constraints_file, | ||
bool is_place_file) { | ||
std::ifstream fstream(constraints_file); | ||
if (!fstream) { | ||
VPR_FATAL_ERROR(VPR_ERROR_PLACE_F, | ||
"'%s' - Cannot open constraints file.\n", | ||
constraints_file); | ||
} | ||
|
||
VTR_LOG("Reading %s.\n", constraints_file); | ||
VTR_LOG("\n"); | ||
|
||
read_place_body(fstream, constraints_file, is_place_file); | ||
|
||
VTR_LOG("Successfully read %s.\n", constraints_file); | ||
VTR_LOG("\n"); | ||
} | ||
|
||
/** | ||
* This function reads the header (first two lines) of a placement file. | ||
* It checks whether the packed netlist file that generated the placement matches the current netlist file. | ||
* It also checks whether the FPGA grid size has stayed the same from when the placement was generated. | ||
* The verify_file_digests bool is used to decide whether to give a warning or an error if the netlist files do not match. | ||
*/ | ||
void read_place_header(std::ifstream& placement_file, | ||
const char* net_file, | ||
const char* place_file, | ||
bool verify_file_digests, | ||
const DeviceGrid& grid) { | ||
auto& cluster_ctx = g_vpr_ctx.clustering(); | ||
auto& place_ctx = g_vpr_ctx.mutable_placement(); | ||
|
||
std::string line; | ||
int lineno = 0; | ||
bool seen_netlist_id = false; | ||
bool seen_grid_dimensions = false; | ||
while (std::getline(fstream, line)) { //Parse line-by-line | ||
|
||
while (std::getline(placement_file, line) && (!seen_netlist_id || !seen_grid_dimensions)) { //Parse line-by-line | ||
++lineno; | ||
|
||
std::vector<std::string> tokens = vtr::split(line); | ||
|
@@ -84,11 +138,6 @@ void read_place(const char* net_file, | |
&& tokens[6] == "blocks") { | ||
//Load the device grid dimensions | ||
|
||
if (seen_grid_dimensions) { | ||
vpr_throw(VPR_ERROR_PLACE_F, place_file, lineno, | ||
"Duplicate device grid dimensions specification"); | ||
} | ||
|
||
size_t place_file_width = vtr::atou(tokens[2]); | ||
size_t place_file_height = vtr::atou(tokens[4]); | ||
if (grid.width() != place_file_width || grid.height() != place_file_height) { | ||
|
@@ -97,194 +146,113 @@ void read_place(const char* net_file, | |
grid.width(), grid.height(), place_file_width, place_file_height); | ||
} | ||
|
||
seen_grid_dimensions = true; | ||
|
||
} else if (tokens.size() == 4 || (tokens.size() == 5 && tokens[4][0] == '#')) { | ||
//Load the block location | ||
// | ||
//We should have 4 tokens of actual data, with an optional 5th (commented) token indicating VPR's | ||
//internal block number | ||
|
||
//Grid dimensions are required by this point | ||
if (!seen_grid_dimensions) { | ||
vpr_throw(VPR_ERROR_PLACE_F, place_file, lineno, | ||
"Missing device grid size specification"); | ||
} | ||
|
||
std::string block_name = tokens[0]; | ||
int block_x = vtr::atoi(tokens[1]); | ||
int block_y = vtr::atoi(tokens[2]); | ||
int sub_tile_index = vtr::atoi(tokens[3]); | ||
|
||
ClusterBlockId blk_id = cluster_ctx.clb_nlist.find_block(block_name); | ||
|
||
if (place_ctx.block_locs.size() != cluster_ctx.clb_nlist.blocks().size()) { | ||
//Resize if needed | ||
place_ctx.block_locs.resize(cluster_ctx.clb_nlist.blocks().size()); | ||
} | ||
|
||
//Set the location | ||
place_ctx.block_locs[blk_id].loc.x = block_x; | ||
place_ctx.block_locs[blk_id].loc.y = block_y; | ||
place_ctx.block_locs[blk_id].loc.sub_tile = sub_tile_index; | ||
seen_grid_dimensions = true; //if you have read the grid dimensions you are done reading the place file header | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix comment at this line |
||
|
||
} else { | ||
//Unrecognized | ||
vpr_throw(VPR_ERROR_PLACE_F, place_file, lineno, | ||
"Invalid line '%s' in placement file", | ||
"Invalid line '%s' in placement file header", | ||
line.c_str()); | ||
} | ||
} | ||
|
||
place_ctx.placement_id = vtr::secure_digest_file(place_file); | ||
} | ||
|
||
/** Reads in blocks whose locations are specified in a constraints file. Constraint file is in .place format. | ||
* All blocks specified in this file will be locked down at their specified x, y, subtile locations. | ||
* (Will not be moved by optimizers during placement | ||
/** | ||
* This function reads either the body of a placement file or a constraints file. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add that constraints file is same format as place |
||
* If it is reading a place file it sets the x, y, and subtile locations of the blocks in the placement context. | ||
* If it is reading a constraints file it does the same and also marks the blocks as locked and marks the grid usage. | ||
* The bool is_place_file indicates if the file should be read as a place file (is_place_file = true) | ||
* or a constraints file (is_place_file = false). | ||
*/ | ||
void read_user_block_loc(const char* constraints_file) { | ||
t_hash **hash_table, *h_ptr; | ||
int xtmp, ytmp; | ||
FILE* fp; | ||
char buf[vtr::bufsize], bname[vtr::bufsize], *ptr; | ||
std::unordered_set<ClusterBlockId> constrained_blocks; | ||
|
||
void read_place_body(std::ifstream& placement_file, | ||
const char* place_file, | ||
bool is_place_file) { | ||
auto& cluster_ctx = g_vpr_ctx.clustering(); | ||
auto& device_ctx = g_vpr_ctx.device(); | ||
auto& place_ctx = g_vpr_ctx.mutable_placement(); | ||
|
||
VTR_LOG("\n"); | ||
VTR_LOG("Reading locations of blocks from '%s'.\n", constraints_file); | ||
fp = fopen(constraints_file, "r"); | ||
if (!fp) VPR_FATAL_ERROR(VPR_ERROR_PLACE_F, | ||
"'%s' - Cannot find block locations file.\n", | ||
constraints_file); | ||
|
||
hash_table = alloc_hash_table(); | ||
for (auto blk_id : cluster_ctx.clb_nlist.blocks()) { | ||
insert_in_hash_table(hash_table, cluster_ctx.clb_nlist.block_name(blk_id).c_str(), size_t(blk_id)); | ||
place_ctx.block_locs[blk_id].loc.x = OPEN; /* Mark as not seen yet. */ | ||
} | ||
|
||
for (size_t i = 0; i < device_ctx.grid.width(); i++) { | ||
for (size_t j = 0; j < device_ctx.grid.height(); j++) { | ||
auto type = device_ctx.grid[i][j].type; | ||
if (!is_empty_type(type)) { | ||
for (int k = 0; k < type->capacity; k++) { | ||
if (place_ctx.grid_blocks[i][j].blocks[k] != INVALID_BLOCK_ID) { | ||
place_ctx.grid_blocks[i][j].blocks[k] = EMPTY_BLOCK_ID; /* Flag for err. check */ | ||
} | ||
} | ||
} | ||
} | ||
} | ||
std::string line; | ||
int lineno = 0; | ||
|
||
ptr = vtr::fgets(buf, vtr::bufsize, fp); | ||
std::vector<ClusterBlockId> seen_blocks; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Comment what this is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should be a vtr::vector_map<ClusterBlockId, int> |
||
|
||
while (ptr != nullptr) { | ||
ptr = vtr::strtok(buf, TOKENS, fp, buf); | ||
if (ptr == nullptr) { | ||
ptr = vtr::fgets(buf, vtr::bufsize, fp); | ||
continue; /* Skip blank or comment lines. */ | ||
} | ||
while (std::getline(placement_file, line)) { //Parse line-by-line | ||
++lineno; | ||
|
||
if (strlen(ptr) + 1 < vtr::bufsize) { | ||
strcpy(bname, ptr); | ||
} else { | ||
vpr_throw(VPR_ERROR_PLACE_F, constraints_file, vtr::get_file_line_number_of_last_opened_file(), | ||
"Block name exceeded buffer size of %zu characters", vtr::bufsize); | ||
} | ||
std::vector<std::string> tokens = vtr::split(line); | ||
|
||
ptr = vtr::strtok(nullptr, TOKENS, fp, buf); | ||
if (ptr == nullptr) { | ||
vpr_throw(VPR_ERROR_PLACE_F, constraints_file, vtr::get_file_line_number_of_last_opened_file(), | ||
"Incomplete.\n"); | ||
} | ||
sscanf(ptr, "%d", &xtmp); | ||
if (tokens.empty()) { | ||
continue; //Skip blank lines | ||
|
||
ptr = vtr::strtok(nullptr, TOKENS, fp, buf); | ||
if (ptr == nullptr) { | ||
vpr_throw(VPR_ERROR_PLACE_F, constraints_file, vtr::get_file_line_number_of_last_opened_file(), | ||
"Incomplete.\n"); | ||
} | ||
sscanf(ptr, "%d", &ytmp); | ||
} else if (tokens[0][0] == '#') { | ||
continue; //Skip commented lines | ||
|
||
ptr = vtr::strtok(nullptr, TOKENS, fp, buf); | ||
if (ptr == nullptr) { | ||
vpr_throw(VPR_ERROR_PLACE_F, constraints_file, vtr::get_file_line_number_of_last_opened_file(), | ||
"Incomplete.\n"); | ||
} | ||
int k; | ||
sscanf(ptr, "%d", &k); | ||
} else if (tokens.size() == 4 || (tokens.size() == 5 && tokens[4][0] == '#')) { | ||
//Load the block location | ||
// | ||
//We should have 4 tokens of actual data, with an optional 5th (commented) token indicating VPR's | ||
//internal block number | ||
|
||
ptr = vtr::strtok(nullptr, TOKENS, fp, buf); | ||
if (ptr != nullptr) { | ||
vpr_throw(VPR_ERROR_PLACE_F, constraints_file, vtr::get_file_line_number_of_last_opened_file(), | ||
"Extra characters at end of line.\n"); | ||
} | ||
std::string block_name = tokens[0]; | ||
int block_x = vtr::atoi(tokens[1]); | ||
int block_y = vtr::atoi(tokens[2]); | ||
int sub_tile_index = vtr::atoi(tokens[3]); | ||
|
||
h_ptr = get_hash_entry(hash_table, bname); | ||
if (h_ptr == nullptr) { | ||
VTR_LOG_WARN("[Line %d] Block %s invalid, no such block.\n", | ||
vtr::get_file_line_number_of_last_opened_file(), bname); | ||
ptr = vtr::fgets(buf, vtr::bufsize, fp); | ||
continue; | ||
} | ||
ClusterBlockId bnum(h_ptr->index); | ||
int i = xtmp; | ||
int j = ytmp; | ||
ClusterBlockId blk_id = cluster_ctx.clb_nlist.find_block(block_name); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. find what this returns if it doesn't find the block name - use for invalid block name check |
||
|
||
if (place_ctx.block_locs[bnum].loc.x != OPEN) { | ||
VPR_THROW(VPR_ERROR_PLACE_F, constraints_file, vtr::get_file_line_number_of_last_opened_file(), | ||
"Block %s is listed twice in constraints file.\n", bname); | ||
} | ||
//Check if block is listed twice in constraints file | ||
if (find(seen_blocks.begin(), seen_blocks.end(), blk_id) != seen_blocks.end()) { | ||
VPR_THROW(VPR_ERROR_PLACE, "The block with ID %d is listed twice in the constraints file.\n", blk_id); | ||
} | ||
|
||
if (i < 0 || i > int(device_ctx.grid.width() - 1) || j < 0 || j > int(device_ctx.grid.height() - 1)) { | ||
VPR_THROW(VPR_ERROR_PLACE_F, constraints_file, 0, | ||
"Block #%zu (%s) location, (%d,%d) is out of range.\n", size_t(bnum), bname, i, j); | ||
} | ||
//Check if block location is out of range of grid dimensions | ||
if (block_x < 0 || block_x > int(device_ctx.grid.width() - 1) | ||
|| block_y < 0 || block_y > int(device_ctx.grid.height() - 1)) { | ||
VPR_THROW(VPR_ERROR_PLACE, "The block with ID %d is out of range at location (%d, %d). \n", blk_id, block_x, block_y); | ||
} | ||
|
||
place_ctx.block_locs[bnum].loc.x = i; /* Will be reloaded by initial_placement anyway. */ | ||
place_ctx.block_locs[bnum].loc.y = j; /* We need to set .x only as a done flag. */ | ||
place_ctx.block_locs[bnum].loc.sub_tile = k; | ||
place_ctx.block_locs[bnum].is_fixed = true; | ||
if (place_ctx.block_locs.size() != cluster_ctx.clb_nlist.blocks().size()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. check if we need this. if we do, should be out of the loop |
||
//Resize if needed | ||
place_ctx.block_locs.resize(cluster_ctx.clb_nlist.blocks().size()); | ||
} | ||
|
||
auto physical_tile = device_ctx.grid[i][j].type; | ||
auto logical_block = cluster_ctx.clb_nlist.block_type(bnum); | ||
if (!is_sub_tile_compatible(physical_tile, logical_block, place_ctx.block_locs[bnum].loc.sub_tile)) { | ||
VPR_THROW(VPR_ERROR_PLACE_F, constraints_file, 0, | ||
"Attempt to place block %s at illegal location (%d, %d).\n", bname, i, j); | ||
} | ||
//Set the location | ||
place_ctx.block_locs[blk_id].loc.x = block_x; | ||
place_ctx.block_locs[blk_id].loc.y = block_y; | ||
place_ctx.block_locs[blk_id].loc.sub_tile = sub_tile_index; | ||
|
||
if (k >= physical_tile->capacity || k < 0) { | ||
VPR_THROW(VPR_ERROR_PLACE_F, constraints_file, vtr::get_file_line_number_of_last_opened_file(), | ||
"Block %s subtile number (%d) is out of range.\n", bname, k); | ||
} | ||
place_ctx.grid_blocks[i][j].blocks[k] = bnum; | ||
place_ctx.grid_blocks[i][j].usage++; | ||
//Check if block is at an illegal location | ||
auto physical_tile = device_ctx.grid[block_x][block_y].type; | ||
auto logical_block = cluster_ctx.clb_nlist.block_type(blk_id); | ||
if (!is_sub_tile_compatible(physical_tile, logical_block, place_ctx.block_locs[blk_id].loc.sub_tile)) { | ||
VPR_THROW(VPR_ERROR_PLACE, place_file, 0, "Attempt to place block %d at illegal location (%d, %d). \n", blk_id, block_x, block_y); | ||
} | ||
|
||
constrained_blocks.insert(bnum); | ||
if (sub_tile_index >= physical_tile->capacity || sub_tile_index < 0) { | ||
VPR_THROW(VPR_ERROR_PLACE, place_file, vtr::get_file_line_number_of_last_opened_file(), "Block %d subtile number (%d) is out of range. \n", blk_id, sub_tile_index); | ||
} | ||
|
||
ptr = vtr::fgets(buf, vtr::bufsize, fp); | ||
} | ||
//need to lock down blocks and mark grid block usage if it is a constraints file | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. explain why you need to do this (if place file, initial placement does instead) |
||
if (!is_place_file) { | ||
place_ctx.block_locs[blk_id].is_fixed = true; | ||
place_ctx.grid_blocks[block_x][block_y].blocks[sub_tile_index] = blk_id; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Try setting grid all the time, check that it works |
||
place_ctx.grid_blocks[block_x][block_y].usage++; | ||
} | ||
|
||
for (auto blk_id : cluster_ctx.clb_nlist.blocks()) { | ||
auto result = constrained_blocks.find(blk_id); | ||
if (result == constrained_blocks.end()) { | ||
continue; | ||
} | ||
//add to vector of blocks that have been seen | ||
seen_blocks.push_back(blk_id); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. change once you refactor to vector map |
||
|
||
if (place_ctx.block_locs[blk_id].loc.x == OPEN) { | ||
VPR_THROW(VPR_ERROR_PLACE_F, constraints_file, 0, | ||
"Block %s location was not specified in the constraints file.\n", cluster_ctx.clb_nlist.block_name(blk_id).c_str()); | ||
} else { | ||
//Unrecognized | ||
vpr_throw(VPR_ERROR_PLACE_F, place_file, lineno, | ||
"Invalid line '%s' in file", | ||
line.c_str()); | ||
} | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add in check for place file to see if it has checked all blocks |
||
fclose(fp); | ||
free_hash_table(hash_table); | ||
VTR_LOG("Successfully read %s.\n", constraints_file); | ||
VTR_LOG("\n"); | ||
if (is_place_file) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add comment to explain why There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. for entire place file, want to make hash so we can write into routing file for later error checking, dont need for constraint |
||
place_ctx.placement_id = vtr::secure_digest_file(place_file); | ||
} | ||
} | ||
|
||
/** | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Say what the header is - two lines in any order that give netlist and grid files used to generate placement. Also mention grid gives an error if it doesn't match