diff options
-rw-r--r-- | README.md | 15 | ||||
-rw-r--r-- | common/nextpnr.cc | 13 | ||||
-rw-r--r-- | common/nextpnr.h | 155 | ||||
-rw-r--r-- | common/place_common.cc | 95 | ||||
-rw-r--r-- | common/place_common.h | 81 | ||||
-rw-r--r-- | common/placer1.cc | 181 | ||||
-rw-r--r-- | common/router1.cc | 107 | ||||
-rw-r--r-- | default.nix | 28 | ||||
-rw-r--r-- | ecp5/arch.cc | 184 | ||||
-rw-r--r-- | ecp5/arch.h | 263 | ||||
-rw-r--r-- | ecp5/arch_pybindings.h | 18 | ||||
-rw-r--r-- | ecp5/bitstream.cc | 5 | ||||
-rw-r--r-- | gui/designwidget.cc | 26 | ||||
-rw-r--r-- | gui/fpgaviewwidget.cc | 142 | ||||
-rw-r--r-- | gui/fpgaviewwidget.h | 77 | ||||
-rw-r--r-- | ice40/arch.cc | 305 | ||||
-rw-r--r-- | ice40/arch.h | 309 | ||||
-rw-r--r-- | ice40/arch_place.cc | 69 | ||||
-rw-r--r-- | ice40/arch_pybindings.cc | 32 | ||||
-rw-r--r-- | ice40/arch_pybindings.h | 18 | ||||
-rw-r--r-- | ice40/bitstream.cc | 13 | ||||
-rw-r--r-- | ice40/main.cc | 24 | ||||
-rw-r--r-- | ice40/place_legaliser.cc | 73 | ||||
-rw-r--r-- | nextpnr.nix | 53 |
24 files changed, 902 insertions, 1384 deletions
@@ -78,21 +78,6 @@ Running `./nextpnr-ecp5 --json ecp5/synth/blinky.json --basecfg ecp5/synth/ulx3s_empty.config --bit ecp5/synth/ulx3s.bit` - Note that `ulx3s_empty.config` contains fixed/unknown bits to be copied to the output bitstream - You can also use `--textcfg out.config` to write a text file describing the bitstream for debugging - -Nix ---- - -As an alternative to getting the prerequisites yourself, you can use Nix/NixOS and run the following to get dropped into a shell with nextpnr built: - - nix-shell - -Or, you can add the `nextpnr.nix` file into your /etc/nixos/configuration.nix: - - environment.systemPackages = [ - ... - ( import /home/q3k/Software/nextpnr/nextpnr.nix ) - ... - ]; Notes ------- diff --git a/common/nextpnr.cc b/common/nextpnr.cc index 01c1397e..3861e5fe 100644 --- a/common/nextpnr.cc +++ b/common/nextpnr.cc @@ -21,10 +21,6 @@ NEXTPNR_NAMESPACE_BEGIN -MutateContext BaseCtx::rwproxy(void) { return MutateContext(reinterpret_cast<Arch *>(this)); } - -ReadContext BaseCtx::rproxy(void) const { return ReadContext(reinterpret_cast<const Arch *>(this)); } - assertion_failure::assertion_failure(std::string msg, std::string expr_str, std::string filename, int line) : runtime_error("Assertion failure: " + msg + " (" + filename + ":" + std::to_string(line) + ")"), msg(msg), expr_str(expr_str), filename(filename), line(line) @@ -170,21 +166,20 @@ uint32_t Context::checksum() const void Context::check() const { - auto &&proxy = rproxy(); for (auto &n : nets) { auto ni = n.second.get(); NPNR_ASSERT(n.first == ni->name); for (auto &w : ni->wires) { - NPNR_ASSERT(n.first == proxy.getBoundWireNet(w.first)); + NPNR_ASSERT(n.first == getBoundWireNet(w.first)); if (w.second.pip != PipId()) { NPNR_ASSERT(w.first == getPipDstWire(w.second.pip)); - NPNR_ASSERT(n.first == proxy.getBoundPipNet(w.second.pip)); + NPNR_ASSERT(n.first == getBoundPipNet(w.second.pip)); } } } for (auto w : getWires()) { - IdString net = proxy.getBoundWireNet(w); + IdString net = getBoundWireNet(w); if (net != IdString()) { NPNR_ASSERT(nets.at(net)->wires.count(w)); } @@ -193,7 +188,7 @@ void Context::check() const for (auto &c : cells) { NPNR_ASSERT(c.first == c.second->name); if (c.second->bel != BelId()) - NPNR_ASSERT(proxy.getBoundBelCell(c.second->bel) == c.first); + NPNR_ASSERT(getBoundBelCell(c.second->bel) == c.first); for (auto &port : c.second->ports) { NetInfo *net = port.second.net; if (net != nullptr) { diff --git a/common/nextpnr.h b/common/nextpnr.h index 6228e653..50465869 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -19,7 +19,6 @@ #include <algorithm> #include <assert.h> -#include <boost/thread/shared_mutex.hpp> #include <memory> #include <stdexcept> #include <stdint.h> @@ -239,48 +238,21 @@ struct CellInfo std::unordered_map<IdString, IdString> pins; }; -struct UIUpdatesRequired +struct BaseCtx { - bool allUIReload; - bool frameUIReload; - std::unordered_set<BelId> belUIReload; - std::unordered_set<WireId> wireUIReload; - std::unordered_set<PipId> pipUIReload; - std::unordered_set<GroupId> groupUIReload; -}; - -class ReadContext; -class MutateContext; -class BaseReadCtx; -class BaseMutateCtx; - -// Data that every architecture object should contain. -class BaseCtx -{ - friend class ReadContext; - friend class MutateContext; - friend class BaseReadCtx; - friend class BaseMutateCtx; - - private: - mutable boost::shared_mutex mtx_; + // -------------------------------------------------------------- - bool allUiReload = false; - bool frameUiReload = false; - std::unordered_set<BelId> belUiReload; - std::unordered_set<WireId> wireUiReload; - std::unordered_set<PipId> pipUiReload; - std::unordered_set<GroupId> groupUiReload; + mutable std::unordered_map<std::string, int> *idstring_str_to_idx; + mutable std::vector<const std::string *> *idstring_idx_to_str; - public: IdString id(const std::string &s) const { return IdString(this, s); } + IdString id(const char *s) const { return IdString(this, s); } - // TODO(q3k): These need to be made private. + // -------------------------------------------------------------- + std::unordered_map<IdString, std::unique_ptr<NetInfo>> nets; std::unordered_map<IdString, std::unique_ptr<CellInfo>> cells; - mutable std::unordered_map<std::string, int> *idstring_str_to_idx; - mutable std::vector<const std::string *> *idstring_idx_to_str; BaseCtx() { @@ -288,8 +260,6 @@ class BaseCtx idstring_idx_to_str = new std::vector<const std::string *>; IdString::initialize_add(this, "", 0); IdString::initialize_arch(this); - - allUiReload = true; } ~BaseCtx() @@ -304,67 +274,24 @@ class BaseCtx // -------------------------------------------------------------- - // Get a readwrite proxy to arch - this will keep a readwrite lock on the - // entire architecture until the proxy object goes out of scope. - MutateContext rwproxy(void); - // Get a read-only proxy to arch - this will keep a read lock on the - // entire architecture until the proxy object goes out of scope. Other read - // locks can be taken while this one still exists. Ie., the UI can draw - // elements while the PnR is going a RO operation. - ReadContext rproxy(void) const; -}; - -// State-accessing read-only methods that every architecture object should -// contain. -class BaseReadCtx -{ - protected: - const BaseCtx *base_; - - public: - BaseReadCtx(const BaseCtx *base) : base_(base) {} -}; - -// State-accesssing read/write methods that every architecture object should -// contain. -class BaseMutateCtx -{ - protected: - BaseCtx *base_; - - public: - BaseMutateCtx(BaseCtx *base) : base_(base) {} - - void refreshUi(void) { base_->allUiReload = true; } + bool allUiReload = false; + bool frameUiReload = false; + std::unordered_set<BelId> belUiReload; + std::unordered_set<WireId> wireUiReload; + std::unordered_set<PipId> pipUiReload; + std::unordered_set<GroupId> groupUiReload; - void refreshUiFrame(void) { base_->frameUiReload = true; } + void refreshUi() { allUiReload = true; } - void refreshUiBel(BelId bel) { base_->belUiReload.insert(bel); } + void refreshUiFrame() { frameUiReload = true; } - void refreshUiWire(WireId wire) { base_->wireUiReload.insert(wire); } + void refreshUiBel(BelId bel) { belUiReload.insert(bel); } - void refreshUiPip(PipId pip) { base_->pipUiReload.insert(pip); } + void refreshUiWire(WireId wire) { wireUiReload.insert(wire); } - void refreshUiGroup(GroupId group) { base_->groupUiReload.insert(group); } + void refreshUiPip(PipId pip) { pipUiReload.insert(pip); } - UIUpdatesRequired getUIUpdatesRequired(void) - { - UIUpdatesRequired req; - req.allUIReload = base_->allUiReload; - req.frameUIReload = base_->frameUiReload; - req.belUIReload = base_->belUiReload; - req.wireUIReload = base_->wireUiReload; - req.pipUIReload = base_->pipUiReload; - req.groupUIReload = base_->groupUiReload; - - base_->allUiReload = false; - base_->frameUiReload = false; - base_->belUiReload.clear(); - base_->wireUiReload.clear(); - base_->pipUiReload.clear(); - base_->groupUiReload.clear(); - return req; - } + void refreshUiGroup(GroupId group) { groupUiReload.insert(group); } }; NEXTPNR_NAMESPACE_END @@ -373,50 +300,6 @@ NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_BEGIN -// Read proxy to access ReadMethods while holding lock on underlying BaseCtx. -class ReadContext : public ArchReadMethods -{ - friend class BaseCtx; - - private: - boost::shared_mutex *lock_; - ReadContext(const Arch *parent) : ArchReadMethods(parent), lock_(&parent->mtx_) { lock_->lock_shared(); } - - public: - ~ReadContext() - { - if (lock_ != nullptr) { - lock_->unlock_shared(); - } - } - ReadContext(ReadContext &&other) : ArchReadMethods(other), lock_(other.lock_) { other.lock_ = nullptr; } -}; - -// Read proxy to access MutateMethods while holding lock on underlying BaseCtx. -class MutateContext : public ArchReadMethods, public ArchMutateMethods -{ - friend class BaseCtx; - - private: - boost::shared_mutex *lock_; - MutateContext(Arch *parent) : ArchReadMethods(parent), ArchMutateMethods(parent), lock_(&parent->mtx_) - { - lock_->lock(); - } - - public: - ~MutateContext() - { - if (lock_ != nullptr) { - lock_->unlock(); - } - } - MutateContext(MutateContext &&other) : ArchReadMethods(other), ArchMutateMethods(other), lock_(other.lock_) - { - other.lock_ = nullptr; - } -}; - struct Context : Arch { bool verbose = false; diff --git a/common/place_common.cc b/common/place_common.cc index 9694b6fe..60735890 100644 --- a/common/place_common.cc +++ b/common/place_common.cc @@ -2,7 +2,6 @@ * nextpnr -- Next Generation Place and Route * * Copyright (C) 2018 David Shah <david@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 @@ -25,8 +24,84 @@ NEXTPNR_NAMESPACE_BEGIN +// Get the total estimated wirelength for a net +wirelen_t get_net_wirelength(const Context *ctx, const NetInfo *net, float &tns) +{ + wirelen_t wirelength = 0; + int driver_x, driver_y; + bool driver_gb; + CellInfo *driver_cell = net->driver.cell; + if (!driver_cell) + return 0; + 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)); + if (driver_gb) + return 0; + float worst_slack = 1000; + int xmin = driver_x, xmax = driver_x, ymin = driver_y, ymax = driver_y; + for (auto load : net->users) { + if (load.cell == nullptr) + continue; + CellInfo *load_cell = load.cell; + if (load_cell->bel == BelId()) + continue; + if (ctx->timing_driven) { + WireId user_wire = ctx->getWireBelPin(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) + tns += slack; + worst_slack = std::min(slack, worst_slack); + } + + int load_x, load_y; + bool load_gb; + ctx->estimatePosition(load_cell->bel, load_x, load_y, load_gb); + if (load_gb) + continue; + xmin = std::min(xmin, load_x); + ymin = std::min(ymin, load_y); + xmax = std::max(xmax, load_x); + ymax = std::max(ymax, load_y); + } + if (ctx->timing_driven) { + wirelength = wirelen_t((((ymax - ymin) + (xmax - xmin)) * std::min(5.0, (1.0 + std::exp(-worst_slack / 5))))); + } else { + wirelength = wirelen_t((ymax - ymin) + (xmax - xmin)); + } + + return wirelength; +} + +// Get the total wirelength for a cell +wirelen_t get_cell_wirelength(const Context *ctx, const CellInfo *cell) +{ + std::set<IdString> nets; + for (auto p : cell->ports) { + if (p.second.net) + nets.insert(p.second.net->name); + } + wirelen_t wirelength = 0; + float tns = 0; + for (auto n : nets) { + wirelength += get_net_wirelength(ctx, ctx->nets.at(n).get(), tns); + } + return wirelength; +} + +wirelen_t get_cell_wirelength_at_bel(const Context *ctx, CellInfo *cell, BelId bel) +{ + BelId oldBel = cell->bel; + cell->bel = bel; + wirelen_t wirelen = get_cell_wirelength(ctx, cell); + cell->bel = oldBel; + return wirelen; +} + // Placing a single cell -bool place_single_cell(MutateContext &proxy, Context *ctx, CellInfo *cell, bool require_legality) +bool place_single_cell(Context *ctx, CellInfo *cell, bool require_legality) { bool all_placed = false; int iters = 25; @@ -37,13 +112,13 @@ bool place_single_cell(MutateContext &proxy, Context *ctx, CellInfo *cell, bool CellInfo *ripup_target = nullptr; BelId ripup_bel = BelId(); if (cell->bel != BelId()) { - proxy.unbindBel(cell->bel); + ctx->unbindBel(cell->bel); } BelType targetType = ctx->belTypeFromId(cell->type); for (auto bel : ctx->getBels()) { - if (ctx->getBelType(bel) == targetType && (!require_legality || proxy.isValidBelForCell(cell, bel))) { - if (proxy.checkBelAvail(bel)) { - wirelen_t wirelen = get_cell_wirelength_at_bel(proxy, ctx, cell, bel); + if (ctx->getBelType(bel) == targetType && (!require_legality || ctx->isValidBelForCell(cell, bel))) { + if (ctx->checkBelAvail(bel)) { + wirelen_t wirelen = get_cell_wirelength_at_bel(ctx, cell, bel); if (iters >= 4) wirelen += ctx->rng(25); if (wirelen <= best_wirelen) { @@ -51,11 +126,11 @@ bool place_single_cell(MutateContext &proxy, Context *ctx, CellInfo *cell, bool best_bel = bel; } } else { - wirelen_t wirelen = get_cell_wirelength_at_bel(proxy, ctx, cell, bel); + wirelen_t wirelen = get_cell_wirelength_at_bel(ctx, cell, bel); if (iters >= 4) wirelen += ctx->rng(25); if (wirelen <= best_ripup_wirelen) { - ripup_target = proxy.getCell(proxy.getBoundBelCell(bel)); + ripup_target = ctx->cells.at(ctx->getBoundBelCell(bel)).get(); if (ripup_target->belStrength < STRENGTH_STRONG) { best_ripup_wirelen = wirelen; ripup_bel = bel; @@ -73,12 +148,12 @@ bool place_single_cell(MutateContext &proxy, Context *ctx, CellInfo *cell, bool log_error("failed to place cell '%s' of type '%s'\n", cell->name.c_str(ctx), cell->type.c_str(ctx)); } --iters; - proxy.unbindBel(ripup_target->bel); + ctx->unbindBel(ripup_target->bel); best_bel = ripup_bel; } else { all_placed = true; } - proxy.bindBel(best_bel, cell->name, STRENGTH_WEAK); + ctx->bindBel(best_bel, cell->name, STRENGTH_WEAK); cell = ripup_target; } diff --git a/common/place_common.h b/common/place_common.h index dac2e607..67956072 100644 --- a/common/place_common.h +++ b/common/place_common.h @@ -22,92 +22,21 @@ #include "nextpnr.h" -#include <set> - NEXTPNR_NAMESPACE_BEGIN typedef int64_t wirelen_t; -// Get the total estimated wirelength for a net -template <typename T> wirelen_t get_net_wirelength(const T &proxy, const Context *ctx, const NetInfo *net, float &tns) -{ - wirelen_t wirelength = 0; - int driver_x, driver_y; - bool driver_gb; - CellInfo *driver_cell = net->driver.cell; - if (!driver_cell) - return 0; - if (driver_cell->bel == BelId()) - return 0; - ctx->estimatePosition(driver_cell->bel, driver_x, driver_y, driver_gb); - WireId drv_wire = proxy.getWireBelPin(driver_cell->bel, ctx->portPinFromId(net->driver.port)); - if (driver_gb) - return 0; - float worst_slack = 1000; - int xmin = driver_x, xmax = driver_x, ymin = driver_y, ymax = driver_y; - for (auto load : net->users) { - if (load.cell == nullptr) - continue; - CellInfo *load_cell = load.cell; - if (load_cell->bel == BelId()) - continue; - if (ctx->timing_driven) { - WireId user_wire = proxy.getWireBelPin(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) - tns += slack; - worst_slack = std::min(slack, worst_slack); - } - - int load_x, load_y; - bool load_gb; - ctx->estimatePosition(load_cell->bel, load_x, load_y, load_gb); - if (load_gb) - continue; - xmin = std::min(xmin, load_x); - ymin = std::min(ymin, load_y); - xmax = std::max(xmax, load_x); - ymax = std::max(ymax, load_y); - } - if (ctx->timing_driven) { - wirelength = wirelen_t((((ymax - ymin) + (xmax - xmin)) * std::min(5.0, (1.0 + std::exp(-worst_slack / 5))))); - } else { - wirelength = wirelen_t((ymax - ymin) + (xmax - xmin)); - } - - return wirelength; -} +// Return the wirelength of a net +wirelen_t get_net_wirelength(const Context *ctx, const NetInfo *net, float &tns); // Return the wirelength of all nets connected to a cell -template <typename T> wirelen_t get_cell_wirelength(const T &proxy, const Context *ctx, const CellInfo *cell) -{ - std::set<IdString> nets; - for (auto p : cell->ports) { - if (p.second.net) - nets.insert(p.second.net->name); - } - wirelen_t wirelength = 0; - float tns = 0; - for (auto n : nets) { - wirelength += get_net_wirelength(proxy, ctx, ctx->nets.at(n).get(), tns); - } - return wirelength; -} +wirelen_t get_cell_wirelength(const Context *ctx, const CellInfo *cell); // Return the wirelength of all nets connected to a cell, when the cell is at a given bel -template <typename T> -wirelen_t get_cell_wirelength_at_bel(const T &proxy, const Context *ctx, CellInfo *cell, BelId bel) -{ - BelId oldBel = cell->bel; - cell->bel = bel; - wirelen_t wirelen = get_cell_wirelength(proxy, ctx, cell); - cell->bel = oldBel; - return wirelen; -} +wirelen_t get_cell_wirelength_at_bel(const Context *ctx, CellInfo *cell, BelId bel); // Place a single cell in the lowest wirelength Bel available, optionally requiring validity check -bool place_single_cell(MutateContext &proxy, Context *ctx, CellInfo *cell, bool require_legality); +bool place_single_cell(Context *ctx, CellInfo *cell, bool require_legality); NEXTPNR_NAMESPACE_END diff --git a/common/placer1.cc b/common/placer1.cc index 78515ece..53295a91 100644 --- a/common/placer1.cc +++ b/common/placer1.cc @@ -3,7 +3,6 @@ * * Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com> * Copyright (C) 2018 David Shah <david@symbioticeda.com> - * Copyright (C) 2018 Serge Bazanski <q3k@symbioticeda.com> * * Simulated annealing implementation based on arachne-pnr * Copyright (C) 2015-2018 Cotton Seed @@ -80,33 +79,30 @@ class SAPlacer log_break(); size_t placed_cells = 0; - { - auto &&proxy = ctx->rwproxy(); - // Initial constraints placer - for (auto &cell_entry : ctx->cells) { - CellInfo *cell = cell_entry.second.get(); - auto loc = cell->attrs.find(ctx->id("BEL")); - if (loc != cell->attrs.end()) { - std::string loc_name = loc->second; - BelId bel = proxy.getBelByName(ctx->id(loc_name)); - if (bel == BelId()) { - log_error("No Bel named \'%s\' located for " - "this chip (processing BEL attribute on \'%s\')\n", - loc_name.c_str(), cell->name.c_str(ctx)); - } - - BelType bel_type = ctx->getBelType(bel); - if (bel_type != ctx->belTypeFromId(cell->type)) { - log_error("Bel \'%s\' of type \'%s\' does not match cell " - "\'%s\' of type \'%s\'", - loc_name.c_str(), ctx->belTypeToId(bel_type).c_str(ctx), cell->name.c_str(ctx), - cell->type.c_str(ctx)); - } + // Initial constraints placer + for (auto &cell_entry : ctx->cells) { + CellInfo *cell = cell_entry.second.get(); + auto loc = cell->attrs.find(ctx->id("BEL")); + if (loc != cell->attrs.end()) { + std::string loc_name = loc->second; + BelId bel = ctx->getBelByName(ctx->id(loc_name)); + if (bel == BelId()) { + log_error("No Bel named \'%s\' located for " + "this chip (processing BEL attribute on \'%s\')\n", + loc_name.c_str(), cell->name.c_str(ctx)); + } - proxy.bindBel(bel, cell->name, STRENGTH_USER); - locked_bels.insert(bel); - placed_cells++; + BelType bel_type = ctx->getBelType(bel); + if (bel_type != ctx->belTypeFromId(cell->type)) { + log_error("Bel \'%s\' of type \'%s\' does not match cell " + "\'%s\' of type \'%s\'", + loc_name.c_str(), ctx->belTypeToId(bel_type).c_str(ctx), cell->name.c_str(ctx), + cell->type.c_str(ctx)); } + + ctx->bindBel(bel, cell->name, STRENGTH_USER); + locked_bels.insert(bel); + placed_cells++; } } int constr_placed_cells = placed_cells; @@ -126,15 +122,12 @@ class SAPlacer // Place cells randomly initially log_info("Creating initial placement for remaining %d cells.\n", int(autoplaced.size())); - { - auto &&proxy = ctx->rwproxy(); - for (auto cell : autoplaced) { - place_initial(proxy, 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())); - } + for (auto cell : autoplaced) { + 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())); } if ((placed_cells - constr_placed_cells) % 500 != 0) log_info(" initial placement placed %d/%d cells\n", int(placed_cells - constr_placed_cells), @@ -145,13 +138,10 @@ class SAPlacer // Calculate wirelength after initial placement curr_wirelength = 0; curr_tns = 0; - { - auto &&proxy = ctx->rproxy(); - for (auto &net : ctx->nets) { - wirelen_t wl = get_net_wirelength(proxy, ctx, net.second.get(), curr_tns); - wirelengths[net.first] = wl; - curr_wirelength += wl; - } + for (auto &net : ctx->nets) { + wirelen_t wl = get_net_wirelength(ctx, net.second.get(), curr_tns); + wirelengths[net.first] = wl; + curr_wirelength += wl; } int n_no_progress = 0; @@ -168,18 +158,15 @@ class SAPlacer "%.0f, est tns = %.02fns\n", iter, temp, double(curr_wirelength), curr_tns); - { - auto &&proxy = ctx->rwproxy(); - for (int m = 0; m < 15; ++m) { - // Loop through all automatically placed cells - for (auto cell : autoplaced) { - // Find another random Bel for this cell - BelId try_bel = random_bel_for_cell(cell); - // If valid, try and swap to a new position and see if - // the new position is valid/worthwhile - if (try_bel != BelId() && try_bel != cell->bel) - try_swap_position(proxy, cell, try_bel); - } + for (int m = 0; m < 15; ++m) { + // Loop through all automatically placed cells + for (auto cell : autoplaced) { + // Find another random Bel for this cell + BelId try_bel = random_bel_for_cell(cell); + // If valid, try and swap to a new position and see if + // the new position is valid/worthwhile + if (try_bel != BelId() && try_bel != cell->bel) + try_swap_position(cell, try_bel); } } // Heuristic to improve placement on the 8k @@ -240,33 +227,27 @@ class SAPlacer // accumulating over time curr_wirelength = 0; curr_tns = 0; - { - auto &&proxy = ctx->rproxy(); - for (auto &net : ctx->nets) { - wirelen_t wl = get_net_wirelength(proxy, ctx, net.second.get(), curr_tns); - wirelengths[net.first] = wl; - curr_wirelength += wl; - } + for (auto &net : ctx->nets) { + wirelen_t wl = get_net_wirelength(ctx, net.second.get(), curr_tns); + wirelengths[net.first] = wl; + curr_wirelength += wl; } } - { - // Final post-pacement validitiy check - auto &&proxy = ctx->rproxy(); - for (auto bel : ctx->getBels()) { - IdString cell = proxy.getBoundBelCell(bel); - if (!proxy.isBelLocationValid(bel)) { - std::string cell_text = "no cell"; - if (cell != IdString()) - cell_text = std::string("cell '") + cell.str(ctx) + "'"; - if (ctx->force) { - log_warning("post-placement validity check failed for Bel '%s' " - "(%s)\n", - ctx->getBelName(bel).c_str(ctx), cell_text.c_str()); - } else { - log_error("post-placement validity check failed for Bel '%s' " - "(%s)\n", - ctx->getBelName(bel).c_str(ctx), cell_text.c_str()); - } + // Final post-pacement validitiy check + for (auto bel : ctx->getBels()) { + IdString cell = ctx->getBoundBelCell(bel); + if (!ctx->isBelLocationValid(bel)) { + std::string cell_text = "no cell"; + if (cell != IdString()) + cell_text = std::string("cell '") + cell.str(ctx) + "'"; + if (ctx->force) { + log_warning("post-placement validity check failed for Bel '%s' " + "(%s)\n", + ctx->getBelName(bel).c_str(ctx), cell_text.c_str()); + } else { + log_error("post-placement validity check failed for Bel '%s' " + "(%s)\n", + ctx->getBelName(bel).c_str(ctx), cell_text.c_str()); } } } @@ -275,7 +256,7 @@ class SAPlacer private: // Initial random placement - void place_initial(MutateContext &proxy, CellInfo *cell) + void place_initial(CellInfo *cell) { bool all_placed = false; int iters = 25; @@ -286,12 +267,12 @@ class SAPlacer CellInfo *ripup_target = nullptr; BelId ripup_bel = BelId(); if (cell->bel != BelId()) { - proxy.unbindBel(cell->bel); + ctx->unbindBel(cell->bel); } BelType targetType = ctx->belTypeFromId(cell->type); for (auto bel : ctx->getBels()) { - if (ctx->getBelType(bel) == targetType && (proxy.isValidBelForCell(cell, bel) || !require_legal)) { - if (proxy.checkBelAvail(bel)) { + if (ctx->getBelType(bel) == targetType && (ctx->isValidBelForCell(cell, bel) || !require_legal)) { + if (ctx->checkBelAvail(bel)) { uint64_t score = ctx->rng64(); if (score <= best_score) { best_score = score; @@ -301,7 +282,7 @@ class SAPlacer uint64_t score = ctx->rng64(); if (score <= best_ripup_score) { best_ripup_score = score; - ripup_target = ctx->cells.at(proxy.getBoundBelCell(bel)).get(); + ripup_target = ctx->cells.at(ctx->getBoundBelCell(bel)).get(); ripup_bel = bel; } } @@ -311,12 +292,12 @@ class SAPlacer if (iters == 0 || ripup_bel == BelId()) log_error("failed to place cell '%s' of type '%s'\n", cell->name.c_str(ctx), cell->type.c_str(ctx)); --iters; - proxy.unbindBel(ripup_target->bel); + ctx->unbindBel(ripup_target->bel); best_bel = ripup_bel; } else { all_placed = true; } - proxy.bindBel(best_bel, cell->name, STRENGTH_WEAK); + ctx->bindBel(best_bel, cell->name, STRENGTH_WEAK); // Back annotate location cell->attrs[ctx->id("BEL")] = ctx->getBelName(cell->bel).str(ctx); @@ -325,14 +306,14 @@ class SAPlacer } // Attempt a SA position swap, return true on success or false on failure - bool try_swap_position(MutateContext &proxy, CellInfo *cell, BelId newBel) + bool try_swap_position(CellInfo *cell, BelId newBel) { static std::unordered_set<NetInfo *> update; static std::vector<std::pair<IdString, wirelen_t>> new_lengths; new_lengths.clear(); update.clear(); BelId oldBel = cell->bel; - IdString other = proxy.getBoundBelCell(newBel); + IdString other = ctx->getBoundBelCell(newBel); CellInfo *other_cell = nullptr; if (other != IdString()) { other_cell = ctx->cells[other].get(); @@ -340,9 +321,9 @@ class SAPlacer return false; } wirelen_t new_wirelength = 0, delta; - proxy.unbindBel(oldBel); + ctx->unbindBel(oldBel); if (other != IdString()) { - proxy.unbindBel(newBel); + ctx->unbindBel(newBel); } for (const auto &port : cell->ports) @@ -355,16 +336,16 @@ class SAPlacer update.insert(port.second.net); } - proxy.bindBel(newBel, cell->name, STRENGTH_WEAK); + ctx->bindBel(newBel, cell->name, STRENGTH_WEAK); if (other != IdString()) { - proxy.bindBel(oldBel, other_cell->name, STRENGTH_WEAK); + ctx->bindBel(oldBel, other_cell->name, STRENGTH_WEAK); } if (require_legal) { - if (!proxy.isBelLocationValid(newBel) || ((other != IdString() && !proxy.isBelLocationValid(oldBel)))) { - proxy.unbindBel(newBel); + if (!ctx->isBelLocationValid(newBel) || ((other != IdString() && !ctx->isBelLocationValid(oldBel)))) { + ctx->unbindBel(newBel); if (other != IdString()) - proxy.unbindBel(oldBel); + ctx->unbindBel(oldBel); goto swap_fail; } } @@ -375,7 +356,7 @@ class SAPlacer for (auto net : update) { new_wirelength -= wirelengths.at(net->name); float temp_tns = 0; - wirelen_t net_new_wl = get_net_wirelength<>(proxy, ctx, net, temp_tns); + wirelen_t net_new_wl = get_net_wirelength(ctx, net, temp_tns); new_wirelength += net_new_wl; new_lengths.push_back(std::make_pair(net->name, net_new_wl)); } @@ -388,8 +369,8 @@ class SAPlacer improved = true; } else { if (other != IdString()) - proxy.unbindBel(oldBel); - proxy.unbindBel(newBel); + ctx->unbindBel(oldBel); + ctx->unbindBel(newBel); goto swap_fail; } curr_wirelength = new_wirelength; @@ -398,9 +379,9 @@ class SAPlacer return true; swap_fail: - proxy.bindBel(oldBel, cell->name, STRENGTH_WEAK); + ctx->bindBel(oldBel, cell->name, STRENGTH_WEAK); if (other != IdString()) { - proxy.bindBel(newBel, other, STRENGTH_WEAK); + ctx->bindBel(newBel, other, STRENGTH_WEAK); } return false; } diff --git a/common/router1.cc b/common/router1.cc index dc75a153..94c7070e 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -2,7 +2,6 @@ * 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 @@ -74,7 +73,7 @@ struct RipupScoreboard std::unordered_map<std::pair<IdString, PipId>, int, hash_id_pip> netPipScores; }; -void ripup_net(MutateContext &proxy, Context *ctx, IdString net_name) +void ripup_net(Context *ctx, IdString net_name) { auto net_info = ctx->nets.at(net_name).get(); std::vector<PipId> pips; @@ -91,10 +90,10 @@ void ripup_net(MutateContext &proxy, Context *ctx, IdString net_name) } for (auto pip : pips) - proxy.unbindPip(pip); + ctx->unbindPip(pip); for (auto wire : wires) - proxy.unbindWire(wire); + ctx->unbindWire(wire); NPNR_ASSERT(net_info->wires.empty()); } @@ -115,7 +114,7 @@ struct Router delay_t maxDelay = 0.0; WireId failedDest; - void route(MutateContext &proxy, const std::unordered_map<WireId, delay_t> &src_wires, WireId dst_wire) + void route(const std::unordered_map<WireId, delay_t> &src_wires, WireId dst_wire) { std::priority_queue<QueuedWire, std::vector<QueuedWire>, QueuedWire::Greater> queue; @@ -149,10 +148,10 @@ struct Router bool foundRipupNet = false; thisVisitCnt++; - if (!proxy.checkWireAvail(next_wire)) { + if (!ctx->checkWireAvail(next_wire)) { if (!ripup) continue; - IdString ripupWireNet = proxy.getConflictingWireNet(next_wire); + IdString ripupWireNet = ctx->getConflictingWireNet(next_wire); if (ripupWireNet == net_name || ripupWireNet == IdString()) continue; @@ -167,10 +166,10 @@ struct Router foundRipupNet = true; } - if (!proxy.checkPipAvail(pip)) { + if (!ctx->checkPipAvail(pip)) { if (!ripup) continue; - IdString ripupPipNet = proxy.getConflictingPipNet(pip); + IdString ripupPipNet = ctx->getConflictingPipNet(pip); if (ripupPipNet == net_name || ripupPipNet == IdString()) continue; @@ -228,10 +227,7 @@ struct Router { std::unordered_map<WireId, delay_t> src_wires; src_wires[src_wire] = 0; - { - auto &&proxy = ctx->rwproxy(); - route(proxy, src_wires, dst_wire); - } + route(src_wires, dst_wire); routedOkay = visited.count(dst_wire); if (ctx->debug) { @@ -276,7 +272,7 @@ struct Router if (driver_port_it != net_info->driver.cell->pins.end()) driver_port = driver_port_it->second; - auto src_wire = ctx->rproxy().getWireBelPin(src_bel, ctx->portPinFromId(driver_port)); + auto src_wire = ctx->getWireBelPin(src_bel, ctx->portPinFromId(driver_port)); if (src_wire == WireId()) log_error("No wire found for port %s (pin %s) on source cell %s " @@ -290,10 +286,8 @@ struct Router std::unordered_map<WireId, delay_t> src_wires; src_wires[src_wire] = 0; - auto &&proxy = ctx->rwproxy(); - - ripup_net(proxy, ctx, net_name); - proxy.bindWire(src_wire, net_name, STRENGTH_WEAK); + ripup_net(ctx, net_name); + ctx->bindWire(src_wire, net_name, STRENGTH_WEAK); std::vector<PortRef> users_array = net_info->users; ctx->shuffle(users_array); @@ -318,7 +312,7 @@ struct Router if (user_port_it != user_it.cell->pins.end()) user_port = user_port_it->second; - auto dst_wire = proxy.getWireBelPin(dst_bel, ctx->portPinFromId(user_port)); + auto dst_wire = ctx->getWireBelPin(dst_bel, ctx->portPinFromId(user_port)); if (dst_wire == WireId()) log_error("No wire found for port %s (pin %s) on destination " @@ -331,7 +325,7 @@ struct Router log(" Path delay estimate: %.2f\n", float(ctx->estimateDelay(src_wire, dst_wire))); } - route(proxy, src_wires, dst_wire); + route(src_wires, dst_wire); if (visited.count(dst_wire) == 0) { if (ctx->debug) @@ -340,7 +334,7 @@ struct Router else if (ripup) log_info("Failed to route %s -> %s.\n", ctx->getWireName(src_wire).c_str(ctx), ctx->getWireName(dst_wire).c_str(ctx)); - ripup_net(proxy, ctx, net_name); + ripup_net(ctx, net_name); failedDest = dst_wire; return; } @@ -361,15 +355,15 @@ struct Router if (src_wires.count(cursor)) break; - IdString conflicting_wire_net = proxy.getConflictingWireNet(cursor); + IdString conflicting_wire_net = ctx->getConflictingWireNet(cursor); if (conflicting_wire_net != IdString()) { NPNR_ASSERT(ripup); NPNR_ASSERT(conflicting_wire_net != net_name); - proxy.unbindWire(cursor); - if (!proxy.checkWireAvail(cursor)) - ripup_net(proxy, ctx, conflicting_wire_net); + ctx->unbindWire(cursor); + if (!ctx->checkWireAvail(cursor)) + ripup_net(ctx, conflicting_wire_net); rippedNets.insert(conflicting_wire_net); scores.wireScores[cursor]++; @@ -378,15 +372,15 @@ struct Router } PipId pip = visited[cursor].pip; - IdString conflicting_pip_net = proxy.getConflictingPipNet(pip); + IdString conflicting_pip_net = ctx->getConflictingPipNet(pip); if (conflicting_pip_net != IdString()) { NPNR_ASSERT(ripup); NPNR_ASSERT(conflicting_pip_net != net_name); - proxy.unbindPip(pip); - if (!proxy.checkPipAvail(pip)) - ripup_net(proxy, ctx, conflicting_pip_net); + ctx->unbindPip(pip); + if (!ctx->checkPipAvail(pip)) + ripup_net(ctx, conflicting_pip_net); rippedNets.insert(conflicting_pip_net); scores.pipScores[visited[cursor].pip]++; @@ -394,7 +388,7 @@ struct Router scores.netPipScores[std::make_pair(conflicting_pip_net, visited[cursor].pip)]++; } - proxy.bindPip(visited[cursor].pip, net_name, STRENGTH_WEAK); + ctx->bindPip(visited[cursor].pip, net_name, STRENGTH_WEAK); src_wires[cursor] = visited[cursor].delay; cursor = ctx->getPipSrcWire(visited[cursor].pip); } @@ -443,48 +437,45 @@ bool router1(Context *ctx) delay_t estimatedTotalDelay = 0.0; int estimatedTotalDelayCnt = 0; - { - auto &&proxy = ctx->rproxy(); - for (auto net_name : netsQueue) { - auto net_info = ctx->nets.at(net_name).get(); + for (auto net_name : netsQueue) { + auto net_info = ctx->nets.at(net_name).get(); - auto src_bel = net_info->driver.cell->bel; + auto src_bel = net_info->driver.cell->bel; - if (src_bel == BelId()) - continue; + if (src_bel == BelId()) + continue; - IdString driver_port = net_info->driver.port; + 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 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 = proxy.getWireBelPin(src_bel, ctx->portPinFromId(driver_port)); + auto src_wire = ctx->getWireBelPin(src_bel, ctx->portPinFromId(driver_port)); - if (src_wire == WireId()) - continue; + if (src_wire == WireId()) + continue; - for (auto &user_it : net_info->users) { - auto dst_bel = user_it.cell->bel; + for (auto &user_it : net_info->users) { + auto dst_bel = user_it.cell->bel; - if (dst_bel == BelId()) - continue; + if (dst_bel == BelId()) + continue; - IdString user_port = user_it.port; + IdString user_port = user_it.port; - auto user_port_it = user_it.cell->pins.find(user_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; + if (user_port_it != user_it.cell->pins.end()) + user_port = user_port_it->second; - auto dst_wire = proxy.getWireBelPin(dst_bel, ctx->portPinFromId(user_port)); + auto dst_wire = ctx->getWireBelPin(dst_bel, ctx->portPinFromId(user_port)); - if (dst_wire == WireId()) - continue; + if (dst_wire == WireId()) + continue; - estimatedTotalDelay += ctx->estimateDelay(src_wire, dst_wire); - estimatedTotalDelayCnt++; - } + estimatedTotalDelay += ctx->estimateDelay(src_wire, dst_wire); + estimatedTotalDelayCnt++; } } diff --git a/default.nix b/default.nix deleted file mode 100644 index 664e3669..00000000 --- a/default.nix +++ /dev/null @@ -1,28 +0,0 @@ -# -# nextpnr -- Next Generation Place and Route -# -# 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 -# 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. -# - - -with import <nixpkgs> {}; - -stdenv.mkDerivation rec { - name = "env"; - env = buildEnv { name = name; paths = buildInputs; }; - buildInputs = [ - ( import ./nextpnr.nix ) - ]; -} diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 1938c297..51f4db84 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -151,7 +151,7 @@ IdString Arch::archArgsToId(ArchArgs args) const // ----------------------------------------------------------------------- -BelId ArchReadMethods::getBelByName(IdString name) const +BelId Arch::getBelByName(IdString name) const { BelId ret; auto it = bel_by_name.find(name); @@ -160,9 +160,9 @@ BelId ArchReadMethods::getBelByName(IdString name) const Location loc; std::string basename; - std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(parent_)); + std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(this)); ret.location = loc; - const LocationTypePOD *loci = parent_->locInfo(ret); + const LocationTypePOD *loci = locInfo(ret); for (int i = 0; i < loci->num_bels; i++) { if (std::strcmp(loci->bel_data[i].name.get(), basename.c_str()) == 0) { ret.index = i; @@ -185,14 +185,14 @@ BelRange Arch::getBelsAtSameTile(BelId bel) const return br; } -WireId ArchReadMethods::getWireBelPin(BelId bel, PortPin pin) const +WireId Arch::getWireBelPin(BelId bel, PortPin pin) const { WireId ret; NPNR_ASSERT(bel != BelId()); - int num_bel_wires = parent_->locInfo(bel)->bel_data[bel.index].num_bel_wires; - const BelWirePOD *bel_wires = parent_->locInfo(bel)->bel_data[bel.index].bel_wires.get(); + 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) { ret.location = bel.location + bel_wires[i].rel_wire_loc; @@ -205,7 +205,7 @@ WireId ArchReadMethods::getWireBelPin(BelId bel, PortPin pin) const // ----------------------------------------------------------------------- -WireId ArchReadMethods::getWireByName(IdString name) const +WireId Arch::getWireByName(IdString name) const { WireId ret; auto it = wire_by_name.find(name); @@ -214,9 +214,9 @@ WireId ArchReadMethods::getWireByName(IdString name) const Location loc; std::string basename; - std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(parent_)); + std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(this)); ret.location = loc; - const LocationTypePOD *loci = parent_->locInfo(ret); + const LocationTypePOD *loci = locInfo(ret); for (int i = 0; i < loci->num_wires; i++) { if (std::strcmp(loci->wire_data[i].name.get(), basename.c_str()) == 0) { ret.index = i; @@ -233,7 +233,7 @@ WireId ArchReadMethods::getWireByName(IdString name) const // ----------------------------------------------------------------------- -PipId ArchReadMethods::getPipByName(IdString name) const +PipId Arch::getPipByName(IdString name) const { auto it = pip_by_name.find(name); if (it != pip_by_name.end()) @@ -242,13 +242,13 @@ PipId ArchReadMethods::getPipByName(IdString name) const PipId ret; Location loc; std::string basename; - std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(parent_)); - const LocationTypePOD *loci = parent_->locInfo(ret); + std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(this)); + const LocationTypePOD *loci = locInfo(ret); for (int i = 0; i < loci->num_pips; i++) { PipId curr; curr.location = loc; curr.index = i; - pip_by_name[parent_->getPipName(curr)] = curr; + pip_by_name[getPipName(curr)] = curr; } return pip_by_name[name]; } @@ -296,7 +296,7 @@ bool Arch::route() { return router1(getCtx()); } // ----------------------------------------------------------------------- -std::vector<GraphicElement> ArchReadMethods::getDecalGraphics(DecalId decalId) const +std::vector<GraphicElement> Arch::getDecalGraphics(DecalId decalId) const { std::vector<GraphicElement> ret; // FIXME @@ -315,9 +315,9 @@ DecalXY Arch::getGroupDecal(GroupId pip) const { return {}; }; // ----------------------------------------------------------------------- -bool ArchReadMethods::isValidBelForCell(CellInfo *cell, BelId bel) const { return true; } +bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const { return true; } -bool ArchReadMethods::isBelLocationValid(BelId bel) const { return true; } +bool Arch::isBelLocationValid(BelId bel) const { return true; } // ----------------------------------------------------------------------- @@ -330,156 +330,4 @@ IdString Arch::getPortClock(const CellInfo *cell, IdString port) const { return bool Arch::isClockPort(const CellInfo *cell, IdString port) const { return false; } -bool ArchReadMethods::checkWireAvail(WireId wire) const -{ - NPNR_ASSERT(wire != WireId()); - return wire_to_net.find(wire) == wire_to_net.end() || wire_to_net.at(wire) == IdString(); -} - -bool ArchReadMethods::checkPipAvail(PipId pip) const -{ - NPNR_ASSERT(pip != PipId()); - return pip_to_net.find(pip) == pip_to_net.end() || pip_to_net.at(pip) == IdString(); -} - -bool ArchReadMethods::checkBelAvail(BelId bel) const -{ - NPNR_ASSERT(bel != BelId()); - return bel_to_cell.find(bel) == bel_to_cell.end() || bel_to_cell.at(bel) == IdString(); -} - -IdString ArchReadMethods::getConflictingBelCell(BelId bel) const -{ - NPNR_ASSERT(bel != BelId()); - if (bel_to_cell.find(bel) == bel_to_cell.end()) - return IdString(); - else - return bel_to_cell.at(bel); -} - -IdString ArchReadMethods::getConflictingWireNet(WireId wire) const -{ - NPNR_ASSERT(wire != WireId()); - if (wire_to_net.find(wire) == wire_to_net.end()) - return IdString(); - else - return wire_to_net.at(wire); -} - -IdString ArchReadMethods::getConflictingPipNet(PipId pip) const -{ - NPNR_ASSERT(pip != PipId()); - if (pip_to_net.find(pip) == pip_to_net.end()) - return IdString(); - else - return pip_to_net.at(pip); -} - -IdString ArchReadMethods::getBoundWireNet(WireId wire) const -{ - NPNR_ASSERT(wire != WireId()); - if (wire_to_net.find(wire) == wire_to_net.end()) - return IdString(); - else - return wire_to_net.at(wire); -} - -IdString ArchReadMethods::getBoundPipNet(PipId pip) const -{ - NPNR_ASSERT(pip != PipId()); - if (pip_to_net.find(pip) == pip_to_net.end()) - return IdString(); - else - return pip_to_net.at(pip); -} - -IdString ArchReadMethods::getBoundBelCell(BelId bel) const -{ - NPNR_ASSERT(bel != BelId()); - if (bel_to_cell.find(bel) == bel_to_cell.end()) - return IdString(); - else - return bel_to_cell.at(bel); -} - -void ArchMutateMethods::unbindWire(WireId wire) -{ - NPNR_ASSERT(wire != WireId()); - NPNR_ASSERT(wire_to_net[wire] != IdString()); - - auto &net_wires = parent_->nets[wire_to_net[wire]]->wires; - auto it = net_wires.find(wire); - NPNR_ASSERT(it != net_wires.end()); - - auto pip = it->second.pip; - if (pip != PipId()) { - pip_to_net[pip] = IdString(); - } - - net_wires.erase(it); - wire_to_net[wire] = IdString(); -} - -void ArchMutateMethods::unbindPip(PipId pip) -{ - NPNR_ASSERT(pip != PipId()); - NPNR_ASSERT(pip_to_net[pip] != IdString()); - - WireId dst; - dst.index = parent_->locInfo(pip)->pip_data[pip.index].dst_idx; - dst.location = pip.location + parent_->locInfo(pip)->pip_data[pip.index].rel_dst_loc; - NPNR_ASSERT(wire_to_net[dst] != IdString()); - wire_to_net[dst] = IdString(); - parent_->nets[pip_to_net[pip]]->wires.erase(dst); - - pip_to_net[pip] = IdString(); -} - -void ArchMutateMethods::unbindBel(BelId bel) -{ - NPNR_ASSERT(bel != BelId()); - NPNR_ASSERT(bel_to_cell[bel] != IdString()); - parent_->cells[bel_to_cell[bel]]->bel = BelId(); - parent_->cells[bel_to_cell[bel]]->belStrength = STRENGTH_NONE; - bel_to_cell[bel] = IdString(); -} - -void ArchMutateMethods::bindWire(WireId wire, IdString net, PlaceStrength strength) -{ - NPNR_ASSERT(wire != WireId()); - NPNR_ASSERT(wire_to_net[wire] == IdString()); - wire_to_net[wire] = net; - parent_->nets[net]->wires[wire].pip = PipId(); - parent_->nets[net]->wires[wire].strength = strength; -} - -void ArchMutateMethods::bindPip(PipId pip, IdString net, PlaceStrength strength) -{ - NPNR_ASSERT(pip != PipId()); - NPNR_ASSERT(pip_to_net[pip] == IdString()); - - pip_to_net[pip] = net; - - WireId dst; - dst.index = parent_->locInfo(pip)->pip_data[pip.index].dst_idx; - dst.location = pip.location + parent_->locInfo(pip)->pip_data[pip.index].rel_dst_loc; - NPNR_ASSERT(wire_to_net[dst] == IdString()); - wire_to_net[dst] = net; - parent_->nets[net]->wires[dst].pip = pip; - parent_->nets[net]->wires[dst].strength = strength; -} - -void ArchMutateMethods::bindBel(BelId bel, IdString cell, PlaceStrength strength) -{ - NPNR_ASSERT(bel != BelId()); - NPNR_ASSERT(bel_to_cell[bel] == IdString()); - bel_to_cell[bel] = cell; - parent_->cells[cell]->bel = bel; - parent_->cells[cell]->belStrength = strength; -} - -CellInfo *ArchMutateMethods::getCell(IdString cell) { return parent_->cells.at(cell).get(); } - - - NEXTPNR_NAMESPACE_END diff --git a/ecp5/arch.h b/ecp5/arch.h index 06cf6488..930c488e 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -339,10 +339,8 @@ struct ArchArgs struct Arch : BaseCtx { - // We let proxy methods access our state. - friend class ArchMutateMethods; - friend class ArchReadMethods; -private: + const ChipInfoPOD *chip_info; + mutable std::unordered_map<IdString, BelId> bel_by_name; mutable std::unordered_map<IdString, WireId> wire_by_name; mutable std::unordered_map<IdString, PipId> pip_by_name; @@ -352,9 +350,6 @@ private: std::unordered_map<PipId, IdString> pip_to_net; std::unordered_map<PipId, IdString> switches_locked; -public: - const ChipInfoPOD *chip_info; - ArchArgs args; Arch(ArchArgs args); @@ -371,6 +366,8 @@ public: // ------------------------------------------------- + BelId getBelByName(IdString name) const; + template <typename Id> const LocationTypePOD *locInfo(Id &id) const { return &(chip_info->locations[chip_info->location_type[id.location.y * chip_info->width + id.location.x]]); @@ -386,6 +383,48 @@ public: uint32_t getBelChecksum(BelId bel) const { return bel.index; } + void bindBel(BelId bel, IdString cell, PlaceStrength strength) + { + NPNR_ASSERT(bel != BelId()); + NPNR_ASSERT(bel_to_cell[bel] == IdString()); + bel_to_cell[bel] = cell; + cells[cell]->bel = bel; + cells[cell]->belStrength = strength; + } + + void unbindBel(BelId bel) + { + NPNR_ASSERT(bel != BelId()); + NPNR_ASSERT(bel_to_cell[bel] != IdString()); + cells[bel_to_cell[bel]]->bel = BelId(); + cells[bel_to_cell[bel]]->belStrength = STRENGTH_NONE; + bel_to_cell[bel] = IdString(); + } + + bool checkBelAvail(BelId bel) const + { + NPNR_ASSERT(bel != BelId()); + return bel_to_cell.find(bel) == bel_to_cell.end() || bel_to_cell.at(bel) == IdString(); + } + + IdString getBoundBelCell(BelId bel) const + { + NPNR_ASSERT(bel != BelId()); + if (bel_to_cell.find(bel) == bel_to_cell.end()) + return IdString(); + else + return bel_to_cell.at(bel); + } + + IdString getConflictingBelCell(BelId bel) const + { + NPNR_ASSERT(bel != BelId()); + if (bel_to_cell.find(bel) == bel_to_cell.end()) + return IdString(); + else + return bel_to_cell.at(bel); + } + BelRange getBels() const { BelRange range; @@ -421,6 +460,8 @@ public: return locInfo(bel)->bel_data[bel.index].type; } + WireId getWireBelPin(BelId bel, PortPin pin) const; + BelPin getBelPinUphill(WireId wire) const { BelPin ret; @@ -448,6 +489,8 @@ public: // ------------------------------------------------- + WireId getWireByName(IdString name) const; + IdString getWireName(WireId wire) const { NPNR_ASSERT(wire != WireId()); @@ -460,6 +503,57 @@ public: uint32_t getWireChecksum(WireId wire) const { return wire.index; } + void bindWire(WireId wire, IdString net, PlaceStrength strength) + { + NPNR_ASSERT(wire != WireId()); + NPNR_ASSERT(wire_to_net[wire] == IdString()); + wire_to_net[wire] = net; + nets[net]->wires[wire].pip = PipId(); + nets[net]->wires[wire].strength = strength; + } + + void unbindWire(WireId wire) + { + NPNR_ASSERT(wire != WireId()); + NPNR_ASSERT(wire_to_net[wire] != IdString()); + + auto &net_wires = nets[wire_to_net[wire]]->wires; + auto it = net_wires.find(wire); + NPNR_ASSERT(it != net_wires.end()); + + auto pip = it->second.pip; + if (pip != PipId()) { + pip_to_net[pip] = IdString(); + } + + net_wires.erase(it); + wire_to_net[wire] = IdString(); + } + + bool checkWireAvail(WireId wire) const + { + NPNR_ASSERT(wire != WireId()); + return wire_to_net.find(wire) == wire_to_net.end() || wire_to_net.at(wire) == IdString(); + } + + IdString getBoundWireNet(WireId wire) const + { + NPNR_ASSERT(wire != WireId()); + if (wire_to_net.find(wire) == wire_to_net.end()) + return IdString(); + else + return wire_to_net.at(wire); + } + + IdString getConflictingWireNet(WireId wire) const + { + NPNR_ASSERT(wire != WireId()); + if (wire_to_net.find(wire) == wire_to_net.end()) + return IdString(); + else + return wire_to_net.at(wire); + } + WireRange getWires() const { WireRange range; @@ -475,10 +569,66 @@ public: // ------------------------------------------------- + PipId getPipByName(IdString name) const; IdString getPipName(PipId pip) const; uint32_t getPipChecksum(PipId pip) const { return pip.index; } + void bindPip(PipId pip, IdString net, PlaceStrength strength) + { + NPNR_ASSERT(pip != PipId()); + NPNR_ASSERT(pip_to_net[pip] == IdString()); + + pip_to_net[pip] = net; + + WireId dst; + dst.index = locInfo(pip)->pip_data[pip.index].dst_idx; + dst.location = pip.location + locInfo(pip)->pip_data[pip.index].rel_dst_loc; + NPNR_ASSERT(wire_to_net[dst] == IdString()); + wire_to_net[dst] = net; + nets[net]->wires[dst].pip = pip; + nets[net]->wires[dst].strength = strength; + } + + void unbindPip(PipId pip) + { + NPNR_ASSERT(pip != PipId()); + NPNR_ASSERT(pip_to_net[pip] != IdString()); + + WireId dst; + dst.index = locInfo(pip)->pip_data[pip.index].dst_idx; + dst.location = pip.location + locInfo(pip)->pip_data[pip.index].rel_dst_loc; + NPNR_ASSERT(wire_to_net[dst] != IdString()); + wire_to_net[dst] = IdString(); + nets[pip_to_net[pip]]->wires.erase(dst); + + pip_to_net[pip] = IdString(); + } + + bool checkPipAvail(PipId pip) const + { + NPNR_ASSERT(pip != PipId()); + return pip_to_net.find(pip) == pip_to_net.end() || pip_to_net.at(pip) == IdString(); + } + + IdString getBoundPipNet(PipId pip) const + { + NPNR_ASSERT(pip != PipId()); + if (pip_to_net.find(pip) == pip_to_net.end()) + return IdString(); + else + return pip_to_net.at(pip); + } + + IdString getConflictingPipNet(PipId pip) const + { + NPNR_ASSERT(pip != PipId()); + if (pip_to_net.find(pip) == pip_to_net.end()) + return IdString(); + else + return pip_to_net.at(pip); + } + AllPipRange getPips() const { AllPipRange range; @@ -561,7 +711,6 @@ public: // ------------------------------------------------- - // TODO(q3k) move this to archproxies? GroupId getGroupByName(IdString name) const { return GroupId(); } IdString getGroupName(GroupId group) const { return IdString(); } std::vector<GroupId> getGroups() const { return std::vector<GroupId>(); } @@ -572,8 +721,6 @@ public: // ------------------------------------------------- - // These are also specific to the chip and not state, so they're available - // on arch directly. void estimatePosition(BelId bel, int &x, int &y, bool &gb) const; delay_t estimateDelay(WireId src, WireId dst) const; delay_t getDelayEpsilon() const { return 20; } @@ -589,7 +736,8 @@ public: // ------------------------------------------------- - // TODO(q3k) move this to archproxies? + std::vector<GraphicElement> getDecalGraphics(DecalId decal) const; + DecalXY getFrameDecal() const; DecalXY getBelDecal(BelId bel) const; DecalXY getWireDecal(WireId wire) const; @@ -607,100 +755,11 @@ public: bool isClockPort(const CellInfo *cell, IdString port) const; // Return true if a port is a net bool isGlobalNet(const NetInfo *net) const; -}; - -class ArchReadMethods : public BaseReadCtx -{ - private: - const Arch *parent_; - const ChipInfoPOD *chip_info; - const std::unordered_map<BelId, IdString> &bel_to_cell; - const std::unordered_map<WireId, IdString> &wire_to_net; - const std::unordered_map<PipId, IdString> &pip_to_net; - const std::unordered_map<PipId, IdString> &switches_locked; - std::unordered_map<IdString, BelId> &bel_by_name; - std::unordered_map<IdString, WireId> &wire_by_name; - std::unordered_map<IdString, PipId> &pip_by_name; - - public: - ~ArchReadMethods() noexcept {} - ArchReadMethods(const Arch *parent) - : BaseReadCtx(parent), parent_(parent), chip_info(parent->chip_info), bel_to_cell(parent->bel_to_cell), - wire_to_net(parent->wire_to_net), pip_to_net(parent->pip_to_net), - switches_locked(parent->switches_locked), bel_by_name(parent->bel_by_name), - wire_by_name(parent->wire_by_name), pip_by_name(parent->pip_by_name) - { - } - ArchReadMethods(ArchReadMethods &&other) noexcept : ArchReadMethods(other.parent_) {} - ArchReadMethods(const ArchReadMethods &other) : ArchReadMethods(other.parent_) {} - - /// Perform placement validity checks, returning false on failure (all implemented in arch_place.cc) - // Whether or not a given cell can be placed at a given Bel - // This is not intended for Bel type checks, but finer-grained constraints - // such as conflicting set/reset signals, etc + // ------------------------------------------------- + // Placement validity checks bool isValidBelForCell(CellInfo *cell, BelId bel) const; - // Return true whether all Bels at a given location are valid bool isBelLocationValid(BelId bel) const; - - bool checkWireAvail(WireId wire) const; - bool checkPipAvail(PipId pip) const; - bool checkBelAvail(BelId bel) const; - - WireId getWireByName(IdString name) const; - WireId getWireBelPin(BelId bel, PortPin pin) const; - PipId getPipByName(IdString name) const; - - IdString getConflictingWireNet(WireId wire) const; - IdString getConflictingPipNet(PipId pip) const; - IdString getConflictingBelCell(BelId bel) const; - - IdString getBoundWireNet(WireId wire) const; - IdString getBoundPipNet(PipId pip) const; - IdString getBoundBelCell(BelId bel) const; - - BelId getBelByName(IdString name) const; - - std::vector<GraphicElement> getDecalGraphics(DecalId decal) const; }; -class ArchMutateMethods : public BaseMutateCtx -{ - friend class MutateContext; - - private: - Arch *parent_; - const ChipInfoPOD *chip_info; - - std::unordered_map<BelId, IdString> &bel_to_cell; - std::unordered_map<WireId, IdString> &wire_to_net; - std::unordered_map<PipId, IdString> &pip_to_net; - std::unordered_map<PipId, IdString> &switches_locked; - std::unordered_map<IdString, BelId> &bel_by_name; - std::unordered_map<IdString, WireId> &wire_by_name; - std::unordered_map<IdString, PipId> &pip_by_name; - - public: - ~ArchMutateMethods() noexcept {} - ArchMutateMethods(Arch *parent) - : BaseMutateCtx(parent), parent_(parent), chip_info(parent->chip_info), bel_to_cell(parent->bel_to_cell), - wire_to_net(parent->wire_to_net), pip_to_net(parent->pip_to_net), - switches_locked(parent->switches_locked), bel_by_name(parent->bel_by_name), - wire_by_name(parent->wire_by_name), pip_by_name(parent->pip_by_name) - { - } - ArchMutateMethods(ArchMutateMethods &&other) noexcept : ArchMutateMethods(other.parent_) {} - ArchMutateMethods(const ArchMutateMethods &other) : ArchMutateMethods(other.parent_) {} - - void unbindWire(WireId wire); - void unbindPip(PipId pip); - void unbindBel(BelId bel); - void bindWire(WireId wire, IdString net, PlaceStrength strength); - void bindPip(PipId pip, IdString net, PlaceStrength strength); - void bindBel(BelId bel, IdString cell, PlaceStrength strength); - // Returned pointer is valid as long as Proxy object exists. - CellInfo *getCell(IdString cell); -}; - - NEXTPNR_NAMESPACE_END diff --git a/ecp5/arch_pybindings.h b/ecp5/arch_pybindings.h index 6256af18..a5044f29 100644 --- a/ecp5/arch_pybindings.h +++ b/ecp5/arch_pybindings.h @@ -30,11 +30,7 @@ namespace PythonConversion { template <> struct string_converter<BelId> { - BelId from_str(Context *ctx, std::string name) - { - auto &&proxy = ctx->rproxy(); - return proxy.getBelByName(ctx->id(name)); - } + BelId from_str(Context *ctx, std::string name) { return ctx->getBelByName(ctx->id(name)); } std::string to_str(Context *ctx, BelId id) { @@ -53,22 +49,14 @@ template <> struct string_converter<BelType> template <> struct string_converter<WireId> { - WireId from_str(Context *ctx, std::string name) - { - auto &&proxy = ctx->rproxy(); - return proxy.getWireByName(ctx->id(name)); - } + WireId from_str(Context *ctx, std::string name) { return ctx->getWireByName(ctx->id(name)); } std::string to_str(Context *ctx, WireId id) { return ctx->getWireName(id).str(ctx); } }; template <> struct string_converter<PipId> { - PipId from_str(Context *ctx, std::string name) - { - auto &&proxy = ctx->rproxy(); - return proxy.getPipByName(ctx->id(name)); - } + PipId from_str(Context *ctx, std::string name) { return ctx->getPipByName(ctx->id(name)); } std::string to_str(Context *ctx, PipId id) { return ctx->getPipName(id).str(ctx); } }; diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc index b2376391..e70d6bb2 100644 --- a/ecp5/bitstream.cc +++ b/ecp5/bitstream.cc @@ -155,7 +155,6 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex { Trellis::Chip empty_chip(ctx->getChipName()); Trellis::ChipConfig cc; - auto &&proxy = ctx->rproxy(); std::set<std::string> cib_tiles = {"CIB", "CIB_LR", "CIB_LR_S", "CIB_EFB0", "CIB_EFB1"}; @@ -173,7 +172,7 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex // Add all set, configurable pips to the config for (auto pip : ctx->getPips()) { - if (proxy.getBoundPipNet(pip) != IdString()) { + if (ctx->getBoundPipNet(pip) != IdString()) { if (ctx->getPipType(pip) == 0) { // ignore fixed pips std::string tile = empty_chip.get_tile_by_position_and_type(pip.location.y, pip.location.x, ctx->getPipTiletype(pip)); @@ -228,7 +227,7 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex (ci->ports.find(ctx->id("T")) == ci->ports.end() || ci->ports.at(ctx->id("T")).net == nullptr)) { // Tie tristate low if unconnected for outputs or bidir std::string jpt = fmt_str("X" << bel.location.x << "/Y" << bel.location.y << "/JPADDT" << pio.back()); - WireId jpt_wire = proxy.getWireByName(ctx->id(jpt)); + WireId jpt_wire = ctx->getWireByName(ctx->id(jpt)); PipId jpt_pip = *ctx->getPipsUphill(jpt_wire).begin(); WireId cib_wire = ctx->getPipSrcWire(jpt_pip); std::string cib_tile = diff --git a/gui/designwidget.cc b/gui/designwidget.cc index a6ebba5e..edf9f1ec 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -334,14 +334,12 @@ void DesignWidget::onItemSelectionChanged() return;
}
- auto &&proxy = ctx->rproxy();
-
std::vector<DecalXY> decals;
clearProperties();
if (type == ElementType::BEL) {
IdString c = static_cast<IdStringTreeItem *>(clickItem)->getData();
- BelId bel = proxy.getBelByName(c);
+ BelId bel = ctx->getBelByName(c);
decals.push_back(ctx->getBelDecal(bel));
Q_EMIT selected(decals);
@@ -358,20 +356,20 @@ void DesignWidget::onItemSelectionChanged() topItem->addSubProperty(typeItem);
QtVariantProperty *availItem = readOnlyManager->addProperty(QVariant::Bool, "Available");
- availItem->setValue(proxy.checkBelAvail(bel));
+ availItem->setValue(ctx->checkBelAvail(bel));
topItem->addSubProperty(availItem);
QtVariantProperty *cellItem = readOnlyManager->addProperty(QVariant::String, "Bound Cell");
- cellItem->setValue(proxy.getBoundBelCell(bel).c_str(ctx));
+ cellItem->setValue(ctx->getBoundBelCell(bel).c_str(ctx));
topItem->addSubProperty(cellItem);
QtVariantProperty *conflictItem = readOnlyManager->addProperty(QVariant::String, "Conflicting Cell");
- conflictItem->setValue(proxy.getConflictingBelCell(bel).c_str(ctx));
+ conflictItem->setValue(ctx->getConflictingBelCell(bel).c_str(ctx));
topItem->addSubProperty(conflictItem);
} else if (type == ElementType::WIRE) {
IdString c = static_cast<IdStringTreeItem *>(clickItem)->getData();
- WireId wire = proxy.getWireByName(c);
+ WireId wire = ctx->getWireByName(c);
decals.push_back(ctx->getWireDecal(wire));
Q_EMIT selected(decals);
@@ -384,15 +382,15 @@ void DesignWidget::onItemSelectionChanged() topItem->addSubProperty(nameItem);
QtVariantProperty *availItem = readOnlyManager->addProperty(QVariant::Bool, "Available");
- availItem->setValue(proxy.checkWireAvail(wire));
+ availItem->setValue(ctx->checkWireAvail(wire));
topItem->addSubProperty(availItem);
QtVariantProperty *cellItem = readOnlyManager->addProperty(QVariant::String, "Bound Net");
- cellItem->setValue(proxy.getBoundWireNet(wire).c_str(ctx));
+ cellItem->setValue(ctx->getBoundWireNet(wire).c_str(ctx));
topItem->addSubProperty(cellItem);
QtVariantProperty *conflictItem = readOnlyManager->addProperty(QVariant::String, "Conflicting Net");
- conflictItem->setValue(proxy.getConflictingWireNet(wire).c_str(ctx));
+ conflictItem->setValue(ctx->getConflictingWireNet(wire).c_str(ctx));
topItem->addSubProperty(conflictItem);
BelPin uphill = ctx->getBelPinUphill(wire);
@@ -448,7 +446,7 @@ void DesignWidget::onItemSelectionChanged() */
} else if (type == ElementType::PIP) {
IdString c = static_cast<IdStringTreeItem *>(clickItem)->getData();
- PipId pip = proxy.getPipByName(c);
+ PipId pip = ctx->getPipByName(c);
decals.push_back(ctx->getPipDecal(pip));
Q_EMIT selected(decals);
@@ -461,15 +459,15 @@ void DesignWidget::onItemSelectionChanged() topItem->addSubProperty(nameItem);
QtVariantProperty *availItem = readOnlyManager->addProperty(QVariant::Bool, "Available");
- availItem->setValue(proxy.checkPipAvail(pip));
+ availItem->setValue(ctx->checkPipAvail(pip));
topItem->addSubProperty(availItem);
QtVariantProperty *cellItem = readOnlyManager->addProperty(QVariant::String, "Bound Net");
- cellItem->setValue(proxy.getBoundPipNet(pip).c_str(ctx));
+ cellItem->setValue(ctx->getBoundPipNet(pip).c_str(ctx));
topItem->addSubProperty(cellItem);
QtVariantProperty *conflictItem = readOnlyManager->addProperty(QVariant::String, "Conflicting Net");
- conflictItem->setValue(proxy.getConflictingPipNet(pip).c_str(ctx));
+ conflictItem->setValue(ctx->getConflictingPipNet(pip).c_str(ctx));
topItem->addSubProperty(conflictItem);
QtVariantProperty *srcWireItem = readOnlyManager->addProperty(QVariant::String, "Src Wire");
diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index f8fefd97..1d0e8b57 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -23,7 +23,6 @@ #include <QApplication> #include <QCoreApplication> #include <QMouseEvent> -#include <QTimer> #include <QWidget> #include "fpgaviewwidget.h" @@ -196,7 +195,7 @@ bool LineShader::compile(void) return true; } -void LineShader::draw(const LineShaderData &line, const QColor &color, const float thickness, const QMatrix4x4 &projection) +void LineShader::draw(const LineShaderData &line, const QColor &color, float thickness, const QMatrix4x4 &projection) { auto gl = QOpenGLContext::currentContext()->functions(); vao_.bind(); @@ -266,10 +265,6 @@ FPGAViewWidget::FPGAViewWidget(QWidget *parent) : QOpenGLWidget(parent), lineSha if (fmt.minorVersion() < 1) { printf("Could not get OpenGL 3.1 context - trying anyway...\n "); } - - QTimer *timer = new QTimer(this); - connect(timer, SIGNAL(timeout()), this, SLOT(update())); - timer->start(5000); } FPGAViewWidget::~FPGAViewWidget() {} @@ -293,6 +288,73 @@ void FPGAViewWidget::initializeGL() glClearColor(backgroundColor_.red() / 255, backgroundColor_.green() / 255, backgroundColor_.blue() / 255, 0.0); } +void FPGAViewWidget::drawDecal(LineShaderData &out, const DecalXY &decal) +{ + const float scale = 1.0; + float offsetX = 0.0, offsetY = 0.0; + + for (auto &el : ctx_->getDecalGraphics(decal.decal)) { + offsetX = decal.x; + offsetY = decal.y; + + if (el.type == GraphicElement::G_BOX) { + auto line = PolyLine(true); + line.point(offsetX + scale * el.x1, offsetY + scale * el.y1); + line.point(offsetX + scale * el.x2, offsetY + scale * el.y1); + line.point(offsetX + scale * el.x2, offsetY + scale * el.y2); + line.point(offsetX + scale * el.x1, offsetY + scale * el.y2); + line.build(out); + } + + if (el.type == GraphicElement::G_LINE) { + PolyLine(offsetX + scale * el.x1, offsetY + scale * el.y1, offsetX + scale * el.x2, offsetY + scale * el.y2) + .build(out); + } + } +} + +void FPGAViewWidget::drawDecal(LineShaderData out[], const DecalXY &decal) +{ + const float scale = 1.0; + float offsetX = 0.0, offsetY = 0.0; + + for (auto &el : ctx_->getDecalGraphics(decal.decal)) { + offsetX = decal.x; + offsetY = decal.y; + + if (el.type == GraphicElement::G_BOX) { + auto line = PolyLine(true); + line.point(offsetX + scale * el.x1, offsetY + scale * el.y1); + line.point(offsetX + scale * el.x2, offsetY + scale * el.y1); + line.point(offsetX + scale * el.x2, offsetY + scale * el.y2); + line.point(offsetX + scale * el.x1, offsetY + scale * el.y2); + switch (el.style) { + case GraphicElement::G_FRAME: + case GraphicElement::G_INACTIVE: + case GraphicElement::G_ACTIVE: + line.build(out[el.style]); + break; + default: + break; + } + } + + if (el.type == GraphicElement::G_LINE) { + auto line = PolyLine(offsetX + scale * el.x1, offsetY + scale * el.y1, offsetX + scale * el.x2, + offsetY + scale * el.y2); + switch (el.style) { + case GraphicElement::G_FRAME: + case GraphicElement::G_INACTIVE: + case GraphicElement::G_ACTIVE: + line.build(out[el.style]); + break; + default: + break; + } + } + } +} + QMatrix4x4 FPGAViewWidget::getProjection(void) { QMatrix4x4 matrix; @@ -326,44 +388,27 @@ void FPGAViewWidget::paintGL() } lineShader_.draw(grid, gridColor_, thick1Px, matrix); + LineShaderData shaders[4] = {[GraphicElement::G_FRAME] = LineShaderData(), + [GraphicElement::G_HIDDEN] = LineShaderData(), + [GraphicElement::G_INACTIVE] = LineShaderData(), + [GraphicElement::G_ACTIVE] = LineShaderData()}; + if (ctx_) { - auto &&proxy = ctx_->rwproxy(); - auto updates = proxy.getUIUpdatesRequired(); - - // Collapse all updates to a full redraw. - // TODO(q3k) fix this. - - bool redraw = (updates.allUIReload - || !updates.belUIReload.empty() - || !updates.wireUIReload.empty() - || !updates.pipUIReload.empty() - || !updates.groupUIReload.empty() - || updates.frameUIReload); - - if (redraw) { - shaders_[0].clear(); - shaders_[1].clear(); - shaders_[2].clear(); - shaders_[3].clear(); - - // Draw Bels. - for (auto bel : ctx_->getBels()) { - drawDecal(proxy, shaders_, ctx_->getBelDecal(bel)); - } - // Draw Wires. - for (auto wire : ctx_->getWires()) { - drawDecal(proxy, shaders_, ctx_->getWireDecal(wire)); - } - // Draw Pips. - for (auto pip : ctx_->getPips()) { - drawDecal(proxy, shaders_, ctx_->getPipDecal(pip)); - } - // Draw Groups. - for (auto group : ctx_->getGroups()) { - drawDecal(proxy, shaders_, ctx_->getGroupDecal(group)); - } - // Draw Frame Graphics. - drawDecal(proxy, shaders_, ctx_->getFrameDecal()); + // Draw Bels. + for (auto bel : ctx_->getBels()) { + drawDecal(shaders, ctx_->getBelDecal(bel)); + } + // Draw Wires. + for (auto wire : ctx_->getWires()) { + drawDecal(shaders, ctx_->getWireDecal(wire)); + } + // Draw Pips. + for (auto pip : ctx_->getPips()) { + drawDecal(shaders, ctx_->getPipDecal(pip)); + } + // Draw Groups. + for (auto group : ctx_->getGroups()) { + drawDecal(shaders, ctx_->getGroupDecal(group)); } if (selectedItemsChanged) @@ -371,17 +416,16 @@ void FPGAViewWidget::paintGL() selectedItemsChanged = false; selectedShader_.clear(); for (auto decal : selectedItems_) { - drawDecal(proxy, selectedShader_, decal); + drawDecal(selectedShader_, 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); + 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); lineShader_.draw(selectedShader_, gSelectedColor_, thick11Px, matrix); - //lineShader_.draw(frame, matrix); } void FPGAViewWidget::onSelectedArchItem(std::vector<DecalXY> decals) diff --git a/gui/fpgaviewwidget.h b/gui/fpgaviewwidget.h index 0a9599c9..dd86277e 100644 --- a/gui/fpgaviewwidget.h +++ b/gui/fpgaviewwidget.h @@ -51,6 +51,8 @@ struct LineShaderData std::vector<GLfloat> miters; std::vector<GLuint> indices; + LineShaderData(void) {} + void clear(void) { vertices.clear(); @@ -201,7 +203,7 @@ class LineShader bool compile(void); // Render a LineShaderData with a given M/V/P transformation. - void draw(const LineShaderData &data, const QColor &color, const float thickness, const QMatrix4x4 &projection); + void draw(const LineShaderData &data, const QColor &color, float thickness, const QMatrix4x4 &projection); }; class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions @@ -238,76 +240,8 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE; - - template <typename T> - void drawDecal(const T &proxy, LineShaderData &out, const DecalXY &decal) - { - const float scale = 1.0; - float offsetX = 0.0, offsetY = 0.0; - - for (auto &el : proxy.getDecalGraphics(decal.decal)) { - offsetX = decal.x; - offsetY = decal.y; - - if (el.type == GraphicElement::G_BOX) { - auto line = PolyLine(true); - line.point(offsetX + scale * el.x1, offsetY + scale * el.y1); - line.point(offsetX + scale * el.x2, offsetY + scale * el.y1); - line.point(offsetX + scale * el.x2, offsetY + scale * el.y2); - line.point(offsetX + scale * el.x1, offsetY + scale * el.y2); - line.build(out); - } - - if (el.type == GraphicElement::G_LINE) { - PolyLine(offsetX + scale * el.x1, offsetY + scale * el.y1, offsetX + scale * el.x2, offsetY + scale * el.y2) - .build(out); - } - } - } - - template <typename T> - void drawDecal(const T &proxy, LineShaderData out[], const DecalXY &decal) - { - const float scale = 1.0; - float offsetX = 0.0, offsetY = 0.0; - - for (auto &el : proxy.getDecalGraphics(decal.decal)) { - offsetX = decal.x; - offsetY = decal.y; - - if (el.type == GraphicElement::G_BOX) { - auto line = PolyLine(true); - line.point(offsetX + scale * el.x1, offsetY + scale * el.y1); - line.point(offsetX + scale * el.x2, offsetY + scale * el.y1); - line.point(offsetX + scale * el.x2, offsetY + scale * el.y2); - line.point(offsetX + scale * el.x1, offsetY + scale * el.y2); - switch (el.style) { - case GraphicElement::G_FRAME: - case GraphicElement::G_INACTIVE: - case GraphicElement::G_ACTIVE: - line.build(out[el.style]); - break; - default: - break; - } - } - - if (el.type == GraphicElement::G_LINE) { - auto line = PolyLine(offsetX + scale * el.x1, offsetY + scale * el.y1, offsetX + scale * el.x2, - offsetY + scale * el.y2); - switch (el.style) { - case GraphicElement::G_FRAME: - case GraphicElement::G_INACTIVE: - case GraphicElement::G_ACTIVE: - line.build(out[el.style]); - break; - default: - break; - } - } - } - } - + void drawDecal(LineShaderData &data, const DecalXY &decal); + void drawDecal(LineShaderData out[], const DecalXY &decal); public Q_SLOTS: void newContext(Context *ctx); void onSelectedArchItem(std::vector<DecalXY> decals); @@ -336,7 +270,6 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions QColor gSelectedColor_; QColor frameColor_; - LineShaderData shaders_[4]; LineShaderData selectedShader_; std::vector<DecalXY> selectedItems_; bool selectedItemsChanged; diff --git a/ice40/arch.cc b/ice40/arch.cc index 4727597b..adc37dbd 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -2,7 +2,6 @@ * 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 @@ -29,6 +28,8 @@ NEXTPNR_NAMESPACE_BEGIN +// ----------------------------------------------------------------------- + IdString Arch::belTypeToId(BelType type) const { if (type == TYPE_ICESTORM_LC) @@ -238,6 +239,22 @@ IdString Arch::archArgsToId(ArchArgs args) const // ----------------------------------------------------------------------- +BelId Arch::getBelByName(IdString name) const +{ + BelId ret; + + if (bel_by_name.empty()) { + for (int i = 0; i < chip_info->num_bels; i++) + bel_by_name[id(chip_info->bel_data[i].name.get())] = i; + } + + auto it = bel_by_name.find(name); + if (it != bel_by_name.end()) + ret.index = it->second; + + return ret; +} + BelRange Arch::getBelsAtSameTile(BelId bel) const { BelRange br; @@ -256,8 +273,63 @@ BelRange Arch::getBelsAtSameTile(BelId bel) const return br; } +WireId Arch::getWireBelPin(BelId bel, PortPin pin) const +{ + WireId 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++) + if (bel_wires[i].port == pin) { + ret.index = bel_wires[i].wire_index; + break; + } + + return ret; +} + // ----------------------------------------------------------------------- +WireId Arch::getWireByName(IdString name) const +{ + WireId ret; + + if (wire_by_name.empty()) { + for (int i = 0; i < chip_info->num_wires; i++) + wire_by_name[id(chip_info->wire_data[i].name.get())] = i; + } + + auto it = wire_by_name.find(name); + if (it != wire_by_name.end()) + ret.index = it->second; + + return ret; +} + +// ----------------------------------------------------------------------- + +PipId Arch::getPipByName(IdString name) const +{ + PipId ret; + + if (pip_by_name.empty()) { + for (int i = 0; i < chip_info->num_pips; i++) { + PipId pip; + pip.index = i; + pip_by_name[getPipName(pip)] = i; + } + } + + auto it = pip_by_name.find(name); + if (it != pip_by_name.end()) + ret.index = it->second; + + return ret; +} + IdString Arch::getPipName(PipId pip) const { NPNR_ASSERT(pip != PipId()); @@ -300,8 +372,6 @@ std::string Arch::getBelPackagePin(BelId bel) const // ----------------------------------------------------------------------- -// TODO(cliffordvienna): lock all of this - GroupId Arch::getGroupByName(IdString name) const { for (auto g : getGroups()) @@ -425,7 +495,7 @@ DecalXY Arch::getGroupDecal(GroupId group) const return decalxy; }; -std::vector<GraphicElement> ArchReadMethods::getDecalGraphics(DecalId decal) const +std::vector<GraphicElement> Arch::getDecalGraphics(DecalId decal) const { std::vector<GraphicElement> ret; @@ -458,7 +528,7 @@ std::vector<GraphicElement> ArchReadMethods::getDecalGraphics(DecalId decal) con BelId bel; bel.index = decal.index; - auto bel_type = parent_->getBelType(bel); + auto bel_type = getBelType(bel); if (bel_type == TYPE_ICESTORM_LC) { GraphicElement el; @@ -533,7 +603,8 @@ std::vector<GraphicElement> ArchReadMethods::getDecalGraphics(DecalId decal) con } if (bel_type == TYPE_ICESTORM_RAM) { - for (int i = 0; i < 2; i++) { + for (int i = 0; i < 2; i++) + { int tx = chip_info->bel_data[bel.index].x; int ty = chip_info->bel_data[bel.index].y + i; @@ -543,7 +614,7 @@ std::vector<GraphicElement> ArchReadMethods::getDecalGraphics(DecalId decal) con el.x1 = chip_info->bel_data[bel.index].x + logic_cell_x1; el.x2 = chip_info->bel_data[bel.index].x + logic_cell_x2; el.y1 = chip_info->bel_data[bel.index].y + logic_cell_y1; - el.y2 = chip_info->bel_data[bel.index].y + logic_cell_y2 + 7 * logic_cell_pitch; + el.y2 = chip_info->bel_data[bel.index].y + logic_cell_y2 + 7*logic_cell_pitch; el.z = 0; ret.push_back(el); @@ -620,224 +691,4 @@ bool Arch::isGlobalNet(const NetInfo *net) const return net->driver.cell != nullptr && net->driver.port == id_glb_buf_out; } -// ----------------------------------------------------------------------- - -bool ArchReadMethods::checkBelAvail(BelId bel) const -{ - NPNR_ASSERT(bel != BelId()); - return bel_to_cell[bel.index] == IdString(); -} - -IdString ArchReadMethods::getBoundBelCell(BelId bel) const -{ - NPNR_ASSERT(bel != BelId()); - return bel_to_cell[bel.index]; -} - -IdString ArchReadMethods::getConflictingBelCell(BelId bel) const -{ - NPNR_ASSERT(bel != BelId()); - return bel_to_cell[bel.index]; -} - -WireId ArchReadMethods::getWireBelPin(BelId bel, PortPin pin) const -{ - WireId 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++) - if (bel_wires[i].port == pin) { - ret.index = bel_wires[i].wire_index; - break; - } - - return ret; -} - -WireId ArchReadMethods::getWireByName(IdString name) const -{ - WireId ret; - - if (wire_by_name.empty()) { - for (int i = 0; i < chip_info->num_wires; i++) - wire_by_name[parent_->id(chip_info->wire_data[i].name.get())] = i; - } - - auto it = wire_by_name.find(name); - if (it != wire_by_name.end()) - ret.index = it->second; - - return ret; -} - -bool ArchReadMethods::checkWireAvail(WireId wire) const -{ - NPNR_ASSERT(wire != WireId()); - return wire_to_net[wire.index] == IdString(); -} - -IdString ArchReadMethods::getBoundWireNet(WireId wire) const -{ - NPNR_ASSERT(wire != WireId()); - return wire_to_net[wire.index]; -} - -IdString ArchReadMethods::getConflictingWireNet(WireId wire) const -{ - NPNR_ASSERT(wire != WireId()); - return wire_to_net[wire.index]; -} - -PipId ArchReadMethods::getPipByName(IdString name) const -{ - PipId ret; - - if (pip_by_name.empty()) { - for (int i = 0; i < chip_info->num_pips; i++) { - PipId pip; - pip.index = i; - pip_by_name[parent_->getPipName(pip)] = i; - } - } - - auto it = pip_by_name.find(name); - if (it != pip_by_name.end()) - ret.index = it->second; - - return ret; -} - -bool ArchReadMethods::checkPipAvail(PipId pip) const -{ - NPNR_ASSERT(pip != PipId()); - return switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString(); -} - -IdString ArchReadMethods::getBoundPipNet(PipId pip) const -{ - NPNR_ASSERT(pip != PipId()); - return pip_to_net[pip.index]; -} - -IdString ArchReadMethods::getConflictingPipNet(PipId pip) const -{ - NPNR_ASSERT(pip != PipId()); - return switches_locked[chip_info->pip_data[pip.index].switch_index]; -} - -BelId ArchReadMethods::getBelByName(IdString name) const -{ - BelId ret; - - if (bel_by_name.empty()) { - for (int i = 0; i < chip_info->num_bels; i++) - bel_by_name[parent_->id(chip_info->bel_data[i].name.get())] = i; - } - - auto it = bel_by_name.find(name); - if (it != bel_by_name.end()) - ret.index = it->second; - - return ret; -} - -// ----------------------------------------------------------------------- - -void ArchMutateMethods::bindBel(BelId bel, IdString cell, PlaceStrength strength) -{ - NPNR_ASSERT(bel != BelId()); - NPNR_ASSERT(bel_to_cell[bel.index] == IdString()); - bel_to_cell[bel.index] = cell; - parent_->cells[cell]->bel = bel; - parent_->cells[cell]->belStrength = strength; - refreshUiBel(bel); -} - -void ArchMutateMethods::unbindBel(BelId bel) -{ - NPNR_ASSERT(bel != BelId()); - NPNR_ASSERT(bel_to_cell[bel.index] != IdString()); - parent_->cells[bel_to_cell[bel.index]]->bel = BelId(); - parent_->cells[bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE; - bel_to_cell[bel.index] = IdString(); - refreshUiBel(bel); -} - -void ArchMutateMethods::bindWire(WireId wire, IdString net, PlaceStrength strength) -{ - NPNR_ASSERT(wire != WireId()); - NPNR_ASSERT(wire_to_net[wire.index] == IdString()); - - wire_to_net[wire.index] = net; - parent_->nets[net]->wires[wire].pip = PipId(); - parent_->nets[net]->wires[wire].strength = strength; - refreshUiWire(wire); -} - -void ArchMutateMethods::unbindWire(WireId wire) -{ - NPNR_ASSERT(wire != WireId()); - NPNR_ASSERT(wire_to_net[wire.index] != IdString()); - - auto &net_wires = parent_->nets[wire_to_net[wire.index]]->wires; - auto it = net_wires.find(wire); - NPNR_ASSERT(it != net_wires.end()); - - auto pip = it->second.pip; - if (pip != PipId()) { - pip_to_net[pip.index] = IdString(); - switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString(); - refreshUiPip(pip); - } - - net_wires.erase(it); - wire_to_net[wire.index] = IdString(); - refreshUiWire(wire); -} - -void ArchMutateMethods::bindPip(PipId pip, IdString net, PlaceStrength strength) -{ - NPNR_ASSERT(pip != PipId()); - NPNR_ASSERT(pip_to_net[pip.index] == IdString()); - NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString()); - - pip_to_net[pip.index] = net; - switches_locked[chip_info->pip_data[pip.index].switch_index] = net; - - WireId dst; - dst.index = chip_info->pip_data[pip.index].dst; - NPNR_ASSERT(wire_to_net[dst.index] == IdString()); - wire_to_net[dst.index] = net; - parent_->nets[net]->wires[dst].pip = pip; - parent_->nets[net]->wires[dst].strength = strength; - - refreshUiPip(pip); - refreshUiWire(dst); -} - -void ArchMutateMethods::unbindPip(PipId pip) -{ - NPNR_ASSERT(pip != PipId()); - NPNR_ASSERT(pip_to_net[pip.index] != IdString()); - NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != IdString()); - - WireId dst; - dst.index = chip_info->pip_data[pip.index].dst; - NPNR_ASSERT(wire_to_net[dst.index] != IdString()); - wire_to_net[dst.index] = IdString(); - parent_->nets[pip_to_net[pip.index]]->wires.erase(dst); - - pip_to_net[pip.index] = IdString(); - switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString(); - - refreshUiPip(pip); - refreshUiWire(dst); -} - -CellInfo *ArchMutateMethods::getCell(IdString cell) { return parent_->cells.at(cell).get(); } - NEXTPNR_NAMESPACE_END diff --git a/ice40/arch.h b/ice40/arch.h index 25ed8ebf..a02e0ced 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -2,7 +2,6 @@ * 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 @@ -325,37 +324,19 @@ struct ArchArgs std::string package; }; -/// Forward declare proxy classes for Arch. - -class ArchMutateMethods; -class ArchReadMethods; - -/// Arch/Context -// Arch is the main state class of the PnR algorithms. It keeps note of mapped -// cells/nets, locked switches, etc. -// -// In order to mutate state in Arch, you can do one of two things: -// - directly call one of the wrapper methods to mutate state -// - get a read or readwrite proxy to the Arch, and call methods on it - -class Arch : public BaseCtx +struct Arch : BaseCtx { - // We let proxy methods access our state. - friend class ArchMutateMethods; - friend class ArchReadMethods; + const ChipInfoPOD *chip_info; + const PackageInfoPOD *package_info; - private: - std::vector<IdString> bel_to_cell; - std::vector<IdString> wire_to_net; - std::vector<IdString> pip_to_net; - std::vector<IdString> switches_locked; mutable std::unordered_map<IdString, int> bel_by_name; mutable std::unordered_map<IdString, int> wire_by_name; mutable std::unordered_map<IdString, int> pip_by_name; - public: - const ChipInfoPOD *chip_info; - const PackageInfoPOD *package_info; + std::vector<IdString> bel_to_cell; + std::vector<IdString> wire_to_net; + std::vector<IdString> pip_to_net; + std::vector<IdString> switches_locked; ArchArgs args; Arch(ArchArgs args); @@ -373,8 +354,7 @@ class Arch : public BaseCtx // ------------------------------------------------- - /// Methods to get chip info - don't need to use a wrapper, as these are - /// static per lifetime of object. + BelId getBelByName(IdString name) const; IdString getBelName(BelId bel) const { @@ -384,6 +364,42 @@ class Arch : public BaseCtx uint32_t getBelChecksum(BelId bel) const { return bel.index; } + void bindBel(BelId bel, IdString cell, PlaceStrength strength) + { + NPNR_ASSERT(bel != BelId()); + NPNR_ASSERT(bel_to_cell[bel.index] == IdString()); + bel_to_cell[bel.index] = cell; + cells[cell]->bel = bel; + cells[cell]->belStrength = strength; + } + + void unbindBel(BelId bel) + { + NPNR_ASSERT(bel != BelId()); + NPNR_ASSERT(bel_to_cell[bel.index] != IdString()); + cells[bel_to_cell[bel.index]]->bel = BelId(); + cells[bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE; + bel_to_cell[bel.index] = IdString(); + } + + bool checkBelAvail(BelId bel) const + { + NPNR_ASSERT(bel != BelId()); + return bel_to_cell[bel.index] == IdString(); + } + + IdString getBoundBelCell(BelId bel) const + { + NPNR_ASSERT(bel != BelId()); + return bel_to_cell[bel.index]; + } + + IdString getConflictingBelCell(BelId bel) const + { + NPNR_ASSERT(bel != BelId()); + return bel_to_cell[bel.index]; + } + BelRange getBels() const { BelRange range; @@ -397,11 +413,11 @@ class Arch : public BaseCtx BelRange range; // FIXME #if 0 - if (type == "TYPE_A") { - range.b.cursor = bels_type_a_begin; - range.e.cursor = bels_type_a_end; - } - ... + if (type == "TYPE_A") { + range.b.cursor = bels_type_a_begin; + range.e.cursor = bels_type_a_end; + } + ... #endif return range; } @@ -414,6 +430,8 @@ class Arch : public BaseCtx return chip_info->bel_data[bel.index].type; } + WireId getWireBelPin(BelId bel, PortPin pin) const; + BelPin getBelPinUphill(WireId wire) const { BelPin ret; @@ -438,6 +456,8 @@ class Arch : public BaseCtx // ------------------------------------------------- + WireId getWireByName(IdString name) const; + IdString getWireName(WireId wire) const { NPNR_ASSERT(wire != WireId()); @@ -446,6 +466,115 @@ class Arch : public BaseCtx uint32_t getWireChecksum(WireId wire) const { return wire.index; } + void bindWire(WireId wire, IdString net, PlaceStrength strength) + { + NPNR_ASSERT(wire != WireId()); + NPNR_ASSERT(wire_to_net[wire.index] == IdString()); + wire_to_net[wire.index] = net; + nets[net]->wires[wire].pip = PipId(); + nets[net]->wires[wire].strength = strength; + } + + void unbindWire(WireId wire) + { + NPNR_ASSERT(wire != WireId()); + NPNR_ASSERT(wire_to_net[wire.index] != IdString()); + + auto &net_wires = nets[wire_to_net[wire.index]]->wires; + auto it = net_wires.find(wire); + NPNR_ASSERT(it != net_wires.end()); + + auto pip = it->second.pip; + if (pip != PipId()) { + pip_to_net[pip.index] = IdString(); + switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString(); + } + + net_wires.erase(it); + wire_to_net[wire.index] = IdString(); + } + + bool checkWireAvail(WireId wire) const + { + NPNR_ASSERT(wire != WireId()); + return wire_to_net[wire.index] == IdString(); + } + + IdString getBoundWireNet(WireId wire) const + { + NPNR_ASSERT(wire != WireId()); + return wire_to_net[wire.index]; + } + + IdString getConflictingWireNet(WireId wire) const + { + NPNR_ASSERT(wire != WireId()); + return wire_to_net[wire.index]; + } + + WireRange getWires() const + { + WireRange range; + range.b.cursor = 0; + range.e.cursor = chip_info->num_wires; + return range; + } + + // ------------------------------------------------- + + PipId getPipByName(IdString name) const; + + void bindPip(PipId pip, IdString net, PlaceStrength strength) + { + NPNR_ASSERT(pip != PipId()); + NPNR_ASSERT(pip_to_net[pip.index] == IdString()); + NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString()); + + pip_to_net[pip.index] = net; + switches_locked[chip_info->pip_data[pip.index].switch_index] = net; + + WireId dst; + dst.index = chip_info->pip_data[pip.index].dst; + NPNR_ASSERT(wire_to_net[dst.index] == IdString()); + wire_to_net[dst.index] = net; + nets[net]->wires[dst].pip = pip; + nets[net]->wires[dst].strength = strength; + } + + void unbindPip(PipId pip) + { + NPNR_ASSERT(pip != PipId()); + NPNR_ASSERT(pip_to_net[pip.index] != IdString()); + NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != IdString()); + + WireId dst; + dst.index = chip_info->pip_data[pip.index].dst; + NPNR_ASSERT(wire_to_net[dst.index] != IdString()); + wire_to_net[dst.index] = IdString(); + nets[pip_to_net[pip.index]]->wires.erase(dst); + + pip_to_net[pip.index] = IdString(); + switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString(); + } + + bool checkPipAvail(PipId pip) const + { + NPNR_ASSERT(pip != PipId()); + return switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString(); + } + + IdString getBoundPipNet(PipId pip) const + { + NPNR_ASSERT(pip != PipId()); + return pip_to_net[pip.index]; + } + + IdString getConflictingPipNet(PipId pip) const + { + NPNR_ASSERT(pip != PipId()); + return switches_locked[chip_info->pip_data[pip.index].switch_index]; + } + AllPipRange getPips() const { AllPipRange range; @@ -453,7 +582,7 @@ class Arch : public BaseCtx range.e.cursor = chip_info->num_pips; return range; } - + IdString getPipName(PipId pip) const; uint32_t getPipChecksum(PipId pip) const { return pip.index; } @@ -509,20 +638,11 @@ class Arch : public BaseCtx return range; } - WireRange getWires() const - { - WireRange range; - range.b.cursor = 0; - range.e.cursor = chip_info->num_wires; - return range; - } - BelId getPackagePinBel(const std::string &pin) const; std::string getBelPackagePin(BelId bel) const; // ------------------------------------------------- - // TODO(q3k) move this to archproxies? GroupId getGroupByName(IdString name) const; IdString getGroupName(GroupId group) const; std::vector<GroupId> getGroups() const; @@ -533,8 +653,6 @@ class Arch : public BaseCtx // ------------------------------------------------- - // These are also specific to the chip and not state, so they're available - // on arch directly. void estimatePosition(BelId bel, int &x, int &y, bool &gb) const; delay_t estimateDelay(WireId src, WireId dst) const; delay_t getDelayEpsilon() const { return 20; } @@ -550,7 +668,8 @@ class Arch : public BaseCtx // ------------------------------------------------- - // TODO(q3k) move this to archproxies? + std::vector<GraphicElement> getDecalGraphics(DecalId decal) const; + DecalXY getFrameDecal() const; DecalXY getBelDecal(BelId bel) const; DecalXY getWireDecal(WireId wire) const; @@ -571,106 +690,24 @@ class Arch : public BaseCtx // ------------------------------------------------- - IdString id_glb_buf_out; - IdString id_icestorm_lc, id_sb_io, id_sb_gb; - IdString id_cen, id_clk, id_sr; - IdString id_i0, id_i1, id_i2, id_i3; - IdString id_dff_en, id_neg_clk; -}; + // Perform placement validity checks, returning false on failure (all implemented in arch_place.cc) -// Read-only methods on Arch that require state access. -class ArchReadMethods : public BaseReadCtx -{ - private: - const Arch *parent_; - const ChipInfoPOD *chip_info; - const std::vector<IdString> &bel_to_cell; - const std::vector<IdString> &wire_to_net; - const std::vector<IdString> &pip_to_net; - const std::vector<IdString> &switches_locked; - std::unordered_map<IdString, int> &bel_by_name; - std::unordered_map<IdString, int> &wire_by_name; - std::unordered_map<IdString, int> &pip_by_name; - - public: - ~ArchReadMethods() noexcept {} - ArchReadMethods(const Arch *parent) - : BaseReadCtx(parent), parent_(parent), chip_info(parent->chip_info), bel_to_cell(parent->bel_to_cell), - wire_to_net(parent->wire_to_net), pip_to_net(parent->pip_to_net), - switches_locked(parent->switches_locked), bel_by_name(parent->bel_by_name), - wire_by_name(parent->wire_by_name), pip_by_name(parent->pip_by_name) - { - } - ArchReadMethods(ArchReadMethods &&other) noexcept : ArchReadMethods(other.parent_) {} - ArchReadMethods(const ArchReadMethods &other) : ArchReadMethods(other.parent_) {} - - /// Perform placement validity checks, returning false on failure (all implemented in arch_place.cc) // Whether or not a given cell can be placed at a given Bel // This is not intended for Bel type checks, but finer-grained constraints // such as conflicting set/reset signals, etc bool isValidBelForCell(CellInfo *cell, BelId bel) const; + // Return true whether all Bels at a given location are valid bool isBelLocationValid(BelId bel) const; + // Helper function for above bool logicCellsCompatible(const std::vector<const CellInfo *> &cells) const; - bool checkWireAvail(WireId wire) const; - bool checkPipAvail(PipId pip) const; - bool checkBelAvail(BelId bel) const; - - WireId getWireByName(IdString name) const; - WireId getWireBelPin(BelId bel, PortPin pin) const; - PipId getPipByName(IdString name) const; - - IdString getConflictingWireNet(WireId wire) const; - IdString getConflictingPipNet(PipId pip) const; - IdString getConflictingBelCell(BelId bel) const; - - IdString getBoundWireNet(WireId wire) const; - IdString getBoundPipNet(PipId pip) const; - IdString getBoundBelCell(BelId bel) const; - - BelId getBelByName(IdString name) const; - - std::vector<GraphicElement> getDecalGraphics(DecalId decal) const; -}; - -// State mutating methods on Arch. -class ArchMutateMethods : public BaseMutateCtx -{ - friend class MutateContext; - - private: - Arch *parent_; - const ChipInfoPOD *chip_info; - std::vector<IdString> &bel_to_cell; - std::vector<IdString> &wire_to_net; - std::vector<IdString> &pip_to_net; - std::vector<IdString> &switches_locked; - std::unordered_map<IdString, int> &bel_by_name; - std::unordered_map<IdString, int> &wire_by_name; - std::unordered_map<IdString, int> &pip_by_name; - - public: - ArchMutateMethods(Arch *parent) - : BaseMutateCtx(parent), parent_(parent), chip_info(parent->chip_info), bel_to_cell(parent->bel_to_cell), - wire_to_net(parent->wire_to_net), pip_to_net(parent->pip_to_net), - switches_locked(parent->switches_locked), bel_by_name(parent->bel_by_name), - wire_by_name(parent->wire_by_name), pip_by_name(parent->pip_by_name) - { - } - ArchMutateMethods(ArchMutateMethods &&other) : ArchMutateMethods(other.parent_) {} - ArchMutateMethods(const ArchMutateMethods &other) : ArchMutateMethods(other.parent_) {} - ~ArchMutateMethods() {} - - void unbindWire(WireId wire); - void unbindPip(PipId pip); - void unbindBel(BelId bel); - void bindWire(WireId wire, IdString net, PlaceStrength strength); - void bindPip(PipId pip, IdString net, PlaceStrength strength); - void bindBel(BelId bel, IdString cell, PlaceStrength strength); - // Returned pointer is valid as long as Proxy object exists. - CellInfo *getCell(IdString cell); + IdString id_glb_buf_out; + IdString id_icestorm_lc, id_sb_io, id_sb_gb; + IdString id_cen, id_clk, id_sr; + IdString id_i0, id_i1, id_i2, id_i3; + IdString id_dff_en, id_neg_clk; }; NEXTPNR_NAMESPACE_END diff --git a/ice40/arch_place.cc b/ice40/arch_place.cc index 42efceab..dc1bc3eb 100644 --- a/ice40/arch_place.cc +++ b/ice40/arch_place.cc @@ -3,7 +3,6 @@ * * Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com> * Copyright (C) 2018 David Shah <david@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 @@ -25,44 +24,44 @@ NEXTPNR_NAMESPACE_BEGIN -bool ArchReadMethods::logicCellsCompatible(const std::vector<const CellInfo *> &cells) const +bool Arch::logicCellsCompatible(const std::vector<const CellInfo *> &cells) const { bool dffs_exist = false, dffs_neg = false; const NetInfo *cen = nullptr, *clk = nullptr, *sr = nullptr; int locals_count = 0; for (auto cell : cells) { - if (bool_or_default(cell->params, parent_->id_dff_en)) { + if (bool_or_default(cell->params, id_dff_en)) { if (!dffs_exist) { dffs_exist = true; - cen = get_net_or_empty(cell, parent_->id_cen); - clk = get_net_or_empty(cell, parent_->id_clk); - sr = get_net_or_empty(cell, parent_->id_sr); + cen = get_net_or_empty(cell, id_cen); + clk = get_net_or_empty(cell, id_clk); + sr = get_net_or_empty(cell, id_sr); - if (!parent_->isGlobalNet(cen) && cen != nullptr) + if (!isGlobalNet(cen) && cen != nullptr) locals_count++; - if (!parent_->isGlobalNet(clk) && clk != nullptr) + if (!isGlobalNet(clk) && clk != nullptr) locals_count++; - if (!parent_->isGlobalNet(sr) && sr != nullptr) + if (!isGlobalNet(sr) && sr != nullptr) locals_count++; - if (bool_or_default(cell->params, parent_->id_neg_clk)) { + if (bool_or_default(cell->params, id_neg_clk)) { dffs_neg = true; } } else { - if (cen != get_net_or_empty(cell, parent_->id_cen)) + if (cen != get_net_or_empty(cell, id_cen)) return false; - if (clk != get_net_or_empty(cell, parent_->id_clk)) + if (clk != get_net_or_empty(cell, id_clk)) return false; - if (sr != get_net_or_empty(cell, parent_->id_sr)) + if (sr != get_net_or_empty(cell, id_sr)) return false; - if (dffs_neg != bool_or_default(cell->params, parent_->id_neg_clk)) + if (dffs_neg != bool_or_default(cell->params, id_neg_clk)) return false; } } - const NetInfo *i0 = get_net_or_empty(cell, parent_->id_i0), *i1 = get_net_or_empty(cell, parent_->id_i1), - *i2 = get_net_or_empty(cell, parent_->id_i2), *i3 = get_net_or_empty(cell, parent_->id_i3); + const NetInfo *i0 = get_net_or_empty(cell, id_i0), *i1 = get_net_or_empty(cell, id_i1), + *i2 = get_net_or_empty(cell, id_i2), *i3 = get_net_or_empty(cell, id_i3); if (i0 != nullptr) locals_count++; if (i1 != nullptr) @@ -76,14 +75,14 @@ bool ArchReadMethods::logicCellsCompatible(const std::vector<const CellInfo *> & return locals_count <= 32; } -bool ArchReadMethods::isBelLocationValid(BelId bel) const +bool Arch::isBelLocationValid(BelId bel) const { - if (parent_->getBelType(bel) == TYPE_ICESTORM_LC) { + if (getBelType(bel) == TYPE_ICESTORM_LC) { std::vector<const CellInfo *> bel_cells; - for (auto bel_other : parent_->getBelsAtSameTile(bel)) { + for (auto bel_other : getBelsAtSameTile(bel)) { IdString cell_other = getBoundBelCell(bel_other); if (cell_other != IdString()) { - const CellInfo *ci_other = parent_->cells.at(cell_other).get(); + const CellInfo *ci_other = cells.at(cell_other).get(); bel_cells.push_back(ci_other); } } @@ -93,40 +92,40 @@ bool ArchReadMethods::isBelLocationValid(BelId bel) const if (cellId == IdString()) return true; else - return isValidBelForCell(parent_->cells.at(cellId).get(), bel); + return isValidBelForCell(cells.at(cellId).get(), bel); } } -bool ArchReadMethods::isValidBelForCell(CellInfo *cell, BelId bel) const +bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const { - if (cell->type == parent_->id_icestorm_lc) { - NPNR_ASSERT(parent_->getBelType(bel) == TYPE_ICESTORM_LC); + if (cell->type == id_icestorm_lc) { + NPNR_ASSERT(getBelType(bel) == TYPE_ICESTORM_LC); std::vector<const CellInfo *> bel_cells; - for (auto bel_other : parent_->getBelsAtSameTile(bel)) { + for (auto bel_other : getBelsAtSameTile(bel)) { IdString cell_other = getBoundBelCell(bel_other); if (cell_other != IdString() && bel_other != bel) { - const CellInfo *ci_other = parent_->cells.at(cell_other).get(); + const CellInfo *ci_other = cells.at(cell_other).get(); bel_cells.push_back(ci_other); } } bel_cells.push_back(cell); return logicCellsCompatible(bel_cells); - } else if (cell->type == parent_->id_sb_io) { - return parent_->getBelPackagePin(bel) != ""; - } else if (cell->type == parent_->id_sb_gb) { + } else if (cell->type == id_sb_io) { + return getBelPackagePin(bel) != ""; + } else if (cell->type == id_sb_gb) { bool is_reset = false, is_cen = false; - NPNR_ASSERT(cell->ports.at(parent_->id_glb_buf_out).net != nullptr); - for (auto user : cell->ports.at(parent_->id_glb_buf_out).net->users) { - if (is_reset_port(parent_, user)) + NPNR_ASSERT(cell->ports.at(id_glb_buf_out).net != nullptr); + for (auto user : cell->ports.at(id_glb_buf_out).net->users) { + if (is_reset_port(this, user)) is_reset = true; - if (is_enable_port(parent_, user)) + if (is_enable_port(this, user)) is_cen = true; } - IdString glb_net = parent_->getWireName(getWireBelPin(bel, PIN_GLOBAL_BUFFER_OUTPUT)); - int glb_id = std::stoi(std::string("") + glb_net.str(parent_).back()); + IdString glb_net = getWireName(getWireBelPin(bel, PIN_GLOBAL_BUFFER_OUTPUT)); + int glb_id = std::stoi(std::string("") + glb_net.str(this).back()); if (is_reset && is_cen) return false; else if (is_reset) diff --git a/ice40/arch_pybindings.cc b/ice40/arch_pybindings.cc index a2a90191..fd5109b4 100644 --- a/ice40/arch_pybindings.cc +++ b/ice40/arch_pybindings.cc @@ -65,13 +65,25 @@ void arch_wrap_python() fn_wrapper_1a<Context, decltype(&Context::getBelType), &Context::getBelType, conv_to_str<BelType>, conv_from_str<BelId>>::def_wrap(ctx_cls, "getBelType"); + fn_wrapper_1a<Context, decltype(&Context::checkBelAvail), &Context::checkBelAvail, pass_through<bool>, + conv_from_str<BelId>>::def_wrap(ctx_cls, "checkBelAvail"); fn_wrapper_1a<Context, decltype(&Context::getBelChecksum), &Context::getBelChecksum, pass_through<uint32_t>, conv_from_str<BelId>>::def_wrap(ctx_cls, "getBelChecksum"); + fn_wrapper_3a_v<Context, decltype(&Context::bindBel), &Context::bindBel, conv_from_str<BelId>, + conv_from_str<IdString>, pass_through<PlaceStrength>>::def_wrap(ctx_cls, "bindBel"); + fn_wrapper_1a_v<Context, decltype(&Context::unbindBel), &Context::unbindBel, conv_from_str<BelId>>::def_wrap( + ctx_cls, "unbindBel"); + fn_wrapper_1a<Context, decltype(&Context::getBoundBelCell), &Context::getBoundBelCell, conv_to_str<IdString>, + conv_from_str<BelId>>::def_wrap(ctx_cls, "getBoundBelCell"); + fn_wrapper_1a<Context, decltype(&Context::getConflictingBelCell), &Context::getConflictingBelCell, + conv_to_str<IdString>, conv_from_str<BelId>>::def_wrap(ctx_cls, "getConflictingBelCell"); fn_wrapper_0a<Context, decltype(&Context::getBels), &Context::getBels, wrap_context<BelRange>>::def_wrap(ctx_cls, "getBels"); 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, @@ -79,6 +91,16 @@ void arch_wrap_python() fn_wrapper_1a<Context, decltype(&Context::getWireChecksum), &Context::getWireChecksum, pass_through<uint32_t>, conv_from_str<WireId>>::def_wrap(ctx_cls, "getWireChecksum"); + fn_wrapper_3a_v<Context, decltype(&Context::bindWire), &Context::bindWire, conv_from_str<WireId>, + conv_from_str<IdString>, pass_through<PlaceStrength>>::def_wrap(ctx_cls, "bindWire"); + fn_wrapper_1a_v<Context, decltype(&Context::unbindWire), &Context::unbindWire, conv_from_str<WireId>>::def_wrap( + ctx_cls, "unbindWire"); + fn_wrapper_1a<Context, decltype(&Context::checkWireAvail), &Context::checkWireAvail, pass_through<bool>, + conv_from_str<WireId>>::def_wrap(ctx_cls, "checkWireAvail"); + fn_wrapper_1a<Context, decltype(&Context::getBoundWireNet), &Context::getBoundWireNet, conv_to_str<IdString>, + conv_from_str<WireId>>::def_wrap(ctx_cls, "getBoundWireNet"); + fn_wrapper_1a<Context, decltype(&Context::getConflictingWireNet), &Context::getConflictingWireNet, + conv_to_str<IdString>, conv_from_str<WireId>>::def_wrap(ctx_cls, "getConflictingWireNet"); fn_wrapper_0a<Context, decltype(&Context::getWires), &Context::getWires, wrap_context<WireRange>>::def_wrap( ctx_cls, "getWires"); @@ -87,6 +109,16 @@ void arch_wrap_python() ctx_cls, "getPips"); fn_wrapper_1a<Context, decltype(&Context::getPipChecksum), &Context::getPipChecksum, pass_through<uint32_t>, conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipChecksum"); + fn_wrapper_3a_v<Context, decltype(&Context::bindPip), &Context::bindPip, conv_from_str<PipId>, + conv_from_str<IdString>, pass_through<PlaceStrength>>::def_wrap(ctx_cls, "bindPip"); + fn_wrapper_1a_v<Context, decltype(&Context::unbindPip), &Context::unbindPip, conv_from_str<PipId>>::def_wrap( + ctx_cls, "unbindPip"); + fn_wrapper_1a<Context, decltype(&Context::checkPipAvail), &Context::checkPipAvail, pass_through<bool>, + conv_from_str<PipId>>::def_wrap(ctx_cls, "checkPipAvail"); + fn_wrapper_1a<Context, decltype(&Context::getBoundPipNet), &Context::getBoundPipNet, conv_to_str<IdString>, + conv_from_str<PipId>>::def_wrap(ctx_cls, "getBoundPipNet"); + fn_wrapper_1a<Context, decltype(&Context::getConflictingPipNet), &Context::getConflictingPipNet, + conv_to_str<IdString>, conv_from_str<PipId>>::def_wrap(ctx_cls, "getConflictingPipNet"); fn_wrapper_1a<Context, decltype(&Context::getPipsDownhill), &Context::getPipsDownhill, wrap_context<PipRange>, conv_from_str<WireId>>::def_wrap(ctx_cls, "getPipsDownhill"); diff --git a/ice40/arch_pybindings.h b/ice40/arch_pybindings.h index 7440e29d..e502905f 100644 --- a/ice40/arch_pybindings.h +++ b/ice40/arch_pybindings.h @@ -31,11 +31,7 @@ namespace PythonConversion { template <> struct string_converter<BelId> { - BelId from_str(Context *ctx, std::string name) - { - auto &&proxy = ctx->rproxy(); - return proxy.getBelByName(ctx->id(name)); - } + BelId from_str(Context *ctx, std::string name) { return ctx->getBelByName(ctx->id(name)); } std::string to_str(Context *ctx, BelId id) { @@ -54,22 +50,14 @@ template <> struct string_converter<BelType> template <> struct string_converter<WireId> { - WireId from_str(Context *ctx, std::string name) - { - auto &&proxy = ctx->rproxy(); - return proxy.getWireByName(ctx->id(name)); - } + WireId from_str(Context *ctx, std::string name) { return ctx->getWireByName(ctx->id(name)); } std::string to_str(Context *ctx, WireId id) { return ctx->getWireName(id).str(ctx); } }; template <> struct string_converter<PipId> { - PipId from_str(Context *ctx, std::string name) - { - auto &&proxy = ctx->rproxy(); - return proxy.getPipByName(ctx->id(name)); - } + PipId from_str(Context *ctx, std::string name) { return ctx->getPipByName(ctx->id(name)); } std::string to_str(Context *ctx, PipId id) { return ctx->getPipName(id).str(ctx); } }; diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc index 87a96a22..a62c6c09 100644 --- a/ice40/bitstream.cc +++ b/ice40/bitstream.cc @@ -92,7 +92,6 @@ char get_hexdigit(int i) { return std::string("0123456789ABCDEF").at(i); } void write_asc(const Context *ctx, std::ostream &out) { - auto &&proxy = ctx->rproxy(); // [y][x][row][col] const ChipInfoPOD &ci = *ctx->chip_info; const BitstreamInfoPOD &bi = *ci.bits_info; @@ -129,7 +128,7 @@ void write_asc(const Context *ctx, std::ostream &out) } // Set pips for (auto pip : ctx->getPips()) { - if (proxy.getBoundPipNet(pip) != IdString()) { + if (ctx->pip_to_net[pip.index] != IdString()) { const PipInfoPOD &pi = ci.pip_data[pip.index]; const SwitchInfoPOD &swi = bi.switches[pi.switch_index]; for (int i = 0; i < swi.num_bits; i++) { @@ -200,8 +199,8 @@ void write_asc(const Context *ctx, std::ostream &out) NPNR_ASSERT(iez != -1); bool input_en = false; - if (!proxy.checkWireAvail(proxy.getWireBelPin(bel, PIN_D_IN_0)) || - !proxy.checkWireAvail(proxy.getWireBelPin(bel, PIN_D_IN_1))) { + 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())) { input_en = true; } @@ -272,7 +271,7 @@ void write_asc(const Context *ctx, std::ostream &out) } // Set config bits in unused IO and RAM for (auto bel : ctx->getBels()) { - if (proxy.checkBelAvail(bel) && ctx->getBelType(bel) == TYPE_SB_IO) { + if (ctx->bel_to_cell[bel.index] == IdString() && ctx->getBelType(bel) == TYPE_SB_IO) { const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO]; const BelInfoPOD &beli = ci.bel_data[bel.index]; int x = beli.x, y = beli.y, z = beli.z; @@ -285,7 +284,7 @@ void write_asc(const Context *ctx, std::ostream &out) set_config(ti, config.at(iey).at(iex), "IoCtrl.REN_" + std::to_string(iez), false); } } - } else if (proxy.checkBelAvail(bel) && ctx->getBelType(bel) == TYPE_ICESTORM_RAM) { + } else if (ctx->bel_to_cell[bel.index] == IdString() && ctx->getBelType(bel) == TYPE_ICESTORM_RAM) { const BelInfoPOD &beli = ci.bel_data[bel.index]; int x = beli.x, y = beli.y; const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_RAMB]; @@ -432,7 +431,7 @@ void write_asc(const Context *ctx, std::ostream &out) // Write symbols // const bool write_symbols = 1; for (auto wire : ctx->getWires()) { - IdString net = proxy.getBoundWireNet(wire); + IdString net = ctx->getBoundWireNet(wire); if (net != IdString()) out << ".sym " << wire.index << " " << net.str(ctx) << std::endl; } diff --git a/ice40/main.cc b/ice40/main.cc index fdfe1f25..e77bdd34 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -51,8 +51,7 @@ void svg_dump_decal(const Context *ctx, const DecalXY &decal) const float scale = 10.0, offset = 10.0; const std::string style = "stroke=\"black\" stroke-width=\"0.1\" fill=\"none\""; - auto &&proxy = ctx->rproxy(); - for (auto &el : proxy.getDecalGraphics(decal.decal)) { + for (auto &el : ctx->getDecalGraphics(decal.decal)) { if (el.type == GraphicElement::G_BOX) { std::cout << "<rect x=\"" << (offset + scale * (decal.x + el.x1)) << "\" y=\"" << (offset + scale * (decal.y + el.y1)) << "\" height=\"" << (scale * (el.y2 - el.y1)) @@ -304,32 +303,31 @@ int main(int argc, char *argv[]) } if (vm.count("tmfuzz")) { - auto &&proxy = ctx->rproxy(); std::vector<WireId> src_wires, dst_wires; /*for (auto w : ctx->getWires()) src_wires.push_back(w);*/ for (auto b : ctx->getBels()) { if (ctx->getBelType(b) == TYPE_ICESTORM_LC) { - src_wires.push_back(proxy.getWireBelPin(b, PIN_O)); + src_wires.push_back(ctx->getWireBelPin(b, PIN_O)); } if (ctx->getBelType(b) == TYPE_SB_IO) { - src_wires.push_back(proxy.getWireBelPin(b, PIN_D_IN_0)); + src_wires.push_back(ctx->getWireBelPin(b, PIN_D_IN_0)); } } for (auto b : ctx->getBels()) { if (ctx->getBelType(b) == TYPE_ICESTORM_LC) { - dst_wires.push_back(proxy.getWireBelPin(b, PIN_I0)); - dst_wires.push_back(proxy.getWireBelPin(b, PIN_I1)); - dst_wires.push_back(proxy.getWireBelPin(b, PIN_I2)); - dst_wires.push_back(proxy.getWireBelPin(b, PIN_I3)); - dst_wires.push_back(proxy.getWireBelPin(b, PIN_CEN)); - dst_wires.push_back(proxy.getWireBelPin(b, PIN_CIN)); + 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)); } if (ctx->getBelType(b) == TYPE_SB_IO) { - dst_wires.push_back(proxy.getWireBelPin(b, PIN_D_OUT_0)); - dst_wires.push_back(proxy.getWireBelPin(b, PIN_OUTPUT_ENABLE)); + dst_wires.push_back(ctx->getWireBelPin(b, PIN_D_OUT_0)); + dst_wires.push_back(ctx->getWireBelPin(b, PIN_OUTPUT_ENABLE)); } } diff --git a/ice40/place_legaliser.cc b/ice40/place_legaliser.cc index fcb47cfd..559358c7 100644 --- a/ice40/place_legaliser.cc +++ b/ice40/place_legaliser.cc @@ -119,17 +119,13 @@ class PlacementLegaliser bool legalise() { - log_info("Legalising logic cells...\n"); + log_info("Legalising design..\n"); init_logic_cells(); - log_info("Legalising carries...\n"); bool legalised_carries = legalise_carries(); if (!legalised_carries && !ctx->force) return false; - log_info("Legalising others...\n"); legalise_others(); - log_info("Legalising logic tiles...\n"); legalise_logic_tiles(); - log_info("Replacing cells...\n"); bool replaced_cells = replace_cells(); return legalised_carries && replaced_cells; } @@ -137,7 +133,6 @@ class PlacementLegaliser private: void init_logic_cells() { - auto &&proxy = ctx->rproxy(); for (auto bel : ctx->getBels()) { // Initialise the logic bels vector with unavailable invalid bels, dimensions [0..width][0..height[0..7] logic_bels.resize(ctx->chip_info->width + 1, @@ -148,7 +143,7 @@ class PlacementLegaliser // Using the non-standard API here to get (x, y, z) rather than just (x, y) auto bi = ctx->chip_info->bel_data[bel.index]; int x = bi.x, y = bi.y, z = bi.z; - IdString cell = proxy.getBoundBelCell(bel); + IdString cell = ctx->getBoundBelCell(bel); if (cell != IdString() && ctx->cells.at(cell)->belStrength >= STRENGTH_FIXED) logic_bels.at(x).at(y).at(z) = std::make_pair(bel, true); // locked out of use else @@ -200,33 +195,28 @@ class PlacementLegaliser } } bool success = true; - // Find midpoints for all chains, before we start tearing them up std::vector<CellChain> all_chains; - { - auto &&proxy = ctx->rproxy(); - for (auto &base_chain : carry_chains) { - if (ctx->verbose) { - log_info("Found carry chain: \n"); - for (auto entry : base_chain.cells) - log_info(" %s\n", entry->name.c_str(ctx)); - log_info("\n"); - } - std::vector<CellChain> split_chains = split_carry_chain(proxy, base_chain); - for (auto &chain : split_chains) { - get_chain_midpoint(ctx, chain, chain.mid_x, chain.mid_y); - all_chains.push_back(chain); - } + for (auto &base_chain : carry_chains) { + if (ctx->verbose) { + log_info("Found carry chain: \n"); + for (auto entry : base_chain.cells) + log_info(" %s\n", entry->name.c_str(ctx)); + log_info("\n"); + } + std::vector<CellChain> split_chains = split_carry_chain(base_chain); + for (auto &chain : split_chains) { + get_chain_midpoint(ctx, chain, chain.mid_x, chain.mid_y); + all_chains.push_back(chain); } } // Actual chain placement - auto &&proxy = ctx->rwproxy(); for (auto &chain : all_chains) { if (ctx->verbose) log_info("Placing carry chain starting at '%s'\n", chain.cells.front()->name.c_str(ctx)); float base_x = chain.mid_x, base_y = chain.mid_y - (chain.cells.size() / 16.0f); // Find Bel meeting requirements closest to the target base, returning location as <x, y, z> - auto chain_origin_bel = find_closest_bel(proxy, base_x, base_y, chain); + auto chain_origin_bel = find_closest_bel(base_x, base_y, chain); int place_x = std::get<0>(chain_origin_bel), place_y = std::get<1>(chain_origin_bel), place_z = std::get<2>(chain_origin_bel); if (place_x == -1) { @@ -243,7 +233,7 @@ class PlacementLegaliser // Place carry chain for (int i = 0; i < int(chain.cells.size()); i++) { int target_z = place_y * 8 + place_z + i; - place_lc(proxy, chain.cells.at(i), place_x, target_z / 8, target_z % 8); + place_lc(chain.cells.at(i), place_x, target_z / 8, target_z % 8); if (ctx->verbose) log_info(" Cell '%s' placed at (%d, %d, %d)\n", chain.cells.at(i)->name.c_str(ctx), place_x, target_z / 8, target_z % 8); @@ -253,7 +243,7 @@ class PlacementLegaliser } // Find Bel closest to a location, meeting chain requirements - std::tuple<int, int, int> find_closest_bel(MutateContext &proxy, float target_x, float target_y, CellChain &chain) + std::tuple<int, int, int> find_closest_bel(float target_x, float target_y, CellChain &chain) { std::tuple<int, int, int> best_origin = std::make_tuple(-1, -1, -1); wirelen_t best_wirelength = std::numeric_limits<wirelen_t>::max(); @@ -270,7 +260,7 @@ class PlacementLegaliser valid = false; break; } else { - wirelen += get_cell_wirelength_at_bel(proxy, ctx, chain.cells.at(k), lb.first); + wirelen += get_cell_wirelength_at_bel(ctx, chain.cells.at(k), lb.first); } } if (valid && wirelen < best_wirelength) { @@ -283,7 +273,7 @@ class PlacementLegaliser } // Split a carry chain into multiple legal chains - std::vector<CellChain> split_carry_chain(const ReadContext &proxy, CellChain &carryc) + std::vector<CellChain> split_carry_chain(CellChain &carryc) { bool start_of_chain = true; std::vector<CellChain> chains; @@ -308,7 +298,7 @@ class PlacementLegaliser } tile.push_back(cell); chains.back().cells.push_back(cell); - bool split_chain = (!proxy.logicCellsCompatible(tile)) || (int(chains.back().cells.size()) > max_length); + bool split_chain = (!ctx->logicCellsCompatible(tile)) || (int(chains.back().cells.size()) > max_length); if (split_chain) { CellInfo *passout = make_carry_pass_out(cell->ports.at(ctx->id("COUT"))); tile.pop_back(); @@ -335,22 +325,22 @@ class PlacementLegaliser } // Place a logic cell at a given grid location, handling rip-up etc - void place_lc(MutateContext &proxy, CellInfo *cell, int x, int y, int z) + void place_lc(CellInfo *cell, int x, int y, int z) { auto &loc = logic_bels.at(x).at(y).at(z); NPNR_ASSERT(!loc.second); BelId bel = loc.first; // Check if there is a cell presently at the location, which we will need to rip up - IdString existing = proxy.getBoundBelCell(bel); + IdString existing = ctx->getBoundBelCell(bel); if (existing != IdString()) { // TODO: keep track of the previous position of the ripped up cell, as a hint rippedCells.insert(existing); - proxy.unbindBel(bel); + ctx->unbindBel(bel); } if (cell->bel != BelId()) { - proxy.unbindBel(cell->bel); + ctx->unbindBel(cell->bel); } - proxy.bindBel(bel, cell->name, STRENGTH_LOCKED); + ctx->bindBel(bel, cell->name, STRENGTH_LOCKED); rippedCells.erase(cell->name); // If cell was ripped up previously, no need to re-place loc.second = true; // Bel is now unavailable for further use } @@ -433,20 +423,19 @@ class PlacementLegaliser // Legalise logic tiles void legalise_logic_tiles() { - auto &&proxy = ctx->rwproxy(); int width = ctx->chip_info->width, height = ctx->chip_info->height; for (int x = 1; x < width; x++) { for (int y = 1; y < height; y++) { BelId tileBel = logic_bels.at(x).at(y).at(0).first; if (tileBel != BelId()) { bool changed = true; - while (!proxy.isBelLocationValid(tileBel) && changed) { + while (!ctx->isBelLocationValid(tileBel) && changed) { changed = false; int max_score = 0; CellInfo *target = nullptr; for (int z = 0; z < 8; z++) { BelId bel = logic_bels.at(x).at(y).at(z).first; - IdString cell = proxy.getBoundBelCell(bel); + IdString cell = ctx->getBoundBelCell(bel); if (cell != IdString()) { CellInfo *ci = ctx->cells.at(cell).get(); if (ci->belStrength >= STRENGTH_STRONG) @@ -459,7 +448,7 @@ class PlacementLegaliser } } if (target != nullptr) { - proxy.unbindBel(target->bel); + ctx->unbindBel(target->bel); rippedCells.insert(target->name); changed = true; } @@ -472,14 +461,13 @@ class PlacementLegaliser // Legalise other tiles void legalise_others() { - auto &&proxy = ctx->rwproxy(); std::vector<CellInfo *> legalised_others; for (auto cell : sorted(ctx->cells)) { CellInfo *ci = cell.second; if (!is_lc(ctx, ci)) { if (ci->belStrength < STRENGTH_STRONG && ci->bel != BelId()) { - if (!proxy.isValidBelForCell(ci, ci->bel)) { - place_single_cell(proxy, ctx, ci, true); + if (!ctx->isValidBelForCell(ci, ci->bel)) { + place_single_cell(ctx, ci, true); } legalised_others.push_back(ci); } @@ -494,11 +482,10 @@ class PlacementLegaliser // Replace ripped-up cells bool replace_cells() { - auto &&proxy = ctx->rwproxy(); bool success = true; for (auto cell : sorted(rippedCells)) { CellInfo *ci = ctx->cells.at(cell).get(); - bool placed = place_single_cell(proxy, ctx, ci, true); + bool placed = place_single_cell(ctx, ci, true); if (!placed) { if (ctx->force) { log_warning("failed to place cell '%s' of type '%s'\n", cell.c_str(ctx), ci->type.c_str(ctx)); diff --git a/nextpnr.nix b/nextpnr.nix deleted file mode 100644 index bbd2c127..00000000 --- a/nextpnr.nix +++ /dev/null @@ -1,53 +0,0 @@ -# -# nextpnr -- Next Generation Place and Route -# -# 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 -# 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. -# - -with import <nixpkgs> {}; - -let - gitRev = "a8c84e90a39c54174dd24b5b76bd17aed8311481"; - gitBranch = "master"; -in - stdenv.mkDerivation rec { - name = "nextpnr-${version}"; - version = "1.0.0"; - - src = ./.; - - buildInputs = [ - python3 (boost.override { python = python3; }) - qt5.qtbase - ]; - - nativeBuildInputs = [ cmake icestorm ]; - - cmakeFlags= [ - "-DARCH=ice40" - "-DICEBOX_ROOT=${icestorm}/share/icebox" - ]; - - enableParallelBuilding = true; - - meta = with stdenv.lib; { - description = "Next Generation Place-and-Route tool for FPGAs"; - homepage = "https://gitlab.com/symbioticeda/nextpnr"; - license = licenses.bsd0; - platforms = platforms.linux; - }; - } - - |