From bd36cc12755e4c90cfdaaa593e5af31c5ba38fa5 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 4 Aug 2018 13:41:42 +0200 Subject: Refactor ice40 timing fuzzer used to create delay estimates Signed-off-by: Clifford Wolf --- ice40/arch.cc | 16 --------- ice40/arch.h | 2 ++ ice40/delay.cc | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ice40/main.cc | 47 ++----------------------- ice40/tmfuzz.py | 69 ++++++++++++++++++++++++++++++++++++ 5 files changed, 180 insertions(+), 61 deletions(-) create mode 100644 ice40/delay.cc create mode 100644 ice40/tmfuzz.py (limited to 'ice40') diff --git a/ice40/arch.cc b/ice40/arch.cc index 2430b7ce..d44d8c19 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -639,22 +639,6 @@ std::vector Arch::getGroupGroups(GroupId group) const // ----------------------------------------------------------------------- -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; - - NPNR_ASSERT(dst != WireId()); - int x2 = chip_info->wire_data[dst.index].x; - int y2 = chip_info->wire_data[dst.index].y; - - int xd = x2 - x1, yd = y2 - y1; - int xscale = 120, yscale = 120, offset = 0; - - return xscale * abs(xd) + yscale * abs(yd) + offset; -} - delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const { const auto &driver = net_info->driver; diff --git a/ice40/arch.h b/ice40/arch.h index 0be76296..324915eb 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -842,4 +842,6 @@ struct Arch : BaseCtx float placer_constraintWeight = 10; }; +void ice40DelayFuzzerMain(Context *ctx); + NEXTPNR_NAMESPACE_END diff --git a/ice40/delay.cc b/ice40/delay.cc new file mode 100644 index 00000000..8bf8211c --- /dev/null +++ b/ice40/delay.cc @@ -0,0 +1,107 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf + * Copyright (C) 2018 Serge Bazanski + * + * 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 + +void ice40DelayFuzzerMain(Context *ctx) +{ + std::vector 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 < 1000) + { + NPNR_ASSERT(index < int(srcWires.size())); + NPNR_ASSERT(index < int(dstWires.size())); + + WireId src = srcWires[index]; + WireId dst = dstWires[index++]; + std::unordered_map route; + + if (!ctx->getActualRouteDelay(src, dst, nullptr, &route, false)) + continue; + + 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++; + } +} + +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; + + NPNR_ASSERT(dst != WireId()); + int x2 = chip_info->wire_data[dst.index].x; + int y2 = chip_info->wire_data[dst.index].y; + + int xd = x2 - x1, yd = y2 - y1; + int xscale = 120, yscale = 120, offset = 0; + + return xscale * abs(xd) + yscale * abs(yd) + offset; +} + +NEXTPNR_NAMESPACE_END diff --git a/ice40/main.cc b/ice40/main.cc index b9eee627..358bf3c5 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -314,51 +314,8 @@ int main(int argc, char *argv[]) if (vm.count("test")) ctx->archcheck(); - if (vm.count("tmfuzz")) { - std::vector src_wires, dst_wires; - - /*for (auto w : ctx->getWires()) - src_wires.push_back(w);*/ - for (auto b : ctx->getBels()) { - if (ctx->getBelType(b) == TYPE_ICESTORM_LC) { - src_wires.push_back(ctx->getBelPinWire(b, PIN_O)); - } - if (ctx->getBelType(b) == TYPE_SB_IO) { - src_wires.push_back(ctx->getBelPinWire(b, PIN_D_IN_0)); - } - } - - for (auto b : ctx->getBels()) { - if (ctx->getBelType(b) == TYPE_ICESTORM_LC) { - dst_wires.push_back(ctx->getBelPinWire(b, PIN_I0)); - dst_wires.push_back(ctx->getBelPinWire(b, PIN_I1)); - dst_wires.push_back(ctx->getBelPinWire(b, PIN_I2)); - dst_wires.push_back(ctx->getBelPinWire(b, PIN_I3)); - dst_wires.push_back(ctx->getBelPinWire(b, PIN_CEN)); - dst_wires.push_back(ctx->getBelPinWire(b, PIN_CIN)); - } - if (ctx->getBelType(b) == TYPE_SB_IO) { - dst_wires.push_back(ctx->getBelPinWire(b, PIN_D_OUT_0)); - dst_wires.push_back(ctx->getBelPinWire(b, PIN_OUTPUT_ENABLE)); - } - } - - ctx->shuffle(src_wires); - ctx->shuffle(dst_wires); - - for (int i = 0; i < int(src_wires.size()) && i < int(dst_wires.size()); i++) { - delay_t actual_delay; - WireId src = src_wires[i], dst = dst_wires[i]; - if (!ctx->getActualRouteDelay(src, dst, actual_delay)) - continue; - printf("%s %s %.3f %.3f %d %d %d %d %d %d\n", ctx->getWireName(src).c_str(ctx.get()), - ctx->getWireName(dst).c_str(ctx.get()), ctx->getDelayNS(actual_delay), - ctx->getDelayNS(ctx->estimateDelay(src, dst)), ctx->chip_info->wire_data[src.index].x, - ctx->chip_info->wire_data[src.index].y, ctx->chip_info->wire_data[src.index].type, - ctx->chip_info->wire_data[dst.index].x, ctx->chip_info->wire_data[dst.index].y, - ctx->chip_info->wire_data[dst.index].type); - } - } + if (vm.count("tmfuzz")) + ice40DelayFuzzerMain(ctx.get()); if (vm.count("freq")) { auto freq = vm["freq"].as(); diff --git a/ice40/tmfuzz.py b/ice40/tmfuzz.py new file mode 100644 index 00000000..0f725932 --- /dev/null +++ b/ice40/tmfuzz.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# ../nextpnr-ice40 --hx8k --tmfuzz > tmfuzz_hx8k.txt + +import numpy as np +import matplotlib.pyplot as plt +from collections import defaultdict + +device = "hx8k" +sel_src_type = "LUTFF_OUT" +sel_dst_type = "LUTFF_IN_LUT" + +src_dst_pairs = defaultdict(lambda: 0) + +delay_data = list() +delay_map_sum = np.zeros((41, 41)) +delay_map_sum2 = np.zeros((41, 41)) +delay_map_count = np.zeros((41, 41)) + +with open("tmfuzz_%s.txt" % device, "r") as f: + for line in f: + line = line.split() + + if line[0] == "dst": + dst_xy = (int(line[1]), int(line[2])) + dst_type = line[3] + dst_wire = line[4] + + src_xy = (int(line[1]), int(line[2])) + src_type = line[3] + src_wire = line[4] + + delay = int(line[5]) + estdelay = int(line[6]) + + src_dst_pairs[src_type, dst_type] += 1 + + if src_type == sel_src_type and dst_type == sel_dst_type: + delay_data.append((delay, estdelay)) + relx = 20 + dst_xy[0] - src_xy[0] + rely = 20 + dst_xy[1] - src_xy[1] + + if (0 <= relx <= 40) and (0 <= rely <= 40): + delay_map_sum[relx, rely] += delay + delay_map_sum2[relx, rely] += delay*delay + delay_map_count[relx, rely] += 1 + +delay_data = np.array(delay_data) + +#%% + +print("Src-Dst-Type pair summary:") +for cnt, src, dst in sorted([(v, k[0], k[1]) for k, v in src_dst_pairs.items()]): + print("%20s %20s %5d%s" % (src, dst, cnt, " *" if src == sel_src_type and dst == sel_dst_type else "")) +print() + +#%% + +plt.figure() +plt.imshow(delay_map_sum / delay_map_count) +plt.colorbar() +plt.show() + +#%% + +plt.figure() +plt.plot(delay_data[:,0], delay_data[:,1], ".") +plt.show() + -- cgit v1.2.3