diff options
| -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 | 14 | ||||
| -rw-r--r-- | common/router1.cc | 312 | ||||
| -rw-r--r-- | common/timing.cc | 4 | ||||
| -rw-r--r-- | common/timing.h | 2 | ||||
| -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 | 
25 files changed, 1112 insertions, 596 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 be20c072..461fc4e8 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;          wirelen_t min_metric = curr_metric; @@ -185,6 +191,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;              } @@ -242,8 +249,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)) { @@ -261,6 +272,7 @@ class SAPlacer                  }              }          } +        ctx->unlock();          return true;      } @@ -446,7 +458,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 86fb1a44..431770da 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -22,6 +22,7 @@  #include "log.h"  #include "router1.h" +#include "timing.h"  namespace { @@ -251,7 +252,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 +264,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 +297,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 +315,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 +331,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 +341,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) { -            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; - -            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)); - +        for (int user_idx : users_array) {              if (ctx->debug) -                log("    Destination bel: %s\n", ctx->getBelName(dst_bel).c_str(ctx)); +                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)); -            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,35 +452,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]; @@ -542,46 +479,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;              } @@ -596,8 +517,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(); @@ -605,73 +525,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; @@ -696,6 +578,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; @@ -730,13 +613,43 @@ bool router1(Context *ctx)              std::unordered_set<IdString> normalRouteNets, ripupQueue; -            if (ctx->verbose || iterCnt == 1) -                log_info("routing queue contains %d jobs.\n", int(jobQueue.size())); +            if (iterCnt == 1) { +                if (ctx->verbose) +                    log_info("routing queue contains %d jobs.\n", int(jobQueue.size())); +            } else { +                static auto actual_delay = [](Context *ctx, WireId src, WireId dst) { +                    delay_t total_delay = 0; +                    WireId last = dst; +                    auto net_name = ctx->getBoundWireNet(src); +                    if (net_name != IdString()) { +                        auto net = ctx->nets.at(net_name).get(); +                        while (last != src) { +                            total_delay += ctx->getWireDelay(last).maxDelay(); +                            auto pip = net->wires.at(last).pip; +                            NPNR_ASSERT(ctx->getBoundPipNet(pip) == net_name); +                            total_delay += ctx->getPipDelay(pip).maxDelay(); +                            last = ctx->getPipSrcWire(pip); +                            if (ctx->getBoundWireNet(last) != net_name) { +                                log_warning("Wire %s bound to %s not %s!\n", ctx->getWireName(last).c_str(ctx), ctx->getBoundWireNet(last).c_str(ctx), net_name.c_str(ctx)); +                                break; +                            } +                            NPNR_ASSERT(ctx->getBoundWireNet(last) == net_name); +                        } +                        NPNR_ASSERT(last != WireId()); +                    } +                    if (last != src) +                        total_delay += ctx->estimateDelay(src, last); +                    else +                        total_delay += ctx->getWireDelay(last).maxDelay(); +                    return total_delay; +                }; +                update_budget(ctx, actual_delay); +            }              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; @@ -745,8 +658,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));                  } @@ -767,15 +680,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 " @@ -829,8 +746,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)) @@ -848,9 +767,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; @@ -858,6 +776,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); @@ -867,6 +787,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(); @@ -889,11 +841,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/common/timing.cc b/common/timing.cc index 9723550b..0e84dded 100644 --- a/common/timing.cc +++ b/common/timing.cc @@ -164,7 +164,7 @@ static delay_t follow_net_update(Context *ctx, NetInfo *net, int path_length, de      return net_budget;  } -void update_budget(Context *ctx) +void update_budget(Context *ctx, std::function<delay_t(Context*,WireId,WireId)> delay_fn)  {      delays_t delays;      updates_t updates; @@ -191,7 +191,7 @@ void update_budget(Context *ctx)              if (load_cell->bel == BelId())                  continue;              WireId user_wire = ctx->getWireBelPin(load_cell->bel, ctx->portPinFromId(load.port)); -            delay_t raw_wl = ctx->estimateDelay(drv_wire, user_wire); +            delay_t raw_wl = delay_fn(ctx, drv_wire, user_wire);              delays.emplace(&load_cell->ports.at(load.port), raw_wl);          }      } diff --git a/common/timing.h b/common/timing.h index b5574392..8c098963 100644 --- a/common/timing.h +++ b/common/timing.h @@ -27,7 +27,7 @@ NEXTPNR_NAMESPACE_BEGIN  // Assign "budget" values for all user ports in the design  void assign_budget(Context *ctx); -void update_budget(Context *ctx); +void update_budget(Context *ctx, std::function<delay_t(Context*,WireId,WireId)> delay_fn=&Context::estimateDelay);  NEXTPNR_NAMESPACE_END diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 90f88384..d887aa69 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));  }  delay_t Arch::getBudgetOverride(const PortRef& pr, delay_t v) const diff --git a/ecp5/arch.h b/ecp5/arch.h index ec98d029..38362d6b 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 b9ec1695..f5e94778 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 977cc4d5..2b952da6 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 fa0fd153..51fa6472 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 @@ -531,9 +554,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 1349365c..697d4142 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;  | 
