timing: Add support for clock constraints
Signed-off-by: David Shah <dave@ds0.me>
This commit is contained in:
parent
11579a1046
commit
fc5e6bec9a
@ -381,4 +381,13 @@ void Context::check() const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BaseCtx::addClock(IdString net, float freq)
|
||||||
|
{
|
||||||
|
std::unique_ptr<ClockConstraint> cc(new ClockConstraint());
|
||||||
|
cc->period = getCtx()->getDelayFromNS(1000 / freq);
|
||||||
|
cc->high = getCtx()->getDelayFromNS(500 / freq);
|
||||||
|
cc->low = getCtx()->getDelayFromNS(500 / freq);
|
||||||
|
nets.at(net)->clkconstr = std::move(cc);
|
||||||
|
}
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
@ -297,7 +297,7 @@ struct NetInfo : ArchNetInfo
|
|||||||
// wire -> uphill_pip
|
// wire -> uphill_pip
|
||||||
std::unordered_map<WireId, PipMap> wires;
|
std::unordered_map<WireId, PipMap> wires;
|
||||||
|
|
||||||
ClockConstraint *clkconstr = nullptr;
|
std::unique_ptr<ClockConstraint> clkconstr;
|
||||||
|
|
||||||
TimingConstrObjectId tmg_id;
|
TimingConstrObjectId tmg_id;
|
||||||
|
|
||||||
@ -627,6 +627,9 @@ struct BaseCtx
|
|||||||
|
|
||||||
void addConstraint(std::unique_ptr<TimingConstraint> constr);
|
void addConstraint(std::unique_ptr<TimingConstraint> constr);
|
||||||
void removeConstraint(IdString constrName);
|
void removeConstraint(IdString constrName);
|
||||||
|
|
||||||
|
// Intended to simplify Python API
|
||||||
|
void addClock(IdString net, float freq);
|
||||||
};
|
};
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
@ -315,13 +315,26 @@ struct Timing
|
|||||||
const auto endpoint_arrival = net_arrival + net_delay + setup;
|
const auto endpoint_arrival = net_arrival + net_delay + setup;
|
||||||
auto path_budget = clk_period - endpoint_arrival;
|
auto path_budget = clk_period - endpoint_arrival;
|
||||||
delay_t period;
|
delay_t period;
|
||||||
|
// Set default period
|
||||||
if (edge == startdomain.first.edge) {
|
if (edge == startdomain.first.edge) {
|
||||||
period = clk_period;
|
period = clk_period;
|
||||||
} else {
|
} else {
|
||||||
period = clk_period / 2;
|
period = clk_period / 2;
|
||||||
}
|
}
|
||||||
|
if (clksig != async_clock) {
|
||||||
|
if (ctx->nets.at(clksig)->clkconstr) {
|
||||||
|
if (edge == startdomain.first.edge) {
|
||||||
|
// same edge
|
||||||
|
period = ctx->nets.at(clksig)->clkconstr->period.minDelay();
|
||||||
|
} else if (edge == RISING_EDGE) {
|
||||||
|
// falling -> rising
|
||||||
|
period = ctx->nets.at(clksig)->clkconstr->low.minDelay();
|
||||||
|
} else if (edge == FALLING_EDGE) {
|
||||||
|
// rising -> falling
|
||||||
|
period = ctx->nets.at(clksig)->clkconstr->high.minDelay();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (update) {
|
if (update) {
|
||||||
auto budget_share = budget_override ? 0 : path_budget / net_length_plus_one;
|
auto budget_share = budget_override ? 0 : path_budget / net_length_plus_one;
|
||||||
usr.budget = std::min(usr.budget, net_delay + budget_share);
|
usr.budget = std::min(usr.budget, net_delay + budget_share);
|
||||||
@ -637,8 +650,14 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_fmax, bool p
|
|||||||
if (print_fmax) {
|
if (print_fmax) {
|
||||||
log_break();
|
log_break();
|
||||||
for (auto &clock : clock_reports) {
|
for (auto &clock : clock_reports) {
|
||||||
|
if (ctx->nets.at(clock.first)->clkconstr) {
|
||||||
|
float target = 1000 / ctx->getDelayNS(ctx->nets.at(clock.first)->clkconstr->period.minDelay());
|
||||||
|
log_info("Max frequency for clock '%s': %.02f MHz (%s at %.02f MHz)\n", clock.first.c_str(ctx),
|
||||||
|
clock_fmax[clock.first], (target < clock_fmax[clock.first]) ? "PASS" : "FAIL", target);
|
||||||
|
} else {
|
||||||
log_info("Max frequency for clock '%s': %.02f MHz\n", clock.first.c_str(ctx), clock_fmax[clock.first]);
|
log_info("Max frequency for clock '%s': %.02f MHz\n", clock.first.c_str(ctx), clock_fmax[clock.first]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
log_break();
|
log_break();
|
||||||
|
|
||||||
int start_field_width = 0, end_field_width = 0;
|
int start_field_width = 0, end_field_width = 0;
|
||||||
|
@ -130,6 +130,10 @@ void arch_wrap_python()
|
|||||||
"cells");
|
"cells");
|
||||||
readonly_wrapper<Context, decltype(&Context::nets), &Context::nets, wrap_context<NetMap &>>::def_wrap(ctx_cls,
|
readonly_wrapper<Context, decltype(&Context::nets), &Context::nets, wrap_context<NetMap &>>::def_wrap(ctx_cls,
|
||||||
"nets");
|
"nets");
|
||||||
|
|
||||||
|
fn_wrapper_2a_v<Context, decltype(&Context::addClock), &Context::addClock, conv_from_str<IdString>,
|
||||||
|
pass_through<float>>::def_wrap(ctx_cls, "addClock");
|
||||||
|
|
||||||
WRAP_RANGE(Bel, conv_to_str<BelId>);
|
WRAP_RANGE(Bel, conv_to_str<BelId>);
|
||||||
WRAP_RANGE(Wire, conv_to_str<WireId>);
|
WRAP_RANGE(Wire, conv_to_str<WireId>);
|
||||||
WRAP_RANGE(AllPip, conv_to_str<PipId>);
|
WRAP_RANGE(AllPip, conv_to_str<PipId>);
|
||||||
|
@ -140,6 +140,10 @@ void arch_wrap_python()
|
|||||||
"cells");
|
"cells");
|
||||||
readonly_wrapper<Context, decltype(&Context::nets), &Context::nets, wrap_context<NetMap &>>::def_wrap(ctx_cls,
|
readonly_wrapper<Context, decltype(&Context::nets), &Context::nets, wrap_context<NetMap &>>::def_wrap(ctx_cls,
|
||||||
"nets");
|
"nets");
|
||||||
|
|
||||||
|
fn_wrapper_2a_v<Context, decltype(&Context::addClock), &Context::addClock, conv_from_str<IdString>,
|
||||||
|
pass_through<float>>::def_wrap(ctx_cls, "addClock");
|
||||||
|
|
||||||
WRAP_RANGE(Bel, conv_to_str<BelId>);
|
WRAP_RANGE(Bel, conv_to_str<BelId>);
|
||||||
WRAP_RANGE(Wire, conv_to_str<WireId>);
|
WRAP_RANGE(Wire, conv_to_str<WireId>);
|
||||||
WRAP_RANGE(AllPip, conv_to_str<PipId>);
|
WRAP_RANGE(AllPip, conv_to_str<PipId>);
|
||||||
|
@ -490,6 +490,14 @@ static void insert_global(Context *ctx, NetInfo *net, bool is_reset, bool is_cen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
net->users = keep_users;
|
net->users = keep_users;
|
||||||
|
|
||||||
|
if (net->clkconstr) {
|
||||||
|
glbnet->clkconstr = std::unique_ptr<ClockConstraint>(new ClockConstraint());
|
||||||
|
glbnet->clkconstr->low = net->clkconstr->low;
|
||||||
|
glbnet->clkconstr->high = net->clkconstr->high;
|
||||||
|
glbnet->clkconstr->period = net->clkconstr->period;
|
||||||
|
}
|
||||||
|
|
||||||
ctx->nets[glbnet->name] = std::move(glbnet);
|
ctx->nets[glbnet->name] = std::move(glbnet);
|
||||||
ctx->cells[gb->name] = std::move(gb);
|
ctx->cells[gb->name] = std::move(gb);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user