diff options
-rw-r--r-- | README.md | 4 | ||||
-rw-r--r-- | common/util.h | 20 | ||||
-rw-r--r-- | ecp5/bitstream.cc | 7 | ||||
-rw-r--r-- | ecp5/cells.cc | 17 | ||||
-rw-r--r-- | ice40/cells.cc | 19 |
5 files changed, 58 insertions, 9 deletions
@@ -97,7 +97,9 @@ such as pack, place, route, and write output files.) ### nextpnr-ecp5 For ECP5 support, you must download [Project Trellis](https://github.com/SymbiFlow/prjtrellis), -then follow its instructions to download the latest database and build _libtrellis_. +then follow its instructions to download the latest database and build _libtrellis_. +(for example: `-DTRELLIS_INSTALL_PREFIX=/usr` tells nextpnr to look in `/usr/share/trellis` +and `/usr/lib/trellis`) ``` cmake -DARCH=ecp5 -DTRELLIS_INSTALL_PREFIX=/path/to/prjtrellis . diff --git a/common/util.h b/common/util.h index 2ccfe5d2..9512bd40 100644 --- a/common/util.h +++ b/common/util.h @@ -25,6 +25,8 @@ #include <string> #include "nextpnr.h" +#include "log.h" + NEXTPNR_NAMESPACE_BEGIN // Get a value from a map-style container, returning default if value is not @@ -47,8 +49,9 @@ std::string str_or_default(const Container &ct, const KeyType &key, std::string auto found = ct.find(key); if (found == ct.end()) return def; - else + else { return found->second; + } }; template <typename KeyType> @@ -57,8 +60,11 @@ std::string str_or_default(const std::unordered_map<KeyType, Property> &ct, cons auto found = ct.find(key); if (found == ct.end()) return def; - else + else { + if (!found->second.is_string) + log_error("Expecting string value but got integer %d.\n", int(found->second.intval)); return found->second.as_string(); + } }; // Get a value from a map-style container, converting to int, and returning @@ -79,9 +85,13 @@ int int_or_default(const std::unordered_map<KeyType, Property> &ct, const KeyTyp if (found == ct.end()) return def; else { - if (found->second.is_string) - return std::stoi(found->second.as_string()); - else + if (found->second.is_string) { + try { + return std::stoi(found->second.as_string()); + } catch (std::invalid_argument &e) { + log_error("Expecting numeric value but got '%s'.\n", found->second.as_string().c_str()); + } + } else return found->second.as_int64(); } }; diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc index bc8a6c55..1bdb4188 100644 --- a/ecp5/bitstream.cc +++ b/ecp5/bitstream.cc @@ -650,7 +650,7 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex } // Find bank voltages std::unordered_map<int, IOVoltage> bankVcc; - std::unordered_map<int, bool> bankLvds, bankVref; + std::unordered_map<int, bool> bankLvds, bankVref, bankDiff; for (auto &cell : ctx->cells) { CellInfo *ci = cell.second.get(); @@ -675,6 +675,8 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex if (iotype == "LVDS") bankLvds[bank] = true; + if ((dir == "INPUT" || dir == "BIDIR") && is_differential(ioType_from_str(iotype))) + bankDiff[bank] = true; if ((dir == "INPUT" || dir == "BIDIR") && is_referenced(ioType_from_str(iotype))) bankVref[bank] = true; } @@ -698,6 +700,9 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex cc.tiles[tile.first].add_enum("BANK.DIFF_REF", "ON"); cc.tiles[tile.first].add_enum("BANK.LVDSO", "ON"); } + if (bankDiff[bank]) { + cc.tiles[tile.first].add_enum("BANK.DIFF_REF", "ON"); + } if (bankVref[bank]) { cc.tiles[tile.first].add_enum("BANK.DIFF_REF", "ON"); cc.tiles[tile.first].add_enum("BANK.VREF", "ON"); diff --git a/ecp5/cells.cc b/ecp5/cells.cc index c630c2c3..7f9f1579 100644 --- a/ecp5/cells.cc +++ b/ecp5/cells.cc @@ -432,7 +432,13 @@ void nxio_to_tr(Context *ctx, CellInfo *nxio, CellInfo *trio, std::vector<std::u replace_port(nxio, ctx->id("I"), trio, ctx->id("I")); } else if (nxio->type == ctx->id("$nextpnr_iobuf")) { // N.B. tristate will be dealt with below - trio->params[ctx->id("DIR")] = std::string("BIDIR"); + NetInfo *i = get_net_or_empty(nxio, ctx->id("I")); + if (i == nullptr || i->driver.cell == nullptr) + trio->params[ctx->id("DIR")] = std::string("INPUT"); + else { + log_info("%s: %s.%s\n", ctx->nameOf(i), ctx->nameOf(i->driver.cell), ctx->nameOf(i->driver.port)); + trio->params[ctx->id("DIR")] = std::string("BIDIR"); + } replace_port(nxio, ctx->id("I"), trio, ctx->id("I")); replace_port(nxio, ctx->id("O"), trio, ctx->id("O")); } else { @@ -446,6 +452,15 @@ void nxio_to_tr(Context *ctx, CellInfo *nxio, CellInfo *trio, std::vector<std::u if (dinet != nullptr && dinet->name == nxio->name) rename_net(ctx, dinet, ctx->id(dinet->name.str(ctx) + "$TRELLIS_IO_IN")); + if (ctx->nets.count(nxio->name)) { + int i = 0; + IdString new_name; + do { + new_name = ctx->id(nxio->name.str(ctx) + "$rename$" + std::to_string(i++)); + } while (ctx->nets.count(new_name)); + rename_net(ctx, ctx->nets.at(nxio->name).get(), new_name); + } + // Create a new top port net for accurate IO timing analysis and simulation netlists if (ctx->ports.count(nxio->name)) { IdString tn_netname = nxio->name; diff --git a/ice40/cells.cc b/ice40/cells.cc index f1901c43..d23b6c49 100644 --- a/ice40/cells.cc +++ b/ice40/cells.cc @@ -22,6 +22,7 @@ #include "cells.h" #include "design_utils.h" #include "log.h" +#include "util.h" NEXTPNR_NAMESPACE_BEGIN @@ -424,7 +425,14 @@ void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio, std::unordered_set replace_port(nxio, ctx->id("I"), sbio, ctx->id("D_OUT_0")); } else if (nxio->type == ctx->id("$nextpnr_iobuf")) { // N.B. tristate will be dealt with below - sbio->params[ctx->id("PIN_TYPE")] = 25; + NetInfo *i = get_net_or_empty(nxio, ctx->id("I")); + if (i == nullptr || i->driver.cell == nullptr) + sbio->params[ctx->id("PIN_TYPE")] = 1; + else + sbio->params[ctx->id("PIN_TYPE")] = 25; + auto pu_attr = nxio->attrs.find(ctx->id("PULLUP")); + if (pu_attr != nxio->attrs.end()) + sbio->params[ctx->id("PULLUP")] = pu_attr->second; replace_port(nxio, ctx->id("I"), sbio, ctx->id("D_OUT_0")); replace_port(nxio, ctx->id("O"), sbio, ctx->id("D_IN_0")); } else { @@ -438,6 +446,15 @@ void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio, std::unordered_set if (dinet != nullptr && dinet->name == nxio->name) rename_net(ctx, dinet, ctx->id(dinet->name.str(ctx) + "$SB_IO_IN")); + if (ctx->nets.count(nxio->name)) { + int i = 0; + IdString new_name; + do { + new_name = ctx->id(nxio->name.str(ctx) + "$rename$" + std::to_string(i++)); + } while (ctx->nets.count(new_name)); + rename_net(ctx, ctx->nets.at(nxio->name).get(), new_name); + } + // Create a new top port net for accurate IO timing analysis and simulation netlists if (ctx->ports.count(nxio->name)) { IdString tn_netname = nxio->name; |