Merge pull request #36 from YosysHQ/lutperm
Add LUT input permutations, improvements in ice40 timing model, improvements in router
This commit is contained in:
commit
ba97c233fb
@ -484,7 +484,8 @@ 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);
|
||||
|
||||
// --------------------------------------------------------------
|
||||
|
||||
|
@ -130,7 +130,8 @@ struct Router
|
||||
qw.wire = it.first;
|
||||
qw.pip = PipId();
|
||||
qw.delay = it.second - (it.second / 16);
|
||||
qw.togo = ctx->estimateDelay(qw.wire, dst_wire);
|
||||
if (cfg.useEstimate)
|
||||
qw.togo = ctx->estimateDelay(qw.wire, dst_wire);
|
||||
qw.randtag = ctx->rng();
|
||||
|
||||
queue.push(qw);
|
||||
@ -216,7 +217,8 @@ struct Router
|
||||
next_qw.wire = next_wire;
|
||||
next_qw.pip = pip;
|
||||
next_qw.delay = next_delay;
|
||||
next_qw.togo = ctx->estimateDelay(next_wire, dst_wire);
|
||||
if (cfg.useEstimate)
|
||||
next_qw.togo = ctx->estimateDelay(next_wire, dst_wire);
|
||||
next_qw.randtag = ctx->rng();
|
||||
|
||||
visited[next_qw.wire] = next_qw;
|
||||
@ -420,7 +422,9 @@ struct Router
|
||||
NPNR_ASSERT(ripup);
|
||||
NPNR_ASSERT(conflicting_pip_net != net_name);
|
||||
|
||||
ctx->unbindPip(pip);
|
||||
if (ctx->getBoundPipNet(pip) == conflicting_pip_net)
|
||||
ctx->unbindPip(pip);
|
||||
|
||||
if (!ctx->checkPipAvail(pip))
|
||||
ripup_net(ctx, conflicting_pip_net);
|
||||
|
||||
@ -945,13 +949,33 @@ 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;
|
||||
Router router(this, Router1Cfg(), scores, src_wire, dst_wire);
|
||||
if (router.routedOkay)
|
||||
delay = router.visited.at(dst_wire).delay;
|
||||
return router.routedOkay;
|
||||
Router1Cfg cfg;
|
||||
cfg.useEstimate = useEstimate;
|
||||
|
||||
Router router(this, cfg, scores, src_wire, dst_wire);
|
||||
|
||||
if (!router.routedOkay)
|
||||
return false;
|
||||
|
||||
if (delay != nullptr)
|
||||
*delay = router.visited.at(dst_wire).delay;
|
||||
|
||||
if (route != nullptr) {
|
||||
WireId cursor = dst_wire;
|
||||
while (1) {
|
||||
PipId pip = router.visited.at(cursor).pip;
|
||||
(*route)[cursor] = pip;
|
||||
if (pip == PipId())
|
||||
break;
|
||||
cursor = getPipSrcWire(pip);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
@ -29,6 +29,7 @@ struct Router1Cfg
|
||||
int maxIterCnt = 200;
|
||||
bool cleanupReroute = true;
|
||||
bool fullCleanupReroute = true;
|
||||
bool useEstimate = true;
|
||||
};
|
||||
|
||||
extern bool router1(Context *ctx, const Router1Cfg &cfg);
|
||||
|
102
ice40/arch.cc
102
ice40/arch.cc
@ -174,6 +174,7 @@ Arch::Arch(ArchArgs args) : args(args)
|
||||
if (package_info == nullptr)
|
||||
log_error("Unsupported package '%s'.\n", args.package.c_str());
|
||||
|
||||
bel_carry.resize(chip_info->num_bels);
|
||||
bel_to_cell.resize(chip_info->num_bels);
|
||||
wire_to_net.resize(chip_info->num_wires);
|
||||
pip_to_net.resize(chip_info->num_pips);
|
||||
@ -192,6 +193,7 @@ Arch::Arch(ArchArgs args) : args(args)
|
||||
id_i2 = id("I2");
|
||||
id_i3 = id("I3");
|
||||
id_dff_en = id("DFF_ENABLE");
|
||||
id_carry_en = id("CARRY_ENABLE");
|
||||
id_neg_clk = id("NEG_CLK");
|
||||
id_cin = id("CIN");
|
||||
id_cout = id("COUT");
|
||||
@ -399,6 +401,44 @@ WireId Arch::getWireByName(IdString name) const
|
||||
return ret;
|
||||
}
|
||||
|
||||
IdString Arch::getWireType(WireId wire) const
|
||||
{
|
||||
NPNR_ASSERT(wire != WireId());
|
||||
switch (chip_info->wire_data[wire.index].type) {
|
||||
case WireInfoPOD::WIRE_TYPE_NONE:
|
||||
return IdString();
|
||||
case WireInfoPOD::WIRE_TYPE_GLB2LOCAL:
|
||||
return id("GLB2LOCAL");
|
||||
case WireInfoPOD::WIRE_TYPE_GLB_NETWK:
|
||||
return id("GLB_NETWK");
|
||||
case WireInfoPOD::WIRE_TYPE_LOCAL:
|
||||
return id("LOCAL");
|
||||
case WireInfoPOD::WIRE_TYPE_LUTFF_IN:
|
||||
return id("LUTFF_IN");
|
||||
case WireInfoPOD::WIRE_TYPE_LUTFF_IN_LUT:
|
||||
return id("LUTFF_IN_LUT");
|
||||
case WireInfoPOD::WIRE_TYPE_LUTFF_LOUT:
|
||||
return id("LUTFF_LOUT");
|
||||
case WireInfoPOD::WIRE_TYPE_LUTFF_OUT:
|
||||
return id("LUTFF_OUT");
|
||||
case WireInfoPOD::WIRE_TYPE_LUTFF_COUT:
|
||||
return id("LUTFF_COUT");
|
||||
case WireInfoPOD::WIRE_TYPE_LUTFF_GLOBAL:
|
||||
return id("LUTFF_GLOBAL");
|
||||
case WireInfoPOD::WIRE_TYPE_CARRY_IN_MUX:
|
||||
return id("CARRY_IN_MUX");
|
||||
case WireInfoPOD::WIRE_TYPE_SP4_V:
|
||||
return id("SP4_V");
|
||||
case WireInfoPOD::WIRE_TYPE_SP4_H:
|
||||
return id("SP4_H");
|
||||
case WireInfoPOD::WIRE_TYPE_SP12_V:
|
||||
return id("SP12_V");
|
||||
case WireInfoPOD::WIRE_TYPE_SP12_H:
|
||||
return id("SP12_H");
|
||||
}
|
||||
return IdString();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
PipId Arch::getPipByName(IdString name) const
|
||||
@ -541,9 +581,7 @@ std::vector<GroupId> Arch::getGroups() const
|
||||
group.type = GroupId::TYPE_LOCAL_SW;
|
||||
ret.push_back(group);
|
||||
|
||||
#if 0
|
||||
if (type == TILE_LOGIC)
|
||||
{
|
||||
if (type == TILE_LOGIC) {
|
||||
group.type = GroupId::TYPE_LC0_SW;
|
||||
ret.push_back(group);
|
||||
|
||||
@ -568,7 +606,6 @@ std::vector<GroupId> Arch::getGroups() const
|
||||
group.type = GroupId::TYPE_LC7_SW;
|
||||
ret.push_back(group);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
@ -600,50 +637,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;
|
||||
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 xd = sink_loc.x - driver_loc.x, yd = sink_loc.y - driver_loc.y;
|
||||
int xscale = 120, yscale = 120, offset = 0;
|
||||
|
||||
// if (chip_info->wire_data[src.index].type == WIRE_TYPE_SP4_VERT) {
|
||||
// yd = yd < -4 ? yd + 4 : (yd < 0 ? 0 : yd);
|
||||
// offset = 500;
|
||||
// }
|
||||
|
||||
if (driver.port == id_o)
|
||||
offset += 330;
|
||||
if (sink.port == id_i0 || sink.port == id_i1 || sink.port == id_i2 || sink.port == id_i3)
|
||||
offset += 260;
|
||||
|
||||
return xscale * abs(xd) + yscale * abs(yd) + offset;
|
||||
}
|
||||
|
||||
delay_t Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t budget) const
|
||||
{
|
||||
const auto &driver = net_info->driver;
|
||||
@ -768,6 +761,18 @@ std::vector<GraphicElement> Arch::getDecalGraphics(DecalId decal) const
|
||||
el.y2 = y + local_swbox_y2;
|
||||
ret.push_back(el);
|
||||
}
|
||||
|
||||
if (GroupId::TYPE_LC0_SW <= type && type <= GroupId::TYPE_LC7_SW) {
|
||||
GraphicElement el;
|
||||
el.type = GraphicElement::TYPE_BOX;
|
||||
el.style = GraphicElement::STYLE_FRAME;
|
||||
|
||||
el.x1 = x + lut_swbox_x1;
|
||||
el.x2 = x + lut_swbox_x2;
|
||||
el.y1 = y + logic_cell_y1 + logic_cell_pitch * (type - GroupId::TYPE_LC0_SW);
|
||||
el.y2 = y + logic_cell_y2 + logic_cell_pitch * (type - GroupId::TYPE_LC0_SW);
|
||||
ret.push_back(el);
|
||||
}
|
||||
}
|
||||
|
||||
if (decal.type == DecalId::TYPE_WIRE) {
|
||||
@ -918,6 +923,7 @@ void Arch::assignCellInfo(CellInfo *cell)
|
||||
cell->belType = belTypeFromId(cell->type);
|
||||
if (cell->type == id_icestorm_lc) {
|
||||
cell->lcInfo.dffEnable = bool_or_default(cell->params, id_dff_en);
|
||||
cell->lcInfo.carryEnable = bool_or_default(cell->params, id_carry_en);
|
||||
cell->lcInfo.negClk = bool_or_default(cell->params, id_neg_clk);
|
||||
cell->lcInfo.clk = get_net_or_empty(cell, id_clk);
|
||||
cell->lcInfo.cen = get_net_or_empty(cell, id_cen);
|
||||
|
64
ice40/arch.h
64
ice40/arch.h
@ -64,6 +64,13 @@ NPNR_PACKED_STRUCT(struct BelPortPOD {
|
||||
});
|
||||
|
||||
NPNR_PACKED_STRUCT(struct PipInfoPOD {
|
||||
enum PipFlags : uint32_t
|
||||
{
|
||||
FLAG_NONE = 0,
|
||||
FLAG_ROUTETHRU = 1,
|
||||
FLAG_NOCARRY = 2
|
||||
};
|
||||
|
||||
// RelPtr<char> name;
|
||||
int32_t src, dst;
|
||||
int32_t fast_delay;
|
||||
@ -72,6 +79,7 @@ NPNR_PACKED_STRUCT(struct PipInfoPOD {
|
||||
int16_t src_seg, dst_seg;
|
||||
int16_t switch_mask;
|
||||
int32_t switch_index;
|
||||
PipFlags flags;
|
||||
});
|
||||
|
||||
NPNR_PACKED_STRUCT(struct WireSegmentPOD {
|
||||
@ -80,6 +88,25 @@ NPNR_PACKED_STRUCT(struct WireSegmentPOD {
|
||||
});
|
||||
|
||||
NPNR_PACKED_STRUCT(struct WireInfoPOD {
|
||||
enum WireType : int8_t
|
||||
{
|
||||
WIRE_TYPE_NONE = 0,
|
||||
WIRE_TYPE_GLB2LOCAL = 1,
|
||||
WIRE_TYPE_GLB_NETWK = 2,
|
||||
WIRE_TYPE_LOCAL = 3,
|
||||
WIRE_TYPE_LUTFF_IN = 4,
|
||||
WIRE_TYPE_LUTFF_IN_LUT = 5,
|
||||
WIRE_TYPE_LUTFF_LOUT = 6,
|
||||
WIRE_TYPE_LUTFF_OUT = 7,
|
||||
WIRE_TYPE_LUTFF_COUT = 8,
|
||||
WIRE_TYPE_LUTFF_GLOBAL = 9,
|
||||
WIRE_TYPE_CARRY_IN_MUX = 10,
|
||||
WIRE_TYPE_SP4_V = 11,
|
||||
WIRE_TYPE_SP4_H = 12,
|
||||
WIRE_TYPE_SP12_V = 13,
|
||||
WIRE_TYPE_SP12_H = 14
|
||||
};
|
||||
|
||||
RelPtr<char> name;
|
||||
int32_t num_uphill, num_downhill;
|
||||
RelPtr<int32_t> pips_uphill, pips_downhill;
|
||||
@ -93,9 +120,8 @@ NPNR_PACKED_STRUCT(struct WireInfoPOD {
|
||||
int32_t fast_delay;
|
||||
int32_t slow_delay;
|
||||
|
||||
int8_t x, y;
|
||||
int8_t x, y, z;
|
||||
WireType type;
|
||||
int8_t padding_0;
|
||||
});
|
||||
|
||||
NPNR_PACKED_STRUCT(struct PackagePinPOD {
|
||||
@ -373,6 +399,7 @@ struct Arch : BaseCtx
|
||||
mutable std::unordered_map<IdString, int> pip_by_name;
|
||||
mutable std::unordered_map<Loc, int> bel_by_loc;
|
||||
|
||||
std::vector<bool> bel_carry;
|
||||
std::vector<IdString> bel_to_cell;
|
||||
std::vector<IdString> wire_to_net;
|
||||
std::vector<IdString> pip_to_net;
|
||||
@ -414,9 +441,12 @@ struct Arch : BaseCtx
|
||||
{
|
||||
NPNR_ASSERT(bel != BelId());
|
||||
NPNR_ASSERT(bel_to_cell[bel.index] == IdString());
|
||||
auto &c = cells[cell];
|
||||
|
||||
bel_to_cell[bel.index] = cell;
|
||||
cells[cell]->bel = bel;
|
||||
cells[cell]->belStrength = strength;
|
||||
bel_carry[bel.index] = (c->type == id_icestorm_lc && c->lcInfo.carryEnable);
|
||||
c->bel = bel;
|
||||
c->belStrength = strength;
|
||||
refreshUiBel(bel);
|
||||
}
|
||||
|
||||
@ -427,6 +457,7 @@ struct Arch : BaseCtx
|
||||
cells[bel_to_cell[bel.index]]->bel = BelId();
|
||||
cells[bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE;
|
||||
bel_to_cell[bel.index] = IdString();
|
||||
bel_carry[bel.index] = false;
|
||||
refreshUiBel(bel);
|
||||
}
|
||||
|
||||
@ -490,7 +521,7 @@ struct Arch : BaseCtx
|
||||
return id(chip_info->wire_data[wire.index].name.get());
|
||||
}
|
||||
|
||||
IdString getWireType(WireId wire) const { return IdString(); }
|
||||
IdString getWireType(WireId wire) const;
|
||||
|
||||
uint32_t getWireChecksum(WireId wire) const { return wire.index; }
|
||||
|
||||
@ -614,14 +645,23 @@ struct Arch : BaseCtx
|
||||
bool checkPipAvail(PipId pip) const
|
||||
{
|
||||
NPNR_ASSERT(pip != PipId());
|
||||
int switch_idx = chip_info->pip_data[pip.index].switch_index;
|
||||
auto &pi = chip_info->pip_data[pip.index];
|
||||
auto &si = chip_info->bits_info->switches[pi.switch_index];
|
||||
|
||||
if (switches_locked[switch_idx] != IdString())
|
||||
if (switches_locked[pi.switch_index] != IdString())
|
||||
return false;
|
||||
|
||||
int bel_idx = chip_info->bits_info->switches[switch_idx].bel;
|
||||
if (bel_idx >= 0 && bel_to_cell[bel_idx] != IdString())
|
||||
return false;
|
||||
if (pi.flags & PipInfoPOD::FLAG_ROUTETHRU) {
|
||||
NPNR_ASSERT(si.bel >= 0);
|
||||
if (bel_to_cell[si.bel] != IdString())
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pi.flags & PipInfoPOD::FLAG_NOCARRY) {
|
||||
NPNR_ASSERT(si.bel >= 0);
|
||||
if (bel_carry[si.bel])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -781,7 +821,7 @@ struct Arch : BaseCtx
|
||||
IdString id_icestorm_lc, id_sb_io, id_sb_gb;
|
||||
IdString id_cen, id_clk, id_sr;
|
||||
IdString id_i0, id_i1, id_i2, id_i3;
|
||||
IdString id_dff_en, id_neg_clk;
|
||||
IdString id_dff_en, id_carry_en, id_neg_clk;
|
||||
IdString id_cin, id_cout;
|
||||
IdString id_o, id_lo;
|
||||
IdString id_icestorm_ram, id_rclk, id_wclk;
|
||||
@ -801,4 +841,6 @@ struct Arch : BaseCtx
|
||||
float placer_constraintWeight = 10;
|
||||
};
|
||||
|
||||
void ice40DelayFuzzerMain(Context *ctx);
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
@ -77,17 +77,6 @@ enum PortPin : int32_t
|
||||
PIN_MAXIDX
|
||||
};
|
||||
|
||||
enum WireType : int8_t
|
||||
{
|
||||
WIRE_TYPE_NONE = 0,
|
||||
WIRE_TYPE_LOCAL = 1,
|
||||
WIRE_TYPE_GLOBAL = 2,
|
||||
WIRE_TYPE_SP4_VERT = 3,
|
||||
WIRE_TYPE_SP4_HORZ = 4,
|
||||
WIRE_TYPE_SP12_HORZ = 5,
|
||||
WIRE_TYPE_SP12_VERT = 6
|
||||
};
|
||||
|
||||
struct BelId
|
||||
{
|
||||
int32_t index = -1;
|
||||
@ -167,7 +156,9 @@ struct ArchCellInfo
|
||||
{
|
||||
struct
|
||||
{
|
||||
bool dffEnable, negClk;
|
||||
bool dffEnable;
|
||||
bool carryEnable;
|
||||
bool negClk;
|
||||
int inputCount;
|
||||
const NetInfo *clk, *cen, *sr;
|
||||
} lcInfo;
|
||||
|
@ -229,6 +229,25 @@ static BelPin get_one_bel_pin(const Context *ctx, WireId wire)
|
||||
return *pins.begin();
|
||||
}
|
||||
|
||||
// Permute LUT init value given map (LUT input -> ext input)
|
||||
unsigned permute_lut(unsigned orig_init, const std::unordered_map<int, int> &input_permute)
|
||||
{
|
||||
unsigned new_init = 0;
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
int permute_address = 0;
|
||||
for (int j = 0; j < 4; j++) {
|
||||
if ((i >> j) & 0x1)
|
||||
permute_address |= (1 << input_permute.at(j));
|
||||
}
|
||||
if ((orig_init >> i) & 0x1) {
|
||||
new_init |= (1 << permute_address);
|
||||
}
|
||||
}
|
||||
|
||||
return new_init;
|
||||
}
|
||||
|
||||
void write_asc(const Context *ctx, std::ostream &out)
|
||||
{
|
||||
|
||||
@ -282,22 +301,33 @@ void write_asc(const Context *ctx, std::ostream &out)
|
||||
BelId sw_bel;
|
||||
sw_bel.index = sw_bel_idx;
|
||||
NPNR_ASSERT(ctx->getBelType(sw_bel) == TYPE_ICESTORM_LC);
|
||||
BelPin input = get_one_bel_pin(ctx, ctx->getPipSrcWire(pip));
|
||||
|
||||
if (ci.wire_data[ctx->getPipDstWire(pip).index].type == WireInfoPOD::WIRE_TYPE_LUTFF_IN_LUT)
|
||||
continue; // Permutation pips
|
||||
BelPin output = get_one_bel_pin(ctx, ctx->getPipDstWire(pip));
|
||||
NPNR_ASSERT(input.bel == sw_bel);
|
||||
NPNR_ASSERT(output.bel == sw_bel && output.pin == PIN_O);
|
||||
unsigned lut_init;
|
||||
switch (input.pin) {
|
||||
case PIN_I0:
|
||||
|
||||
WireId permWire;
|
||||
for (auto permPip : ctx->getPipsUphill(ctx->getPipSrcWire(pip))) {
|
||||
if (ctx->getBoundPipNet(permPip) != IdString()) {
|
||||
permWire = ctx->getPipSrcWire(permPip);
|
||||
}
|
||||
}
|
||||
NPNR_ASSERT(permWire != WireId());
|
||||
std::string dName = ci.wire_data[permWire.index].name.get();
|
||||
|
||||
switch (dName.back()) {
|
||||
case '0':
|
||||
lut_init = 2;
|
||||
break;
|
||||
case PIN_I1:
|
||||
case '1':
|
||||
lut_init = 4;
|
||||
break;
|
||||
case PIN_I2:
|
||||
case '2':
|
||||
lut_init = 16;
|
||||
break;
|
||||
case PIN_I3:
|
||||
case '3':
|
||||
lut_init = 256;
|
||||
break;
|
||||
default:
|
||||
@ -345,8 +375,49 @@ void write_asc(const Context *ctx, std::ostream &out)
|
||||
bool set_noreset = get_param_or_def(cell.second.get(), ctx->id("SET_NORESET"));
|
||||
bool carry_enable = get_param_or_def(cell.second.get(), ctx->id("CARRY_ENABLE"));
|
||||
std::vector<bool> lc(20, false);
|
||||
// From arachne-pnr
|
||||
|
||||
// Discover permutation
|
||||
std::unordered_map<int, int> input_perm;
|
||||
std::set<int> unused;
|
||||
for (int i = 0; i < 4; i++)
|
||||
unused.insert(i);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
WireId lut_wire = ctx->getBelPinWire(bel, PortPin(PIN_I0 + i));
|
||||
for (auto pip : ctx->getPipsUphill(lut_wire)) {
|
||||
if (ctx->getBoundPipNet(pip) != IdString()) {
|
||||
std::string name = ci.wire_data[ctx->getPipSrcWire(pip).index].name.get();
|
||||
switch (name.back()) {
|
||||
case '0':
|
||||
input_perm[i] = 0;
|
||||
unused.erase(0);
|
||||
break;
|
||||
case '1':
|
||||
input_perm[i] = 1;
|
||||
unused.erase(1);
|
||||
break;
|
||||
case '2':
|
||||
input_perm[i] = 2;
|
||||
unused.erase(2);
|
||||
break;
|
||||
case '3':
|
||||
input_perm[i] = 3;
|
||||
unused.erase(3);
|
||||
break;
|
||||
default:
|
||||
NPNR_ASSERT_FALSE("failed to determine LUT permutation");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (!input_perm.count(i)) {
|
||||
NPNR_ASSERT(!unused.empty());
|
||||
input_perm[i] = *(unused.begin());
|
||||
unused.erase(input_perm[i]);
|
||||
}
|
||||
}
|
||||
lut_init = permute_lut(lut_init, input_perm);
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if ((lut_init >> i) & 0x1)
|
||||
lc.at(lut_perm.at(i)) = true;
|
||||
|
186
ice40/chipdb.py
186
ice40/chipdb.py
@ -134,12 +134,21 @@ tiletypes["DSP2"] = 7
|
||||
tiletypes["DSP3"] = 8
|
||||
tiletypes["IPCON"] = 9
|
||||
|
||||
wiretypes["LOCAL"] = 1
|
||||
wiretypes["GLOBAL"] = 2
|
||||
wiretypes["SP4_VERT"] = 3
|
||||
wiretypes["SP4_HORZ"] = 4
|
||||
wiretypes["SP12_HORZ"] = 5
|
||||
wiretypes["SP12_VERT"] = 6
|
||||
wiretypes["NONE"] = 0
|
||||
wiretypes["GLB2LOCAL"] = 1
|
||||
wiretypes["GLB_NETWK"] = 2
|
||||
wiretypes["LOCAL"] = 3
|
||||
wiretypes["LUTFF_IN"] = 4
|
||||
wiretypes["LUTFF_IN_LUT"] = 5
|
||||
wiretypes["LUTFF_LOUT"] = 6
|
||||
wiretypes["LUTFF_OUT"] = 7
|
||||
wiretypes["LUTFF_COUT"] = 8
|
||||
wiretypes["LUTFF_GLOBAL"] = 9
|
||||
wiretypes["CARRY_IN_MUX"] = 10
|
||||
wiretypes["SP4_V"] = 11
|
||||
wiretypes["SP4_H"] = 12
|
||||
wiretypes["SP12_V"] = 13
|
||||
wiretypes["SP12_H"] = 14
|
||||
|
||||
def maj_wire_name(name):
|
||||
if name[2].startswith("lutff_"):
|
||||
@ -179,40 +188,84 @@ def cmp_wire_names(newname, oldname):
|
||||
|
||||
def wire_type(name):
|
||||
longname = name
|
||||
name = name.split('/')[-1]
|
||||
wt = None
|
||||
name = name.split('/')
|
||||
|
||||
if name.startswith("glb_netwk_") or name.startswith("padin_"):
|
||||
wt = "GLOBAL"
|
||||
elif name.startswith("D_IN_") or name.startswith("D_OUT_"):
|
||||
wt = "LOCAL"
|
||||
elif name in ("OUT_ENB", "cen", "inclk", "latch", "outclk", "clk", "s_r", "carry_in", "carry_in_mux"):
|
||||
wt = "LOCAL"
|
||||
elif name in ("in_0", "in_1", "in_2", "in_3", "cout", "lout", "out", "fabout") or name.startswith("slf_op") or name.startswith("O_"):
|
||||
wt = "LOCAL"
|
||||
elif name.startswith("local_g") or name.startswith("glb2local_"):
|
||||
wt = "LOCAL"
|
||||
elif name.startswith("span4_horz_") or name.startswith("sp4_h_"):
|
||||
wt = "SP4_HORZ"
|
||||
elif name.startswith("span4_vert_") or name.startswith("sp4_v_") or name.startswith("sp4_r_v_"):
|
||||
wt = "SP4_VERT"
|
||||
elif name.startswith("span12_horz_") or name.startswith("sp12_h_"):
|
||||
wt = "SP12_HORZ"
|
||||
elif name.startswith("span12_vert_") or name.startswith("sp12_v_"):
|
||||
wt = "SP12_VERT"
|
||||
elif name.startswith("MASK_") or name.startswith("RADDR_") or name.startswith("WADDR_"):
|
||||
wt = "LOCAL"
|
||||
elif name.startswith("RDATA_") or name.startswith("WDATA_") or name.startswith("neigh_op_"):
|
||||
wt = "LOCAL"
|
||||
elif name in ("WCLK", "WCLKE", "WE", "RCLK", "RCLKE", "RE"):
|
||||
wt = "LOCAL"
|
||||
elif name in ("PLLOUT_A", "PLLOUT_B"):
|
||||
wt = "LOCAL"
|
||||
if name[0].startswith("X") and name[1].startswith("Y"):
|
||||
name = name[2:]
|
||||
|
||||
if wt is None:
|
||||
print("No type for wire: %s (%s)" % (longname, name), file=sys.stderr)
|
||||
assert 0
|
||||
return wt
|
||||
if name[0].startswith("sp4_v_") or name[0].startswith("sp4_r_v_") or name[0].startswith("span4_vert_"):
|
||||
return "SP4_V"
|
||||
|
||||
if name[0].startswith("sp4_h_") or name[0].startswith("span4_horz_"):
|
||||
return "SP4_H"
|
||||
|
||||
if name[0].startswith("sp12_v_") or name[0].startswith("span12_vert_"):
|
||||
return "SP12_V"
|
||||
|
||||
if name[0].startswith("sp12_h_") or name[0].startswith("span12_horz_"):
|
||||
return "SP12_H"
|
||||
|
||||
if name[0].startswith("glb2local"):
|
||||
return "GLB2LOCAL"
|
||||
|
||||
if name[0].startswith("glb_netwk_"):
|
||||
return "GLB_NETWK"
|
||||
|
||||
if name[0].startswith("local_"):
|
||||
return "LOCAL"
|
||||
|
||||
if name[0].startswith("lutff_"):
|
||||
if name[1].startswith("in_"):
|
||||
return "LUTFF_IN_LUT" if name[1].endswith("_lut") else "LUTFF_IN"
|
||||
|
||||
if name[1] == "lout":
|
||||
return "LUTFF_LOUT"
|
||||
if name[1] == "out":
|
||||
return "LUTFF_OUT"
|
||||
if name[1] == "cout":
|
||||
return "LUTFF_COUT"
|
||||
|
||||
if name[0] == "ram":
|
||||
if name[1].startswith("RADDR_"):
|
||||
return "LUTFF_IN"
|
||||
if name[1].startswith("WADDR_"):
|
||||
return "LUTFF_IN"
|
||||
if name[1].startswith("WDATA_"):
|
||||
return "LUTFF_IN"
|
||||
if name[1].startswith("MASK_"):
|
||||
return "LUTFF_IN"
|
||||
if name[1].startswith("RDATA_"):
|
||||
return "LUTFF_OUT"
|
||||
if name[1] in ("WCLK", "WCLKE", "WE", "RCLK", "RCLKE", "RE"):
|
||||
return "LUTFF_GLOBAL"
|
||||
|
||||
if name[0].startswith("io_"):
|
||||
if name[1].startswith("D_IN_") or name[1] == "OUT_ENB":
|
||||
return "LUTFF_IN"
|
||||
if name[1].startswith("D_OUT_"):
|
||||
return "LUTFF_OUT"
|
||||
if name[0] == "fabout":
|
||||
return "LUTFF_IN"
|
||||
|
||||
if name[0] == "lutff_global" or name[0] == "io_global":
|
||||
return "LUTFF_GLOBAL"
|
||||
|
||||
if name[0] == "carry_in_mux":
|
||||
return "CARRY_IN_MUX"
|
||||
|
||||
if name[0] == "carry_in":
|
||||
return "LUTFF_COUT"
|
||||
|
||||
if name[0].startswith("neigh_op_"):
|
||||
return "NONE"
|
||||
|
||||
if name[0].startswith("padin_"):
|
||||
return "NONE"
|
||||
|
||||
# print("No type for wire: %s (%s)" % (longname, name), file=sys.stderr)
|
||||
# assert 0
|
||||
|
||||
return "NONE"
|
||||
|
||||
def pipdelay(src_idx, dst_idx, db):
|
||||
if db is None:
|
||||
@ -265,9 +318,12 @@ def pipdelay(src_idx, dst_idx, db):
|
||||
if src[2].startswith("local_") and dst[2] in ("io_0/D_OUT_0", "io_0/D_OUT_1", "io_0/OUT_ENB", "io_1/D_OUT_0", "io_1/D_OUT_1", "io_1/OUT_ENB"):
|
||||
return db["IoInMux.I.O"]
|
||||
|
||||
if re.match(r"lutff_\d+/in_\d+", dst[2]):
|
||||
if re.match(r"lutff_\d+/in_\d+$", dst[2]):
|
||||
return db["InMux.I.O"]
|
||||
|
||||
if re.match(r"lutff_\d+/in_\d+_lut", dst[2]):
|
||||
return 0
|
||||
|
||||
if re.match(r"ram/(MASK|RADDR|WADDR|WDATA)_", dst[2]):
|
||||
return db["InMux.I.O"]
|
||||
|
||||
@ -472,7 +528,7 @@ with open(args.filename, "r") as f:
|
||||
wire_uphill[wire_b] = set()
|
||||
wire_downhill[wire_a].add(wire_b)
|
||||
wire_uphill[wire_b].add(wire_a)
|
||||
pip_xy[(wire_a, wire_b)] = (mode[2], mode[3], int(line[0], 2), len(switches) - 1)
|
||||
pip_xy[(wire_a, wire_b)] = (mode[2], mode[3], int(line[0], 2), len(switches) - 1, 0)
|
||||
continue
|
||||
|
||||
if mode[0] == "bits":
|
||||
@ -508,11 +564,14 @@ def add_wire(x, y, name):
|
||||
wire_names[wname] = wire_idx
|
||||
wire_names_r[wire_idx] = wname
|
||||
wire_segments[wire_idx] = dict()
|
||||
if ("TILE_WIRE_" + wname[2].upper().replace("/", "_")) in gfx_wire_ids:
|
||||
wire_segments[wire_idx][(wname[0], wname[1])] = wname[2]
|
||||
return wire_idx
|
||||
|
||||
def add_switch(x, y, bel=-1):
|
||||
switches.append((x, y, [], bel))
|
||||
|
||||
def add_pip(src, dst):
|
||||
def add_pip(src, dst, flags=0):
|
||||
x, y, _, _ = switches[-1]
|
||||
|
||||
if src not in wire_downhill:
|
||||
@ -523,7 +582,7 @@ def add_pip(src, dst):
|
||||
wire_uphill[dst] = set()
|
||||
wire_uphill[dst].add(src)
|
||||
|
||||
pip_xy[(src, dst)] = (x, y, 0, len(switches) - 1)
|
||||
pip_xy[(src, dst)] = (x, y, 0, len(switches) - 1, flags)
|
||||
|
||||
# Add virtual padin wires
|
||||
for i in range(8):
|
||||
@ -557,10 +616,11 @@ def add_bel_lc(x, y, z):
|
||||
else:
|
||||
wire_cin = wire_names[(x, y, "lutff_%d/cout" % (z-1))]
|
||||
|
||||
wire_in_0 = wire_names[(x, y, "lutff_%d/in_0" % z)]
|
||||
wire_in_1 = wire_names[(x, y, "lutff_%d/in_1" % z)]
|
||||
wire_in_2 = wire_names[(x, y, "lutff_%d/in_2" % z)]
|
||||
wire_in_3 = wire_names[(x, y, "lutff_%d/in_3" % z)]
|
||||
wire_in_0 = add_wire(x, y, "lutff_%d/in_0_lut" % z)
|
||||
wire_in_1 = add_wire(x, y, "lutff_%d/in_1_lut" % z)
|
||||
wire_in_2 = add_wire(x, y, "lutff_%d/in_2_lut" % z)
|
||||
wire_in_3 = add_wire(x, y, "lutff_%d/in_3_lut" % z)
|
||||
|
||||
wire_out = wire_names[(x, y, "lutff_%d/out" % z)]
|
||||
wire_cout = wire_names[(x, y, "lutff_%d/cout" % z)]
|
||||
wire_lout = wire_names[(x, y, "lutff_%d/lout" % z)] if z < 7 else None
|
||||
@ -583,10 +643,21 @@ def add_bel_lc(x, y, z):
|
||||
|
||||
# route-through LUTs
|
||||
add_switch(x, y, bel)
|
||||
add_pip(wire_in_0, wire_out)
|
||||
add_pip(wire_in_1, wire_out)
|
||||
add_pip(wire_in_2, wire_out)
|
||||
add_pip(wire_in_3, wire_out)
|
||||
add_pip(wire_in_0, wire_out, 1)
|
||||
add_pip(wire_in_1, wire_out, 1)
|
||||
add_pip(wire_in_2, wire_out, 1)
|
||||
add_pip(wire_in_3, wire_out, 1)
|
||||
|
||||
# LUT permutation pips
|
||||
for i in range(4):
|
||||
add_switch(x, y, bel)
|
||||
for j in range(4):
|
||||
if (i == j) or ((i, j) == (1, 2)) or ((i, j) == (2, 1)):
|
||||
flags = 0
|
||||
else:
|
||||
flags = 2
|
||||
add_pip(wire_names[(x, y, "lutff_%d/in_%d" % (z, i))],
|
||||
wire_names[(x, y, "lutff_%d/in_%d_lut" % (z, j))], flags)
|
||||
|
||||
def add_bel_io(x, y, z):
|
||||
bel = len(bel_name)
|
||||
@ -902,6 +973,7 @@ for wire in range(num_wires):
|
||||
pi["y"] = pip_xy[(src, wire)][1]
|
||||
pi["switch_mask"] = pip_xy[(src, wire)][2]
|
||||
pi["switch_index"] = pip_xy[(src, wire)][3]
|
||||
pi["flags"] = pip_xy[(src, wire)][4]
|
||||
pipinfo.append(pi)
|
||||
pips.append(pipcache[(src, wire)])
|
||||
num_uphill = len(pips)
|
||||
@ -927,6 +999,7 @@ for wire in range(num_wires):
|
||||
pi["y"] = pip_xy[(wire, dst)][1]
|
||||
pi["switch_mask"] = pip_xy[(wire, dst)][2]
|
||||
pi["switch_index"] = pip_xy[(wire, dst)][3]
|
||||
pi["flags"] = pip_xy[(wire, dst)][4]
|
||||
pipinfo.append(pi)
|
||||
pips.append(pipcache[(wire, dst)])
|
||||
num_downhill = len(pips)
|
||||
@ -959,16 +1032,20 @@ for wire in range(num_wires):
|
||||
info["num_bel_pins"] = num_bel_pins
|
||||
info["list_bel_pins"] = ("wire%d_bels" % wire) if num_bel_pins > 0 else None
|
||||
|
||||
avg_x, avg_y = 0, 0
|
||||
if wire in wire_xy:
|
||||
avg_x, avg_y = 0, 0
|
||||
|
||||
for x, y in wire_xy[wire]:
|
||||
avg_x += x
|
||||
avg_y += y
|
||||
avg_x /= len(wire_xy[wire])
|
||||
avg_y /= len(wire_xy[wire])
|
||||
|
||||
info["x"] = int(round(avg_x))
|
||||
info["y"] = int(round(avg_y))
|
||||
info["x"] = int(round(avg_x))
|
||||
info["y"] = int(round(avg_y))
|
||||
else:
|
||||
info["x"] = wire_names_r[wire][0]
|
||||
info["y"] = wire_names_r[wire][1]
|
||||
|
||||
wireinfo.append(info)
|
||||
|
||||
@ -1046,8 +1123,8 @@ for wire, info in enumerate(wireinfo):
|
||||
|
||||
bba.u8(info["x"], "x")
|
||||
bba.u8(info["y"], "y")
|
||||
bba.u8(0, "z") # FIXME
|
||||
bba.u8(wiretypes[wire_type(info["name"])], "type")
|
||||
bba.u8(0, "padding")
|
||||
|
||||
for wire in range(num_wires):
|
||||
if len(wire_segments[wire]):
|
||||
@ -1084,6 +1161,7 @@ for info in pipinfo:
|
||||
bba.u16(dst_seg, "dst_seg")
|
||||
bba.u16(info["switch_mask"], "switch_mask")
|
||||
bba.u32(info["switch_index"], "switch_index")
|
||||
bba.u32(info["flags"], "flags")
|
||||
|
||||
switchinfo = []
|
||||
for switch in switches:
|
||||
|
238
ice40/delay.cc
Normal file
238
ice40/delay.cc
Normal file
@ -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
|
34
ice40/gfx.cc
34
ice40/gfx.cc
@ -391,6 +391,17 @@ void gfxTileWire(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId id,
|
||||
int z = idx / 4;
|
||||
int input = idx % 4;
|
||||
el.x1 = x + local_swbox_x2;
|
||||
el.x2 = x + lut_swbox_x1;
|
||||
el.y1 = y + (logic_cell_y1 + logic_cell_y2) / 2 - 0.0075 + (0.005 * input) + z * logic_cell_pitch;
|
||||
el.y2 = el.y1;
|
||||
g.push_back(el);
|
||||
}
|
||||
|
||||
if (id >= TILE_WIRE_LUTFF_0_IN_0_LUT && id <= TILE_WIRE_LUTFF_7_IN_3_LUT) {
|
||||
int idx = id - TILE_WIRE_LUTFF_0_IN_0_LUT;
|
||||
int z = idx / 4;
|
||||
int input = idx % 4;
|
||||
el.x1 = x + lut_swbox_x2;
|
||||
el.x2 = x + logic_cell_x1;
|
||||
el.y1 = y + (logic_cell_y1 + logic_cell_y2) / 2 - 0.0075 + (0.005 * input) + z * logic_cell_pitch;
|
||||
el.y2 = el.y1;
|
||||
@ -706,10 +717,10 @@ void gfxTilePip(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId src,
|
||||
return;
|
||||
}
|
||||
|
||||
if (TILE_WIRE_LUTFF_0_IN_0 <= src && src <= TILE_WIRE_LUTFF_7_IN_3 && TILE_WIRE_LUTFF_0_OUT <= dst &&
|
||||
if (TILE_WIRE_LUTFF_0_IN_0_LUT <= src && src <= TILE_WIRE_LUTFF_7_IN_3_LUT && TILE_WIRE_LUTFF_0_OUT <= dst &&
|
||||
dst <= TILE_WIRE_LUTFF_7_OUT) {
|
||||
int lut_idx = (src - TILE_WIRE_LUTFF_0_IN_0) / 4;
|
||||
int in_idx = (src - TILE_WIRE_LUTFF_0_IN_0) % 4;
|
||||
int lut_idx = (src - TILE_WIRE_LUTFF_0_IN_0_LUT) / 4;
|
||||
int in_idx = (src - TILE_WIRE_LUTFF_0_IN_0_LUT) % 4;
|
||||
|
||||
GraphicElement el;
|
||||
el.type = GraphicElement::TYPE_ARROW;
|
||||
@ -722,6 +733,23 @@ void gfxTilePip(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId src,
|
||||
return;
|
||||
}
|
||||
|
||||
if (TILE_WIRE_LUTFF_0_IN_0 <= src && src <= TILE_WIRE_LUTFF_7_IN_3 && TILE_WIRE_LUTFF_0_IN_0_LUT <= dst &&
|
||||
dst <= TILE_WIRE_LUTFF_7_IN_3_LUT) {
|
||||
int lut_idx = (src - TILE_WIRE_LUTFF_0_IN_0) / 4;
|
||||
int in_idx = (src - TILE_WIRE_LUTFF_0_IN_0) % 4;
|
||||
int out_idx = (dst - TILE_WIRE_LUTFF_0_IN_0_LUT) % 4;
|
||||
|
||||
GraphicElement el;
|
||||
el.type = GraphicElement::TYPE_ARROW;
|
||||
el.style = style;
|
||||
el.x1 = x + lut_swbox_x1;
|
||||
el.x2 = x + lut_swbox_x2;
|
||||
el.y1 = y + (logic_cell_y1 + logic_cell_y2) / 2 - 0.0075 + (0.005 * in_idx) + lut_idx * logic_cell_pitch;
|
||||
el.y2 = y + (logic_cell_y1 + logic_cell_y2) / 2 - 0.0075 + (0.005 * out_idx) + lut_idx * logic_cell_pitch;
|
||||
g.push_back(el);
|
||||
return;
|
||||
}
|
||||
|
||||
if (src == TILE_WIRE_CARRY_IN && dst == TILE_WIRE_CARRY_IN_MUX) {
|
||||
GraphicElement el;
|
||||
el.type = GraphicElement::TYPE_ARROW;
|
||||
|
51
ice40/gfx.h
51
ice40/gfx.h
@ -34,7 +34,10 @@ const float local_swbox_x2 = 0.73;
|
||||
const float local_swbox_y1 = 0.05;
|
||||
const float local_swbox_y2 = 0.55;
|
||||
|
||||
const float logic_cell_x1 = 0.76;
|
||||
const float lut_swbox_x1 = 0.76;
|
||||
const float lut_swbox_x2 = 0.80;
|
||||
|
||||
const float logic_cell_x1 = 0.83;
|
||||
const float logic_cell_x2 = 0.95;
|
||||
const float logic_cell_y1 = 0.05;
|
||||
const float logic_cell_y2 = 0.10;
|
||||
@ -92,9 +95,6 @@ enum GfxTileWireId
|
||||
TILE_WIRE_LOCAL_G3_6,
|
||||
TILE_WIRE_LOCAL_G3_7,
|
||||
|
||||
TILE_WIRE_CARRY_IN,
|
||||
TILE_WIRE_CARRY_IN_MUX,
|
||||
|
||||
TILE_WIRE_LUTFF_0_IN_0,
|
||||
TILE_WIRE_LUTFF_0_IN_1,
|
||||
TILE_WIRE_LUTFF_0_IN_2,
|
||||
@ -135,6 +135,46 @@ enum GfxTileWireId
|
||||
TILE_WIRE_LUTFF_7_IN_2,
|
||||
TILE_WIRE_LUTFF_7_IN_3,
|
||||
|
||||
TILE_WIRE_LUTFF_0_IN_0_LUT,
|
||||
TILE_WIRE_LUTFF_0_IN_1_LUT,
|
||||
TILE_WIRE_LUTFF_0_IN_2_LUT,
|
||||
TILE_WIRE_LUTFF_0_IN_3_LUT,
|
||||
|
||||
TILE_WIRE_LUTFF_1_IN_0_LUT,
|
||||
TILE_WIRE_LUTFF_1_IN_1_LUT,
|
||||
TILE_WIRE_LUTFF_1_IN_2_LUT,
|
||||
TILE_WIRE_LUTFF_1_IN_3_LUT,
|
||||
|
||||
TILE_WIRE_LUTFF_2_IN_0_LUT,
|
||||
TILE_WIRE_LUTFF_2_IN_1_LUT,
|
||||
TILE_WIRE_LUTFF_2_IN_2_LUT,
|
||||
TILE_WIRE_LUTFF_2_IN_3_LUT,
|
||||
|
||||
TILE_WIRE_LUTFF_3_IN_0_LUT,
|
||||
TILE_WIRE_LUTFF_3_IN_1_LUT,
|
||||
TILE_WIRE_LUTFF_3_IN_2_LUT,
|
||||
TILE_WIRE_LUTFF_3_IN_3_LUT,
|
||||
|
||||
TILE_WIRE_LUTFF_4_IN_0_LUT,
|
||||
TILE_WIRE_LUTFF_4_IN_1_LUT,
|
||||
TILE_WIRE_LUTFF_4_IN_2_LUT,
|
||||
TILE_WIRE_LUTFF_4_IN_3_LUT,
|
||||
|
||||
TILE_WIRE_LUTFF_5_IN_0_LUT,
|
||||
TILE_WIRE_LUTFF_5_IN_1_LUT,
|
||||
TILE_WIRE_LUTFF_5_IN_2_LUT,
|
||||
TILE_WIRE_LUTFF_5_IN_3_LUT,
|
||||
|
||||
TILE_WIRE_LUTFF_6_IN_0_LUT,
|
||||
TILE_WIRE_LUTFF_6_IN_1_LUT,
|
||||
TILE_WIRE_LUTFF_6_IN_2_LUT,
|
||||
TILE_WIRE_LUTFF_6_IN_3_LUT,
|
||||
|
||||
TILE_WIRE_LUTFF_7_IN_0_LUT,
|
||||
TILE_WIRE_LUTFF_7_IN_1_LUT,
|
||||
TILE_WIRE_LUTFF_7_IN_2_LUT,
|
||||
TILE_WIRE_LUTFF_7_IN_3_LUT,
|
||||
|
||||
TILE_WIRE_LUTFF_0_LOUT,
|
||||
TILE_WIRE_LUTFF_1_LOUT,
|
||||
TILE_WIRE_LUTFF_2_LOUT,
|
||||
@ -165,6 +205,9 @@ enum GfxTileWireId
|
||||
TILE_WIRE_LUTFF_GLOBAL_CLK,
|
||||
TILE_WIRE_LUTFF_GLOBAL_S_R,
|
||||
|
||||
TILE_WIRE_CARRY_IN,
|
||||
TILE_WIRE_CARRY_IN_MUX,
|
||||
|
||||
TILE_WIRE_NEIGH_OP_BNL_0,
|
||||
TILE_WIRE_NEIGH_OP_BNL_1,
|
||||
TILE_WIRE_NEIGH_OP_BNL_2,
|
||||
|
@ -45,26 +45,6 @@
|
||||
|
||||
USING_NEXTPNR_NAMESPACE
|
||||
|
||||
void svg_dump_decal(const Context *ctx, const DecalXY &decal)
|
||||
{
|
||||
const float scale = 10.0, offset = 10.0;
|
||||
const std::string style = "stroke=\"black\" stroke-width=\"0.1\" fill=\"none\"";
|
||||
|
||||
for (auto &el : ctx->getDecalGraphics(decal.decal)) {
|
||||
if (el.type == GraphicElement::TYPE_BOX) {
|
||||
std::cout << "<rect x=\"" << (offset + scale * (decal.x + el.x1)) << "\" y=\""
|
||||
<< (offset + scale * (decal.y + el.y1)) << "\" height=\"" << (scale * (el.y2 - el.y1))
|
||||
<< "\" width=\"" << (scale * (el.x2 - el.x1)) << "\" " << style << "/>\n";
|
||||
}
|
||||
|
||||
if (el.type == GraphicElement::TYPE_LINE) {
|
||||
std::cout << "<line x1=\"" << (offset + scale * (decal.x + el.x1)) << "\" y1=\""
|
||||
<< (offset + scale * (decal.y + el.y1)) << "\" x2=\"" << (offset + scale * (decal.x + el.x2))
|
||||
<< "\" y2=\"" << (offset + scale * (decal.y + el.y2)) << "\" " << style << "/>\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void conflicting_options(const boost::program_options::variables_map &vm, const char *opt1, const char *opt2)
|
||||
{
|
||||
if (vm.count(opt1) && !vm[opt1].defaulted() && vm.count(opt2) && !vm[opt2].defaulted()) {
|
||||
@ -91,7 +71,6 @@ int main(int argc, char *argv[])
|
||||
#ifndef NO_GUI
|
||||
options.add_options()("gui", "start gui");
|
||||
#endif
|
||||
options.add_options()("svg", "dump SVG file");
|
||||
options.add_options()("pack-only", "pack design only without placement or routing");
|
||||
|
||||
po::positional_options_description pos;
|
||||
@ -332,64 +311,11 @@ int main(int argc, char *argv[])
|
||||
ctx->placer_constraintWeight = vm["cstrweight"].as<float>();
|
||||
}
|
||||
|
||||
if (vm.count("svg")) {
|
||||
std::cout << "<svg xmlns=\"http://www.w3.org/2000/svg\" "
|
||||
"xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n";
|
||||
for (auto bel : ctx->getBels()) {
|
||||
std::cout << "<!-- " << ctx->getBelName(bel).str(ctx.get()) << " -->\n";
|
||||
svg_dump_decal(ctx.get(), ctx->getBelDecal(bel));
|
||||
}
|
||||
std::cout << "</svg>\n";
|
||||
}
|
||||
|
||||
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>();
|
||||
|
357
ice40/tmfuzz.py
Normal file
357
ice40/tmfuzz.py
Normal file
@ -0,0 +1,357 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# ../nextpnr-ice40 --hx8k --tmfuzz > tmfuzz_hx8k.txt
|
||||
# ../nextpnr-ice40 --lp8k --tmfuzz > tmfuzz_lp8k.txt
|
||||
# ../nextpnr-ice40 --up5k --tmfuzz > tmfuzz_up5k.txt
|
||||
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
from collections import defaultdict
|
||||
|
||||
device = "hx8k"
|
||||
# device = "lp8k"
|
||||
# device = "up5k"
|
||||
|
||||
sel_src_type = "LUTFF_OUT"
|
||||
sel_dst_type = "LUTFF_IN_LUT"
|
||||
|
||||
#%% Read fuzz data
|
||||
|
||||
src_dst_pairs = defaultdict(lambda: 0)
|
||||
|
||||
delay_data = list()
|
||||
all_delay_data = list()
|
||||
|
||||
delay_map_sum = np.zeros((41, 41))
|
||||
delay_map_sum2 = np.zeros((41, 41))
|
||||
delay_map_count = np.zeros((41, 41))
|
||||
|
||||
same_tile_delays = list()
|
||||
neighbour_tile_delays = list()
|
||||
|
||||
type_delta_data = dict()
|
||||
|
||||
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])
|
||||
|
||||
all_delay_data.append((delay, estdelay))
|
||||
|
||||
src_dst_pairs[src_type, dst_type] += 1
|
||||
|
||||
dx = dst_xy[0] - src_xy[0]
|
||||
dy = dst_xy[1] - src_xy[1]
|
||||
|
||||
if src_type == sel_src_type and dst_type == sel_dst_type:
|
||||
if dx == 0 and dy == 0:
|
||||
same_tile_delays.append(delay)
|
||||
|
||||
elif abs(dx) <= 1 and abs(dy) <= 1:
|
||||
neighbour_tile_delays.append(delay)
|
||||
|
||||
else:
|
||||
delay_data.append((delay, estdelay, dx, dy, 0, 0, 0))
|
||||
|
||||
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
|
||||
|
||||
if dst_type == sel_dst_type:
|
||||
if src_type not in type_delta_data:
|
||||
type_delta_data[src_type] = list()
|
||||
|
||||
type_delta_data[src_type].append((dx, dy, delay))
|
||||
|
||||
delay_data = np.array(delay_data)
|
||||
all_delay_data = np.array(all_delay_data)
|
||||
max_delay = np.max(delay_data[:, 0:2])
|
||||
|
||||
mean_same_tile_delays = np.mean(neighbour_tile_delays)
|
||||
mean_neighbour_tile_delays = np.mean(neighbour_tile_delays)
|
||||
|
||||
print("Avg same tile delay: %.2f (%.2f std, N=%d)" % \
|
||||
(mean_same_tile_delays, np.std(same_tile_delays), len(same_tile_delays)))
|
||||
print("Avg neighbour tile delay: %.2f (%.2f std, N=%d)" % \
|
||||
(mean_neighbour_tile_delays, np.std(neighbour_tile_delays), len(neighbour_tile_delays)))
|
||||
|
||||
#%% Apply simple low-weight bluring to fill gaps
|
||||
|
||||
for i in range(0):
|
||||
neigh_sum = np.zeros((41, 41))
|
||||
neigh_sum2 = np.zeros((41, 41))
|
||||
neigh_count = np.zeros((41, 41))
|
||||
|
||||
for x in range(41):
|
||||
for y in range(41):
|
||||
for p in range(-1, 2):
|
||||
for q in range(-1, 2):
|
||||
if p == 0 and q == 0:
|
||||
continue
|
||||
if 0 <= (x+p) <= 40:
|
||||
if 0 <= (y+q) <= 40:
|
||||
neigh_sum[x, y] += delay_map_sum[x+p, y+q]
|
||||
neigh_sum2[x, y] += delay_map_sum2[x+p, y+q]
|
||||
neigh_count[x, y] += delay_map_count[x+p, y+q]
|
||||
|
||||
delay_map_sum += 0.1 * neigh_sum
|
||||
delay_map_sum2 += 0.1 * neigh_sum2
|
||||
delay_map_count += 0.1 * neigh_count
|
||||
|
||||
delay_map = delay_map_sum / delay_map_count
|
||||
delay_map_std = np.sqrt(delay_map_count*delay_map_sum2 - delay_map_sum**2) / delay_map_count
|
||||
|
||||
#%% Print src-dst-pair summary
|
||||
|
||||
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()
|
||||
|
||||
#%% Plot estimate vs actual delay
|
||||
|
||||
plt.figure(figsize=(8, 3))
|
||||
plt.title("Estimate vs Actual Delay")
|
||||
plt.plot(all_delay_data[:, 0], all_delay_data[:, 1], ".")
|
||||
plt.plot(delay_data[:, 0], delay_data[:, 1], ".")
|
||||
plt.plot([0, max_delay], [0, max_delay], "k")
|
||||
plt.ylabel("Estimated Delay")
|
||||
plt.xlabel("Actual Delay")
|
||||
plt.grid()
|
||||
plt.show()
|
||||
|
||||
#%% Plot delay heatmap and std dev heatmap
|
||||
|
||||
plt.figure(figsize=(9, 3))
|
||||
plt.subplot(121)
|
||||
plt.title("Actual Delay Map")
|
||||
plt.imshow(delay_map)
|
||||
plt.colorbar()
|
||||
plt.subplot(122)
|
||||
plt.title("Standard Deviation")
|
||||
plt.imshow(delay_map_std)
|
||||
plt.colorbar()
|
||||
plt.show()
|
||||
|
||||
#%% Generate Model #0
|
||||
|
||||
def nonlinearPreprocessor0(dx, dy):
|
||||
dx, dy = abs(dx), abs(dy)
|
||||
values = [1.0]
|
||||
values.append(dx + dy)
|
||||
return np.array(values)
|
||||
|
||||
A = np.zeros((41*41, len(nonlinearPreprocessor0(0, 0))))
|
||||
b = np.zeros(41*41)
|
||||
|
||||
index = 0
|
||||
for x in range(41):
|
||||
for y in range(41):
|
||||
if delay_map_count[x, y] > 0:
|
||||
A[index, :] = nonlinearPreprocessor0(x-20, y-20)
|
||||
b[index] = delay_map[x, y]
|
||||
index += 1
|
||||
|
||||
model0_params, _, _, _ = np.linalg.lstsq(A, b)
|
||||
print("Model #0 parameters:", model0_params)
|
||||
|
||||
model0_map = np.zeros((41, 41))
|
||||
for x in range(41):
|
||||
for y in range(41):
|
||||
v = np.dot(model0_params, nonlinearPreprocessor0(x-20, y-20))
|
||||
model0_map[x, y] = v
|
||||
|
||||
plt.figure(figsize=(9, 3))
|
||||
plt.subplot(121)
|
||||
plt.title("Model #0 Delay Map")
|
||||
plt.imshow(model0_map)
|
||||
plt.colorbar()
|
||||
plt.subplot(122)
|
||||
plt.title("Model #0 Error Map")
|
||||
plt.imshow(model0_map - delay_map)
|
||||
plt.colorbar()
|
||||
plt.show()
|
||||
|
||||
for i in range(delay_data.shape[0]):
|
||||
dx = delay_data[i, 2]
|
||||
dy = delay_data[i, 3]
|
||||
delay_data[i, 4] = np.dot(model0_params, nonlinearPreprocessor0(dx, dy))
|
||||
|
||||
plt.figure(figsize=(8, 3))
|
||||
plt.title("Model #0 vs Actual Delay")
|
||||
plt.plot(delay_data[:, 0], delay_data[:, 4], ".")
|
||||
plt.plot(delay_map.flat, model0_map.flat, ".")
|
||||
plt.plot([0, max_delay], [0, max_delay], "k")
|
||||
plt.ylabel("Model #0 Delay")
|
||||
plt.xlabel("Actual Delay")
|
||||
plt.grid()
|
||||
plt.show()
|
||||
|
||||
print("In-sample RMS error: %f" % np.sqrt(np.nanmean((delay_map - model0_map)**2)))
|
||||
print("Out-of-sample RMS error: %f" % np.sqrt(np.nanmean((delay_data[:, 0] - delay_data[:, 4])**2)))
|
||||
print()
|
||||
|
||||
#%% Generate Model #1
|
||||
|
||||
def nonlinearPreprocessor1(dx, dy):
|
||||
dx, dy = abs(dx), abs(dy)
|
||||
values = [1.0]
|
||||
values.append(dx + dy) # 1-norm
|
||||
values.append((dx**2 + dy**2)**(1/2)) # 2-norm
|
||||
values.append((dx**3 + dy**3)**(1/3)) # 3-norm
|
||||
return np.array(values)
|
||||
|
||||
A = np.zeros((41*41, len(nonlinearPreprocessor1(0, 0))))
|
||||
b = np.zeros(41*41)
|
||||
|
||||
index = 0
|
||||
for x in range(41):
|
||||
for y in range(41):
|
||||
if delay_map_count[x, y] > 0:
|
||||
A[index, :] = nonlinearPreprocessor1(x-20, y-20)
|
||||
b[index] = delay_map[x, y]
|
||||
index += 1
|
||||
|
||||
model1_params, _, _, _ = np.linalg.lstsq(A, b)
|
||||
print("Model #1 parameters:", model1_params)
|
||||
|
||||
model1_map = np.zeros((41, 41))
|
||||
for x in range(41):
|
||||
for y in range(41):
|
||||
v = np.dot(model1_params, nonlinearPreprocessor1(x-20, y-20))
|
||||
model1_map[x, y] = v
|
||||
|
||||
plt.figure(figsize=(9, 3))
|
||||
plt.subplot(121)
|
||||
plt.title("Model #1 Delay Map")
|
||||
plt.imshow(model1_map)
|
||||
plt.colorbar()
|
||||
plt.subplot(122)
|
||||
plt.title("Model #1 Error Map")
|
||||
plt.imshow(model1_map - delay_map)
|
||||
plt.colorbar()
|
||||
plt.show()
|
||||
|
||||
for i in range(delay_data.shape[0]):
|
||||
dx = delay_data[i, 2]
|
||||
dy = delay_data[i, 3]
|
||||
delay_data[i, 5] = np.dot(model1_params, nonlinearPreprocessor1(dx, dy))
|
||||
|
||||
plt.figure(figsize=(8, 3))
|
||||
plt.title("Model #1 vs Actual Delay")
|
||||
plt.plot(delay_data[:, 0], delay_data[:, 5], ".")
|
||||
plt.plot(delay_map.flat, model1_map.flat, ".")
|
||||
plt.plot([0, max_delay], [0, max_delay], "k")
|
||||
plt.ylabel("Model #1 Delay")
|
||||
plt.xlabel("Actual Delay")
|
||||
plt.grid()
|
||||
plt.show()
|
||||
|
||||
print("In-sample RMS error: %f" % np.sqrt(np.nanmean((delay_map - model1_map)**2)))
|
||||
print("Out-of-sample RMS error: %f" % np.sqrt(np.nanmean((delay_data[:, 0] - delay_data[:, 5])**2)))
|
||||
print()
|
||||
|
||||
#%% Generate Model #2
|
||||
|
||||
def nonlinearPreprocessor2(v):
|
||||
return np.array([1, v, np.sqrt(v)])
|
||||
|
||||
A = np.zeros((41*41, len(nonlinearPreprocessor2(0))))
|
||||
b = np.zeros(41*41)
|
||||
|
||||
index = 0
|
||||
for x in range(41):
|
||||
for y in range(41):
|
||||
if delay_map_count[x, y] > 0:
|
||||
A[index, :] = nonlinearPreprocessor2(model1_map[x, y])
|
||||
b[index] = delay_map[x, y]
|
||||
index += 1
|
||||
|
||||
model2_params, _, _, _ = np.linalg.lstsq(A, b)
|
||||
print("Model #2 parameters:", model2_params)
|
||||
|
||||
model2_map = np.zeros((41, 41))
|
||||
for x in range(41):
|
||||
for y in range(41):
|
||||
v = np.dot(model1_params, nonlinearPreprocessor1(x-20, y-20))
|
||||
v = np.dot(model2_params, nonlinearPreprocessor2(v))
|
||||
model2_map[x, y] = v
|
||||
|
||||
plt.figure(figsize=(9, 3))
|
||||
plt.subplot(121)
|
||||
plt.title("Model #2 Delay Map")
|
||||
plt.imshow(model2_map)
|
||||
plt.colorbar()
|
||||
plt.subplot(122)
|
||||
plt.title("Model #2 Error Map")
|
||||
plt.imshow(model2_map - delay_map)
|
||||
plt.colorbar()
|
||||
plt.show()
|
||||
|
||||
for i in range(delay_data.shape[0]):
|
||||
dx = delay_data[i, 2]
|
||||
dy = delay_data[i, 3]
|
||||
delay_data[i, 6] = np.dot(model2_params, nonlinearPreprocessor2(delay_data[i, 5]))
|
||||
|
||||
plt.figure(figsize=(8, 3))
|
||||
plt.title("Model #2 vs Actual Delay")
|
||||
plt.plot(delay_data[:, 0], delay_data[:, 6], ".")
|
||||
plt.plot(delay_map.flat, model2_map.flat, ".")
|
||||
plt.plot([0, max_delay], [0, max_delay], "k")
|
||||
plt.ylabel("Model #2 Delay")
|
||||
plt.xlabel("Actual Delay")
|
||||
plt.grid()
|
||||
plt.show()
|
||||
|
||||
print("In-sample RMS error: %f" % np.sqrt(np.nanmean((delay_map - model2_map)**2)))
|
||||
print("Out-of-sample RMS error: %f" % np.sqrt(np.nanmean((delay_data[:, 0] - delay_data[:, 6])**2)))
|
||||
print()
|
||||
|
||||
#%% Generate deltas for different source net types
|
||||
|
||||
type_deltas = dict()
|
||||
|
||||
print("Delay deltas for different src types:")
|
||||
for src_type in sorted(type_delta_data.keys()):
|
||||
deltas = list()
|
||||
|
||||
for dx, dy, delay in type_delta_data[src_type]:
|
||||
dx = abs(dx)
|
||||
dy = abs(dy)
|
||||
|
||||
if dx > 1 or dy > 1:
|
||||
est = model0_params[0] + model0_params[1] * (dx + dy)
|
||||
else:
|
||||
est = mean_neighbour_tile_delays
|
||||
deltas.append(delay - est)
|
||||
|
||||
print("%15s: %8.2f (std %6.2f)" % (\
|
||||
src_type, np.mean(deltas), np.std(deltas)))
|
||||
|
||||
type_deltas[src_type] = np.mean(deltas)
|
||||
|
||||
#%% Print C defs of model parameters
|
||||
|
||||
print("--snip--")
|
||||
print("%d, %d, %d," % (mean_neighbour_tile_delays, 128 * model0_params[0], 128 * model0_params[1]))
|
||||
print("%d, %d, %d, %d," % (128 * model1_params[0], 128 * model1_params[1], 128 * model1_params[2], 128 * model1_params[3]))
|
||||
print("%d, %d, %d," % (128 * model2_params[0], 128 * model2_params[1], 128 * model2_params[2]))
|
||||
print("%d, %d, %d, %d" % (type_deltas["LOCAL"], type_deltas["LUTFF_IN"], \
|
||||
(type_deltas["SP4_H"] + type_deltas["SP4_V"]) / 2,
|
||||
(type_deltas["SP12_H"] + type_deltas["SP12_V"]) / 2))
|
||||
print("--snap--")
|
Loading…
Reference in New Issue
Block a user