aboutsummaryrefslogtreecommitdiffstats
path: root/ice40/pack.cc
diff options
context:
space:
mode:
authorDavid Shah <dave@ds0.me>2020-03-29 21:02:16 +0100
committerDavid Shah <dave@ds0.me>2020-03-29 21:02:16 +0100
commit98e2f9ea8171bfb8cd04c74c4807dd21c1d18e85 (patch)
treec9db11bd5f36e0c697a3e16b15ba54c6711bf50c /ice40/pack.cc
parent3d3b222e2a130a5a21c326262c7d208b49bbad67 (diff)
downloadnextpnr-98e2f9ea8171bfb8cd04c74c4807dd21c1d18e85.tar.gz
nextpnr-98e2f9ea8171bfb8cd04c74c4807dd21c1d18e85.tar.bz2
nextpnr-98e2f9ea8171bfb8cd04c74c4807dd21c1d18e85.zip
ice40: Derive oscillator frequency constraints
Signed-off-by: David Shah <dave@ds0.me>
Diffstat (limited to 'ice40/pack.cc')
-rw-r--r--ice40/pack.cc40
1 files changed, 40 insertions, 0 deletions
diff --git a/ice40/pack.cc b/ice40/pack.cc
index 17d004b5..e27d42e5 100644
--- a/ice40/pack.cc
+++ b/ice40/pack.cc
@@ -1101,6 +1101,30 @@ static void pack_special(Context *ctx)
}
}
+ auto MHz = [&](delay_t a) { return 1000.0 / ctx->getDelayNS(a); };
+ auto equals_epsilon = [](delay_t a, delay_t b) { return (std::abs(a - b) / std::max(double(b), 1.0)) < 1e-3; };
+
+ auto set_period = [&](CellInfo *ci, IdString port, delay_t period) {
+ if (!ci->ports.count(port))
+ return;
+ NetInfo *to = ci->ports.at(port).net;
+ if (to == nullptr)
+ return;
+ if (to->clkconstr != nullptr) {
+ if (!equals_epsilon(to->clkconstr->period.delay, period))
+ log_warning(" Overriding derived constraint of %.1f MHz on net %s with user-specified constraint of "
+ "%.1f MHz.\n",
+ MHz(to->clkconstr->period.delay), to->name.c_str(ctx), MHz(period));
+ return;
+ }
+ to->clkconstr = std::unique_ptr<ClockConstraint>(new ClockConstraint());
+ to->clkconstr->low.delay = period / 2;
+ to->clkconstr->high.delay = period / 2;
+ to->clkconstr->period.delay = period;
+ log_info(" Derived frequency constraint of %.1f MHz for net %s\n", MHz(to->clkconstr->period.delay),
+ to->name.c_str(ctx));
+ };
+
for (auto cell : sorted(ctx->cells)) {
CellInfo *ci = cell.second;
if (is_sb_lfosc(ctx, ci)) {
@@ -1112,10 +1136,12 @@ static void pack_special(Context *ctx)
replace_port(ci, ctx->id("CLKLFPU"), packed.get(), ctx->id("CLKLFPU"));
if (bool_or_default(ci->attrs, ctx->id("ROUTE_THROUGH_FABRIC"))) {
replace_port(ci, ctx->id("CLKLF"), packed.get(), ctx->id("CLKLF_FABRIC"));
+ set_period(packed.get(), ctx->id("CLKLF_FABRIC"), 100000000); // 10kHz
} else {
replace_port(ci, ctx->id("CLKLF"), packed.get(), ctx->id("CLKLF"));
std::unique_ptr<CellInfo> gb =
create_padin_gbuf(ctx, packed.get(), ctx->id("CLKLF"), "$gbuf_" + ci->name.str(ctx) + "_lfosc");
+ set_period(gb.get(), id_GLOBAL_BUFFER_OUTPUT, 100000000); // 10kHz
new_cells.push_back(std::move(gb));
}
new_cells.push_back(std::move(packed));
@@ -1132,12 +1158,26 @@ static void pack_special(Context *ctx)
auto port = ctx->id("TRIM" + std::to_string(i));
replace_port(ci, port, packed.get(), port);
}
+ std::string div = packed->params[ctx->id("CLKHF_DIV")].as_string();
+ int frequency;
+ if (div == "0b00")
+ frequency = 48;
+ else if (div == "0b01")
+ frequency = 24;
+ else if (div == "0b10")
+ frequency = 12;
+ else if (div == "0b11")
+ frequency = 6;
+ else
+ log_error("Invalid HFOSC divider value '%s' - expecting 0b00, 0b01, 0b10 or 0b11\n", div.c_str());
if (bool_or_default(ci->attrs, ctx->id("ROUTE_THROUGH_FABRIC"))) {
replace_port(ci, ctx->id("CLKHF"), packed.get(), ctx->id("CLKHF_FABRIC"));
+ set_period(packed.get(), ctx->id("CLKHF_FABRIC"), 1000000 / frequency);
} else {
replace_port(ci, ctx->id("CLKHF"), packed.get(), ctx->id("CLKHF"));
std::unique_ptr<CellInfo> gb =
create_padin_gbuf(ctx, packed.get(), ctx->id("CLKHF"), "$gbuf_" + ci->name.str(ctx) + "_hfosc");
+ set_period(gb.get(), id_GLOBAL_BUFFER_OUTPUT, 1000000 / frequency);
new_cells.push_back(std::move(gb));
}
new_cells.push_back(std::move(packed));