blob: a7bfc6748952e56dfb907aae919c7d48fc3c67f1 [file] [log] [blame]
#include <queue>
#include "place_delay_model.h"
#include "globals.h"
#include "router_lookahead_map.h"
#include "rr_graph2.h"
#include "timing_place_lookup.h"
#include "vtr_log.h"
#include "vtr_math.h"
#include "vpr_error.h"
#ifdef VTR_ENABLE_CAPNPROTO
# include "capnp/serialize.h"
# include "place_delay_model.capnp.h"
# include "ndmatrix_serdes.h"
# include "mmap_file.h"
# include "serdes_utils.h"
#endif /* VTR_ENABLE_CAPNPROTO */
/*
* DeltaDelayModel
*/
float DeltaDelayModel::delay(int from_x, int from_y, int /*from_pin*/, int to_x, int to_y, int /*to_pin*/) const {
int delta_x = std::abs(from_x - to_x);
int delta_y = std::abs(from_y - to_y);
return delays_[delta_x][delta_y];
}
void DeltaDelayModel::dump_echo(std::string filepath) const {
FILE* f = vtr::fopen(filepath.c_str(), "w");
fprintf(f, " ");
for (size_t dx = 0; dx < delays_.dim_size(0); ++dx) {
fprintf(f, " %9zu", dx);
}
fprintf(f, "\n");
for (size_t dy = 0; dy < delays_.dim_size(1); ++dy) {
fprintf(f, "%9zu", dy);
for (size_t dx = 0; dx < delays_.dim_size(0); ++dx) {
fprintf(f, " %9.2e", delays_[dx][dy]);
}
fprintf(f, "\n");
}
vtr::fclose(f);
}
/*
* OverrideDelayModel
*/
float OverrideDelayModel::delay(int from_x, int from_y, int from_pin, int to_x, int to_y, int to_pin) const {
//First check to if there is an override delay value
auto& device_ctx = g_vpr_ctx.device();
auto& grid = device_ctx.grid;
t_physical_tile_type_ptr from_type_ptr = grid[from_x][from_y].type;
t_physical_tile_type_ptr to_type_ptr = grid[to_x][to_y].type;
t_override override_key;
override_key.from_type = from_type_ptr->index;
override_key.from_class = from_type_ptr->pin_class[from_pin];
override_key.to_type = to_type_ptr->index;
override_key.to_class = to_type_ptr->pin_class[to_pin];
//Delay overrides may be different for +/- delta so do not use
//an absolute delta for the look-up
override_key.delta_x = to_x - from_x;
override_key.delta_y = to_y - from_y;
float delay_val = std::numeric_limits<float>::quiet_NaN();
auto override_iter = delay_overrides_.find(override_key);
if (override_iter != delay_overrides_.end()) {
//Found an override
delay_val = override_iter->second;
} else {
//Fall back to the base delay model if no override was found
delay_val = base_delay_model_->delay(from_x, from_y, from_pin, to_x, to_y, to_pin);
}
return delay_val;
}
void OverrideDelayModel::set_delay_override(int from_type, int from_class, int to_type, int to_class, int delta_x, int delta_y, float delay_val) {
t_override override_key;
override_key.from_type = from_type;
override_key.from_class = from_class;
override_key.to_type = to_type;
override_key.to_class = to_class;
override_key.delta_x = delta_x;
override_key.delta_y = delta_y;
auto res = delay_overrides_.insert(std::make_pair(override_key, delay_val));
if (!res.second) { //Key already exists
res.first->second = delay_val; //Overwrite existing delay
}
}
void OverrideDelayModel::dump_echo(std::string filepath) const {
base_delay_model_->dump_echo(filepath);
FILE* f = vtr::fopen(filepath.c_str(), "a");
fprintf(f, "\n");
fprintf(f, "# Delay Overrides\n");
auto& device_ctx = g_vpr_ctx.device();
for (auto kv : delay_overrides_) {
auto override_key = kv.first;
float delay_val = kv.second;
fprintf(f, "from_type: %s to_type: %s from_pin_class: %d to_pin_class: %d delta_x: %d delta_y: %d -> delay: %g\n",
device_ctx.physical_tile_types[override_key.from_type].name,
device_ctx.physical_tile_types[override_key.to_type].name,
override_key.from_class,
override_key.to_class,
override_key.delta_x,
override_key.delta_y,
delay_val);
}
vtr::fclose(f);
}
float OverrideDelayModel::get_delay_override(int from_type, int from_class, int to_type, int to_class, int delta_x, int delta_y) const {
t_override key;
key.from_type = from_type;
key.from_class = from_class;
key.to_type = to_type;
key.to_class = to_class;
key.delta_x = delta_x;
key.delta_y = delta_y;
auto iter = delay_overrides_.find(key);
if (iter == delay_overrides_.end()) {
VPR_THROW(VPR_ERROR_PLACE, "Key not found.");
}
return iter->second;
}
const DeltaDelayModel* OverrideDelayModel::base_delay_model() const {
return base_delay_model_.get();
}
void OverrideDelayModel::set_base_delay_model(std::unique_ptr<DeltaDelayModel> base_delay_model_obj) {
base_delay_model_ = std::move(base_delay_model_obj);
}
// When writing capnp targetted serialization, always allow compilation when
// VTR_ENABLE_CAPNPROTO=OFF. Generally this means throwing an exception
// instead.
//
#ifndef VTR_ENABLE_CAPNPROTO
# define DISABLE_ERROR \
"is disable because VTR_ENABLE_CAPNPROTO=OFF." \
"Re-compile with CMake option VTR_ENABLE_CAPNPROTO=ON to enable."
void DeltaDelayModel::read(const std::string& /*file*/) {
VPR_THROW(VPR_ERROR_PLACE, "DeltaDelayModel::read " DISABLE_ERROR);
}
void DeltaDelayModel::write(const std::string& /*file*/) const {
VPR_THROW(VPR_ERROR_PLACE, "DeltaDelayModel::write " DISABLE_ERROR);
}
void OverrideDelayModel::read(const std::string& /*file*/) {
VPR_THROW(VPR_ERROR_PLACE, "OverrideDelayModel::read " DISABLE_ERROR);
}
void OverrideDelayModel::write(const std::string& /*file*/) const {
VPR_THROW(VPR_ERROR_PLACE, "OverrideDelayModel::write " DISABLE_ERROR);
}
#else /* VTR_ENABLE_CAPNPROTO */
static void ToFloat(float* out, const VprFloatEntry::Reader& in) {
// Getting a scalar field is always "get<field name>()".
*out = in.getValue();
}
static void FromFloat(VprFloatEntry::Builder* out, const float& in) {
// Setting a scalar field is always "set<field name>(value)".
out->setValue(in);
}
void DeltaDelayModel::read(const std::string& file) {
// MmapFile object creates an mmap of the specified path, and will munmap
// when the object leaves scope.
MmapFile f(file);
// FlatArrayMessageReader is used to read the message from the data array
// provided by MmapFile.
::capnp::FlatArrayMessageReader reader(f.getData());
// When reading capnproto files the Reader object to use is named
// <schema name>::Reader.
//
// Initially this object is an empty VprDeltaDelayModel.
VprDeltaDelayModel::Reader model;
// The reader.getRoot performs a cast from the generic capnproto to fit
// with the specified schema.
//
// Note that capnproto does not validate that the incoming data matches the
// schema. If this property is required, some form of check would be
// required.
model = reader.getRoot<VprDeltaDelayModel>();
// ToNdMatrix is a generic function for converting a Matrix capnproto
// to a vtr::NdMatrix.
//
// The use must supply the matrix dimension (2 in this case), the source
// capnproto type (VprFloatEntry),
// target C++ type (flat), and a function to convert from the source capnproto
// type to the target C++ type (ToFloat).
//
// The second argument should be of type Matrix<X>::Reader where X is the
// capnproto element type.
ToNdMatrix<2, VprFloatEntry, float>(&delays_, model.getDelays(), ToFloat);
}
void DeltaDelayModel::write(const std::string& file) const {
// MallocMessageBuilder object is the generate capnproto message builder,
// using malloc for buffer allocation.
::capnp::MallocMessageBuilder builder;
// initRoot<X> returns a X::Builder object that can be used to set the
// fields in the message.
auto model = builder.initRoot<VprDeltaDelayModel>();
// FromNdMatrix is a generic function for converting a vtr::NdMatrix to a
// Matrix message. It is the mirror function of ToNdMatrix described in
// read above.
auto delay_values = model.getDelays();
FromNdMatrix<2, VprFloatEntry, float>(&delay_values, delays_, FromFloat);
// writeMessageToFile writes message to the specified file.
writeMessageToFile(file, &builder);
}
void OverrideDelayModel::read(const std::string& file) {
MmapFile f(file);
::capnp::FlatArrayMessageReader reader(f.getData());
vtr::Matrix<float> delays;
auto model = reader.getRoot<VprOverrideDelayModel>();
ToNdMatrix<2, VprFloatEntry, float>(&delays, model.getDelays(), ToFloat);
base_delay_model_ = std::make_unique<DeltaDelayModel>(delays);
// Reading non-scalar capnproto fields is roughly equivilant to using
// a std::vector of the field type. Actual type is capnp::List<X>::Reader.
auto overrides = model.getDelayOverrides();
std::vector<std::pair<t_override, float> > overrides_arr(overrides.size());
for (size_t i = 0; i < overrides.size(); ++i) {
const auto& elem = overrides[i];
overrides_arr[i].first.from_type = elem.getFromType();
overrides_arr[i].first.to_type = elem.getToType();
overrides_arr[i].first.from_class = elem.getFromClass();
overrides_arr[i].first.to_class = elem.getToClass();
overrides_arr[i].first.delta_x = elem.getDeltaX();
overrides_arr[i].first.delta_y = elem.getDeltaY();
overrides_arr[i].second = elem.getDelay();
}
delay_overrides_ = vtr::make_flat_map2(std::move(overrides_arr));
}
void OverrideDelayModel::write(const std::string& file) const {
::capnp::MallocMessageBuilder builder;
auto model = builder.initRoot<VprOverrideDelayModel>();
auto delays = model.getDelays();
FromNdMatrix<2, VprFloatEntry, float>(&delays, base_delay_model_->delays(), FromFloat);
// Non-scalar capnproto fields should be first initialized with
// init<field name>(count), and then accessed from the returned
// std::vector-like Builder object (specifically capnp::List<X>::Builder).
auto overrides = model.initDelayOverrides(delay_overrides_.size());
auto dst_iter = overrides.begin();
for (const auto& src : delay_overrides_) {
auto elem = *dst_iter++;
elem.setFromType(src.first.from_type);
elem.setToType(src.first.to_type);
elem.setFromClass(src.first.from_class);
elem.setToClass(src.first.to_class);
elem.setDeltaX(src.first.delta_x);
elem.setDeltaY(src.first.delta_y);
elem.setDelay(src.second);
}
writeMessageToFile(file, &builder);
}
#endif