Refactor ice40 timing fuzzer used to create delay estimates
Signed-off-by: Clifford Wolf <clifford@clifford.at>
This commit is contained in:
parent
700e68746a
commit
bd36cc1275
@ -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);
|
||||||
|
|
||||||
// --------------------------------------------------------------
|
// --------------------------------------------------------------
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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
107
ice40/delay.cc
Normal 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
|
@ -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
69
ice40/tmfuzz.py
Normal 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()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user