diff options
Diffstat (limited to 'ice40/delay.cc')
-rw-r--r-- | ice40/delay.cc | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/ice40/delay.cc b/ice40/delay.cc new file mode 100644 index 00000000..a9607140 --- /dev/null +++ b/ice40/delay.cc @@ -0,0 +1,238 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com> + * Copyright (C) 2018 Serge Bazanski <q3k@symbioticeda.com> + * + * 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 < ctx->chip_info->num_wires; 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++]; + std::unordered_map<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->getWireName(cursor).c_str(ctx), 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(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::HX8K) + return model_hx8k; + + if (args.type == ArchArgs::LP384 || args.type == ArchArgs::LP1K || args.type == ArchArgs::LP8K) + return model_lp8k; + + if (args.type == ArchArgs::UP5K) + 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(const NetInfo *net_info, const PortRef &sink) const +{ + const auto &driver = net_info->driver; + auto driver_loc = getBelLocation(driver.cell->bel); + auto sink_loc = getBelLocation(sink.cell->bel); + + if (driver.port == 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 |