Merge branch 'master' into xc7

This commit is contained in:
Eddie Hung 2018-12-26 17:11:58 -08:00
commit 463d9a6920
8 changed files with 97 additions and 15 deletions

View File

@ -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:
```

View File

@ -51,6 +51,7 @@ std::vector<CellChain> find_chains(const Context *ctx, F1 cell_type_predicate, F
CellChain chain;
CellInfo *end = start;
while (end != nullptr) {
if (chained.insert(end->name).second)
chain.cells.push_back(end);
end = get_next(ctx, end);
}

View File

@ -416,7 +416,7 @@ void nxio_to_tr(Context *ctx, CellInfo *nxio, CellInfo *trio, std::vector<std::u
ctx, donet, [](const Context *ctx, const CellInfo *cell) { return cell->type == 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<CellInfo> 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"));

View File

@ -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;
@ -1497,6 +1506,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);

View File

@ -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 {

View File

@ -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<Context> 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;
}

View File

@ -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))
@ -1181,20 +1178,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")) {
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);

View File

@ -21,6 +21,7 @@
#include "pcf.h"
#include <sstream>
#include "log.h"
#include "util.h"
NEXTPNR_NAMESPACE_BEGIN
@ -47,16 +48,42 @@ 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<std::pair<IdString, std::string>> 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()) {
if (!nowarn)
log_warning("unmatched constraint '%s' (on line %d)\n", cell.c_str(), lineno);
} else {
BelId pin_bel = ctx->getPackagePinBel(pin);
@ -67,11 +94,28 @@ 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);
}
}
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) {