From dc10fe031927c7821af05d72f06d8add8d4c0a31 Mon Sep 17 00:00:00 2001 From: David Shah Date: Wed, 19 Dec 2018 10:11:29 +0000 Subject: [PATCH 1/8] ecp5: Fix ODDR when used with manually instantiated TRELLIS_IO Signed-off-by: David Shah --- ecp5/pack.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ecp5/pack.cc b/ecp5/pack.cc index 6ae169c9..cc91ca0e 100644 --- a/ecp5/pack.cc +++ b/ecp5/pack.cc @@ -1497,6 +1497,10 @@ class Ecp5Packer iol = create_pio_iologic(pio, ci); set_iologic_mode(iol, "IDDRX1_ODDRX1"); replace_port(ci, ctx->id("Q"), iol, id_IOLDO); + if (!pio->ports.count(id_IOLDO)) { + pio->ports[id_IOLDO].name = id_IOLDO; + pio->ports[id_IOLDO].type = PORT_IN; + } replace_port(pio, id_I, pio, id_IOLDO); pio->params[ctx->id("DATAMUX_ODDR")] = "IOLDO"; set_iologic_sclk(iol, ci, ctx->id("SCLK"), false); From f21791fe22512812a5f5988c001db9d6926b0ebb Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 18 Dec 2018 15:01:04 +0000 Subject: [PATCH 2/8] common/chain_utils: Don't allow overlapping chains Signed-off-by: David Shah --- common/chain_utils.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/chain_utils.h b/common/chain_utils.h index b783e30b..300d96a1 100644 --- a/common/chain_utils.h +++ b/common/chain_utils.h @@ -51,7 +51,8 @@ std::vector find_chains(const Context *ctx, F1 cell_type_predicate, F CellChain chain; CellInfo *end = start; while (end != nullptr) { - chain.cells.push_back(end); + if (chained.insert(end->name).second) + chain.cells.push_back(end); end = get_next(ctx, end); } if (chain.cells.size() >= min_length) { From 75335d4e1a66f10be81a17e4728e7312b36e59bd Mon Sep 17 00:00:00 2001 From: David Shah Date: Thu, 20 Dec 2018 18:50:34 +0000 Subject: [PATCH 3/8] ice40: Fix LOCK feedthrough insertion with carry or >8 LUTs Signed-off-by: David Shah --- ice40/pack.cc | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/ice40/pack.cc b/ice40/pack.cc index 242f8ceb..536b1b16 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -1181,20 +1181,26 @@ static void pack_special(Context *ctx) log_info(" PLL '%s' has LOCK output, need to pass all outputs via LUT\n", ci->name.c_str(ctx)); bool found_lut = false; bool all_luts = true; + bool found_carry = false; unsigned int lut_count = 0; for (const auto &user : port.net->users) { NPNR_ASSERT(user.cell != nullptr); if (user.cell->type == ctx->id("ICESTORM_LC")) { - found_lut = true; - lut_count++; + if (bool_or_default(user.cell->params, ctx->id("CARRY_ENABLE"), false)) { + found_carry = true; + all_luts = false; + } else { + found_lut = true; + lut_count++; + } } else { all_luts = false; } } - if (found_lut && all_luts) { + if (found_lut && all_luts && lut_count < 8) { // Every user is a LUT, carry on now. - } else if (found_lut && !all_luts && lut_count < 8) { + } else if (found_lut && !all_luts && !found_carry && lut_count < 8) { // Strategy: create a pass-through LUT, move all non-LUT users behind it. log_info(" LUT strategy for %s: move non-LUT users to new LUT\n", port.name.c_str(ctx)); auto pt = spliceLUT(ctx, packed.get(), port.name, true); From 953a3ac5521c720cd920a0e7e7315c37dfaf3680 Mon Sep 17 00:00:00 2001 From: David Shah Date: Thu, 20 Dec 2018 20:52:54 +0000 Subject: [PATCH 4/8] ice40: Add PCF support for -pullup, -pullup_resistor and -nowarn Signed-off-by: David Shah --- ice40/bitstream.cc | 17 +++++++++++++++-- ice40/pcf.cc | 32 ++++++++++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc index d1f51676..141c218b 100644 --- a/ice40/bitstream.cc +++ b/ice40/bitstream.cc @@ -527,10 +527,23 @@ void write_asc(const Context *ctx, std::ostream &out) } if (ctx->args.type == ArchArgs::UP5K) { + std::string pullup_resistor = "100K"; + if (cell.second->attrs.count(ctx->id("PULLUP_RESISTOR"))) + pullup_resistor = cell.second->attrs.at(ctx->id("PULLUP_RESISTOR")); + NPNR_ASSERT(pullup_resistor == "100K" || pullup_resistor == "10K" || pullup_resistor == "6P8K" || + pullup_resistor == "3P3K"); if (iez == 0) { - set_config(ti, config.at(iey).at(iex), "IoCtrl.cf_bit_39", !pullup); + set_config(ti, config.at(iey).at(iex), "IoCtrl.cf_bit_39", + (!pullup) || (pullup_resistor != "100K")); + set_config(ti, config.at(iey).at(iex), "IoCtrl.cf_bit_36", pullup && pullup_resistor == "3P3K"); + set_config(ti, config.at(iey).at(iex), "IoCtrl.cf_bit_37", pullup && pullup_resistor == "6P8K"); + set_config(ti, config.at(iey).at(iex), "IoCtrl.cf_bit_38", pullup && pullup_resistor == "10K"); } else if (iez == 1) { - set_config(ti, config.at(iey).at(iex), "IoCtrl.cf_bit_35", !pullup); + set_config(ti, config.at(iey).at(iex), "IoCtrl.cf_bit_35", + (!pullup) || (pullup_resistor != "100K")); + set_config(ti, config.at(iey).at(iex), "IoCtrl.cf_bit_32", pullup && pullup_resistor == "3P3K"); + set_config(ti, config.at(iey).at(iex), "IoCtrl.cf_bit_33", pullup && pullup_resistor == "6P8K"); + set_config(ti, config.at(iey).at(iex), "IoCtrl.cf_bit_34", pullup && pullup_resistor == "10K"); } } } else { diff --git a/ice40/pcf.cc b/ice40/pcf.cc index ce453af9..a351b95d 100644 --- a/ice40/pcf.cc +++ b/ice40/pcf.cc @@ -47,17 +47,43 @@ bool apply_pcf(Context *ctx, std::string filename, std::istream &in) if (words.size() == 0) continue; std::string cmd = words.at(0); + bool nowarn = false; if (cmd == "set_io") { size_t args_end = 1; - while (args_end < words.size() && words.at(args_end).at(0) == '-') + std::vector> extra_attrs; + while (args_end < words.size() && words.at(args_end).at(0) == '-') { + const auto &setting = words.at(args_end); + if (setting == "-pullup") { + const auto &value = words.at(++args_end); + if (value == "yes" || value == "1") + extra_attrs.emplace_back(std::make_pair(ctx->id("PULLUP"), "1")); + else if (value == "no" || value == "0") + extra_attrs.emplace_back(std::make_pair(ctx->id("PULLUP"), "0")); + else + log_error("Invalid value '%s' for -pullup (on line %d)\n", value.c_str(), lineno); + } else if (setting == "-pullup_resistor") { + const auto &value = words.at(++args_end); + if (ctx->args.type != ArchArgs::UP5K) + log_error("Pullup resistance can only be set on UP5K (on line %d)\n", lineno); + if (value != "3P3K" && value != "6P8K" && value != "10K" && value != "100K") + log_error("Invalid value '%s' for -pullup_resistor (on line %d)\n", value.c_str(), lineno); + extra_attrs.emplace_back(std::make_pair(ctx->id("PULLUP_RESISTOR"), value)); + } else if (setting == "-nowarn") { + nowarn = true; + } else if (setting == "--warn-no-port") { + } else { + log_warning("Ignoring PCF setting '%s' (on line %d)\n", setting.c_str(), lineno); + } args_end++; + } if (args_end >= words.size() - 1) log_error("expected PCF syntax 'set_io cell pin' (on line %d)\n", lineno); std::string cell = words.at(args_end); std::string pin = words.at(args_end + 1); auto fnd_cell = ctx->cells.find(ctx->id(cell)); if (fnd_cell == ctx->cells.end()) { - log_warning("unmatched constraint '%s' (on line %d)\n", cell.c_str(), lineno); + if (!nowarn) + log_warning("unmatched constraint '%s' (on line %d)\n", cell.c_str(), lineno); } else { BelId pin_bel = ctx->getPackagePinBel(pin); if (pin_bel == BelId()) @@ -67,6 +93,8 @@ bool apply_pcf(Context *ctx, std::string filename, std::istream &in) fnd_cell->second->attrs[ctx->id("BEL")] = ctx->getBelName(pin_bel).str(ctx); log_info("constrained '%s' to bel '%s'\n", cell.c_str(), fnd_cell->second->attrs[ctx->id("BEL")].c_str()); + for (const auto &attr : extra_attrs) + fnd_cell->second->attrs[attr.first] = attr.second; } } else { log_error("unsupported PCF command '%s' (on line %d)\n", cmd.c_str(), lineno); From 8f5d5003e99db83c87403f2f26a187e01b0e9bb0 Mon Sep 17 00:00:00 2001 From: David Shah Date: Fri, 21 Dec 2018 14:37:27 +0000 Subject: [PATCH 5/8] Clarify ICEBOX_ROOT parameter Signed-off-by: David Shah --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 86f7ef2d..5b79d1fb 100644 --- a/README.md +++ b/README.md @@ -49,8 +49,9 @@ Getting started ### nextpnr-ice40 -To build the iCE40 version of nextpnr, install [icestorm](http://www.clifford.at/icestorm/) with chipdbs installed in `/usr/local/share/icebox` -(or another location, which should be passed as -DICEBOX_ROOT=/path/to/icebox to CMake). +To build the iCE40 version of nextpnr, install [icestorm](http://www.clifford.at/icestorm/) with chipdbs installed in `/usr/local/share/icebox`, +or another location, which should be passed as `-DICEBOX_ROOT=/path/to/share/icebox` (ensure to point it to `share/icebox` and not where the +icebox binaries are installed) to CMake. Then build and install `nextpnr-ice40` using the following commands: ``` From e76479f379e4ba15b8f788cfb171c0de10feb076 Mon Sep 17 00:00:00 2001 From: David Shah Date: Sat, 22 Dec 2018 10:11:18 +0000 Subject: [PATCH 6/8] ecp5: Fix tristate IO insertion Fixes #191 Signed-off-by: David Shah --- ecp5/cells.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ecp5/cells.cc b/ecp5/cells.cc index 58d4797c..a8e92083 100644 --- a/ecp5/cells.cc +++ b/ecp5/cells.cc @@ -416,7 +416,7 @@ void nxio_to_tr(Context *ctx, CellInfo *nxio, CellInfo *trio, std::vectortype == ctx->id("$_TBUF_"); }, ctx->id("Y")); if (tbuf) { - replace_port(tbuf, ctx->id("I"), trio, ctx->id("I")); + replace_port(tbuf, ctx->id("A"), trio, ctx->id("I")); // Need to invert E to form T std::unique_ptr inv_lut = create_ecp5_cell(ctx, ctx->id("LUT4"), trio->name.str(ctx) + "$invert_T"); replace_port(tbuf, ctx->id("E"), inv_lut.get(), ctx->id("A")); From 1661350d2515a871a25d293e90f2315cb820b2be Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 25 Dec 2018 19:45:10 +0000 Subject: [PATCH 7/8] ecp5: Check for incorrect use of TRELLIS_IO 'B' pin Signed-off-by: David Shah --- ecp5/pack.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ecp5/pack.cc b/ecp5/pack.cc index cc91ca0e..84fce1c7 100644 --- a/ecp5/pack.cc +++ b/ecp5/pack.cc @@ -299,7 +299,16 @@ class Ecp5Packer // iobuf log_info("%s feeds TRELLIS_IO %s, removing %s %s.\n", ci->name.c_str(ctx), trio->name.c_str(ctx), ci->type.c_str(ctx), ci->name.c_str(ctx)); + NetInfo *net = trio->ports.at(ctx->id("B")).net; + if (((ci->type == ctx->id("$nextpnr_ibuf") || ci->type == ctx->id("$nextpnr_iobuf")) && + net->users.size() > 1) || + (ci->type == ctx->id("$nextpnr_obuf") && + (net->users.size() > 2 || net->driver.cell != nullptr)) || + (ci->type == ctx->id("$nextpnr_iobuf") && ci->ports.at(ctx->id("I")).net != nullptr && + ci->ports.at(ctx->id("I")).net->driver.cell != nullptr)) + log_error("Pin B of %s '%s' connected to more than a single top level IO.\n", + trio->type.c_str(ctx), trio->name.c_str(ctx)); if (net != nullptr) { ctx->nets.erase(net->name); trio->ports.at(ctx->id("B")).net = nullptr; From 4444a39fd481cafebb527850e9c7fff38d846154 Mon Sep 17 00:00:00 2001 From: David Shah Date: Wed, 26 Dec 2018 16:00:19 +0000 Subject: [PATCH 8/8] ice40: Improve handling of unconstrained IO Signed-off-by: David Shah --- ice40/main.cc | 7 +++++++ ice40/pack.cc | 3 --- ice40/pcf.cc | 16 ++++++++++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/ice40/main.cc b/ice40/main.cc index 543bd229..286f68db 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -70,6 +70,8 @@ po::options_description Ice40CommandHandler::getArchOptions() specific.add_options()("no-promote-globals", "disable all global promotion"); specific.add_options()("opt-timing", "run post-placement timing optimisation pass (experimental)"); specific.add_options()("tmfuzz", "run path delay estimate fuzzer"); + specific.add_options()("pcf-allow-unconstrained", "don't require PCF to constrain all IO"); + return specific; } void Ice40CommandHandler::validate() @@ -87,6 +89,8 @@ void Ice40CommandHandler::customAfterLoad(Context *ctx) std::ifstream pcf(filename); if (!apply_pcf(ctx, filename, pcf)) log_error("Loading PCF failed.\n"); + } else { + log_warning("No PCF file specified; IO pins will be placed automatically\n"); } } void Ice40CommandHandler::customBitstream(Context *ctx) @@ -164,6 +168,9 @@ std::unique_ptr Ice40CommandHandler::createContext() ctx->settings[ctx->id("no_promote_globals")] = "1"; if (vm.count("opt-timing")) ctx->settings[ctx->id("opt_timing")] = "1"; + if (vm.count("pcf-allow-unconstrained")) + ctx->settings[ctx->id("pcf_allow_unconstrained")] = "1"; + return ctx; } diff --git a/ice40/pack.cc b/ice40/pack.cc index 536b1b16..27387a75 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -478,9 +478,6 @@ static void pack_io(Context *ctx) } packed_cells.insert(ci->name); std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(sb->attrs, sb->attrs.begin())); - if (!sb->attrs.count(ctx->id("BEL"))) - log_warning("IO '%s' is not constrained to a pin and will be automatically placed\n", - ci->name.c_str(ctx)); } else if (is_sb_io(ctx, ci) || is_sb_gb_io(ctx, ci)) { NetInfo *net = ci->ports.at(ctx->id("PACKAGE_PIN")).net; if ((net != nullptr) && (net->users.size() > 1)) diff --git a/ice40/pcf.cc b/ice40/pcf.cc index a351b95d..a8273dd6 100644 --- a/ice40/pcf.cc +++ b/ice40/pcf.cc @@ -21,6 +21,7 @@ #include "pcf.h" #include #include "log.h" +#include "util.h" NEXTPNR_NAMESPACE_BEGIN @@ -100,6 +101,21 @@ bool apply_pcf(Context *ctx, std::string filename, std::istream &in) log_error("unsupported PCF command '%s' (on line %d)\n", cmd.c_str(), lineno); } } + for (auto cell : sorted(ctx->cells)) { + CellInfo *ci = cell.second; + if (ci->type == ctx->id("$nextpnr_ibuf") || ci->type == ctx->id("$nextpnr_obuf") || + ci->type == ctx->id("$nextpnr_iobuf")) { + if (!ci->attrs.count(ctx->id("BEL"))) { + if (bool_or_default(ctx->settings, ctx->id("pcf_allow_unconstrained"))) + log_warning("IO '%s' is unconstrained in PCF and will be automatically placed\n", + cell.first.c_str(ctx)); + else + log_error("IO '%s' is unconstrained in PCF (override this error with " + "--pcf-allow-unconstrained)\n", + cell.first.c_str(ctx)); + } + } + } ctx->settings.emplace(ctx->id("input/pcf"), filename); return true; } catch (log_execution_error_exception) {