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