aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/nextpnr.cc9
-rw-r--r--common/nextpnr.h5
-rw-r--r--common/timing.cc25
-rw-r--r--ecp5/arch_pybindings.cc4
-rw-r--r--ice40/arch_pybindings.cc4
-rw-r--r--ice40/pack.cc8
6 files changed, 51 insertions, 4 deletions
diff --git a/common/nextpnr.cc b/common/nextpnr.cc
index 3621217b..8e8a8d19 100644
--- a/common/nextpnr.cc
+++ b/common/nextpnr.cc
@@ -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
diff --git a/common/nextpnr.h b/common/nextpnr.h
index 216e1532..70af6c71 100644
--- a/common/nextpnr.h
+++ b/common/nextpnr.h
@@ -297,7 +297,7 @@ struct NetInfo : ArchNetInfo
// wire -> uphill_pip
std::unordered_map<WireId, PipMap> wires;
- ClockConstraint *clkconstr = nullptr;
+ std::unique_ptr<ClockConstraint> clkconstr;
TimingConstrObjectId tmg_id;
@@ -627,6 +627,9 @@ struct BaseCtx
void addConstraint(std::unique_ptr<TimingConstraint> constr);
void removeConstraint(IdString constrName);
+
+ // Intended to simplify Python API
+ void addClock(IdString net, float freq);
};
NEXTPNR_NAMESPACE_END
diff --git a/common/timing.cc b/common/timing.cc
index 8351b1f3..fec74312 100644
--- a/common/timing.cc
+++ b/common/timing.cc
@@ -315,13 +315,26 @@ struct Timing
const auto endpoint_arrival = net_arrival + net_delay + setup;
auto path_budget = clk_period - endpoint_arrival;
delay_t period;
-
+ // Set default period
if (edge == startdomain.first.edge) {
period = clk_period;
} else {
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) {
auto budget_share = budget_override ? 0 : path_budget / net_length_plus_one;
usr.budget = std::min(usr.budget, net_delay + budget_share);
@@ -637,7 +650,13 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_fmax, bool p
if (print_fmax) {
log_break();
for (auto &clock : clock_reports) {
- log_info("Max frequency for clock '%s': %.02f MHz\n", clock.first.c_str(ctx), clock_fmax[clock.first]);
+ 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_break();
diff --git a/ecp5/arch_pybindings.cc b/ecp5/arch_pybindings.cc
index 9312b4ad..5e73a673 100644
--- a/ecp5/arch_pybindings.cc
+++ b/ecp5/arch_pybindings.cc
@@ -130,6 +130,10 @@ void arch_wrap_python()
"cells");
readonly_wrapper<Context, decltype(&Context::nets), &Context::nets, wrap_context<NetMap &>>::def_wrap(ctx_cls,
"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(Wire, conv_to_str<WireId>);
WRAP_RANGE(AllPip, conv_to_str<PipId>);
diff --git a/ice40/arch_pybindings.cc b/ice40/arch_pybindings.cc
index f1639ba6..3fafb1f6 100644
--- a/ice40/arch_pybindings.cc
+++ b/ice40/arch_pybindings.cc
@@ -140,6 +140,10 @@ void arch_wrap_python()
"cells");
readonly_wrapper<Context, decltype(&Context::nets), &Context::nets, wrap_context<NetMap &>>::def_wrap(ctx_cls,
"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(Wire, conv_to_str<WireId>);
WRAP_RANGE(AllPip, conv_to_str<PipId>);
diff --git a/ice40/pack.cc b/ice40/pack.cc
index b9360b74..7a27d505 100644
--- a/ice40/pack.cc
+++ b/ice40/pack.cc
@@ -490,6 +490,14 @@ static void insert_global(Context *ctx, NetInfo *net, bool is_reset, bool is_cen
}
}
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->cells[gb->name] = std::move(gb);
}