nextpnr/ice40/delay.cc

241 lines
6.8 KiB
C++
Raw Permalink Normal View History

/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 Claire Xenia Wolf <claire@yosyshq.com>
* Copyright (C) 2018 Serge Bazanski <q3k@q3k.org>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "nextpnr.h"
#include "router1.h"
NEXTPNR_NAMESPACE_BEGIN
#define NUM_FUZZ_ROUTES 100000
void ice40DelayFuzzerMain(Context *ctx)
{
std::vector<WireId> srcWires, dstWires;
for (int i = 0; i < int(ctx->chip_info->wire_data.size()); i++) {
WireId wire;
wire.index = i;
2018-08-05 20:18:34 +08:00
switch (ctx->chip_info->wire_data[i].type) {
case WireInfoPOD::WIRE_TYPE_LUTFF_OUT:
srcWires.push_back(wire);
break;
case WireInfoPOD::WIRE_TYPE_LUTFF_IN_LUT:
dstWires.push_back(wire);
break;
default:
break;
}
}
ctx->shuffle(srcWires);
ctx->shuffle(dstWires);
int index = 0;
int cnt = 0;
2018-08-05 20:18:34 +08:00
while (cnt < NUM_FUZZ_ROUTES) {
if (index >= int(srcWires.size()) || index >= int(dstWires.size())) {
index = 0;
ctx->shuffle(srcWires);
ctx->shuffle(dstWires);
}
WireId src = srcWires[index];
WireId dst = dstWires[index++];
dict<WireId, PipId> route;
#if NUM_FUZZ_ROUTES <= 1000
if (!ctx->getActualRouteDelay(src, dst, nullptr, &route, false))
continue;
#else
if (!ctx->getActualRouteDelay(src, dst, nullptr, &route, true))
continue;
#endif
WireId cursor = dst;
delay_t delay = 0;
while (1) {
delay += ctx->getWireDelay(cursor).maxDelay();
printf("%s %d %d %s %s %d %d\n", cursor == dst ? "dst" : "src",
int(ctx->chip_info->wire_data[cursor.index].x), int(ctx->chip_info->wire_data[cursor.index].y),
ctx->getWireType(cursor).c_str(ctx), ctx->nameOfWire(cursor), int(delay),
int(ctx->estimateDelay(cursor, dst)));
if (cursor == src)
break;
PipId pip = route.at(cursor);
delay += ctx->getPipDelay(pip).maxDelay();
cursor = ctx->getPipSrcWire(pip);
}
cnt++;
if (cnt % 100 == 0)
fprintf(stderr, "Fuzzed %d arcs.\n", cnt);
}
}
namespace {
2018-08-05 20:18:34 +08:00
struct model_params_t
{
int neighbourhood;
int model0_offset;
int model0_norm1;
int model1_offset;
int model1_norm1;
int model1_norm2;
int model1_norm3;
int model2_offset;
int model2_linear;
int model2_sqrt;
int delta_local;
int delta_lutffin;
int delta_sp4;
int delta_sp12;
static const model_params_t &get(const ArchArgs &args)
{
2018-08-05 20:18:34 +08:00
static const model_params_t model_hx8k = {588, 129253, 8658, 118333, 23915, -73105, 57696,
-86797, 89, 3706, -316, -575, -158, -296};
static const model_params_t model_lp8k = {867, 206236, 11043, 191910, 31074, -95972, 75739,
-309793, 30, 11056, -474, -856, -363, -536};
static const model_params_t model_up5k = {1761, 305798, 16705, 296830, 24430, -40369, 33038,
-162662, 94, 4705, -1099, -1761, -418, -838};
2020-07-08 22:45:27 +08:00
if (args.type == ArchArgs::HX1K || args.type == ArchArgs::HX4K || args.type == ArchArgs::HX8K)
return model_hx8k;
2020-07-08 22:45:27 +08:00
if (args.type == ArchArgs::LP384 || args.type == ArchArgs::LP1K || args.type == ArchArgs::LP4K ||
args.type == ArchArgs::LP8K)
return model_lp8k;
2020-07-08 22:45:27 +08:00
if (args.type == ArchArgs::UP3K || args.type == ArchArgs::UP5K || args.type == ArchArgs::U1K ||
args.type == ArchArgs::U2K || args.type == ArchArgs::U4K)
return model_up5k;
NPNR_ASSERT(0);
}
};
} // namespace
delay_t Arch::estimateDelay(WireId src, WireId dst) const
{
NPNR_ASSERT(src != WireId());
int x1 = chip_info->wire_data[src.index].x;
int y1 = chip_info->wire_data[src.index].y;
int z1 = chip_info->wire_data[src.index].z;
int type = chip_info->wire_data[src.index].type;
NPNR_ASSERT(dst != WireId());
int x2 = chip_info->wire_data[dst.index].x;
int y2 = chip_info->wire_data[dst.index].y;
int z2 = chip_info->wire_data[dst.index].z;
int dx = abs(x2 - x1);
int dy = abs(y2 - y1);
const model_params_t &p = model_params_t::get(args);
delay_t v = p.neighbourhood;
if (dx > 1 || dy > 1)
v = (p.model0_offset + p.model0_norm1 * (dx + dy)) / 128;
if (dx == 0 && dy == 0) {
if (type == WireInfoPOD::WIRE_TYPE_LOCAL)
v += p.delta_local;
if (type == WireInfoPOD::WIRE_TYPE_LUTFF_IN || type == WireInfoPOD::WIRE_TYPE_LUTFF_IN_LUT)
v += (z1 == z2) ? p.delta_lutffin : 0;
}
if (type == WireInfoPOD::WIRE_TYPE_SP4_V || type == WireInfoPOD::WIRE_TYPE_SP4_H)
v += p.delta_sp4;
if (type == WireInfoPOD::WIRE_TYPE_SP12_V || type == WireInfoPOD::WIRE_TYPE_SP12_H)
v += p.delta_sp12;
return v;
}
delay_t Arch::predictDelay(BelId src_bel, IdString src_pin, BelId dst_bel, IdString dst_pin) const
{
NPNR_UNUSED(dst_pin);
auto driver_loc = getBelLocation(src_bel);
auto sink_loc = getBelLocation(dst_bel);
if (src_pin == id_COUT) {
if (driver_loc.y == sink_loc.y)
return 0;
return 250;
}
int dx = abs(sink_loc.x - driver_loc.x);
int dy = abs(sink_loc.y - driver_loc.y);
const model_params_t &p = model_params_t::get(args);
if (dx <= 1 && dy <= 1)
return p.neighbourhood;
#if 1
// Model #0
return (p.model0_offset + p.model0_norm1 * (dx + dy)) / 128;
#else
float norm1 = dx + dy;
float dx2 = dx * dx;
float dy2 = dy * dy;
float norm2 = sqrtf(dx2 + dy2);
float dx3 = dx2 * dx;
float dy3 = dy2 * dy;
2018-08-05 20:18:34 +08:00
float norm3 = powf(dx3 + dy3, 1.0 / 3.0);
// Model #1
float v = p.model1_offset;
v += p.model1_norm1 * norm1;
v += p.model1_norm2 * norm2;
v += p.model1_norm3 * norm3;
v /= 128;
// Model #2
v = p.model2_offset + p.model2_linear * v + p.model2_sqrt * sqrtf(v);
v /= 128;
return v;
#endif
}
NEXTPNR_NAMESPACE_END