aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/command.cc2
-rw-r--r--common/router2.cc5
-rw-r--r--ecp5/arch.cc9
-rw-r--r--ecp5/arch.h1
-rw-r--r--ecp5/bitstream.cc24
-rw-r--r--ecp5/docs/primitives.md2
-rw-r--r--ecp5/lpf.cc2
-rw-r--r--ecp5/main.cc6
-rw-r--r--ecp5/pack.cc10
-rw-r--r--ice40/arch.cc2
-rw-r--r--ice40/pack.cc40
11 files changed, 89 insertions, 14 deletions
diff --git a/common/command.cc b/common/command.cc
index 7b4805ae..a7a19989 100644
--- a/common/command.cc
+++ b/common/command.cc
@@ -135,7 +135,7 @@ po::options_description CommandHandler::getGeneralOptions()
general.add_options()(
"router", po::value<std::string>(),
std::string("router algorithm to use; available: " + boost::algorithm::join(Arch::availableRouters, ", ") +
- "; default: " + Arch::defaultPlacer)
+ "; default: " + Arch::defaultRouter)
.c_str());
general.add_options()("slack_redist_iter", po::value<int>(), "number of iterations between slack redistribution");
diff --git a/common/router2.cc b/common/router2.cc
index 00760c78..26e78eaa 100644
--- a/common/router2.cc
+++ b/common/router2.cc
@@ -747,7 +747,7 @@ struct Router2
total_wire_use += int(wire.bound_nets.size());
int overuse = int(wire.bound_nets.size()) - 1;
if (overuse > 0) {
- wire.hist_cong_cost += overuse * hist_cong_weight;
+ wire.hist_cong_cost = std::min(1e9, wire.hist_cong_cost + overuse * hist_cong_weight);
total_overuse += overuse;
overused_wires += 1;
for (auto &bound : wire.bound_nets)
@@ -1082,7 +1082,8 @@ struct Router2
log_info(" iter=%d wires=%d overused=%d overuse=%d archfail=%s\n", iter, total_wire_use, overused_wires,
total_overuse, overused_wires > 0 ? "NA" : std::to_string(arch_fail).c_str());
++iter;
- curr_cong_weight *= cfg.curr_cong_mult;
+ if (curr_cong_weight < 1e9)
+ curr_cong_weight *= cfg.curr_cong_mult;
} while (!failed_nets.empty());
if (cfg.perf_profile) {
std::vector<std::pair<int, IdString>> nets_by_runtime;
diff --git a/ecp5/arch.cc b/ecp5/arch.cc
index 39d2ba17..ab24842e 100644
--- a/ecp5/arch.cc
+++ b/ecp5/arch.cc
@@ -106,7 +106,8 @@ Arch::Arch(ArchArgs args) : args(args)
log_error("Unsupported ECP5 chip type.\n");
}
#else
- if (args.type == ArchArgs::LFE5U_25F || args.type == ArchArgs::LFE5UM_25F || args.type == ArchArgs::LFE5UM5G_25F) {
+ if (args.type == ArchArgs::LFE5U_12F || args.type == ArchArgs::LFE5U_25F || args.type == ArchArgs::LFE5UM_25F ||
+ args.type == ArchArgs::LFE5UM5G_25F) {
chip_info = get_chip_info(reinterpret_cast<const RelPtr<ChipInfoPOD> *>(chipdb_blob_25k));
} else if (args.type == ArchArgs::LFE5U_45F || args.type == ArchArgs::LFE5UM_45F ||
args.type == ArchArgs::LFE5UM5G_45F) {
@@ -139,7 +140,9 @@ Arch::Arch(ArchArgs args) : args(args)
std::string Arch::getChipName() const
{
- if (args.type == ArchArgs::LFE5U_25F) {
+ if (args.type == ArchArgs::LFE5U_12F) {
+ return "LFE5U-12F";
+ } else if (args.type == ArchArgs::LFE5U_25F) {
return "LFE5U-25F";
} else if (args.type == ArchArgs::LFE5U_45F) {
return "LFE5U-45F";
@@ -186,6 +189,8 @@ std::string Arch::getFullChipName() const
IdString Arch::archArgsToId(ArchArgs args) const
{
+ if (args.type == ArchArgs::LFE5U_12F)
+ return id("lfe5u_12f");
if (args.type == ArchArgs::LFE5U_25F)
return id("lfe5u_25f");
if (args.type == ArchArgs::LFE5U_45F)
diff --git a/ecp5/arch.h b/ecp5/arch.h
index 55494b1f..d57b5bc0 100644
--- a/ecp5/arch.h
+++ b/ecp5/arch.h
@@ -431,6 +431,7 @@ struct ArchArgs
enum ArchArgsTypes
{
NONE,
+ LFE5U_12F,
LFE5U_25F,
LFE5U_45F,
LFE5U_85F,
diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc
index 1bdb4188..54d0c0a4 100644
--- a/ecp5/bitstream.cc
+++ b/ecp5/bitstream.cc
@@ -438,8 +438,8 @@ std::vector<std::string> get_pll_tiles(Context *ctx, BelId bel)
void fix_tile_names(Context *ctx, ChipConfig &cc)
{
// Remove the V prefix/suffix on certain tiles if device is a SERDES variant
- if (ctx->args.type == ArchArgs::LFE5U_25F || ctx->args.type == ArchArgs::LFE5U_45F ||
- ctx->args.type == ArchArgs::LFE5U_85F) {
+ if (ctx->args.type == ArchArgs::LFE5U_12F || ctx->args.type == ArchArgs::LFE5U_25F ||
+ ctx->args.type == ArchArgs::LFE5U_45F || ctx->args.type == ArchArgs::LFE5U_85F) {
std::map<std::string, std::string> tiletype_xform;
for (const auto &tile : cc.tiles) {
std::string newname = tile.first;
@@ -580,6 +580,10 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
config_file >> cc;
} else {
switch (ctx->args.type) {
+ case ArchArgs::LFE5U_12F:
+ BaseConfigs::config_empty_lfe5u_25f(cc);
+ cc.chip_name = "LFE5U-12F";
+ break;
case ArchArgs::LFE5U_25F:
BaseConfigs::config_empty_lfe5u_25f(cc);
break;
@@ -927,6 +931,9 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
iovoltage_to_str(vccio).c_str(), ci->name.c_str(ctx));
}
}
+ if (ci->attrs.count(ctx->id("OPENDRAIN")))
+ cc.tiles[pio_tile].add_enum(pio + ".OPENDRAIN",
+ str_or_default(ci->attrs, ctx->id("OPENDRAIN"), "OFF"));
std::string datamux_oddr = str_or_default(ci->params, ctx->id("DATAMUX_ODDR"), "PADDO");
if (datamux_oddr != "PADDO")
cc.tiles[pic_tile].add_enum(pio + ".DATAMUX_ODDR", datamux_oddr);
@@ -1249,9 +1256,14 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
tg.config.add_enum("FEEDBK_PATH", str_or_default(ci->params, ctx->id("FEEDBK_PATH"), "CLKOP"));
tg.config.add_enum("CLKOP_TRIM_POL", str_or_default(ci->params, ctx->id("CLKOP_TRIM_POL"), "RISING"));
- tg.config.add_enum("CLKOP_TRIM_DELAY", str_or_default(ci->params, ctx->id("CLKOP_TRIM_DELAY"), "0"));
+
+ tg.config.add_enum("CLKOP_TRIM_DELAY",
+ intstr_or_default(ci->params, ctx->id("CLKOP_TRIM_DELAY"), "0"));
+
tg.config.add_enum("CLKOS_TRIM_POL", str_or_default(ci->params, ctx->id("CLKOS_TRIM_POL"), "RISING"));
- tg.config.add_enum("CLKOS_TRIM_DELAY", str_or_default(ci->params, ctx->id("CLKOS_TRIM_DELAY"), "0"));
+
+ tg.config.add_enum("CLKOS_TRIM_DELAY",
+ intstr_or_default(ci->params, ctx->id("CLKOS_TRIM_DELAY"), "0"));
tg.config.add_enum("OUTDIVIDER_MUXA", str_or_default(ci->params, ctx->id("OUTDIVIDER_MUXA"),
get_net_or_empty(ci, id_CLKOP) ? "DIVA" : "REFCLK"));
@@ -1429,8 +1441,8 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
Loc loc = ctx->getBelLocation(ci->bel);
bool u = loc.y<15, r = loc.x> 15;
std::string tiletype = fmt_str("DDRDLL_" << (u ? 'U' : 'L') << (r ? 'R' : 'L'));
- if ((ctx->args.type == ArchArgs::LFE5U_25F || ctx->args.type == ArchArgs::LFE5UM_25F ||
- ctx->args.type == ArchArgs::LFE5UM5G_25F) &&
+ if ((ctx->args.type == ArchArgs::LFE5U_12F || ctx->args.type == ArchArgs::LFE5U_25F ||
+ ctx->args.type == ArchArgs::LFE5UM_25F || ctx->args.type == ArchArgs::LFE5UM5G_25F) &&
u)
tiletype += "A";
std::string tile = ctx->getTileByType(tiletype);
diff --git a/ecp5/docs/primitives.md b/ecp5/docs/primitives.md
index aa37f3e5..f7f97d16 100644
--- a/ecp5/docs/primitives.md
+++ b/ecp5/docs/primitives.md
@@ -43,5 +43,5 @@ nextpnr-ecp5 currently supports the following primitives:
- **TRELLIS_SLICE**
- **TSHX2DQA**
- **TSHX2DQSA**
- - **USRMCLK** (untested)
+ - **USRMCLK**
diff --git a/ecp5/lpf.cc b/ecp5/lpf.cc
index ceb1d7ae..e626cc54 100644
--- a/ecp5/lpf.cc
+++ b/ecp5/lpf.cc
@@ -101,6 +101,8 @@ bool Arch::applyLPF(std::string filename, std::istream &in)
if (words.at(3) != "SITE")
log_error("expected 'SITE' after 'LOCATE COMP %s' (on line %d)\n", cell.c_str(), lineno);
auto fnd_cell = cells.find(id(cell));
+ if (words.size() > 5)
+ log_error("unexpected input following LOCATE clause (on line %d)\n", lineno);
if (fnd_cell != cells.end()) {
fnd_cell->second->attrs[id("LOC")] = strip_quotes(words.at(4));
}
diff --git a/ecp5/main.cc b/ecp5/main.cc
index 24a98df4..a24011db 100644
--- a/ecp5/main.cc
+++ b/ecp5/main.cc
@@ -49,6 +49,7 @@ ECP5CommandHandler::ECP5CommandHandler(int argc, char **argv) : CommandHandler(a
po::options_description ECP5CommandHandler::getArchOptions()
{
po::options_description specific("Architecture specific options");
+ specific.add_options()("12k", "set device type to LFE5U-12F");
specific.add_options()("25k", "set device type to LFE5U-25F");
specific.add_options()("45k", "set device type to LFE5U-45F");
specific.add_options()("85k", "set device type to LFE5U-85F");
@@ -125,7 +126,8 @@ std::unique_ptr<Context> ECP5CommandHandler::createContext(std::unordered_map<st
{
ArchArgs chipArgs;
chipArgs.type = ArchArgs::NONE;
-
+ if (vm.count("12k"))
+ chipArgs.type = ArchArgs::LFE5U_12F;
if (vm.count("25k"))
chipArgs.type = ArchArgs::LFE5U_25F;
if (vm.count("45k"))
@@ -179,6 +181,8 @@ std::unique_ptr<Context> ECP5CommandHandler::createContext(std::unordered_map<st
if (chipArgs.type != ArchArgs::NONE)
log_error("Overriding architecture is unsuported.\n");
+ if (arch_type == "lfe5u_12f")
+ chipArgs.type = ArchArgs::LFE5U_12F;
if (arch_type == "lfe5u_25f")
chipArgs.type = ArchArgs::LFE5U_25F;
if (arch_type == "lfe5u_45f")
diff --git a/ecp5/pack.cc b/ecp5/pack.cc
index dac889ce..0872ae58 100644
--- a/ecp5/pack.cc
+++ b/ecp5/pack.cc
@@ -2038,10 +2038,20 @@ class Ecp5Packer
disconnect_port(ctx, prim, port);
};
+ bool warned_oddrx_iddrx = false;
+
auto set_iologic_mode = [&](CellInfo *iol, std::string mode) {
auto &curr_mode = iol->params[ctx->id("MODE")].str;
if (curr_mode != "NONE" && mode == "IREG_OREG")
return;
+ if ((curr_mode == "IDDRXN" && mode == "ODDRXN") || (curr_mode == "ODDRXN" && mode == "IDDRXN")) {
+ if (!warned_oddrx_iddrx) {
+ warned_oddrx_iddrx = true;
+ log_warning("Use of IDDRXN and ODDRXN primitives on the same pin is unofficial and unsupported!\n");
+ }
+ curr_mode = "ODDRXN";
+ return;
+ }
if (curr_mode != "NONE" && curr_mode != "IREG_OREG" && curr_mode != mode)
log_error("IOLOGIC '%s' has conflicting modes '%s' and '%s'\n", iol->name.c_str(ctx), curr_mode.c_str(),
mode.c_str());
diff --git a/ice40/arch.cc b/ice40/arch.cc
index a43c4c21..6d07a949 100644
--- a/ice40/arch.cc
+++ b/ice40/arch.cc
@@ -1037,7 +1037,7 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, in
}
}
if (port == id_OUTPUT_ENABLE) {
- if ((cell->ioInfo.pintype & 0x18) == 0x18) {
+ if ((cell->ioInfo.pintype & 0x30) == 0x30) {
return TMG_REGISTER_INPUT;
} else {
return TMG_ENDPOINT;
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));