Refactor ice40 timing fuzzer used to create delay estimates

Signed-off-by: Clifford Wolf <clifford@clifford.at>
This commit is contained in:
Clifford Wolf 2018-08-04 13:41:42 +02:00
parent 700e68746a
commit bd36cc1275
7 changed files with 184 additions and 64 deletions

View File

@ -484,7 +484,7 @@ struct Context : Arch, DeterministicRNG
delay_t getNetinfoRouteDelay(const NetInfo *net_info, const PortRef &sink) const; delay_t getNetinfoRouteDelay(const NetInfo *net_info, const PortRef &sink) const;
// provided by router1.cc // 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); std::unordered_map<WireId, PipId> *route = nullptr, bool useEstimate = true);
// -------------------------------------------------------------- // --------------------------------------------------------------

View File

@ -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) std::unordered_map<WireId, PipId> *route, bool useEstimate)
{ {
RipupScoreboard scores; RipupScoreboard scores;
@ -959,7 +959,8 @@ bool Context::getActualRouteDelay(WireId src_wire, WireId dst_wire, delay_t &del
if (!router.routedOkay) if (!router.routedOkay)
return false; return false;
delay = router.visited.at(dst_wire).delay; if (delay != nullptr)
*delay = router.visited.at(dst_wire).delay;
if (route != nullptr) { if (route != nullptr) {
WireId cursor = dst_wire; WireId cursor = dst_wire;

View File

@ -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 delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const
{ {
const auto &driver = net_info->driver; const auto &driver = net_info->driver;

View File

@ -842,4 +842,6 @@ struct Arch : BaseCtx
float placer_constraintWeight = 10; float placer_constraintWeight = 10;
}; };
void ice40DelayFuzzerMain(Context *ctx);
NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_END

107
ice40/delay.cc Normal file
View File

@ -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

View File

@ -314,51 +314,8 @@ int main(int argc, char *argv[])
if (vm.count("test")) if (vm.count("test"))
ctx->archcheck(); ctx->archcheck();
if (vm.count("tmfuzz")) { if (vm.count("tmfuzz"))
std::vector<WireId> src_wires, dst_wires; ice40DelayFuzzerMain(ctx.get());
/*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("freq")) { if (vm.count("freq")) {
auto freq = vm["freq"].as<double>(); auto freq = vm["freq"].as<double>();

69
ice40/tmfuzz.py Normal file
View File

@ -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()