
This makes predictDelay be based on an arbitrary belpin pair rather than a arc of a net based on cell placement. This way 'what-if' decisions can be evaluated without actually changing placement; potentially useful for parallel placement. A new helper predictArcDelay behaves like the old predictDelay to minimise the impact on existing passes; only arches need be updated. Signed-off-by: gatecat <gatecat@ds0.me>
241 lines
6.8 KiB
C++
241 lines
6.8 KiB
C++
/*
|
|
* 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;
|
|
|
|
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;
|
|
|
|
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 {
|
|
|
|
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)
|
|
{
|
|
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};
|
|
|
|
if (args.type == ArchArgs::HX1K || args.type == ArchArgs::HX4K || args.type == ArchArgs::HX8K)
|
|
return model_hx8k;
|
|
|
|
if (args.type == ArchArgs::LP384 || args.type == ArchArgs::LP1K || args.type == ArchArgs::LP4K ||
|
|
args.type == ArchArgs::LP8K)
|
|
return model_lp8k;
|
|
|
|
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;
|
|
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
|