mistral: improve timing calculation
This commit is contained in:
parent
ea925f39fb
commit
7a827b1c78
@ -462,6 +462,10 @@ bool Arch::place()
|
|||||||
cfg.cellGroups.back().insert({id_MISTRAL_COMB});
|
cfg.cellGroups.back().insert({id_MISTRAL_COMB});
|
||||||
cfg.cellGroups.back().insert({id_MISTRAL_FF});
|
cfg.cellGroups.back().insert({id_MISTRAL_FF});
|
||||||
|
|
||||||
|
// The Cyclone V is asymmetrical enough that it's somewhat beneficial to prefer connecting things horizontally.
|
||||||
|
cfg.hpwl_scale_x = 1;
|
||||||
|
cfg.hpwl_scale_y = 2;
|
||||||
|
|
||||||
cfg.beta = 0.5; // TODO: find a good value of beta for sensible ALM spreading
|
cfg.beta = 0.5; // TODO: find a good value of beta for sensible ALM spreading
|
||||||
cfg.criticalityExponent = 7;
|
cfg.criticalityExponent = 7;
|
||||||
if (!placer_heap(getCtx(), cfg))
|
if (!placer_heap(getCtx(), cfg))
|
||||||
|
@ -289,6 +289,9 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
ArchArgs args;
|
ArchArgs args;
|
||||||
mistral::CycloneV *cyclonev;
|
mistral::CycloneV *cyclonev;
|
||||||
|
|
||||||
|
// Mistral needs the bitstream configuring before it can use the simulator.
|
||||||
|
bool bitstream_configured = false;
|
||||||
|
|
||||||
Arch(ArchArgs args);
|
Arch(ArchArgs args);
|
||||||
ArchArgs archArgs() const override { return args; }
|
ArchArgs archArgs() const override { return args; }
|
||||||
|
|
||||||
@ -434,6 +437,7 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort,
|
bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort,
|
||||||
DelayQuad &delay) const override; // delay.cc
|
DelayQuad &delay) const override; // delay.cc
|
||||||
DelayQuad getPipDelay(PipId pip) const override; // delay.cc
|
DelayQuad getPipDelay(PipId pip) const override; // delay.cc
|
||||||
|
bool getArcDelayOverride(const NetInfo *net_info, const PortRef &sink, DelayQuad &delay) const override; // delay.cc
|
||||||
|
|
||||||
// -------------------------------------------------
|
// -------------------------------------------------
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "nextpnr.h"
|
#include "nextpnr.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "timing.h"
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
namespace {
|
namespace {
|
||||||
@ -379,6 +380,7 @@ struct MistralBitgen
|
|||||||
write_routing();
|
write_routing();
|
||||||
write_cells();
|
write_cells();
|
||||||
write_labs();
|
write_labs();
|
||||||
|
ctx->bitstream_configured = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
@ -387,6 +389,16 @@ void Arch::build_bitstream()
|
|||||||
{
|
{
|
||||||
MistralBitgen gen(getCtx());
|
MistralBitgen gen(getCtx());
|
||||||
gen.run();
|
gen.run();
|
||||||
|
|
||||||
|
// This is a hack to run timing analysis yet again after the bitstream is
|
||||||
|
// configured in Mistral, because the analogue simulator won't work until
|
||||||
|
// it has a bitstream in the library.
|
||||||
|
//
|
||||||
|
// A better solution would be to move a lot of this bitstream code to
|
||||||
|
// {un,}bind{Bel, Pip} and friends, but we're not there yet.
|
||||||
|
log_info("Running signoff timing analysis...\n");
|
||||||
|
|
||||||
|
timing_analysis(getCtx(), true, true, true, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
172
mistral/delay.cc
172
mistral/delay.cc
@ -246,43 +246,167 @@ bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort
|
|||||||
DelayQuad Arch::getPipDelay(PipId pip) const
|
DelayQuad Arch::getPipDelay(PipId pip) const
|
||||||
{
|
{
|
||||||
WireId src = getPipSrcWire(pip), dst = getPipDstWire(pip);
|
WireId src = getPipSrcWire(pip), dst = getPipDstWire(pip);
|
||||||
if ((src.is_nextpnr_created() && dst.is_nextpnr_created()) || dst.is_nextpnr_created())
|
|
||||||
|
if (src.is_nextpnr_created() || dst.is_nextpnr_created())
|
||||||
return DelayQuad{20};
|
return DelayQuad{20};
|
||||||
|
|
||||||
// This is guesswork based on average of (interconnect delay / number of pips)
|
// This is guesswork based on average of (interconnect delay / number of pips)
|
||||||
auto dst_type = CycloneV::rn2t(dst.node);
|
auto src_type = CycloneV::rn2t(src.node);
|
||||||
|
|
||||||
switch (dst_type) {
|
switch (src_type) {
|
||||||
case CycloneV::rnode_type_t::H14:
|
case CycloneV::rnode_type_t::SCLK:
|
||||||
return DelayQuad{254};
|
return DelayQuad{136, 136, 139, 139};
|
||||||
case CycloneV::rnode_type_t::H3:
|
case CycloneV::rnode_type_t::SCLKB1:
|
||||||
return DelayQuad{214};
|
return DelayQuad{296, 296, 370, 370};
|
||||||
case CycloneV::rnode_type_t::H6:
|
case CycloneV::rnode_type_t::SCLKB2:
|
||||||
return DelayQuad{298};
|
return DelayQuad{71, 71, 83, 83};
|
||||||
case CycloneV::rnode_type_t::V2:
|
case CycloneV::rnode_type_t::HCLK:
|
||||||
return DelayQuad{210};
|
return DelayQuad{183, 183, 239, 239};
|
||||||
case CycloneV::rnode_type_t::V4:
|
case CycloneV::rnode_type_t::HCLKB:
|
||||||
return DelayQuad{262};
|
return DelayQuad{165, 165, 244, 244};
|
||||||
case CycloneV::rnode_type_t::DCMUX:
|
case CycloneV::rnode_type_t::XCLKB1:
|
||||||
return DelayQuad{0};
|
return DelayQuad{97, 97, 125, 125};
|
||||||
case CycloneV::rnode_type_t::GIN:
|
case CycloneV::rnode_type_t::GIN:
|
||||||
return DelayQuad{83}; // need to check with Sarayan
|
return DelayQuad{100};
|
||||||
case CycloneV::rnode_type_t::GOUT:
|
case CycloneV::rnode_type_t::H14:
|
||||||
return DelayQuad{123};
|
return DelayQuad{273, 286, 288, 291};
|
||||||
case CycloneV::rnode_type_t::TCLK:
|
case CycloneV::rnode_type_t::H3:
|
||||||
return DelayQuad{46};
|
return DelayQuad{196, 226, 163, 173};
|
||||||
|
case CycloneV::rnode_type_t::H6:
|
||||||
|
return DelayQuad{220, 275, 199, 217};
|
||||||
|
case CycloneV::rnode_type_t::V12:
|
||||||
|
return DelayQuad{361, 374, 337, 340};
|
||||||
|
case CycloneV::rnode_type_t::V2:
|
||||||
|
return DelayQuad{214, 231, 163, 175};
|
||||||
|
case CycloneV::rnode_type_t::V4:
|
||||||
|
return DelayQuad{290, 294, 243, 245};
|
||||||
|
case CycloneV::rnode_type_t::WM:
|
||||||
|
// WM explicitly has zero delay.
|
||||||
|
return DelayQuad{0};
|
||||||
|
case CycloneV::rnode_type_t::TD:
|
||||||
|
return DelayQuad{208, 208, 177, 177};
|
||||||
default:
|
default:
|
||||||
return DelayQuad{308};
|
return DelayQuad{0};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Arch::getArcDelayOverride(const NetInfo *net_info, const PortRef &sink, DelayQuad &delay) const
|
||||||
|
{
|
||||||
|
if (!this->bitstream_configured)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
WireId src_wire = getCtx()->getNetinfoSourceWire(net_info);
|
||||||
|
WireId dst_wire = getCtx()->getNetinfoSinkWire(net_info, sink, 0);
|
||||||
|
NPNR_ASSERT(src_wire != WireId());
|
||||||
|
|
||||||
|
bool inverted = false;
|
||||||
|
mistral::AnalogSim::wave input_wave[2], output_wave[2];
|
||||||
|
mistral::AnalogSim::time_interval output_delays[2];
|
||||||
|
mistral::AnalogSim::time_interval output_delay_sum[2];
|
||||||
|
std::vector<std::pair<mistral::CycloneV::rnode_t, int>> outputs;
|
||||||
|
auto temp = mistral::CycloneV::T_100;
|
||||||
|
auto est = mistral::CycloneV::EST_SLOW;
|
||||||
|
|
||||||
|
output_delay_sum[0].mi = 0;
|
||||||
|
output_delay_sum[0].mx = 0;
|
||||||
|
output_delay_sum[1].mi = 0;
|
||||||
|
output_delay_sum[1].mx = 0;
|
||||||
|
|
||||||
|
// Mistral's analogue simulator propagates from source to destination,
|
||||||
|
// but nextpnr finds paths from destination to source, so some slight
|
||||||
|
// contortions are necessary.
|
||||||
|
|
||||||
|
std::vector<PipId> pips;
|
||||||
|
|
||||||
|
WireId cursor = dst_wire;
|
||||||
|
while (cursor != WireId() && cursor != src_wire) {
|
||||||
|
auto it = net_info->wires.find(cursor);
|
||||||
|
|
||||||
|
if (it == net_info->wires.end())
|
||||||
|
break;
|
||||||
|
|
||||||
|
PipId pip = it->second.pip;
|
||||||
|
if (pip == PipId())
|
||||||
|
break;
|
||||||
|
|
||||||
|
pips.push_back(pip);
|
||||||
|
cursor = getPipSrcWire(pip);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto it = pips.rbegin(); it != pips.rend(); it++) {
|
||||||
|
PipId pip = *it;
|
||||||
|
auto src = getPipSrcWire(pip);
|
||||||
|
auto dst = getPipDstWire(pip);
|
||||||
|
|
||||||
|
if (src.is_nextpnr_created())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (dst.is_nextpnr_created())
|
||||||
|
dst.node = 0;
|
||||||
|
|
||||||
|
auto mode = cyclonev->rnode_timing_get_mode(src.node);
|
||||||
|
NPNR_ASSERT(mode != mistral::CycloneV::RTM_UNSUPPORTED);
|
||||||
|
|
||||||
|
auto inverting = cyclonev->rnode_is_inverting(src.node);
|
||||||
|
|
||||||
|
if (mode == mistral::CycloneV::RTM_P2P) {
|
||||||
|
if (inverting == mistral::CycloneV::INV_YES || inverting == mistral::CycloneV::INV_PROGRAMMABLE)
|
||||||
|
inverted = !inverted;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode == mistral::CycloneV::RTM_NO_DELAY) {
|
||||||
|
if (inverting)
|
||||||
|
inverted = !inverted;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input_wave[0].empty()) {
|
||||||
|
cyclonev->rnode_timing_build_input_wave(src.node, temp, CycloneV::DELAY_MAX, inverted ? mistral::CycloneV::RF_FALL : mistral::CycloneV::RF_RISE, est, input_wave[0]);
|
||||||
|
cyclonev->rnode_timing_build_input_wave(src.node, temp, CycloneV::DELAY_MAX, inverted ? mistral::CycloneV::RF_RISE : mistral::CycloneV::RF_FALL, est, input_wave[1]);
|
||||||
|
NPNR_ASSERT(!input_wave[mistral::CycloneV::RF_RISE].empty() && !input_wave[mistral::CycloneV::RF_FALL].empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int edge = 0; edge != 2; edge++) {
|
||||||
|
auto actual_edge = edge ? inverted ? mistral::CycloneV::RF_RISE : mistral::CycloneV::RF_FALL : inverted ? mistral::CycloneV::RF_FALL : mistral::CycloneV::RF_RISE;
|
||||||
|
mistral::AnalogSim sim;
|
||||||
|
int input = -1;
|
||||||
|
std::vector<std::pair<mistral::CycloneV::rnode_t, int>> outputs;
|
||||||
|
cyclonev->rnode_timing_build_circuit(src.node, temp, CycloneV::DELAY_MAX, actual_edge, sim, input, outputs);
|
||||||
|
|
||||||
|
sim.set_input_wave(input, input_wave[edge]);
|
||||||
|
auto o = std::find_if(outputs.begin(), outputs.end(), [&](std::pair<mistral::CycloneV::rnode_t, int> output) {
|
||||||
|
return output.first == dst.node;
|
||||||
|
});
|
||||||
|
NPNR_ASSERT(o != outputs.end());
|
||||||
|
|
||||||
|
output_wave[edge].clear();
|
||||||
|
sim.set_output_wave(o->second, output_wave[edge], output_delays[edge]);
|
||||||
|
sim.run();
|
||||||
|
cyclonev->rnode_timing_trim_wave(temp, CycloneV::DELAY_MAX, output_wave[edge], input_wave[edge]);
|
||||||
|
|
||||||
|
output_delay_sum[edge].mi += output_delays[edge].mi;
|
||||||
|
output_delay_sum[edge].mx += output_delays[edge].mx;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inverting == mistral::CycloneV::INV_YES || inverting == mistral::CycloneV::INV_PROGRAMMABLE)
|
||||||
|
inverted = !inverted;
|
||||||
|
}
|
||||||
|
|
||||||
|
delay = DelayQuad{delay_t(output_delay_sum[0].mi*1e12), delay_t(output_delay_sum[0].mx*1e12), delay_t(output_delay_sum[1].mi*1e12), delay_t(output_delay_sum[1].mx*1e12)};
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
delay_t Arch::predictDelay(BelId src_bel, IdString src_pin, BelId dst_bel, IdString dst_pin) const
|
delay_t Arch::predictDelay(BelId src_bel, IdString src_pin, BelId dst_bel, IdString dst_pin) const
|
||||||
{
|
{
|
||||||
NPNR_UNUSED(src_pin);
|
NPNR_UNUSED(src_pin);
|
||||||
NPNR_UNUSED(dst_pin);
|
NPNR_UNUSED(dst_pin);
|
||||||
Loc src_loc = getBelLocation(src_bel);
|
Loc src_loc = getBelLocation(src_bel);
|
||||||
Loc dst_loc = getBelLocation(dst_bel);
|
Loc dst_loc = getBelLocation(dst_bel);
|
||||||
return std::abs(dst_loc.y - src_loc.y) * 100 + std::abs(dst_loc.x - src_loc.x) * 100 + 100;
|
int x_diff = std::abs(dst_loc.x - src_loc.x);
|
||||||
|
int y_diff = std::abs(dst_loc.y - src_loc.y);
|
||||||
|
return 43*x_diff + 114*y_diff + 470;
|
||||||
}
|
}
|
||||||
|
|
||||||
delay_t Arch::estimateDelay(WireId src, WireId dst) const
|
delay_t Arch::estimateDelay(WireId src, WireId dst) const
|
||||||
@ -291,7 +415,9 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const
|
|||||||
int y0 = CycloneV::rn2y(src.node);
|
int y0 = CycloneV::rn2y(src.node);
|
||||||
int x1 = CycloneV::rn2x(dst.node);
|
int x1 = CycloneV::rn2x(dst.node);
|
||||||
int y1 = CycloneV::rn2y(dst.node);
|
int y1 = CycloneV::rn2y(dst.node);
|
||||||
return 300 * std::abs(y1 - y0) + 300 * std::abs(x1 - x0) + 300;
|
int x_diff = std::abs(x1 - x0);
|
||||||
|
int y_diff = std::abs(y1 - y0);
|
||||||
|
return 43*x_diff + 114*y_diff + 470;
|
||||||
}
|
}
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
Loading…
Reference in New Issue
Block a user