diff options
-rw-r--r-- | common/command.cc | 2 | ||||
-rw-r--r-- | common/router2.cc | 5 | ||||
-rw-r--r-- | ecp5/arch.cc | 9 | ||||
-rw-r--r-- | ecp5/arch.h | 1 | ||||
-rw-r--r-- | ecp5/bitstream.cc | 24 | ||||
-rw-r--r-- | ecp5/docs/primitives.md | 2 | ||||
-rw-r--r-- | ecp5/lpf.cc | 2 | ||||
-rw-r--r-- | ecp5/main.cc | 6 | ||||
-rw-r--r-- | ecp5/pack.cc | 10 | ||||
-rw-r--r-- | ice40/arch.cc | 2 | ||||
-rw-r--r-- | ice40/pack.cc | 40 |
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)); |