diff options
author | Eddie Hung <eddie.hung+gitlab@gmail.com> | 2018-07-23 14:14:18 +0000 |
---|---|---|
committer | Eddie Hung <eddie.hung+gitlab@gmail.com> | 2018-07-23 14:14:18 +0000 |
commit | 14c33cd197b420da1ef9a5a2ed5c19e4490ba7c9 (patch) | |
tree | 79af7f375362eeae2a0d9ee96c1bc6f09ab8fcce | |
parent | dfdeb21690181044a95c2b2d64c197c999507b0c (diff) | |
parent | e647604e2a584917ad2fc9acfe838a1395c613c2 (diff) | |
download | nextpnr-14c33cd197b420da1ef9a5a2ed5c19e4490ba7c9.tar.gz nextpnr-14c33cd197b420da1ef9a5a2ed5c19e4490ba7c9.tar.bz2 nextpnr-14c33cd197b420da1ef9a5a2ed5c19e4490ba7c9.zip |
Merge branch 'master' into 'master'
Master
See merge request eddiehung/nextpnr!7
-rw-r--r-- | common/archcheck.cc | 146 | ||||
-rw-r--r-- | common/log.h | 6 | ||||
-rw-r--r-- | common/nextpnr.cc | 61 | ||||
-rw-r--r-- | common/nextpnr.h | 202 | ||||
-rw-r--r-- | common/place_common.cc | 4 | ||||
-rw-r--r-- | common/placer1.cc | 15 | ||||
-rw-r--r-- | common/router1.cc | 276 | ||||
-rw-r--r-- | ecp5/arch.cc | 72 | ||||
-rw-r--r-- | ecp5/arch.h | 69 | ||||
-rwxr-xr-x | ecp5/trellis_import.py | 28 | ||||
-rw-r--r-- | generic/arch.cc | 58 | ||||
-rw-r--r-- | generic/arch.h | 21 | ||||
-rw-r--r-- | gui/designwidget.cc | 23 | ||||
-rw-r--r-- | gui/fpgaviewwidget.cc | 202 | ||||
-rw-r--r-- | gui/fpgaviewwidget.h | 114 | ||||
-rw-r--r-- | gui/ice40/mainwindow.cc | 2 | ||||
-rw-r--r-- | ice40/arch.cc | 49 | ||||
-rw-r--r-- | ice40/arch.h | 72 | ||||
-rw-r--r-- | ice40/arch_place.cc | 2 | ||||
-rw-r--r-- | ice40/arch_pybindings.cc | 10 | ||||
-rw-r--r-- | ice40/bitstream.cc | 85 | ||||
-rw-r--r-- | ice40/chipdb.py | 120 | ||||
-rw-r--r-- | ice40/main.cc | 30 |
23 files changed, 1077 insertions, 590 deletions
diff --git a/common/archcheck.cc b/common/archcheck.cc new file mode 100644 index 00000000..5c4ef26c --- /dev/null +++ b/common/archcheck.cc @@ -0,0 +1,146 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "nextpnr.h" +#include "log.h" + +#if 0 +#define dbg(...) log(__VA_ARGS__) +#else +#define dbg(...) +#endif + +USING_NEXTPNR_NAMESPACE + +namespace { + +void archcheck_names(const Context *ctx) +{ + log_info("Checking entity names.\n"); + + log_info("Checking bel names..\n"); + for (BelId bel : ctx->getBels()) { + IdString name = ctx->getBelName(bel); + BelId bel2 = ctx->getBelByName(name); + log_assert(bel == bel2); + } + + log_info("Checking wire names..\n"); + for (WireId wire : ctx->getWires()) { + IdString name = ctx->getWireName(wire); + WireId wire2 = ctx->getWireByName(name); + log_assert(wire == wire2); + } + + log_info("Checking pip names..\n"); + for (PipId pip : ctx->getPips()) { + IdString name = ctx->getPipName(pip); + PipId pip2 = ctx->getPipByName(name); + log_assert(pip == pip2); + } + + log_break(); +} + +void archcheck_locs(const Context *ctx) +{ + log_info("Checking location data.\n"); + + log_info("Checking all bels..\n"); + for (BelId bel : ctx->getBels()) { + log_assert(bel != BelId()); + dbg("> %s\n", ctx->getBelName(bel).c_str(ctx)); + + Loc loc = ctx->getBelLocation(bel); + dbg(" ... %d %d %d\n", loc.x, loc.y, loc.z); + + log_assert(0 <= loc.x); + log_assert(0 <= loc.y); + log_assert(0 <= loc.z); + log_assert(loc.x < ctx->getGridDimX()); + log_assert(loc.y < ctx->getGridDimY()); + log_assert(loc.z < ctx->getTileDimZ(loc.x, loc.y)); + + BelId bel2 = ctx->getBelByLocation(loc); + dbg(" ... %s\n", ctx->getBelName(bel2).c_str(ctx)); + log_assert(bel == bel2); + } + + log_info("Checking all locations..\n"); + for (int x = 0; x < ctx->getGridDimX(); x++) + for (int y = 0; y < ctx->getGridDimY(); y++) + { + dbg("> %d %d\n", x, y); + std::unordered_set<int> usedz; + + for (int z = 0; z < ctx->getTileDimZ(x, y); z++) { + BelId bel = ctx->getBelByLocation(Loc(x, y, z)); + if (bel == BelId()) + continue; + Loc loc = ctx->getBelLocation(bel); + dbg(" + %d %s\n", z, ctx->getBelName(bel).c_str(ctx)); + log_assert(x == loc.x); + log_assert(y == loc.y); + log_assert(z == loc.z); + usedz.insert(z); + } + + for (BelId bel : ctx->getBelsByTile(x, y)) { + Loc loc = ctx->getBelLocation(bel); + dbg(" - %d %s\n", loc.z, ctx->getBelName(bel).c_str(ctx)); + log_assert(x == loc.x); + log_assert(y == loc.y); + log_assert(usedz.count(loc.z)); + usedz.erase(loc.z); + } + + log_assert(usedz.empty()); + } + + log_break(); +} + +void archcheck_conn(const Context *ctx) +{ +#if 0 + log_info("Checking connectivity data.\n"); + + log_info("Checking all wires..\n"); + for (WireId wire : ctx->getWires()) + { + ... + } +#endif +} + +} // namespace + +NEXTPNR_NAMESPACE_BEGIN + +void Context::archcheck() const +{ + log_info("Running architecture database integrity check.\n"); + log_break(); + + archcheck_names(this); + archcheck_locs(this); + archcheck_conn(this); +} + +NEXTPNR_NAMESPACE_END diff --git a/common/log.h b/common/log.h index c3607e39..35450311 100644 --- a/common/log.h +++ b/common/log.h @@ -69,17 +69,13 @@ NPNR_NORETURN void log_cmd_error(const char *format, ...) NPNR_ATTRIBUTE(format( void log_break(); void log_flush(); -#ifndef NDEBUG static inline void log_assert_worker(bool cond, const char *expr, const char *file, int line) { if (!cond) log_error("Assert `%s' failed in %s:%d.\n", expr, file, line); } #define log_assert(_assert_expr_) \ - YOSYS_NAMESPACE_PREFIX log_assert_worker(_assert_expr_, #_assert_expr_, __FILE__, __LINE__) -#else -#define log_assert(_assert_expr_) -#endif + NEXTPNR_NAMESPACE_PREFIX log_assert_worker(_assert_expr_, #_assert_expr_, __FILE__, __LINE__) #define log_abort() log_error("Abort in %s:%d.\n", __FILE__, __LINE__) #define log_ping() log("-- %s:%d %s --\n", __FILE__, __LINE__, __PRETTY_FUNCTION__) diff --git a/common/nextpnr.cc b/common/nextpnr.cc index 3861e5fe..2c50c9a1 100644 --- a/common/nextpnr.cc +++ b/common/nextpnr.cc @@ -51,6 +51,67 @@ void IdString::initialize_add(const BaseCtx *ctx, const char *s, int idx) ctx->idstring_idx_to_str->push_back(&insert_rc.first->first); } +WireId Context::getNetinfoSourceWire(NetInfo *net_info) const +{ + if (net_info->driver.cell == nullptr) + return WireId(); + + auto src_bel = net_info->driver.cell->bel; + + if (src_bel == BelId()) + return WireId(); + + IdString driver_port = net_info->driver.port; + + auto driver_port_it = net_info->driver.cell->pins.find(driver_port); + if (driver_port_it != net_info->driver.cell->pins.end()) + driver_port = driver_port_it->second; + + return getBelPinWire(src_bel, portPinFromId(driver_port)); +} + +WireId Context::getNetinfoSinkWire(NetInfo *net_info, int user_idx) const +{ + auto &user_info = net_info->users[user_idx]; + auto dst_bel = user_info.cell->bel; + + if (dst_bel == BelId()) + return WireId(); + + IdString user_port = user_info.port; + + auto user_port_it = user_info.cell->pins.find(user_port); + + if (user_port_it != user_info.cell->pins.end()) + user_port = user_port_it->second; + + return getBelPinWire(dst_bel, portPinFromId(user_port)); +} + +delay_t Context::getNetinfoRouteDelay(NetInfo *net_info, int user_idx) const +{ + WireId src_wire = getNetinfoSourceWire(net_info); + WireId cursor = getNetinfoSinkWire(net_info, user_idx); + delay_t delay = 0; + + while (cursor != WireId() && cursor != src_wire) { + auto it = net_info->wires.find(cursor); + if (it == net_info->wires.end()) + break; + PipId pip = it->second.pip; + delay += getPipDelay(pip).maxDelay(); + delay += getWireDelay(cursor).maxDelay(); + cursor = getPipSrcWire(pip); + } + + if (cursor == src_wire) + delay += getWireDelay(src_wire).maxDelay(); + else + delay += estimateDelay(src_wire, cursor); + + return delay; +} + static uint32_t xorshift32(uint32_t x) { x ^= x << 13; diff --git a/common/nextpnr.h b/common/nextpnr.h index 40fd3d13..021772fe 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -2,6 +2,7 @@ * nextpnr -- Next Generation Place and Route * * Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com> + * Copyright (C) 2018 Serge Bazanski <q3k@symbioticeda.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -19,7 +20,10 @@ #include <algorithm> #include <assert.h> +#include <condition_variable> #include <memory> +#include <mutex> +#include <pthread.h> #include <stdexcept> #include <stdint.h> #include <string> @@ -164,6 +168,9 @@ struct Loc { int x = -1, y = -1, z = -1; + Loc() {} + Loc(int x, int y, int z) : x(x), y(y), z(z) {} + bool operator==(const Loc &other) const { return (x == other.x) && (y == other.y) && (z == other.z); } bool operator!=(const Loc &other) const { return (x != other.x) || (y != other.y) || (z == other.z); } }; @@ -267,19 +274,87 @@ struct CellInfo : ArchCellInfo std::unordered_map<IdString, IdString> pins; }; -struct BaseCtx +struct DeterministicRNG { - // -------------------------------------------------------------- + uint64_t rngstate; - mutable std::unordered_map<std::string, int> *idstring_str_to_idx; - mutable std::vector<const std::string *> *idstring_idx_to_str; + DeterministicRNG() : rngstate(0x3141592653589793) {} - IdString id(const std::string &s) const { return IdString(this, s); } + uint64_t rng64() + { + // xorshift64star + // https://arxiv.org/abs/1402.6246 - IdString id(const char *s) const { return IdString(this, s); } + uint64_t retval = rngstate * 0x2545F4914F6CDD1D; - // -------------------------------------------------------------- + rngstate ^= rngstate >> 12; + rngstate ^= rngstate << 25; + rngstate ^= rngstate >> 27; + + return retval; + } + int rng() { return rng64() & 0x3fffffff; } + + int rng(int n) + { + assert(n > 0); + + // round up to power of 2 + int m = n - 1; + m |= (m >> 1); + m |= (m >> 2); + m |= (m >> 4); + m |= (m >> 8); + m |= (m >> 16); + m += 1; + + while (1) { + int x = rng64() & (m - 1); + if (x < n) + return x; + } + } + + void rngseed(uint64_t seed) + { + rngstate = seed ? seed : 0x3141592653589793; + for (int i = 0; i < 5; i++) + rng64(); + } + + template <typename T> void shuffle(std::vector<T> &a) + { + for (size_t i = 0; i != a.size(); i++) { + size_t j = i + rng(a.size() - i); + if (j > i) + std::swap(a[i], a[j]); + } + } + + template <typename T> void sorted_shuffle(std::vector<T> &a) + { + std::sort(a.begin(), a.end()); + shuffle(a); + } +}; + +struct BaseCtx +{ + // Lock to perform mutating actions on the Context. + std::mutex mutex; + pthread_t mutex_owner; + + // Lock to be taken by UI when wanting to access context - the yield() + // method will lock/unlock it when its' released the main mutex to make + // sure the UI is not starved. + std::mutex ui_mutex; + + // ID String database. + mutable std::unordered_map<std::string, int> *idstring_str_to_idx; + mutable std::vector<const std::string *> *idstring_idx_to_str; + + // Placed nets and cells. std::unordered_map<IdString, std::unique_ptr<NetInfo>> nets; std::unordered_map<IdString, std::unique_ptr<CellInfo>> cells; @@ -297,13 +372,57 @@ struct BaseCtx delete idstring_idx_to_str; } + // Must be called before performing any mutating changes on the Ctx/Arch. + void lock(void) + { + mutex.lock(); + mutex_owner = pthread_self(); + } + + void unlock(void) + { + NPNR_ASSERT(pthread_equal(pthread_self(), mutex_owner) != 0); + mutex.unlock(); + } + + // Must be called by the UI before rendering data. This lock will be + // prioritized when processing code calls yield(). + void lock_ui(void) + { + ui_mutex.lock(); + mutex.lock(); + } + + void unlock_ui(void) + { + mutex.unlock(); + ui_mutex.unlock(); + } + + // Yield to UI by unlocking the main mutex, flashing the UI mutex and + // relocking the main mutex. Call this when you're performing a + // long-standing action while holding a lock to let the UI show + // visualization updates. + // Must be called with the main lock taken. + void yield(void) + { + unlock(); + ui_mutex.lock(); + ui_mutex.unlock(); + lock(); + } + + IdString id(const std::string &s) const { return IdString(this, s); } + + IdString id(const char *s) const { return IdString(this, s); } + Context *getCtx() { return reinterpret_cast<Context *>(this); } const Context *getCtx() const { return reinterpret_cast<const Context *>(this); } // -------------------------------------------------------------- - bool allUiReload = false; + bool allUiReload = true; bool frameUiReload = false; std::unordered_set<BelId> belUiReload; std::unordered_set<WireId> wireUiReload; @@ -329,7 +448,7 @@ NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_BEGIN -struct Context : Arch +struct Context : Arch, DeterministicRNG { bool verbose = false; bool debug = false; @@ -341,74 +460,19 @@ struct Context : Arch // -------------------------------------------------------------- + WireId getNetinfoSourceWire(NetInfo *net_info) const; + WireId getNetinfoSinkWire(NetInfo *net_info, int user_idx) const; + delay_t getNetinfoRouteDelay(NetInfo *net_info, int user_idx) const; + // provided by router1.cc bool getActualRouteDelay(WireId src_wire, WireId dst_wire, delay_t &delay); // -------------------------------------------------------------- - uint64_t rngstate = 0x3141592653589793; - - uint64_t rng64() - { - // xorshift64star - // https://arxiv.org/abs/1402.6246 - - uint64_t retval = rngstate * 0x2545F4914F6CDD1D; - - rngstate ^= rngstate >> 12; - rngstate ^= rngstate << 25; - rngstate ^= rngstate >> 27; - - return retval; - } - - int rng() { return rng64() & 0x3fffffff; } - - int rng(int n) - { - assert(n > 0); - - // round up to power of 2 - int m = n - 1; - m |= (m >> 1); - m |= (m >> 2); - m |= (m >> 4); - m |= (m >> 8); - m |= (m >> 16); - m += 1; - - while (1) { - int x = rng64() & (m - 1); - if (x < n) - return x; - } - } - - void rngseed(uint64_t seed) - { - rngstate = seed ? seed : 0x3141592653589793; - for (int i = 0; i < 5; i++) - rng64(); - } - - template <typename T> void shuffle(std::vector<T> &a) - { - for (size_t i = 0; i != a.size(); i++) { - size_t j = i + rng(a.size() - i); - if (j > i) - std::swap(a[i], a[j]); - } - } - - template <typename T> void sorted_shuffle(std::vector<T> &a) - { - std::sort(a.begin(), a.end()); - shuffle(a); - } - uint32_t checksum() const; void check() const; + void archcheck() const; }; NEXTPNR_NAMESPACE_END diff --git a/common/place_common.cc b/common/place_common.cc index 370eff23..95b7b2aa 100644 --- a/common/place_common.cc +++ b/common/place_common.cc @@ -36,7 +36,7 @@ wirelen_t get_net_metric(const Context *ctx, const NetInfo *net, MetricType type if (driver_cell->bel == BelId()) return 0; ctx->estimatePosition(driver_cell->bel, driver_x, driver_y, driver_gb); - WireId drv_wire = ctx->getWireBelPin(driver_cell->bel, ctx->portPinFromId(net->driver.port)); + WireId drv_wire = ctx->getBelPinWire(driver_cell->bel, ctx->portPinFromId(net->driver.port)); if (driver_gb) return 0; float worst_slack = 1000; @@ -48,7 +48,7 @@ wirelen_t get_net_metric(const Context *ctx, const NetInfo *net, MetricType type if (load_cell->bel == BelId()) continue; if (ctx->timing_driven && type == MetricType::COST) { - WireId user_wire = ctx->getWireBelPin(load_cell->bel, ctx->portPinFromId(load.port)); + WireId user_wire = ctx->getBelPinWire(load_cell->bel, ctx->portPinFromId(load.port)); delay_t raw_wl = ctx->estimateDelay(drv_wire, user_wire); float slack = ctx->getDelayNS(load.budget) - ctx->getDelayNS(raw_wl); if (slack < 0) diff --git a/common/placer1.cc b/common/placer1.cc index 74a11040..025c7c15 100644 --- a/common/placer1.cc +++ b/common/placer1.cc @@ -80,6 +80,7 @@ class SAPlacer size_t placed_cells = 0; // Initial constraints placer + ctx->lock(); for (auto &cell_entry : ctx->cells) { CellInfo *cell = cell_entry.second.get(); auto loc = cell->attrs.find(ctx->id("BEL")); @@ -118,16 +119,19 @@ class SAPlacer } std::sort(autoplaced.begin(), autoplaced.end(), [](CellInfo *a, CellInfo *b) { return a->name < b->name; }); ctx->shuffle(autoplaced); + ctx->unlock(); // Place cells randomly initially log_info("Creating initial placement for remaining %d cells.\n", int(autoplaced.size())); for (auto cell : autoplaced) { + ctx->lock(); place_initial(cell); placed_cells++; if ((placed_cells - constr_placed_cells) % 500 == 0) log_info(" initial placement placed %d/%d cells\n", int(placed_cells - constr_placed_cells), int(autoplaced.size())); + ctx->unlock(); } if ((placed_cells - constr_placed_cells) % 500 != 0) log_info(" initial placement placed %d/%d cells\n", int(placed_cells - constr_placed_cells), @@ -136,6 +140,7 @@ class SAPlacer log_info("Running simulated annealing placer.\n"); // Calculate metric after initial placement + ctx->lock(); curr_metric = 0; curr_tns = 0; for (auto &net : ctx->nets) { @@ -143,6 +148,7 @@ class SAPlacer metrics[net.first] = wl; curr_metric += wl; } + ctx->unlock(); int n_no_progress = 0; double avg_metric = curr_metric; @@ -169,6 +175,7 @@ class SAPlacer try_swap_position(cell, try_bel); } } + // Heuristic to improve placement on the 8k if (improved) n_no_progress = 0; @@ -178,6 +185,7 @@ class SAPlacer if (temp <= 1e-3 && n_no_progress >= 5) { if (iter % 5 != 0) log_info(" at iteration #%d: temp = %f, cost = %f\n", iter, temp, double(curr_metric)); + ctx->unlock(); break; } @@ -232,8 +240,12 @@ class SAPlacer metrics[net.first] = wl; curr_metric += wl; } + + // Let the UI show visualization updates. + ctx->yield(); } // Final post-pacement validitiy check + ctx->lock(); for (auto bel : ctx->getBels()) { IdString cell = ctx->getBoundBelCell(bel); if (!ctx->isBelLocationValid(bel)) { @@ -251,6 +263,7 @@ class SAPlacer } } } + ctx->unlock(); return true; } @@ -436,7 +449,9 @@ bool placer1(Context *ctx) placer.place(); log_info("Checksum: 0x%08x\n", ctx->checksum()); #ifndef NDEBUG + ctx->lock(); ctx->check(); + ctx->unlock(); #endif return true; } catch (log_execution_error_exception) { diff --git a/common/router1.cc b/common/router1.cc index 1ea50448..fbf3c467 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -251,7 +251,8 @@ struct Router } } - Router(Context *ctx, RipupScoreboard &scores, IdString net_name, int user_idx = -1, bool reroute = false, bool ripup = false, delay_t ripup_penalty = 0) + Router(Context *ctx, RipupScoreboard &scores, IdString net_name, int user_idx = -1, bool reroute = false, + bool ripup = false, delay_t ripup_penalty = 0) : ctx(ctx), scores(scores), net_name(net_name), ripup(ripup), ripup_penalty(ripup_penalty) { auto net_info = ctx->nets.at(net_name).get(); @@ -262,42 +263,26 @@ struct Router if (ctx->debug) log(" Source: %s.%s.\n", net_info->driver.cell->name.c_str(ctx), net_info->driver.port.c_str(ctx)); - auto src_bel = net_info->driver.cell->bel; - - if (src_bel == BelId()) - log_error("Source cell %s (%s) is not mapped to a bel.\n", net_info->driver.cell->name.c_str(ctx), - net_info->driver.cell->type.c_str(ctx)); - - if (ctx->debug) - log(" Source bel: %s\n", ctx->getBelName(src_bel).c_str(ctx)); - - IdString driver_port = net_info->driver.port; - - auto driver_port_it = net_info->driver.cell->pins.find(driver_port); - if (driver_port_it != net_info->driver.cell->pins.end()) - driver_port = driver_port_it->second; - - auto src_wire = ctx->getWireBelPin(src_bel, ctx->portPinFromId(driver_port)); + auto src_wire = ctx->getNetinfoSourceWire(net_info); if (src_wire == WireId()) - log_error("No wire found for port %s (pin %s) on source cell %s " - "(bel %s).\n", - net_info->driver.port.c_str(ctx), driver_port.c_str(ctx), net_info->driver.cell->name.c_str(ctx), - ctx->getBelName(src_bel).c_str(ctx)); + log_error("No wire found for port %s on source cell %s.\n", net_info->driver.port.c_str(ctx), + net_info->driver.cell->name.c_str(ctx)); if (ctx->debug) log(" Source wire: %s\n", ctx->getWireName(src_wire).c_str(ctx)); std::unordered_map<WireId, delay_t> src_wires; - std::vector<PortRef> users_array; + std::vector<int> users_array; if (user_idx < 0) { // route all users - users_array = net_info->users; + for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) + users_array.push_back(user_idx); ctx->shuffle(users_array); } else { // route only the selected user - users_array.push_back(net_info->users[user_idx]); + users_array.push_back(user_idx); } if (reroute) { @@ -311,32 +296,16 @@ struct Router ctx->bindWire(src_wire, net_name, STRENGTH_WEAK); src_wires[src_wire] = ctx->getWireDelay(src_wire).maxDelay(); - for (auto &user_it : net_info->users) { - auto dst_bel = user_it.cell->bel; - - if (dst_bel == BelId()) - log_error("Destination cell %s (%s) is not mapped to a bel.\n", user_it.cell->name.c_str(ctx), - user_it.cell->type.c_str(ctx)); - - if (ctx->debug) - log(" Destination bel: %s\n", ctx->getBelName(dst_bel).c_str(ctx)); - - IdString user_port = user_it.port; - - auto user_port_it = user_it.cell->pins.find(user_port); - - if (user_port_it != user_it.cell->pins.end()) - user_port = user_port_it->second; - - auto dst_wire = ctx->getWireBelPin(dst_bel, ctx->portPinFromId(user_port)); + for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) { + auto dst_wire = ctx->getNetinfoSinkWire(net_info, user_idx); if (dst_wire == WireId()) - log_error("No wire found for port %s (pin %s) on destination " - "cell %s (bel %s).\n", - user_it.port.c_str(ctx), user_port.c_str(ctx), user_it.cell->name.c_str(ctx), - ctx->getBelName(dst_bel).c_str(ctx)); + log_error("No wire found for port %s on destination cell %s.\n", + net_info->users[user_idx].port.c_str(ctx), + net_info->users[user_idx].cell->name.c_str(ctx)); - std::function<delay_t(WireId)> register_existing_path = [ctx, net_info, &src_wires, ®ister_existing_path](WireId wire) -> delay_t { + std::function<delay_t(WireId)> register_existing_path = + [ctx, net_info, &src_wires, ®ister_existing_path](WireId wire) -> delay_t { auto it = src_wires.find(wire); if (it != src_wires.end()) return it->second; @@ -345,7 +314,7 @@ struct Router delay_t delay = register_existing_path(ctx->getPipSrcWire(pip)); delay += ctx->getPipDelay(pip).maxDelay(); delay += ctx->getWireDelay(wire).maxDelay(); - delay -= 2*ctx->getDelayEpsilon(); + delay -= 2 * ctx->getDelayEpsilon(); src_wires[wire] = delay; return delay; @@ -361,7 +330,7 @@ struct Router } register_existing_path(dst_wire); - check_next_user_for_existing_path:; + check_next_user_for_existing_path:; } std::vector<WireId> ripup_wires; @@ -371,39 +340,22 @@ struct Router for (auto &it : ripup_wires) { if (ctx->debug) - log(" Unbind dangling wire for net %s: %s\n", - net_name.c_str(ctx), ctx->getWireName(it).c_str(ctx)); + log(" Unbind dangling wire for net %s: %s\n", net_name.c_str(ctx), + ctx->getWireName(it).c_str(ctx)); ctx->unbindWire(it); } } - for (auto &user_it : users_array) { + for (int user_idx : users_array) { if (ctx->debug) - log(" Route to: %s.%s.\n", user_it.cell->name.c_str(ctx), user_it.port.c_str(ctx)); - - auto dst_bel = user_it.cell->bel; + log(" Route to: %s.%s.\n", net_info->users[user_idx].cell->name.c_str(ctx), + net_info->users[user_idx].port.c_str(ctx)); - if (dst_bel == BelId()) - log_error("Destination cell %s (%s) is not mapped to a bel.\n", user_it.cell->name.c_str(ctx), - user_it.cell->type.c_str(ctx)); - - if (ctx->debug) - log(" Destination bel: %s\n", ctx->getBelName(dst_bel).c_str(ctx)); - - IdString user_port = user_it.port; - - auto user_port_it = user_it.cell->pins.find(user_port); - - if (user_port_it != user_it.cell->pins.end()) - user_port = user_port_it->second; - - auto dst_wire = ctx->getWireBelPin(dst_bel, ctx->portPinFromId(user_port)); + auto dst_wire = ctx->getNetinfoSinkWire(net_info, user_idx); if (dst_wire == WireId()) - log_error("No wire found for port %s (pin %s) on destination " - "cell %s (bel %s).\n", - user_it.port.c_str(ctx), user_port.c_str(ctx), user_it.cell->name.c_str(ctx), - ctx->getBelName(dst_bel).c_str(ctx)); + log_error("No wire found for port %s on destination cell %s.\n", + net_info->users[user_idx].port.c_str(ctx), net_info->users[user_idx].cell->name.c_str(ctx)); if (ctx->debug) { log(" Destination wire: %s\n", ctx->getWireName(dst_wire).c_str(ctx)); @@ -499,34 +451,19 @@ struct RouteJob }; }; -void addFullNetRouteJob(Context *ctx, IdString net_name, - std::unordered_map<IdString, std::vector<bool>> &cache, - std::priority_queue<RouteJob, std::vector<RouteJob>, RouteJob::Greater> &queue) +void addFullNetRouteJob(Context *ctx, IdString net_name, std::unordered_map<IdString, std::vector<bool>> &cache, + std::priority_queue<RouteJob, std::vector<RouteJob>, RouteJob::Greater> &queue) { NetInfo *net_info = ctx->nets.at(net_name).get(); if (net_info->driver.cell == nullptr) return; - auto src_bel = net_info->driver.cell->bel; - - if (src_bel == BelId()) - log_error("Source cell %s (%s) is not mapped to a bel.\n", net_info->driver.cell->name.c_str(ctx), - net_info->driver.cell->type.c_str(ctx)); - - IdString driver_port = net_info->driver.port; - - auto driver_port_it = net_info->driver.cell->pins.find(driver_port); - if (driver_port_it != net_info->driver.cell->pins.end()) - driver_port = driver_port_it->second; - - auto src_wire = ctx->getWireBelPin(src_bel, ctx->portPinFromId(driver_port)); + auto src_wire = ctx->getNetinfoSourceWire(net_info); if (src_wire == WireId()) - log_error("No wire found for port %s (pin %s) on source cell %s " - "(bel %s).\n", - net_info->driver.port.c_str(ctx), driver_port.c_str(ctx), net_info->driver.cell->name.c_str(ctx), - ctx->getBelName(src_bel).c_str(ctx)); + log_error("No wire found for port %s on source cell %s.\n", net_info->driver.port.c_str(ctx), + net_info->driver.cell->name.c_str(ctx)); auto &net_cache = cache[net_name]; @@ -541,46 +478,30 @@ void addFullNetRouteJob(Context *ctx, IdString net_name, bool got_slack = false; - for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) - { + for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) { if (net_cache[user_idx]) continue; - auto &user_info = net_info->users[user_idx]; - auto dst_bel = user_info.cell->bel; - - if (dst_bel == BelId()) - log_error("Destination cell %s (%s) is not mapped to a bel.\n", - user_info.cell->name.c_str(ctx), user_info.cell->type.c_str(ctx)); - - IdString user_port = user_info.port; - - auto user_port_it = user_info.cell->pins.find(user_port); - - if (user_port_it != user_info.cell->pins.end()) - user_port = user_port_it->second; - - auto dst_wire = ctx->getWireBelPin(dst_bel, ctx->portPinFromId(user_port)); + auto dst_wire = ctx->getNetinfoSinkWire(net_info, user_idx); if (dst_wire == WireId()) - log_error("No wire found for port %s (pin %s) on destination " - "cell %s (bel %s).\n", - user_info.port.c_str(ctx), user_port.c_str(ctx), user_info.cell->name.c_str(ctx), - ctx->getBelName(dst_bel).c_str(ctx)); + log_error("No wire found for port %s on destination cell %s.\n", net_info->users[user_idx].port.c_str(ctx), + net_info->users[user_idx].cell->name.c_str(ctx)); if (user_idx == 0) - job.slack = user_info.budget - ctx->estimateDelay(src_wire, dst_wire); + job.slack = net_info->users[user_idx].budget - ctx->estimateDelay(src_wire, dst_wire); else - job.slack = std::min(job.slack, user_info.budget - ctx->estimateDelay(src_wire, dst_wire)); + job.slack = std::min(job.slack, net_info->users[user_idx].budget - ctx->estimateDelay(src_wire, dst_wire)); WireId cursor = dst_wire; while (src_wire != cursor) { auto it = net_info->wires.find(cursor); if (it == net_info->wires.end()) { if (!got_slack) - job.slack = user_info.budget - ctx->estimateDelay(src_wire, dst_wire); + job.slack = net_info->users[user_idx].budget - ctx->estimateDelay(src_wire, dst_wire); else - job.slack = std::min(job.slack, user_info.budget - ctx->estimateDelay(src_wire, dst_wire)); + job.slack = std::min(job.slack, + net_info->users[user_idx].budget - ctx->estimateDelay(src_wire, dst_wire)); got_slack = true; break; } @@ -595,8 +516,7 @@ void addFullNetRouteJob(Context *ctx, IdString net_name, net_cache[user_idx] = true; } -void addNetRouteJobs(Context *ctx, IdString net_name, - std::unordered_map<IdString, std::vector<bool>> &cache, +void addNetRouteJobs(Context *ctx, IdString net_name, std::unordered_map<IdString, std::vector<bool>> &cache, std::priority_queue<RouteJob, std::vector<RouteJob>, RouteJob::Greater> &queue) { NetInfo *net_info = ctx->nets.at(net_name).get(); @@ -604,73 +524,35 @@ void addNetRouteJobs(Context *ctx, IdString net_name, if (net_info->driver.cell == nullptr) return; - auto src_bel = net_info->driver.cell->bel; - - if (src_bel == BelId()) - log_error("Source cell %s (%s) is not mapped to a bel.\n", net_info->driver.cell->name.c_str(ctx), - net_info->driver.cell->type.c_str(ctx)); - - IdString driver_port = net_info->driver.port; - - auto driver_port_it = net_info->driver.cell->pins.find(driver_port); - if (driver_port_it != net_info->driver.cell->pins.end()) - driver_port = driver_port_it->second; - - auto src_wire = ctx->getWireBelPin(src_bel, ctx->portPinFromId(driver_port)); + auto src_wire = ctx->getNetinfoSourceWire(net_info); if (src_wire == WireId()) - log_error("No wire found for port %s (pin %s) on source cell %s " - "(bel %s).\n", - net_info->driver.port.c_str(ctx), driver_port.c_str(ctx), net_info->driver.cell->name.c_str(ctx), - ctx->getBelName(src_bel).c_str(ctx)); + log_error("No wire found for port %s on source cell %s.\n", net_info->driver.port.c_str(ctx), + net_info->driver.cell->name.c_str(ctx)); auto &net_cache = cache[net_name]; if (net_cache.empty()) net_cache.resize(net_info->users.size()); - for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) - { + for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) { if (net_cache[user_idx]) continue; - auto &user_info = net_info->users[user_idx]; - auto dst_bel = user_info.cell->bel; - - if (dst_bel == BelId()) - log_error("Destination cell %s (%s) is not mapped to a bel.\n", - user_info.cell->name.c_str(ctx), user_info.cell->type.c_str(ctx)); - - IdString user_port = user_info.port; - - auto user_port_it = user_info.cell->pins.find(user_port); - - if (user_port_it != user_info.cell->pins.end()) - user_port = user_port_it->second; - - auto dst_wire = ctx->getWireBelPin(dst_bel, ctx->portPinFromId(user_port)); + auto dst_wire = ctx->getNetinfoSinkWire(net_info, user_idx); if (dst_wire == WireId()) - log_error("No wire found for port %s (pin %s) on destination " - "cell %s (bel %s).\n", - user_info.port.c_str(ctx), user_port.c_str(ctx), user_info.cell->name.c_str(ctx), - ctx->getBelName(dst_bel).c_str(ctx)); + log_error("No wire found for port %s on destination cell %s.\n", net_info->users[user_idx].port.c_str(ctx), + net_info->users[user_idx].cell->name.c_str(ctx)); WireId cursor = dst_wire; while (src_wire != cursor) { auto it = net_info->wires.find(cursor); if (it == net_info->wires.end()) { - if (ctx->debug) - log("Adding job [%s %d]: %s %s (%s) -> %s %s (%s)\n", - net_name.c_str(ctx), user_idx, - ctx->getBelName(src_bel).c_str(ctx), driver_port.c_str(ctx), - ctx->getWireName(src_wire).c_str(ctx), - ctx->getBelName(dst_bel).c_str(ctx), user_port.c_str(ctx), - ctx->getWireName(dst_wire).c_str(ctx)); RouteJob job; job.net = net_name; job.user_idx = user_idx; - job.slack = user_info.budget - ctx->estimateDelay(src_wire, dst_wire); + job.slack = net_info->users[user_idx].budget - ctx->estimateDelay(src_wire, dst_wire); job.randtag = ctx->rng(); queue.push(job); net_cache[user_idx] = true; @@ -695,6 +577,7 @@ bool router1(Context *ctx) log_break(); log_info("Routing..\n"); + ctx->lock(); std::unordered_map<IdString, std::vector<bool>> jobCache; std::priority_queue<RouteJob, std::vector<RouteJob>, RouteJob::Greater> jobQueue; @@ -735,7 +618,7 @@ bool router1(Context *ctx) bool printNets = ctx->verbose && (jobQueue.size() < 10); while (!jobQueue.empty()) { - if(ctx->debug) + if (ctx->debug) log("Next job slack: %f\n", double(jobQueue.top().slack)); auto net_name = jobQueue.top().net; @@ -744,8 +627,8 @@ bool router1(Context *ctx) if (printNets) { if (user_idx < 0) - log_info(" routing all %d users of net %s\n", - int(ctx->nets.at(net_name)->users.size()), net_name.c_str(ctx)); + log_info(" routing all %d users of net %s\n", int(ctx->nets.at(net_name)->users.size()), + net_name.c_str(ctx)); else log_info(" routing user %d of net %s\n", user_idx, net_name.c_str(ctx)); } @@ -766,15 +649,19 @@ bool router1(Context *ctx) normalRouteNets.insert(net_name); } - if ((ctx->verbose || iterCnt == 1) && !printNets && (jobCnt % 100 == 0)) + if ((ctx->verbose || iterCnt == 1) && !printNets && (jobCnt % 100 == 0)) { log_info(" processed %d jobs. (%d routed, %d failed)\n", jobCnt, jobCnt - failedCnt, failedCnt); + ctx->yield(); + } } NPNR_ASSERT(jobQueue.empty()); jobCache.clear(); - if ((ctx->verbose || iterCnt == 1) && (jobCnt % 100 != 0)) + if ((ctx->verbose || iterCnt == 1) && (jobCnt % 100 != 0)) { log_info(" processed %d jobs. (%d routed, %d failed)\n", jobCnt, jobCnt - failedCnt, failedCnt); + ctx->yield(); + } if (ctx->verbose) log_info(" visited %d PIPs (%.2f%% revisits, %.2f%% overtime " @@ -828,8 +715,10 @@ bool router1(Context *ctx) ripCnt += router.rippedNets.size(); - if ((ctx->verbose || iterCnt == 1) && !printNets && (netCnt % 100 == 0)) + if ((ctx->verbose || iterCnt == 1) && !printNets && (netCnt % 100 == 0)) { log_info(" routed %d nets, ripped %d nets.\n", netCnt, ripCnt); + ctx->yield(); + } } if ((ctx->verbose || iterCnt == 1) && (netCnt % 100 != 0)) @@ -847,9 +736,8 @@ bool router1(Context *ctx) } if (!ctx->verbose) - log_info("iteration %d: routed %d nets without ripup, routed %d nets with ripup.\n", - iterCnt, int(normalRouteNets.size()), int(ripupQueue.size())); - + log_info("iteration %d: routed %d nets without ripup, routed %d nets with ripup.\n", iterCnt, + int(normalRouteNets.size()), int(ripupQueue.size())); totalVisitCnt += visitCnt; totalRevisitCnt += revisitCnt; @@ -857,6 +745,8 @@ bool router1(Context *ctx) if (iterCnt == 8 || iterCnt == 16 || iterCnt == 32 || iterCnt == 64 || iterCnt == 128) ripup_penalty += ctx->getRipupDelayPenalty(); + + ctx->yield(); } log_info("routing complete after %d iterations.\n", iterCnt); @@ -866,6 +756,38 @@ bool router1(Context *ctx) totalVisitCnt, (100.0 * totalRevisitCnt) / totalVisitCnt, (100.0 * totalOvertimeRevisitCnt) / totalVisitCnt); + { + float tns = 0; + int tns_net_count = 0; + int tns_arc_count = 0; + for (auto &net_it : ctx->nets) { + bool got_negative_slack = false; + NetInfo *net_info = ctx->nets.at(net_it.first).get(); + for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) { + delay_t arc_delay = ctx->getNetinfoRouteDelay(net_info, user_idx); + delay_t arc_budget = net_info->users[user_idx].budget; + delay_t arc_slack = arc_budget - arc_delay; + if (arc_slack < 0) { + if (!got_negative_slack) { + if (ctx->verbose) + log_info("net %s has negative slack arcs:\n", net_info->name.c_str(ctx)); + tns_net_count++; + } + if (ctx->verbose) + log_info(" arc %s -> %s has %f ns slack (delay %f, budget %f)\n", + ctx->getWireName(ctx->getNetinfoSourceWire(net_info)).c_str(ctx), + ctx->getWireName(ctx->getNetinfoSinkWire(net_info, user_idx)).c_str(ctx), + ctx->getDelayNS(arc_slack), ctx->getDelayNS(arc_delay), + ctx->getDelayNS(arc_budget)); + tns += ctx->getDelayNS(arc_slack); + tns_arc_count++; + } + } + } + log_info("final tns with respect to arc budgets: %f ns (%d nets, %d arcs)\n", tns, tns_net_count, + tns_arc_count); + } + NPNR_ASSERT(jobQueue.empty()); jobCache.clear(); @@ -888,11 +810,13 @@ bool router1(Context *ctx) log_info("Checksum: 0x%08x\n", ctx->checksum()); #ifndef NDEBUG ctx->check(); + ctx->unlock(); #endif return true; } catch (log_execution_error_exception) { #ifndef NDEBUG ctx->check(); + ctx->unlock(); #endif return false; } diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 1510a27f..7ac56378 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -206,7 +206,7 @@ BelRange Arch::getBelsAtSameTile(BelId bel) const return br; } -WireId Arch::getWireBelPin(BelId bel, PortPin pin) const +WireId Arch::getBelPinWire(BelId bel, PortPin pin) const { WireId ret; @@ -224,6 +224,20 @@ WireId Arch::getWireBelPin(BelId bel, PortPin pin) const return ret; } +PortType Arch::getBelPinType(BelId bel, PortPin pin) const +{ + NPNR_ASSERT(bel != BelId()); + + int num_bel_wires = locInfo(bel)->bel_data[bel.index].num_bel_wires; + const BelWirePOD *bel_wires = locInfo(bel)->bel_data[bel.index].bel_wires.get(); + + for (int i = 0; i < num_bel_wires; i++) + if (bel_wires[i].port == pin) + return PortType(bel_wires[i].type); + + return PORT_INOUT; +} + // ----------------------------------------------------------------------- WireId Arch::getWireByName(IdString name) const @@ -314,6 +328,60 @@ std::string Arch::getBelPackagePin(BelId bel) const } return ""; } + +std::vector<PortPin> Arch::getBelPins(BelId bel) const + +{ + std::vector<PortPin> ret; + NPNR_ASSERT(bel != BelId()); + + int num_bel_wires = locInfo(bel)->bel_data[bel.index].num_bel_wires; + const BelWirePOD *bel_wires = locInfo(bel)->bel_data[bel.index].bel_wires.get(); + + for (int i = 0; i < num_bel_wires; i++) + ret.push_back(bel_wires[i].port); + + return ret; +} + +BelId Arch::getBelByLocation(Loc loc) const +{ + if (loc.x >= chip_info->width || loc.y >= chip_info->height) + return BelId(); + const LocationTypePOD &locI = chip_info->locations[chip_info->location_type[loc.y * chip_info->width + loc.x]]; + for (int i = 0; i < locI.num_bels; i++) { + if (locI.bel_data[i].z == loc.z) { + BelId bi; + bi.location.x = loc.x; + bi.location.y = loc.y; + bi.index = i; + return bi; + } + } + return BelId(); +} + +BelRange Arch::getBelsByTile(int x, int y) const +{ + BelRange br; + + int num_bels = 0; + + if (x < chip_info->width && y < chip_info->height) { + const LocationTypePOD &locI = chip_info->locations[chip_info->location_type[y * chip_info->width + x]]; + num_bels = locI.num_bels; + } + + br.b.cursor_tile = y * chip_info->width + x; + br.e.cursor_tile = y * chip_info->width + x; + br.b.cursor_index = 0; + br.e.cursor_index = num_bels - 1; + br.b.chip = chip_info; + br.e.chip = chip_info; + ++br.e; + return br; +} + // ----------------------------------------------------------------------- void Arch::estimatePosition(BelId bel, int &x, int &y, bool &gb) const @@ -325,7 +393,7 @@ void Arch::estimatePosition(BelId bel, int &x, int &y, bool &gb) const delay_t Arch::estimateDelay(WireId src, WireId dst) const { - return abs(src.location.x - dst.location.x) + abs(src.location.y - dst.location.y); + return 200 * (abs(src.location.x - dst.location.x) + abs(src.location.y - dst.location.y)); } // ----------------------------------------------------------------------- diff --git a/ecp5/arch.h b/ecp5/arch.h index bf36ef2f..b3ef5195 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -50,11 +50,13 @@ NPNR_PACKED_STRUCT(struct BelWirePOD { LocationPOD rel_wire_loc; int32_t wire_index; PortPin port; + int32_t type; }); NPNR_PACKED_STRUCT(struct BelInfoPOD { RelPtr<char> name; BelType type; + int32_t z; int32_t num_bel_wires; RelPtr<BelWirePOD> bel_wires; }); @@ -84,9 +86,8 @@ NPNR_PACKED_STRUCT(struct WireInfoPOD { int32_t num_uphill, num_downhill; RelPtr<PipLocatorPOD> pips_uphill, pips_downhill; - int32_t num_bels_downhill; - BelPortPOD bel_uphill; - RelPtr<BelPortPOD> bels_downhill; + int32_t num_bel_pins; + RelPtr<BelPortPOD> bel_pins; }); NPNR_PACKED_STRUCT(struct LocationTypePOD { @@ -387,6 +388,11 @@ struct Arch : BaseCtx IdString portPinToId(PortPin type) const; PortPin portPinFromId(IdString id) const; + // ------------------------------------------------- + + int getGridDimX() const { return chip_info->width; }; + int getGridDimY() const { return chip_info->height; }; + int getTileDimZ(int, int) const { return 4; }; // ------------------------------------------------- @@ -425,6 +431,20 @@ struct Arch : BaseCtx bel_to_cell[bel] = IdString(); } + Loc getBelLocation(BelId bel) const + { + Loc loc; + loc.x = bel.location.x; + loc.y = bel.location.y; + loc.z = locInfo(bel)->bel_data[bel.index].z; + return loc; + } + + BelId getBelByLocation(Loc loc) const; + BelRange getBelsByTile(int x, int y) const; + + bool getBelGlobalBuf(BelId bel) const { return false; } + bool checkBelAvail(BelId bel) const { NPNR_ASSERT(bel != BelId()); @@ -462,20 +482,6 @@ struct Arch : BaseCtx return range; } - BelRange getBelsByType(BelType type) const - { - BelRange range; -// FIXME -#if 0 - if (type == "TYPE_A") { - range.b.cursor = bels_type_a_begin; - range.e.cursor = bels_type_a_end; - } - ... -#endif - return range; - } - BelRange getBelsAtSameTile(BelId bel) const; BelType getBelType(BelId bel) const @@ -484,33 +490,21 @@ struct Arch : BaseCtx return locInfo(bel)->bel_data[bel.index].type; } - WireId getWireBelPin(BelId bel, PortPin pin) const; - - BelPin getBelPinUphill(WireId wire) const - { - BelPin ret; - NPNR_ASSERT(wire != WireId()); - - if (locInfo(wire)->wire_data[wire.index].bel_uphill.bel_index >= 0) { - ret.bel.index = locInfo(wire)->wire_data[wire.index].bel_uphill.bel_index; - ret.bel.location = wire.location + locInfo(wire)->wire_data[wire.index].bel_uphill.rel_bel_loc; - ret.pin = locInfo(wire)->wire_data[wire.index].bel_uphill.port; - } - - return ret; - } + WireId getBelPinWire(BelId bel, PortPin pin) const; - BelPinRange getBelPinsDownhill(WireId wire) const + BelPinRange getWireBelPins(WireId wire) const { BelPinRange range; NPNR_ASSERT(wire != WireId()); - range.b.ptr = locInfo(wire)->wire_data[wire.index].bels_downhill.get(); + range.b.ptr = locInfo(wire)->wire_data[wire.index].bel_pins.get(); range.b.wire_loc = wire.location; - range.e.ptr = range.b.ptr + locInfo(wire)->wire_data[wire.index].num_bels_downhill; + range.e.ptr = range.b.ptr + locInfo(wire)->wire_data[wire.index].num_bel_pins; range.e.wire_loc = wire.location; return range; } + std::vector<PortPin> getBelPins(BelId bel) const; + // ------------------------------------------------- WireId getWireByName(IdString name) const; @@ -581,6 +575,7 @@ struct Arch : BaseCtx DelayInfo getWireDelay(WireId wire) const { DelayInfo delay; + delay.delay = 0; return delay; } @@ -694,7 +689,7 @@ struct Arch : BaseCtx { DelayInfo delay; NPNR_ASSERT(pip != PipId()); - delay.delay = locInfo(pip)->pip_data[pip.index].delay; + delay.delay = locInfo(pip)->pip_data[pip.index].delay * 100; return delay; } @@ -739,6 +734,8 @@ struct Arch : BaseCtx BelId getPackagePinBel(const std::string &pin) const; std::string getBelPackagePin(BelId bel) const; + PortType getBelPinType(BelId bel, PortPin pin) const; + // ------------------------------------------------- GroupId getGroupByName(IdString name) const { return GroupId(); } diff --git a/ecp5/trellis_import.py b/ecp5/trellis_import.py index af5386e7..b5cd53f1 100755 --- a/ecp5/trellis_import.py +++ b/ecp5/trellis_import.py @@ -401,12 +401,12 @@ def write_database(dev_name, ddrg, endianness): for up in wire.arcsUphill: write_loc(up.rel, "rel_loc") bba.u32(up.id, "index") - if len(wire.belsDownhill) > 0: - bba.l("loc%d_wire%d_downbels" % (idx, wire_idx), "BelPortPOD") - for db in wire.belsDownhill: - write_loc(db.bel.rel, "rel_bel_loc") - bba.u32(db.bel.id, "bel_index") - bba.u32(portpins[ddrg.to_str(db.pin)], "port") + if len(wire.belPins) > 0: + bba.l("loc%d_wire%d_belpins" % (idx, wire_idx), "BelPortPOD") + for bp in wire.belPins: + write_loc(bp.bel.rel, "rel_bel_loc") + bba.u32(bp.bel.id, "bel_index") + bba.u32(portpins[ddrg.to_str(bp.pin)], "port") bba.l("loc%d_wires" % idx, "WireInfoPOD") for wire_idx in range(len(loctype.wires)): wire = loctype.wires[wire_idx] @@ -415,28 +415,24 @@ def write_database(dev_name, ddrg, endianness): bba.u32(len(wire.arcsDownhill), "num_downhill") bba.r("loc%d_wire%d_uppips" % (idx, wire_idx) if len(wire.arcsUphill) > 0 else None, "pips_uphill") bba.r("loc%d_wire%d_downpips" % (idx, wire_idx) if len(wire.arcsDownhill) > 0 else None, "pips_downhill") - bba.u32(len(wire.belsDownhill), "num_bels_downhill") - write_loc(wire.belUphill.bel.rel, "uphill_bel_loc") - if wire.belUphill.pin != -1: - bba.u32(wire.belUphill.bel.id, "uphill_bel_idx") - bba.u32(portpins[ddrg.to_str(wire.belUphill.pin)], "uphill_bel_pin") - else: - bba.u32(0xFFFFFFFF, "bel_uphill.bel_index") - bba.u32(0, "bel_uphill.port") - bba.r("loc%d_wire%d_downbels" % (idx, wire_idx) if len(wire.belsDownhill) > 0 else None, "bels_downhill") + bba.u32(len(wire.belPins), "num_bel_pins") + bba.r("loc%d_wire%d_belpins" % (idx, wire_idx) if len(wire.belPins) > 0 else None, "bel_pins") + if len(loctype.bels) > 0: for bel_idx in range(len(loctype.bels)): bel = loctype.bels[bel_idx] - bba.l("loc%d_bel%d_wires" % (idx, bel_idx), "BelPortPOD") + bba.l("loc%d_bel%d_wires" % (idx, bel_idx), "BelWirePOD") for pin in bel.wires: write_loc(pin.wire.rel, "rel_wire_loc") bba.u32(pin.wire.id, "wire_index") bba.u32(portpins[ddrg.to_str(pin.pin)], "port") + bba.u32(int(pin.dir), "dir") bba.l("loc%d_bels" % idx, "BelInfoPOD") for bel_idx in range(len(loctype.bels)): bel = loctype.bels[bel_idx] bba.s(ddrg.to_str(bel.name), "name") bba.u32(bel_types[ddrg.to_str(bel.type)], "type") + bba.u32(bel.z, "z") bba.u32(len(bel.wires), "num_bel_wires") bba.r("loc%d_bel%d_wires" % (idx, bel_idx), "bel_wires") diff --git a/generic/arch.cc b/generic/arch.cc index b7ec847e..0fff2e4c 100644 --- a/generic/arch.cc +++ b/generic/arch.cc @@ -62,28 +62,38 @@ void Arch::addAlias(IdString name, IdString srcWire, IdString dstWire, DelayInfo pip_ids.push_back(name); } -void Arch::addBel(IdString name, IdString type, int x, int y, int z, bool gb) +void Arch::addBel(IdString name, IdString type, Loc loc, bool gb) { - Loc loc; - loc.x = x; - loc.y = y; - loc.z = z; - NPNR_ASSERT(bels.count(name) == 0); NPNR_ASSERT(bel_by_loc.count(loc) == 0); BelInfo &bi = bels[name]; bi.name = name; bi.type = type; - bi.x = x; - bi.y = y; - bi.z = z; + bi.x = loc.x; + bi.y = loc.y; + bi.z = loc.z; bi.gb = gb; bel_ids.push_back(name); - bel_ids_by_type[type].push_back(name); - bel_by_loc[loc] = name; - bels_by_tile[x][y].push_back(name); + + if (bels_by_tile.size() <= loc.x) + bels_by_tile.resize(loc.x + 1); + + if (bels_by_tile[loc.x].size() <= loc.y) + bels_by_tile[loc.x].resize(loc.y + 1); + + bels_by_tile[loc.x][loc.y].push_back(name); + + if (tileDimZ.size() <= loc.x) + tileDimZ.resize(loc.x + 1); + + if (tileDimZ[loc.x].size() <= loc.y) + tileDimZ[loc.x].resize(loc.y + 1); + + gridDimX = std::max(gridDimX, loc.x + 1); + gridDimY = std::max(gridDimY, loc.x + 1); + tileDimZ[loc.x][loc.y] = std::max(tileDimZ[loc.x][loc.y], loc.z + 1); } void Arch::addBelInput(IdString bel, IdString name, IdString wire) @@ -95,6 +105,7 @@ void Arch::addBelInput(IdString bel, IdString name, IdString wire) pi.type = PORT_IN; wires.at(wire).downhill_bel_pins.push_back(BelPin{bel, name}); + wires.at(wire).bel_pins.push_back(BelPin{bel, name}); } void Arch::addBelOutput(IdString bel, IdString name, IdString wire) @@ -106,6 +117,7 @@ void Arch::addBelOutput(IdString bel, IdString name, IdString wire) pi.type = PORT_OUT; wires.at(wire).uphill_bel_pin = BelPin{bel, name}; + wires.at(wire).bel_pins.push_back(BelPin{bel, name}); } void Arch::addBelInout(IdString bel, IdString name, IdString wire) @@ -117,6 +129,7 @@ void Arch::addBelInout(IdString bel, IdString name, IdString wire) pi.type = PORT_INOUT; wires.at(wire).downhill_bel_pins.push_back(BelPin{bel, name}); + wires.at(wire).bel_pins.push_back(BelPin{bel, name}); } void Arch::addGroupBel(IdString group, IdString bel) { groups[group].bels.push_back(bel); } @@ -210,21 +223,18 @@ IdString Arch::getConflictingBelCell(BelId bel) const { return bels.at(bel).boun const std::vector<BelId> &Arch::getBels() const { return bel_ids; } -const std::vector<BelId> &Arch::getBelsByType(BelType type) const -{ - static std::vector<BelId> empty_list; - if (bel_ids_by_type.count(type)) - return bel_ids_by_type.at(type); - return empty_list; -} - BelType Arch::getBelType(BelId bel) const { return bels.at(bel).type; } -WireId Arch::getWireBelPin(BelId bel, PortPin pin) const { return bels.at(bel).pins.at(pin).wire; } +WireId Arch::getBelPinWire(BelId bel, PortPin pin) const { return bels.at(bel).pins.at(pin).wire; } -BelPin Arch::getBelPinUphill(WireId wire) const { return wires.at(wire).uphill_bel_pin; } +PortType Arch::getBelPinType(BelId bel, PortPin pin) const { return bels.at(bel).pins.at(pin).type; } -const std::vector<BelPin> &Arch::getBelPinsDownhill(WireId wire) const { return wires.at(wire).downhill_bel_pins; } +std::vector<PortPin> Arch::getBelPins(BelId bel) const +{ + std::vector<PortPin> ret; + for (auto &it : bels.at(bel).pins) + ret.push_back(it.first); +} // --------------------------------------------------------------- @@ -272,6 +282,8 @@ IdString Arch::getBoundWireNet(WireId wire) const { return wires.at(wire).bound_ IdString Arch::getConflictingWireNet(WireId wire) const { return wires.at(wire).bound_net; } +const std::vector<BelPin> &Arch::getWireBelPins(WireId wire) const { return wires.at(wire).bel_pins; } + const std::vector<WireId> &Arch::getWires() const { return wire_ids; } // --------------------------------------------------------------- diff --git a/generic/arch.h b/generic/arch.h index e1516569..61e6b033 100644 --- a/generic/arch.h +++ b/generic/arch.h @@ -43,6 +43,7 @@ struct WireInfo std::vector<PipId> downhill, uphill, aliases; BelPin uphill_bel_pin; std::vector<BelPin> downhill_bel_pins; + std::vector<BelPin> bel_pins; DecalXY decalxy; int x, y; }; @@ -83,21 +84,23 @@ struct Arch : BaseCtx std::unordered_map<GroupId, GroupInfo> groups; std::vector<IdString> bel_ids, wire_ids, pip_ids; - std::unordered_map<IdString, std::vector<IdString>> bel_ids_by_type; std::unordered_map<Loc, BelId> bel_by_loc; - std::unordered_map<int, std::unordered_map<int, std::vector<BelId>>> bels_by_tile; + std::vector<std::vector<std::vector<BelId>>> bels_by_tile; std::unordered_map<DecalId, std::vector<GraphicElement>> decal_graphics; DecalXY frame_decalxy; + int gridDimX, gridDimY; + std::vector<std::vector<int>> tileDimZ; + float grid_distance_to_delay; void addWire(IdString name, int x, int y); void addPip(IdString name, IdString srcWire, IdString dstWire, DelayInfo delay); void addAlias(IdString name, IdString srcWire, IdString dstWire, DelayInfo delay); - void addBel(IdString name, IdString type, int x, int y, int z, bool gb); + void addBel(IdString name, IdString type, Loc loc, bool gb); void addBelInput(IdString bel, IdString name, IdString wire); void addBelOutput(IdString bel, IdString name, IdString wire); void addBelInout(IdString bel, IdString name, IdString wire); @@ -130,6 +133,10 @@ struct Arch : BaseCtx BelType belTypeFromId(IdString id) const { return id; } PortPin portPinFromId(IdString id) const { return id; } + int getGridDimX() const { return gridDimX; } + int getGridDimY() const { return gridDimY; } + int getTileDimZ(int x, int y) const { return tileDimZ[x][y]; } + BelId getBelByName(IdString name) const; IdString getBelName(BelId bel) const; Loc getBelLocation(BelId bel) const; @@ -143,11 +150,10 @@ struct Arch : BaseCtx IdString getBoundBelCell(BelId bel) const; IdString getConflictingBelCell(BelId bel) const; const std::vector<BelId> &getBels() const; - const std::vector<BelId> &getBelsByType(BelType type) const; BelType getBelType(BelId bel) const; - WireId getWireBelPin(BelId bel, PortPin pin) const; - BelPin getBelPinUphill(WireId wire) const; - const std::vector<BelPin> &getBelPinsDownhill(WireId wire) const; + WireId getBelPinWire(BelId bel, PortPin pin) const; + PortType getBelPinType(BelId bel, PortPin pin) const; + std::vector<PortPin> getBelPins(BelId bel) const; WireId getWireByName(IdString name) const; IdString getWireName(WireId wire) const; @@ -159,6 +165,7 @@ struct Arch : BaseCtx IdString getConflictingWireNet(WireId wire) const; DelayInfo getWireDelay(WireId wire) const { return DelayInfo(); } const std::vector<WireId> &getWires() const; + const std::vector<BelPin> &getWireBelPins(WireId wire) const; PipId getPipByName(IdString name) const; IdString getPipName(PipId pip) const; diff --git a/gui/designwidget.cc b/gui/designwidget.cc index a59307f0..91ec5163 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -497,6 +497,14 @@ void DesignWidget::onItemSelectionChanged() addProperty(topItem, QVariant::String, "Conflicting Cell", ctx->getConflictingBelCell(bel).c_str(ctx),
ElementType::CELL);
+ QtProperty *belpinsItem = addSubGroup(topItem, "Ports");
+ for (const auto &item : ctx->getBelPins(bel)) {
+ QtProperty *portInfoItem = addSubGroup(belpinsItem, ctx->portPinToId(item).c_str(ctx));
+ addProperty(portInfoItem, QVariant::String, "Name", ctx->portPinToId(item).c_str(ctx));
+ addProperty(portInfoItem, QVariant::Int, "Type", int(ctx->getBelPinType(bel, item)));
+ WireId wire = ctx->getBelPinWire(bel, item);
+ addProperty(portInfoItem, QVariant::String, "Wire", ctx->getWireName(wire).c_str(ctx), ElementType::WIRE);
+ }
} else if (type == ElementType::WIRE) {
WireId wire = ctx->getWireByName(c);
QtProperty *topItem = addTopLevelProperty("Wire");
@@ -515,23 +523,14 @@ void DesignWidget::onItemSelectionChanged() addProperty(delayItem, QVariant::Double, "Min Fall", delay.minFallDelay());
addProperty(delayItem, QVariant::Double, "Max Fall", delay.maxFallDelay());
- QtProperty *belpinItem = addSubGroup(topItem, "BelPin Uphill");
- BelPin uphill = ctx->getBelPinUphill(wire);
- if (uphill.bel != BelId())
- addProperty(belpinItem, QVariant::String, "Bel", ctx->getBelName(uphill.bel).c_str(ctx), ElementType::BEL);
- else
- addProperty(belpinItem, QVariant::String, "Bel", "", ElementType::BEL);
-
- addProperty(belpinItem, QVariant::String, "PortPin", ctx->portPinToId(uphill.pin).c_str(ctx), ElementType::BEL);
-
- QtProperty *downhillItem = addSubGroup(topItem, "BelPin Downhill");
- for (const auto &item : ctx->getBelPinsDownhill(wire)) {
+ QtProperty *belpinsItem = addSubGroup(topItem, "BelPins");
+ for (const auto &item : ctx->getWireBelPins(wire)) {
QString belname = "";
if (item.bel != BelId())
belname = ctx->getBelName(item.bel).c_str(ctx);
QString pinname = ctx->portPinToId(item.pin).c_str(ctx);
- QtProperty *dhItem = addSubGroup(downhillItem, belname + "-" + pinname);
+ QtProperty *dhItem = addSubGroup(belpinsItem, belname + "-" + pinname);
addProperty(dhItem, QVariant::String, "Bel", belname, ElementType::BEL);
addProperty(dhItem, QVariant::String, "PortPin", pinname);
}
diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index c926e5fa..9343419b 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -241,26 +241,26 @@ void LineShader::draw(const LineShaderData &line, const QColor &color, float thi } FPGAViewWidget::FPGAViewWidget(QWidget *parent) - : QOpenGLWidget(parent), lineShader_(this), zoom_(500.f), ctx_(nullptr), selectedItemsChanged_(false) + : QOpenGLWidget(parent), lineShader_(this), zoom_(500.f), ctx_(nullptr), paintTimer_(this), + rendererData_(new FPGAViewWidget::RendererData), rendererArgs_(new FPGAViewWidget::RendererArgs) { - backgroundColor_ = QColor("#000000"); - gridColor_ = QColor("#333"); - gFrameColor_ = QColor("#d0d0d0"); - gHiddenColor_ = QColor("#606060"); - gInactiveColor_ = QColor("#303030"); - gActiveColor_ = QColor("#f0f0f0"); - gSelectedColor_ = QColor("#ff6600"); - frameColor_ = QColor("#0066ba"); - highlightColors[0] = QColor("#6495ed"); - highlightColors[1] = QColor("#7fffd4"); - highlightColors[2] = QColor("#98fb98"); - highlightColors[3] = QColor("#ffd700"); - highlightColors[4] = QColor("#cd5c5c"); - highlightColors[5] = QColor("#fa8072"); - highlightColors[6] = QColor("#ff69b4"); - highlightColors[7] = QColor("#da70d6"); - for (int i = 0; i < 8; i++) - highlightItemsChanged_[i] = false; + colors_.background = QColor("#000000"); + colors_.grid = QColor("#333"); + colors_.frame = QColor("#d0d0d0"); + colors_.hidden = QColor("#606060"); + colors_.inactive = QColor("#303030"); + colors_.active = QColor("#f0f0f0"); + colors_.selected = QColor("#ff6600"); + colors_.highlight[0] = QColor("#6495ed"); + colors_.highlight[1] = QColor("#7fffd4"); + colors_.highlight[2] = QColor("#98fb98"); + colors_.highlight[3] = QColor("#ffd700"); + colors_.highlight[4] = QColor("#cd5c5c"); + colors_.highlight[5] = QColor("#fa8072"); + colors_.highlight[6] = QColor("#ff69b4"); + colors_.highlight[7] = QColor("#da70d6"); + + rendererArgs_->highlightedOrSelectedChanged = false; auto fmt = format(); fmt.setMajorVersion(3); @@ -268,7 +268,6 @@ FPGAViewWidget::FPGAViewWidget(QWidget *parent) setFormat(fmt); fmt = format(); - // printf("FPGAViewWidget running on OpenGL %d.%d\n", fmt.majorVersion(), fmt.minorVersion()); if (fmt.majorVersion() < 3) { printf("Could not get OpenGL 3.0 context. Aborting.\n"); log_abort(); @@ -276,6 +275,13 @@ FPGAViewWidget::FPGAViewWidget(QWidget *parent) if (fmt.minorVersion() < 1) { printf("Could not get OpenGL 3.1 context - trying anyway...\n "); } + + connect(&paintTimer_, SIGNAL(timeout()), this, SLOT(update())); + paintTimer_.start(1000 / 20); // paint GL 20 times per second + + renderRunner_ = std::unique_ptr<PeriodicRunner>(new PeriodicRunner(this, [this] { renderLines(); })); + renderRunner_->start(); + renderRunner_->startTimer(1000 / 2); // render lines 2 times per second } FPGAViewWidget::~FPGAViewWidget() {} @@ -283,8 +289,7 @@ FPGAViewWidget::~FPGAViewWidget() {} void FPGAViewWidget::newContext(Context *ctx) { ctx_ = ctx; - selectedItems_.clear(); - update(); + pokeRenderer(); } QSize FPGAViewWidget::minimumSizeHint() const { return QSize(640, 480); } @@ -297,7 +302,8 @@ void FPGAViewWidget::initializeGL() log_error("Could not compile shader.\n"); } initializeOpenGLFunctions(); - glClearColor(backgroundColor_.red() / 255, backgroundColor_.green() / 255, backgroundColor_.blue() / 255, 0.0); + glClearColor(colors_.background.red() / 255, colors_.background.green() / 255, colors_.background.blue() / 255, + 0.0); } void FPGAViewWidget::drawDecal(LineShaderData &out, const DecalXY &decal) @@ -398,67 +404,143 @@ void FPGAViewWidget::paintGL() PolyLine(-100.0f, i, 100.0f, i).build(grid); PolyLine(i, -100.0f, i, 100.0f).build(grid); } - lineShader_.draw(grid, gridColor_, thick1Px, matrix); + lineShader_.draw(grid, colors_.grid, thick1Px, matrix); - LineShaderData shaders[4] = {LineShaderData(), LineShaderData(), LineShaderData(), LineShaderData()}; + rendererDataLock_.lock(); + lineShader_.draw(rendererData_->decals[0], colors_.frame, thick11Px, matrix); + lineShader_.draw(rendererData_->decals[1], colors_.hidden, thick11Px, matrix); + lineShader_.draw(rendererData_->decals[2], colors_.inactive, thick11Px, matrix); + lineShader_.draw(rendererData_->decals[3], colors_.active, thick11Px, matrix); - if (ctx_) { - // Draw Bels. + for (int i = 0; i < 8; i++) + lineShader_.draw(rendererData_->highlighted[i], colors_.highlight[i], thick11Px, matrix); + + lineShader_.draw(rendererData_->selected, colors_.selected, thick11Px, matrix); + rendererDataLock_.unlock(); +} + +void FPGAViewWidget::pokeRenderer(void) { renderRunner_->poke(); } + +void FPGAViewWidget::renderLines(void) +{ + if (ctx_ == nullptr) + return; + + ctx_->lock_ui(); + + // For now, collapse any decal changes into change of all decals. + // TODO(q3k): fix this + bool decalsChanged = false; + if (ctx_->allUiReload) { + ctx_->allUiReload = false; + decalsChanged = true; + } + if (ctx_->frameUiReload) { + ctx_->frameUiReload = false; + decalsChanged = true; + } + if (ctx_->belUiReload.size() > 0) { + ctx_->belUiReload.clear(); + decalsChanged = true; + } + if (ctx_->wireUiReload.size() > 0) { + ctx_->wireUiReload.clear(); + decalsChanged = true; + } + if (ctx_->pipUiReload.size() > 0) { + ctx_->pipUiReload.clear(); + decalsChanged = true; + } + if (ctx_->groupUiReload.size() > 0) { + ctx_->groupUiReload.clear(); + decalsChanged = true; + } + + // Local copy of decals, taken as fast as possible to not block the P&R. + std::vector<DecalXY> belDecals; + std::vector<DecalXY> wireDecals; + std::vector<DecalXY> pipDecals; + std::vector<DecalXY> groupDecals; + if (decalsChanged) { for (auto bel : ctx_->getBels()) { - drawDecal(shaders, ctx_->getBelDecal(bel)); + belDecals.push_back(ctx_->getBelDecal(bel)); } - // Draw Wires. for (auto wire : ctx_->getWires()) { - drawDecal(shaders, ctx_->getWireDecal(wire)); + wireDecals.push_back(ctx_->getWireDecal(wire)); } - // Draw Pips. for (auto pip : ctx_->getPips()) { - drawDecal(shaders, ctx_->getPipDecal(pip)); + pipDecals.push_back(ctx_->getPipDecal(pip)); } - // Draw Groups. for (auto group : ctx_->getGroups()) { - drawDecal(shaders, ctx_->getGroupDecal(group)); + groupDecals.push_back(ctx_->getGroupDecal(group)); } + } + ctx_->unlock_ui(); - if (selectedItemsChanged_) { - selectedItemsChanged_ = false; - selectedShader_.clear(); - for (auto decal : selectedItems_) { - drawDecal(selectedShader_, decal); - } + rendererArgsLock_.lock(); + auto selectedItems = rendererArgs_->selectedItems; + auto highlightedItems = rendererArgs_->highlightedItems; + auto highlightedOrSelectedChanged = rendererArgs_->highlightedOrSelectedChanged; + rendererArgs_->highlightedOrSelectedChanged = false; + rendererArgsLock_.unlock(); + + if (decalsChanged) { + auto data = std::unique_ptr<FPGAViewWidget::RendererData>(new FPGAViewWidget::RendererData); + // Draw Bels. + for (auto const &decal : belDecals) { + drawDecal(data->decals, decal); + } + // Draw Wires. + for (auto const &decal : wireDecals) { + drawDecal(data->decals, decal); + } + // Draw Pips. + for (auto const &decal : pipDecals) { + drawDecal(data->decals, decal); + } + // Draw Groups. + for (auto const &decal : groupDecals) { + drawDecal(data->decals, decal); + } + + // Swap over. + rendererDataLock_.lock(); + rendererData_ = std::move(data); + rendererDataLock_.unlock(); + } + + rendererDataLock_.lock(); + if (decalsChanged || highlightedOrSelectedChanged) { + rendererData_->selected.clear(); + for (auto &decal : selectedItems) { + drawDecal(rendererData_->selected, decal); } for (int i = 0; i < 8; i++) { - if (highlightItemsChanged_[i]) { - highlightItemsChanged_[i] = false; - highlightShader_[i].clear(); - for (auto decal : highlightItems_[i]) { - drawDecal(highlightShader_[i], decal); - } + rendererData_->highlighted[i].clear(); + for (auto &decal : highlightedItems[i]) { + drawDecal(rendererData_->highlighted[i], decal); } } } - - lineShader_.draw(shaders[0], gFrameColor_, thick11Px, matrix); - lineShader_.draw(shaders[1], gHiddenColor_, thick11Px, matrix); - lineShader_.draw(shaders[2], gInactiveColor_, thick11Px, matrix); - lineShader_.draw(shaders[3], gActiveColor_, thick11Px, matrix); - for (int i = 0; i < 8; i++) - lineShader_.draw(highlightShader_[i], highlightColors[i], thick11Px, matrix); - lineShader_.draw(selectedShader_, gSelectedColor_, thick11Px, matrix); + rendererDataLock_.unlock(); } void FPGAViewWidget::onSelectedArchItem(std::vector<DecalXY> decals) { - selectedItems_ = decals; - selectedItemsChanged_ = true; - update(); + rendererArgsLock_.lock(); + rendererArgs_->selectedItems = decals; + rendererArgs_->highlightedOrSelectedChanged = true; + rendererArgsLock_.unlock(); + pokeRenderer(); } void FPGAViewWidget::onHighlightGroupChanged(std::vector<DecalXY> decals, int group) { - highlightItems_[group] = decals; - highlightItemsChanged_[group] = true; - update(); + rendererArgsLock_.lock(); + rendererArgs_->highlightedItems[group] = decals; + rendererArgs_->highlightedOrSelectedChanged = true; + rendererArgsLock_.unlock(); + pokeRenderer(); } void FPGAViewWidget::resizeGL(int width, int height) {} diff --git a/gui/fpgaviewwidget.h b/gui/fpgaviewwidget.h index 33eb2800..b87c5d0a 100644 --- a/gui/fpgaviewwidget.h +++ b/gui/fpgaviewwidget.h @@ -21,12 +21,16 @@ #define MAPGLWIDGET_H #include <QMainWindow> +#include <QMutex> #include <QOpenGLBuffer> #include <QOpenGLFunctions> #include <QOpenGLShaderProgram> #include <QOpenGLVertexArrayObject> #include <QOpenGLWidget> #include <QPainter> +#include <QThread> +#include <QTimer> +#include <QWaitCondition> #include "nextpnr.h" @@ -206,17 +210,58 @@ class LineShader void draw(const LineShaderData &data, const QColor &color, float thickness, const QMatrix4x4 &projection); }; +class PeriodicRunner : public QThread +{ + Q_OBJECT + private: + QMutex mutex_; + QWaitCondition condition_; + bool abort_; + std::function<void()> target_; + QTimer timer_; + + public: + explicit PeriodicRunner(QObject *parent, std::function<void()> target) + : QThread(parent), abort_(false), target_(target), timer_(this) + { + connect(&timer_, &QTimer::timeout, this, &PeriodicRunner::poke); + } + + void run(void) override + { + for (;;) { + mutex_.lock(); + condition_.wait(&mutex_); + + if (abort_) { + mutex_.unlock(); + return; + } + + target_(); + + mutex_.unlock(); + } + } + + void startTimer(int msecs) { timer_.start(msecs); } + + ~PeriodicRunner() + { + mutex_.lock(); + abort_ = true; + condition_.wakeOne(); + mutex_.unlock(); + + wait(); + } + + void poke(void) { condition_.wakeOne(); } +}; + class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions { Q_OBJECT - Q_PROPERTY(QColor backgroundColor MEMBER backgroundColor_ DESIGNABLE true) - Q_PROPERTY(QColor gridColor MEMBER gridColor_ DESIGNABLE true) - Q_PROPERTY(QColor gFrameColor MEMBER gFrameColor_ DESIGNABLE true) - Q_PROPERTY(QColor gHiddenColor MEMBER gHiddenColor_ DESIGNABLE true) - Q_PROPERTY(QColor gInactiveColor MEMBER gInactiveColor_ DESIGNABLE true) - Q_PROPERTY(QColor gActiveColor MEMBER gActiveColor_ DESIGNABLE true) - Q_PROPERTY(QColor gSelectedColor MEMBER gSelectedColor_ DESIGNABLE true) - Q_PROPERTY(QColor frameColor MEMBER frameColor_ DESIGNABLE true) public: FPGAViewWidget(QWidget *parent = 0); @@ -246,8 +291,11 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions void newContext(Context *ctx); void onSelectedArchItem(std::vector<DecalXY> decals); void onHighlightGroupChanged(std::vector<DecalXY> decals, int group); + void pokeRenderer(void); private: + void renderLines(void); + QPoint lastPos_; LineShader lineShader_; QMatrix4x4 viewMove_; @@ -262,24 +310,40 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions const float zoomLvl2_ = 50.0f; Context *ctx_; + QTimer paintTimer_; + + std::unique_ptr<PeriodicRunner> renderRunner_; - QColor backgroundColor_; - QColor gridColor_; - QColor gFrameColor_; - QColor gHiddenColor_; - QColor gInactiveColor_; - QColor gActiveColor_; - QColor gSelectedColor_; - QColor frameColor_; - - LineShaderData selectedShader_; - std::vector<DecalXY> selectedItems_; - bool selectedItemsChanged_; - - LineShaderData highlightShader_[8]; - std::vector<DecalXY> highlightItems_[8]; - bool highlightItemsChanged_[8]; - QColor highlightColors[8]; + struct + { + QColor background; + QColor grid; + QColor frame; + QColor hidden; + QColor inactive; + QColor active; + QColor selected; + QColor highlight[8]; + } colors_; + + struct RendererData + { + LineShaderData decals[4]; + LineShaderData selected; + LineShaderData highlighted[8]; + }; + + struct RendererArgs + { + std::vector<DecalXY> selectedItems; + std::vector<DecalXY> highlightedItems[8]; + bool highlightedOrSelectedChanged; + }; + + std::unique_ptr<RendererData> rendererData_; + QMutex rendererDataLock_; + std::unique_ptr<RendererArgs> rendererArgs_; + QMutex rendererArgsLock_; }; NEXTPNR_NAMESPACE_END diff --git a/gui/ice40/mainwindow.cc b/gui/ice40/mainwindow.cc index 847698c5..810a98ae 100644 --- a/gui/ice40/mainwindow.cc +++ b/gui/ice40/mainwindow.cc @@ -222,7 +222,7 @@ void MainWindow::new_proj() QString package = QInputDialog::getItem(this, "Select package", "Package:", getSupportedPackages(chipArgs.type),
0, false, &ok);
- if (ok && !item.isEmpty()) {
+ if (ok && !item.isEmpty()) {
currentProj = "";
currentJson = "";
currentPCF = "";
diff --git a/ice40/arch.cc b/ice40/arch.cc index e9a7d2b6..65b21afd 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -19,13 +19,13 @@ #include <algorithm> #include <cmath> +#include "cells.h" #include "gfx.h" #include "log.h" #include "nextpnr.h" #include "placer1.h" #include "router1.h" #include "util.h" -#include "cells.h" NEXTPNR_NAMESPACE_BEGIN // ----------------------------------------------------------------------- @@ -279,17 +279,11 @@ BelRange Arch::getBelsByTile(int x, int y) const // In iCE40 chipdb bels at the same tile are consecutive and dense z ordinates are used BelRange br; - Loc loc; - loc.x = x; - loc.y = y; - loc.z = 0; - - br.b.cursor = Arch::getBelByLocation(loc).index; + br.b.cursor = Arch::getBelByLocation(Loc(x, y, 0)).index; br.e.cursor = br.b.cursor; if (br.e.cursor != -1) { - while (br.e.cursor < chip_info->num_bels && - chip_info->bel_data[br.e.cursor].x == x && + while (br.e.cursor < chip_info->num_bels && chip_info->bel_data[br.e.cursor].x == x && chip_info->bel_data[br.e.cursor].y == y) br.e.cursor++; } @@ -314,7 +308,21 @@ BelRange Arch::getBelsAtSameTile(BelId bel) const return br; } -WireId Arch::getWireBelPin(BelId bel, PortPin pin) const +PortType Arch::getBelPinType(BelId bel, PortPin pin) const +{ + NPNR_ASSERT(bel != BelId()); + + int num_bel_wires = chip_info->bel_data[bel.index].num_bel_wires; + const BelWirePOD *bel_wires = chip_info->bel_data[bel.index].bel_wires.get(); + + for (int i = 0; i < num_bel_wires; i++) + if (bel_wires[i].port == pin) + return PortType(bel_wires[i].type); + + return PORT_INOUT; +} + +WireId Arch::getBelPinWire(BelId bel, PortPin pin) const { WireId ret; @@ -332,6 +340,21 @@ WireId Arch::getWireBelPin(BelId bel, PortPin pin) const return ret; } +std::vector<PortPin> Arch::getBelPins(BelId bel) const +{ + std::vector<PortPin> ret; + + NPNR_ASSERT(bel != BelId()); + + int num_bel_wires = chip_info->bel_data[bel.index].num_bel_wires; + const BelWirePOD *bel_wires = chip_info->bel_data[bel.index].bel_wires.get(); + + for (int i = 0; i < num_bel_wires; i++) + ret.push_back(bel_wires[i].port); + + return ret; +} + // ----------------------------------------------------------------------- WireId Arch::getWireByName(IdString name) const @@ -525,9 +548,9 @@ DecalXY Arch::getWireDecal(WireId wire) const DecalXY Arch::getPipDecal(PipId pip) const { DecalXY decalxy; - // decalxy.decal.type = DecalId::TYPE_PIP; - // decalxy.decal.index = pip.index; - // decalxy.decal.active = pip_to_net.at(pip.index) != IdString(); + decalxy.decal.type = DecalId::TYPE_PIP; + decalxy.decal.index = pip.index; + decalxy.decal.active = pip_to_net.at(pip.index) != IdString(); return decalxy; }; diff --git a/ice40/arch.h b/ice40/arch.h index 21169298..d4d71cfc 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -46,6 +46,7 @@ template <typename T> struct RelPtr NPNR_PACKED_STRUCT(struct BelWirePOD { int32_t wire_index; PortPin port; + int32_t type; }); NPNR_PACKED_STRUCT(struct BelInfoPOD { @@ -86,6 +87,9 @@ NPNR_PACKED_STRUCT(struct WireInfoPOD { BelPortPOD bel_uphill; RelPtr<BelPortPOD> bels_downhill; + int32_t num_bel_pins; + RelPtr<BelPortPOD> bel_pins; + int32_t num_segments; RelPtr<WireSegmentPOD> segments; @@ -373,6 +377,12 @@ struct Arch : BaseCtx // ------------------------------------------------- + int getGridDimX() const { return 34; } + int getGridDimY() const { return 34; } + int getTileDimZ(int, int) const { return 8; } + + // ------------------------------------------------- + BelId getBelByName(IdString name) const; IdString getBelName(BelId bel) const @@ -390,6 +400,7 @@ struct Arch : BaseCtx bel_to_cell[bel.index] = cell; cells[cell]->bel = bel; cells[cell]->belStrength = strength; + refreshUiBel(bel); } void unbindBel(BelId bel) @@ -399,6 +410,7 @@ struct Arch : BaseCtx cells[bel_to_cell[bel.index]]->bel = BelId(); cells[bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE; bel_to_cell[bel.index] = IdString(); + refreshUiBel(bel); } bool checkBelAvail(BelId bel) const @@ -427,20 +439,6 @@ struct Arch : BaseCtx return range; } - BelRange getBelsByType(BelType type) const - { - BelRange range; -// FIXME -#if 0 - if (type == "TYPE_A") { - range.b.cursor = bels_type_a_begin; - range.e.cursor = bels_type_a_end; - } - ... -#endif - return range; - } - Loc getBelLocation(BelId bel) const { Loc loc; @@ -453,10 +451,7 @@ struct Arch : BaseCtx BelId getBelByLocation(Loc loc) const; BelRange getBelsByTile(int x, int y) const; - bool getBelGlobalBuf(BelId bel) const - { - return chip_info->bel_data[bel.index].type == TYPE_SB_GB; - } + bool getBelGlobalBuf(BelId bel) const { return chip_info->bel_data[bel.index].type == TYPE_SB_GB; } BelRange getBelsAtSameTile(BelId bel) const NPNR_DEPRECATED; @@ -466,29 +461,9 @@ struct Arch : BaseCtx return chip_info->bel_data[bel.index].type; } - WireId getWireBelPin(BelId bel, PortPin pin) const; - - BelPin getBelPinUphill(WireId wire) const - { - BelPin ret; - NPNR_ASSERT(wire != WireId()); - - if (chip_info->wire_data[wire.index].bel_uphill.bel_index >= 0) { - ret.bel.index = chip_info->wire_data[wire.index].bel_uphill.bel_index; - ret.pin = chip_info->wire_data[wire.index].bel_uphill.port; - } - - return ret; - } - - BelPinRange getBelPinsDownhill(WireId wire) const - { - BelPinRange range; - NPNR_ASSERT(wire != WireId()); - range.b.ptr = chip_info->wire_data[wire.index].bels_downhill.get(); - range.e.ptr = range.b.ptr + chip_info->wire_data[wire.index].num_bels_downhill; - return range; - } + WireId getBelPinWire(BelId bel, PortPin pin) const; + PortType getBelPinType(BelId bel, PortPin pin) const; + std::vector<PortPin> getBelPins(BelId bel) const; // ------------------------------------------------- @@ -509,6 +484,7 @@ struct Arch : BaseCtx wire_to_net[wire.index] = net; nets[net]->wires[wire].pip = PipId(); nets[net]->wires[wire].strength = strength; + refreshUiWire(wire); } void unbindWire(WireId wire) @@ -528,6 +504,7 @@ struct Arch : BaseCtx net_wires.erase(it); wire_to_net[wire.index] = IdString(); + refreshUiWire(wire); } bool checkWireAvail(WireId wire) const @@ -554,6 +531,15 @@ struct Arch : BaseCtx return delay; } + BelPinRange getWireBelPins(WireId wire) const + { + BelPinRange range; + NPNR_ASSERT(wire != WireId()); + range.b.ptr = chip_info->wire_data[wire.index].bel_pins.get(); + range.e.ptr = range.b.ptr + chip_info->wire_data[wire.index].num_bel_pins; + return range; + } + WireRange getWires() const { WireRange range; @@ -581,6 +567,8 @@ struct Arch : BaseCtx wire_to_net[dst.index] = net; nets[net]->wires[dst].pip = pip; nets[net]->wires[dst].strength = strength; + refreshUiPip(pip); + refreshUiWire(dst); } void unbindPip(PipId pip) @@ -597,6 +585,8 @@ struct Arch : BaseCtx pip_to_net[pip.index] = IdString(); switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString(); + refreshUiPip(pip); + refreshUiWire(dst); } bool checkPipAvail(PipId pip) const diff --git a/ice40/arch_place.cc b/ice40/arch_place.cc index 116ab7d3..cf1276a7 100644 --- a/ice40/arch_place.cc +++ b/ice40/arch_place.cc @@ -110,7 +110,7 @@ bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const } else if (cell->type == id_sb_gb) { NPNR_ASSERT(cell->ports.at(id_glb_buf_out).net != nullptr); const NetInfo *net = cell->ports.at(id_glb_buf_out).net; - IdString glb_net = getWireName(getWireBelPin(bel, PIN_GLOBAL_BUFFER_OUTPUT)); + IdString glb_net = getWireName(getBelPinWire(bel, PIN_GLOBAL_BUFFER_OUTPUT)); int glb_id = std::stoi(std::string("") + glb_net.str(this).back()); if (net->is_reset && net->is_enable) return false; diff --git a/ice40/arch_pybindings.cc b/ice40/arch_pybindings.cc index fd5109b4..246d0f57 100644 --- a/ice40/arch_pybindings.cc +++ b/ice40/arch_pybindings.cc @@ -82,12 +82,10 @@ void arch_wrap_python() fn_wrapper_1a<Context, decltype(&Context::getBelsAtSameTile), &Context::getBelsAtSameTile, wrap_context<BelRange>, conv_from_str<BelId>>::def_wrap(ctx_cls, "getBelsAtSameTile"); - fn_wrapper_2a<Context, decltype(&Context::getWireBelPin), &Context::getWireBelPin, conv_to_str<WireId>, - conv_from_str<BelId>, conv_from_str<PortPin>>::def_wrap(ctx_cls, "getWireBelPin"); - fn_wrapper_1a<Context, decltype(&Context::getBelPinUphill), &Context::getBelPinUphill, wrap_context<BelPin>, - conv_from_str<WireId>>::def_wrap(ctx_cls, "getBelPinUphill"); - fn_wrapper_1a<Context, decltype(&Context::getBelPinsDownhill), &Context::getBelPinsDownhill, - wrap_context<BelPinRange>, conv_from_str<WireId>>::def_wrap(ctx_cls, "getBelPinsDownhill"); + fn_wrapper_2a<Context, decltype(&Context::getBelPinWire), &Context::getBelPinWire, conv_to_str<WireId>, + conv_from_str<BelId>, conv_from_str<PortPin>>::def_wrap(ctx_cls, "getBelPinWire"); + fn_wrapper_1a<Context, decltype(&Context::getWireBelPins), &Context::getWireBelPins, wrap_context<BelPinRange>, + conv_from_str<WireId>>::def_wrap(ctx_cls, "getWireBelPins"); fn_wrapper_1a<Context, decltype(&Context::getWireChecksum), &Context::getWireChecksum, pass_through<uint32_t>, conv_from_str<WireId>>::def_wrap(ctx_cls, "getWireChecksum"); diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc index 7fd3f8ac..9ac8e857 100644 --- a/ice40/bitstream.cc +++ b/ice40/bitstream.cc @@ -319,8 +319,8 @@ void write_asc(const Context *ctx, std::ostream &out) NPNR_ASSERT(iez != -1);
bool input_en = false;
- if ((ctx->wire_to_net[ctx->getWireBelPin(bel, PIN_D_IN_0).index] != IdString()) ||
- (ctx->wire_to_net[ctx->getWireBelPin(bel, PIN_D_IN_1).index] != IdString())) {
+ if ((ctx->wire_to_net[ctx->getBelPinWire(bel, PIN_D_IN_0).index] != IdString()) ||
+ (ctx->wire_to_net[ctx->getBelPinWire(bel, PIN_D_IN_1).index] != IdString())) {
input_en = true;
}
@@ -482,8 +482,9 @@ void write_asc(const Context *ctx, std::ostream &out) set_config(ti, config.at(y).at(x),
"Cascade.IPCON_LC0" + std::to_string(lc_idx) + "_inmux02_5", true);
else
- set_config(ti, config.at(y).at(x), "Cascade.MULT" + std::to_string(int(tile - TILE_DSP0)) +
- "_LC0" + std::to_string(lc_idx) + "_inmux02_5",
+ set_config(ti, config.at(y).at(x),
+ "Cascade.MULT" + std::to_string(int(tile - TILE_DSP0)) + "_LC0" +
+ std::to_string(lc_idx) + "_inmux02_5",
true);
}
}
@@ -717,42 +718,44 @@ bool read_asc(Context *ctx, std::istream &in) for (auto w : net.second->wires) {
if (w.second.pip == PipId()) {
WireId wire = w.first;
- BelPin belpin = ctx->getBelPinUphill(wire);
- if (ctx->checkBelAvail(belpin.bel)) {
- if (ctx->getBelType(belpin.bel) == TYPE_ICESTORM_LC) {
- std::unique_ptr<CellInfo> created = create_ice_cell(ctx, ctx->id("ICESTORM_LC"));
- IdString name = created->name;
- ctx->cells[name] = std::move(created);
- ctx->bindBel(belpin.bel, name, STRENGTH_WEAK);
- // TODO: Add port mapping to nets
- }
- if (ctx->getBelType(belpin.bel) == TYPE_SB_IO) {
- std::unique_ptr<CellInfo> created = create_ice_cell(ctx, ctx->id("SB_IO"));
- IdString name = created->name;
- ctx->cells[name] = std::move(created);
- ctx->bindBel(belpin.bel, name, STRENGTH_WEAK);
- // TODO: Add port mapping to nets
- }
- if (ctx->getBelType(belpin.bel) == TYPE_SB_GB) {
- std::unique_ptr<CellInfo> created = create_ice_cell(ctx, ctx->id("SB_GB"));
- IdString name = created->name;
- ctx->cells[name] = std::move(created);
- ctx->bindBel(belpin.bel, name, STRENGTH_WEAK);
- // TODO: Add port mapping to nets
- }
- if (ctx->getBelType(belpin.bel) == TYPE_SB_WARMBOOT) {
- std::unique_ptr<CellInfo> created = create_ice_cell(ctx, ctx->id("SB_WARMBOOT"));
- IdString name = created->name;
- ctx->cells[name] = std::move(created);
- ctx->bindBel(belpin.bel, name, STRENGTH_WEAK);
- // TODO: Add port mapping to nets
- }
- if (ctx->getBelType(belpin.bel) == TYPE_ICESTORM_LFOSC) {
- std::unique_ptr<CellInfo> created = create_ice_cell(ctx, ctx->id("ICESTORM_LFOSC"));
- IdString name = created->name;
- ctx->cells[name] = std::move(created);
- ctx->bindBel(belpin.bel, name, STRENGTH_WEAK);
- // TODO: Add port mapping to nets
+ for (auto belpin : ctx->getWireBelPins(wire)) {
+
+ if (ctx->checkBelAvail(belpin.bel)) {
+ if (ctx->getBelType(belpin.bel) == TYPE_ICESTORM_LC) {
+ std::unique_ptr<CellInfo> created = create_ice_cell(ctx, ctx->id("ICESTORM_LC"));
+ IdString name = created->name;
+ ctx->cells[name] = std::move(created);
+ ctx->bindBel(belpin.bel, name, STRENGTH_WEAK);
+ // TODO: Add port mapping to nets
+ }
+ if (ctx->getBelType(belpin.bel) == TYPE_SB_IO) {
+ std::unique_ptr<CellInfo> created = create_ice_cell(ctx, ctx->id("SB_IO"));
+ IdString name = created->name;
+ ctx->cells[name] = std::move(created);
+ ctx->bindBel(belpin.bel, name, STRENGTH_WEAK);
+ // TODO: Add port mapping to nets
+ }
+ if (ctx->getBelType(belpin.bel) == TYPE_SB_GB) {
+ std::unique_ptr<CellInfo> created = create_ice_cell(ctx, ctx->id("SB_GB"));
+ IdString name = created->name;
+ ctx->cells[name] = std::move(created);
+ ctx->bindBel(belpin.bel, name, STRENGTH_WEAK);
+ // TODO: Add port mapping to nets
+ }
+ if (ctx->getBelType(belpin.bel) == TYPE_SB_WARMBOOT) {
+ std::unique_ptr<CellInfo> created = create_ice_cell(ctx, ctx->id("SB_WARMBOOT"));
+ IdString name = created->name;
+ ctx->cells[name] = std::move(created);
+ ctx->bindBel(belpin.bel, name, STRENGTH_WEAK);
+ // TODO: Add port mapping to nets
+ }
+ if (ctx->getBelType(belpin.bel) == TYPE_ICESTORM_LFOSC) {
+ std::unique_ptr<CellInfo> created = create_ice_cell(ctx, ctx->id("ICESTORM_LFOSC"));
+ IdString name = created->name;
+ ctx->cells[name] = std::move(created);
+ ctx->bindBel(belpin.bel, name, STRENGTH_WEAK);
+ // TODO: Add port mapping to nets
+ }
}
}
}
@@ -762,7 +765,7 @@ bool read_asc(Context *ctx, std::istream &in) if (cell.second->bel != BelId()) {
for (auto &port : cell.second->ports) {
PortPin pin = ctx->portPinFromId(port.first);
- WireId wire = ctx->getWireBelPin(cell.second->bel, pin);
+ WireId wire = ctx->getBelPinWire(cell.second->bel, pin);
if (wire != WireId()) {
IdString name = ctx->getBoundWireNet(wire);
if (name != IdString()) {
diff --git a/ice40/chipdb.py b/ice40/chipdb.py index 329fef56..0e8e3ba7 100644 --- a/ice40/chipdb.py +++ b/ice40/chipdb.py @@ -43,6 +43,7 @@ packages = list() wire_uphill_belport = dict() wire_downhill_belports = dict() +wire_belports = dict() wire_names = dict() wire_names_r = dict() @@ -372,8 +373,12 @@ with open(args.filename, "r") as f: if line[0] == ".extra_cell": if len(line) >= 5: mode = ("extra_cell", (line[4], int(line[1]), int(line[2]), int(line[3]))) - else: + elif line[3] == "WARMBOOT": + mode = ("extra_cell", (line[3], int(line[1]), int(line[2]), 0)) + elif line[3] == "PLL": mode = ("extra_cell", (line[3], int(line[1]), int(line[2]), 3)) + else: + assert 0 extra_cells[mode[1]] = [] continue @@ -449,12 +454,18 @@ def add_bel_input(bel, wire, port): if wire not in wire_downhill_belports: wire_downhill_belports[wire] = set() wire_downhill_belports[wire].add((bel, port)) - bel_wires[bel].append((wire, port)) + if wire not in wire_belports: + wire_belports[wire] = set() + wire_belports[wire].add((bel, port)) + bel_wires[bel].append((wire, port, 0)) def add_bel_output(bel, wire, port): assert wire not in wire_uphill_belport wire_uphill_belport[wire] = (bel, port) - bel_wires[bel].append((wire, port)) + if wire not in wire_belports: + wire_belports[wire] = set() + wire_belports[wire].add((bel, port)) + bel_wires[bel].append((wire, port, 1)) def add_bel_lc(x, y, z): bel = len(bel_name) @@ -557,11 +568,14 @@ def add_bel_ram(x, y): add_bel_input(bel, wire_names[(x, y1, "ram/RCLKE")], "RCLKE") add_bel_input(bel, wire_names[(x, y1, "ram/RE")], "RE") -def add_bel_gb(x, y, g): +def add_bel_gb(xy, x, y, g): + if xy[0] != x or xy[1] != y: + return + bel = len(bel_name) bel_name.append("X%d/Y%d/gb" % (x, y)) bel_type.append("SB_GB") - bel_pos.append((x, y, 0)) + bel_pos.append((x, y, 2)) bel_wires.append(list()) add_bel_input(bel, wire_names[(x, y, "fabout")], "USER_SIGNAL_TO_GLOBAL_BUFFER") @@ -598,51 +612,58 @@ for tile_xy, tile_type in sorted(tiles.items()): if tile_type == "logic": for i in range(8): add_bel_lc(tile_xy[0], tile_xy[1], i) + if tile_type == "io": for i in range(2): add_bel_io(tile_xy[0], tile_xy[1], i) + + if dev_name == "1k": + add_bel_gb(tile_xy, 7, 0, 0) + add_bel_gb(tile_xy, 7, 17, 1) + add_bel_gb(tile_xy, 13, 9, 2) + add_bel_gb(tile_xy, 0, 9, 3) + add_bel_gb(tile_xy, 6, 17, 4) + add_bel_gb(tile_xy, 6, 0, 5) + add_bel_gb(tile_xy, 0, 8, 6) + add_bel_gb(tile_xy, 13, 8, 7) + elif dev_name == "5k": + add_bel_gb(tile_xy, 13, 0, 0) + add_bel_gb(tile_xy, 13, 31, 1) + add_bel_gb(tile_xy, 19, 31, 2) + add_bel_gb(tile_xy, 6, 31, 3) + add_bel_gb(tile_xy, 12, 31, 4) + add_bel_gb(tile_xy, 12, 0, 5) + add_bel_gb(tile_xy, 6, 0, 6) + add_bel_gb(tile_xy, 19, 0, 7) + elif dev_name == "8k": + add_bel_gb(tile_xy, 33, 16, 7) + add_bel_gb(tile_xy, 0, 16, 6) + add_bel_gb(tile_xy, 17, 33, 1) + add_bel_gb(tile_xy, 17, 0, 0) + add_bel_gb(tile_xy, 0, 17, 3) + add_bel_gb(tile_xy, 33, 17, 2) + add_bel_gb(tile_xy, 16, 0, 5) + add_bel_gb(tile_xy, 16, 33, 4) + elif dev_name == "384": + add_bel_gb(tile_xy, 7, 4, 7) + add_bel_gb(tile_xy, 0, 4, 6) + add_bel_gb(tile_xy, 4, 9, 1) + add_bel_gb(tile_xy, 4, 0, 0) + add_bel_gb(tile_xy, 0, 5, 3) + add_bel_gb(tile_xy, 7, 5, 2) + add_bel_gb(tile_xy, 3, 0, 5) + add_bel_gb(tile_xy, 3, 9, 4) + if tile_type == "ramb": add_bel_ram(tile_xy[0], tile_xy[1]) -if dev_name == "1k": - add_bel_gb( 7, 0, 0) - add_bel_gb( 7, 17, 1) - add_bel_gb(13, 9, 2) - add_bel_gb( 0, 9, 3) - add_bel_gb( 6, 17, 4) - add_bel_gb( 6, 0, 5) - add_bel_gb( 0, 8, 6) - add_bel_gb(13, 8, 7) -elif dev_name == "5k": - add_bel_gb(13, 0, 0) - add_bel_gb(13, 31, 1) - add_bel_gb(19, 31, 2) - add_bel_gb( 6, 31, 3) - add_bel_gb(12, 31, 4) - add_bel_gb(12, 0, 5) - add_bel_gb( 6, 0, 6) - add_bel_gb(19, 0, 7) -elif dev_name == "8k": - add_bel_gb(33, 16, 7) - add_bel_gb( 0, 16, 6) - add_bel_gb(17, 33, 1) - add_bel_gb(17, 0, 0) - add_bel_gb( 0, 17, 3) - add_bel_gb(33, 17, 2) - add_bel_gb(16, 0, 5) - add_bel_gb(16, 33, 4) -elif dev_name == "384": - add_bel_gb( 7, 4, 7) - add_bel_gb( 0, 4, 6) - add_bel_gb( 4, 9, 1) - add_bel_gb( 4, 0, 0) - add_bel_gb( 0, 5, 3) - add_bel_gb( 7, 5, 2) - add_bel_gb( 3, 0, 5) - add_bel_gb( 3, 9, 4) + for ec in sorted(extra_cells.keys()): + if ec[1] == tile_xy[0] and ec[2] == tile_xy[1]: + add_bel_ec(ec) for ec in sorted(extra_cells.keys()): - add_bel_ec(ec) + if ec[1] == 0 and ec[2] == 0: + add_bel_ec(ec) class BinaryBlobAssembler: def __init__(self, cname, endianness, nodebug = False): @@ -913,6 +934,7 @@ for bel in range(len(bel_name)): for i in range(len(bel_wires[bel])): bba.u32(bel_wires[bel][i][0], "wire_index") bba.u32(portpins[bel_wires[bel][i][1]], "port") + bba.u32(bel_wires[bel][i][2], "type") index += 1 bba.l("bel_data_%s" % dev_name, "BelInfoPOD") @@ -988,6 +1010,15 @@ for wire in range(num_wires): else: num_bels_downhill = 0 + if wire in wire_belports: + num_bel_pins = len(wire_belports[wire]) + bba.l("wire%d_bels" % wire, "BelPortPOD") + for belport in sorted(wire_belports[wire]): + bba.u32(belport[0], "bel_index") + bba.u32(portpins[belport[1]], "port") + else: + num_bel_pins = 0 + info = dict() info["name"] = "X%d/Y%d/%s" % wire_names_r[wire] @@ -1000,6 +1031,9 @@ for wire in range(num_wires): info["num_bels_downhill"] = num_bels_downhill info["list_bels_downhill"] = ("wire%d_downbels" % wire) if num_bels_downhill > 0 else None + info["num_bel_pins"] = num_bel_pins + info["list_bel_pins"] = ("wire%d_bels" % wire) if num_bel_pins > 0 else None + if wire in wire_uphill_belport: info["uphill_bel"] = wire_uphill_belport[wire][0] info["uphill_pin"] = portpins[wire_uphill_belport[wire][1]] @@ -1085,6 +1119,8 @@ for wire, info in enumerate(wireinfo): bba.u32(info["uphill_bel"], "bel_uphill.bel_index") bba.u32(info["uphill_pin"], "bel_uphill.port") bba.r(info["list_bels_downhill"], "bels_downhill") + bba.u32(info["num_bel_pins"], "num_bel_pins") + bba.r(info["list_bel_pins"], "bel_pins") bba.u32(len(wire_segments[wire]), "num_segments") if len(wire_segments[wire]): bba.r("wire_segments_%d" % wire, "segments") diff --git a/ice40/main.cc b/ice40/main.cc index 70324a91..4de05d00 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -69,8 +69,8 @@ void svg_dump_decal(const Context *ctx, const DecalXY &decal) void conflicting_options(const boost::program_options::variables_map &vm, const char *opt1, const char *opt2) { if (vm.count(opt1) && !vm[opt1].defaulted() && vm.count(opt2) && !vm[opt2].defaulted()) { - std::string msg = "Conflicting options '"+ std::string(opt1) + "' and '" + std::string(opt1) + "'."; - log_error("%s\n",msg.c_str()); + std::string msg = "Conflicting options '" + std::string(opt1) + "' and '" + std::string(opt1) + "'."; + log_error("%s\n", msg.c_str()); } } @@ -107,6 +107,7 @@ int main(int argc, char *argv[]) options.add_options()("seed", po::value<int>(), "seed value for random number generator"); options.add_options()("version,V", "show version"); options.add_options()("tmfuzz", "run path delay estimate fuzzer"); + options.add_options()("test", "check architecture database integrity"); #ifdef ICE40_HX1K_ONLY options.add_options()("hx1k", "set device type to iCE40HX1K"); #else @@ -315,6 +316,9 @@ int main(int argc, char *argv[]) std::cout << "</svg>\n"; } + if (vm.count("test")) + ctx->archcheck(); + if (vm.count("tmfuzz")) { std::vector<WireId> src_wires, dst_wires; @@ -322,25 +326,25 @@ int main(int argc, char *argv[]) src_wires.push_back(w);*/ for (auto b : ctx->getBels()) { if (ctx->getBelType(b) == TYPE_ICESTORM_LC) { - src_wires.push_back(ctx->getWireBelPin(b, PIN_O)); + src_wires.push_back(ctx->getBelPinWire(b, PIN_O)); } if (ctx->getBelType(b) == TYPE_SB_IO) { - src_wires.push_back(ctx->getWireBelPin(b, PIN_D_IN_0)); + src_wires.push_back(ctx->getBelPinWire(b, PIN_D_IN_0)); } } for (auto b : ctx->getBels()) { if (ctx->getBelType(b) == TYPE_ICESTORM_LC) { - dst_wires.push_back(ctx->getWireBelPin(b, PIN_I0)); - dst_wires.push_back(ctx->getWireBelPin(b, PIN_I1)); - dst_wires.push_back(ctx->getWireBelPin(b, PIN_I2)); - dst_wires.push_back(ctx->getWireBelPin(b, PIN_I3)); - dst_wires.push_back(ctx->getWireBelPin(b, PIN_CEN)); - dst_wires.push_back(ctx->getWireBelPin(b, PIN_CIN)); + dst_wires.push_back(ctx->getBelPinWire(b, PIN_I0)); + dst_wires.push_back(ctx->getBelPinWire(b, PIN_I1)); + dst_wires.push_back(ctx->getBelPinWire(b, PIN_I2)); + dst_wires.push_back(ctx->getBelPinWire(b, PIN_I3)); + dst_wires.push_back(ctx->getBelPinWire(b, PIN_CEN)); + dst_wires.push_back(ctx->getBelPinWire(b, PIN_CIN)); } if (ctx->getBelType(b) == TYPE_SB_IO) { - dst_wires.push_back(ctx->getWireBelPin(b, PIN_D_OUT_0)); - dst_wires.push_back(ctx->getWireBelPin(b, PIN_OUTPUT_ENABLE)); + dst_wires.push_back(ctx->getBelPinWire(b, PIN_D_OUT_0)); + dst_wires.push_back(ctx->getBelPinWire(b, PIN_OUTPUT_ENABLE)); } } @@ -360,8 +364,10 @@ int main(int argc, char *argv[]) ctx->chip_info->wire_data[dst.index].type); } } + if (vm.count("freq")) ctx->target_freq = vm["freq"].as<double>() * 1e6; + ctx->timing_driven = true; if (vm.count("no-tmdriv")) ctx->timing_driven = false; |