Merge branch 'master' into xc7
This commit is contained in:
commit
463d9a6920
@ -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:
|
||||
|
||||
```
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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"));
|
||||
|
13
ecp5/pack.cc
13
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;
|
||||
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
46
ice40/pcf.cc
46
ice40/pcf.cc
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user