aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClifford Wolf <clifford@clifford.at>2018-08-04 13:41:42 +0200
committerClifford Wolf <clifford@clifford.at>2018-08-04 13:41:42 +0200
commitbd36cc12755e4c90cfdaaa593e5af31c5ba38fa5 (patch)
tree062552e994990605fac8ab40ea44102d72eecf7b
parent700e68746ae5cf4d9b7761c4bfa515e4af5fb2b4 (diff)
downloadnextpnr-bd36cc12755e4c90cfdaaa593e5af31c5ba38fa5.tar.gz
nextpnr-bd36cc12755e4c90cfdaaa593e5af31c5ba38fa5.tar.bz2
nextpnr-bd36cc12755e4c90cfdaaa593e5af31c5ba38fa5.zip
Refactor ice40 timing fuzzer used to create delay estimates
Signed-off-by: Clifford Wolf <clifford@clifford.at>
-rw-r--r--common/nextpnr.h2
-rw-r--r--common/router1.cc5
-rw-r--r--ice40/arch.cc16
-rw-r--r--ice40/arch.h2
-rw-r--r--ice40/delay.cc107
-rw-r--r--ice40/main.cc47
-rw-r--r--ice40/tmfuzz.py69
7 files changed, 184 insertions, 64 deletions
diff --git a/common/nextpnr.h b/common/nextpnr.h
index ba45c195..bb55d4ff 100644
--- a/common/nextpnr.h
+++ b/common/nextpnr.h
@@ -484,7 +484,7 @@ struct Context : Arch, DeterministicRNG
delay_t getNetinfoRouteDelay(const NetInfo *net_info, const PortRef &sink) const;
// provided by router1.cc
- bool getActualRouteDelay(WireId src_wire, WireId dst_wire, delay_t &delay,
+ bool getActualRouteDelay(WireId src_wire, WireId dst_wire, delay_t *delay = nullptr,
std::unordered_map<WireId, PipId> *route = nullptr, bool useEstimate = true);
// --------------------------------------------------------------
diff --git a/common/router1.cc b/common/router1.cc
index ad2d7c9e..03a06072 100644
--- a/common/router1.cc
+++ b/common/router1.cc
@@ -947,7 +947,7 @@ bool router1(Context *ctx, const Router1Cfg &cfg)
}
}
-bool Context::getActualRouteDelay(WireId src_wire, WireId dst_wire, delay_t &delay,
+bool Context::getActualRouteDelay(WireId src_wire, WireId dst_wire, delay_t *delay,
std::unordered_map<WireId, PipId> *route, bool useEstimate)
{
RipupScoreboard scores;
@@ -959,7 +959,8 @@ bool Context::getActualRouteDelay(WireId src_wire, WireId dst_wire, delay_t &del
if (!router.routedOkay)
return false;
- delay = router.visited.at(dst_wire).delay;
+ if (delay != nullptr)
+ *delay = router.visited.at(dst_wire).delay;
if (route != nullptr) {
WireId cursor = dst_wire;
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<GroupId> 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 <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
+
+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 < 1000)
+ {
+ NPNR_ASSERT(index < int(srcWires.size()));
+ NPNR_ASSERT(index < int(dstWires.size()));
+
+ WireId src = srcWires[index];
+ WireId dst = dstWires[index++];
+ std::unordered_map<WireId, PipId> 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<WireId> 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<double>();
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()
+