Using hashlib in arches
Signed-off-by: gatecat <gatecat@ds0.me>
This commit is contained in:
parent
f4fed62c05
commit
ecc19c2c08
@ -441,23 +441,23 @@ template <typename R> struct BaseArch : ArchAPI<R>
|
|||||||
|
|
||||||
// --------------------------------------------------------------
|
// --------------------------------------------------------------
|
||||||
// These structures are used to provide default implementations of bel/wire/pip binding. Arches might want to
|
// These structures are used to provide default implementations of bel/wire/pip binding. Arches might want to
|
||||||
// replace them with their own, for example to use faster access structures than unordered_map. Arches might also
|
// replace them with their own, for example to use faster access structures than dict. Arches might also
|
||||||
// want to add extra checks around these functions
|
// want to add extra checks around these functions
|
||||||
std::unordered_map<BelId, CellInfo *> base_bel2cell;
|
dict<BelId, CellInfo *> base_bel2cell;
|
||||||
std::unordered_map<WireId, NetInfo *> base_wire2net;
|
dict<WireId, NetInfo *> base_wire2net;
|
||||||
std::unordered_map<PipId, NetInfo *> base_pip2net;
|
dict<PipId, NetInfo *> base_pip2net;
|
||||||
|
|
||||||
// For the default cell/bel bucket implementations
|
// For the default cell/bel bucket implementations
|
||||||
std::vector<IdString> cell_types;
|
std::vector<IdString> cell_types;
|
||||||
std::vector<BelBucketId> bel_buckets;
|
std::vector<BelBucketId> bel_buckets;
|
||||||
std::unordered_map<BelBucketId, std::vector<BelId>> bucket_bels;
|
dict<BelBucketId, std::vector<BelId>> bucket_bels;
|
||||||
|
|
||||||
// Arches that want to use the default cell types and bel buckets *must* call these functions in their constructor
|
// Arches that want to use the default cell types and bel buckets *must* call these functions in their constructor
|
||||||
bool cell_types_initialised = false;
|
bool cell_types_initialised = false;
|
||||||
bool bel_buckets_initialised = false;
|
bool bel_buckets_initialised = false;
|
||||||
void init_cell_types()
|
void init_cell_types()
|
||||||
{
|
{
|
||||||
std::unordered_set<IdString> bel_types;
|
pool<IdString> bel_types;
|
||||||
for (auto bel : this->getBels())
|
for (auto bel : this->getBels())
|
||||||
bel_types.insert(this->getBelType(bel));
|
bel_types.insert(this->getBelType(bel));
|
||||||
std::copy(bel_types.begin(), bel_types.end(), std::back_inserter(cell_types));
|
std::copy(bel_types.begin(), bel_types.end(), std::back_inserter(cell_types));
|
||||||
|
@ -74,6 +74,15 @@ template <> struct hash_ops<int64_t> : hash_int_ops
|
|||||||
static inline unsigned int hash(int64_t a) { return mkhash((unsigned int)(a), (unsigned int)(a >> 32)); }
|
static inline unsigned int hash(int64_t a) { return mkhash((unsigned int)(a), (unsigned int)(a >> 32)); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <> struct hash_ops<uint32_t> : hash_int_ops
|
||||||
|
{
|
||||||
|
static inline unsigned int hash(uint32_t a) { return a; }
|
||||||
|
};
|
||||||
|
template <> struct hash_ops<uint64_t> : hash_int_ops
|
||||||
|
{
|
||||||
|
static inline unsigned int hash(uint64_t a) { return mkhash((unsigned int)(a), (unsigned int)(a >> 32)); }
|
||||||
|
};
|
||||||
|
|
||||||
template <> struct hash_ops<std::string>
|
template <> struct hash_ops<std::string>
|
||||||
{
|
{
|
||||||
static inline bool cmp(const std::string &a, const std::string &b) { return a == b; }
|
static inline bool cmp(const std::string &a, const std::string &b) { return a == b; }
|
||||||
|
26
ecp5/arch.h
26
ecp5/arch.h
@ -419,23 +419,9 @@ struct DelayKey
|
|||||||
{
|
{
|
||||||
return celltype == other.celltype && from == other.from && to == other.to;
|
return celltype == other.celltype && from == other.from && to == other.to;
|
||||||
}
|
}
|
||||||
|
unsigned int hash() const { return mkhash(celltype.hash(), mkhash(from.hash(), to.hash())); }
|
||||||
};
|
};
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
|
||||||
namespace std {
|
|
||||||
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX DelayKey>
|
|
||||||
{
|
|
||||||
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX DelayKey &dk) const noexcept
|
|
||||||
{
|
|
||||||
std::size_t seed = std::hash<NEXTPNR_NAMESPACE_PREFIX IdString>()(dk.celltype);
|
|
||||||
seed ^= std::hash<NEXTPNR_NAMESPACE_PREFIX IdString>()(dk.from) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
|
||||||
seed ^= std::hash<NEXTPNR_NAMESPACE_PREFIX IdString>()(dk.to) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
|
||||||
return seed;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // namespace std
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
|
||||||
|
|
||||||
struct ArchRanges : BaseArchRanges
|
struct ArchRanges : BaseArchRanges
|
||||||
{
|
{
|
||||||
using ArchArgsT = ArchArgs;
|
using ArchArgsT = ArchArgs;
|
||||||
@ -458,15 +444,15 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
const PackageInfoPOD *package_info;
|
const PackageInfoPOD *package_info;
|
||||||
const SpeedGradePOD *speed_grade;
|
const SpeedGradePOD *speed_grade;
|
||||||
|
|
||||||
mutable std::unordered_map<IdStringList, PipId> pip_by_name;
|
mutable dict<IdStringList, PipId> pip_by_name;
|
||||||
|
|
||||||
std::vector<CellInfo *> bel_to_cell;
|
std::vector<CellInfo *> bel_to_cell;
|
||||||
std::unordered_map<WireId, int> wire_fanout;
|
dict<WireId, int> wire_fanout;
|
||||||
|
|
||||||
// fast access to X and Y IdStrings for building object names
|
// fast access to X and Y IdStrings for building object names
|
||||||
std::vector<IdString> x_ids, y_ids;
|
std::vector<IdString> x_ids, y_ids;
|
||||||
// inverse of the above for name->object mapping
|
// inverse of the above for name->object mapping
|
||||||
std::unordered_map<IdString, int> id_to_x, id_to_y;
|
dict<IdString, int> id_to_x, id_to_y;
|
||||||
|
|
||||||
ArchArgs args;
|
ArchArgs args;
|
||||||
Arch(ArchArgs args);
|
Arch(ArchArgs args);
|
||||||
@ -914,10 +900,10 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
// Improves directivity of routing to DSP inputs, avoids issues
|
// Improves directivity of routing to DSP inputs, avoids issues
|
||||||
// with different routes to the same physical reset wire causing
|
// with different routes to the same physical reset wire causing
|
||||||
// conflicts and slow routing
|
// conflicts and slow routing
|
||||||
std::unordered_map<WireId, std::pair<int, int>> wire_loc_overrides;
|
dict<WireId, std::pair<int, int>> wire_loc_overrides;
|
||||||
void setup_wire_locations();
|
void setup_wire_locations();
|
||||||
|
|
||||||
mutable std::unordered_map<DelayKey, std::pair<bool, DelayQuad>> celldelay_cache;
|
mutable dict<DelayKey, std::pair<bool, DelayQuad>> celldelay_cache;
|
||||||
|
|
||||||
static const std::string defaultPlacer;
|
static const std::string defaultPlacer;
|
||||||
static const std::vector<std::string> availablePlacers;
|
static const std::vector<std::string> availablePlacers;
|
||||||
|
@ -669,8 +669,8 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Find bank voltages
|
// Find bank voltages
|
||||||
std::unordered_map<int, IOVoltage> bankVcc;
|
dict<int, IOVoltage> bankVcc;
|
||||||
std::unordered_map<int, bool> bankLvds, bankVref, bankDiff;
|
dict<int, bool> bankLvds, bankVref, bankDiff;
|
||||||
|
|
||||||
for (auto &cell : ctx->cells) {
|
for (auto &cell : ctx->cells) {
|
||||||
CellInfo *ci = cell.second.get();
|
CellInfo *ci = cell.second.get();
|
||||||
|
@ -422,7 +422,7 @@ void dram_to_ram_slice(Context *ctx, CellInfo *ram, CellInfo *lc, CellInfo *ramw
|
|||||||
}
|
}
|
||||||
|
|
||||||
void nxio_to_tr(Context *ctx, CellInfo *nxio, CellInfo *trio, std::vector<std::unique_ptr<CellInfo>> &created_cells,
|
void nxio_to_tr(Context *ctx, CellInfo *nxio, CellInfo *trio, std::vector<std::unique_ptr<CellInfo>> &created_cells,
|
||||||
std::unordered_set<IdString> &todelete_cells)
|
pool<IdString> &todelete_cells)
|
||||||
{
|
{
|
||||||
if (nxio->type == ctx->id("$nextpnr_ibuf")) {
|
if (nxio->type == ctx->id("$nextpnr_ibuf")) {
|
||||||
trio->params[ctx->id("DIR")] = std::string("INPUT");
|
trio->params[ctx->id("DIR")] = std::string("INPUT");
|
||||||
|
@ -65,7 +65,7 @@ void dram_to_ram_slice(Context *ctx, CellInfo *ram, CellInfo *lc, CellInfo *ramw
|
|||||||
|
|
||||||
// Convert a nextpnr IO buffer to a TRELLIS_IO
|
// Convert a nextpnr IO buffer to a TRELLIS_IO
|
||||||
void nxio_to_tr(Context *ctx, CellInfo *nxio, CellInfo *trio, std::vector<std::unique_ptr<CellInfo>> &created_cells,
|
void nxio_to_tr(Context *ctx, CellInfo *nxio, CellInfo *trio, std::vector<std::unique_ptr<CellInfo>> &created_cells,
|
||||||
std::unordered_set<IdString> &todelete_cells);
|
pool<IdString> &todelete_cells);
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ class Ecp5GlobalRouter
|
|||||||
|
|
||||||
std::vector<NetInfo *> get_clocks()
|
std::vector<NetInfo *> get_clocks()
|
||||||
{
|
{
|
||||||
std::unordered_map<IdString, int> clockCount;
|
dict<IdString, int> clockCount;
|
||||||
for (auto &net : ctx->nets) {
|
for (auto &net : ctx->nets) {
|
||||||
NetInfo *ni = net.second.get();
|
NetInfo *ni = net.second.get();
|
||||||
if (ni->name == ctx->id("$PACKER_GND_NET") || ni->name == ctx->id("$PACKER_VCC_NET"))
|
if (ni->name == ctx->id("$PACKER_GND_NET") || ni->name == ctx->id("$PACKER_VCC_NET"))
|
||||||
@ -147,7 +147,7 @@ class Ecp5GlobalRouter
|
|||||||
WireId globalWire;
|
WireId globalWire;
|
||||||
IdString global_name = ctx->id(fmt_str("G_HPBX" << std::setw(2) << std::setfill('0') << global_index << "00"));
|
IdString global_name = ctx->id(fmt_str("G_HPBX" << std::setw(2) << std::setfill('0') << global_index << "00"));
|
||||||
std::queue<WireId> upstream;
|
std::queue<WireId> upstream;
|
||||||
std::unordered_map<WireId, PipId> backtrace;
|
dict<WireId, PipId> backtrace;
|
||||||
upstream.push(userWire);
|
upstream.push(userWire);
|
||||||
bool already_routed = false;
|
bool already_routed = false;
|
||||||
WireId next;
|
WireId next;
|
||||||
@ -230,7 +230,7 @@ class Ecp5GlobalRouter
|
|||||||
bool simple_router(NetInfo *net, WireId src, WireId dst, bool allow_fail = false)
|
bool simple_router(NetInfo *net, WireId src, WireId dst, bool allow_fail = false)
|
||||||
{
|
{
|
||||||
std::queue<WireId> visit;
|
std::queue<WireId> visit;
|
||||||
std::unordered_map<WireId, PipId> backtrace;
|
dict<WireId, PipId> backtrace;
|
||||||
visit.push(src);
|
visit.push(src);
|
||||||
WireId cursor;
|
WireId cursor;
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -340,7 +340,7 @@ class Ecp5GlobalRouter
|
|||||||
bool has_short_route(WireId src, WireId dst, int thresh = 7)
|
bool has_short_route(WireId src, WireId dst, int thresh = 7)
|
||||||
{
|
{
|
||||||
std::queue<WireId> visit;
|
std::queue<WireId> visit;
|
||||||
std::unordered_map<WireId, PipId> backtrace;
|
dict<WireId, PipId> backtrace;
|
||||||
visit.push(src);
|
visit.push(src);
|
||||||
WireId cursor;
|
WireId cursor;
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -376,7 +376,7 @@ class Ecp5GlobalRouter
|
|||||||
return length < thresh;
|
return length < thresh;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_set<WireId> used_pclkcib;
|
pool<WireId> used_pclkcib;
|
||||||
|
|
||||||
std::set<WireId> get_candidate_pclkcibs(BelId dcc)
|
std::set<WireId> get_candidate_pclkcibs(BelId dcc)
|
||||||
{
|
{
|
||||||
@ -535,7 +535,7 @@ class Ecp5GlobalRouter
|
|||||||
fab_globals.insert(i);
|
fab_globals.insert(i);
|
||||||
}
|
}
|
||||||
std::vector<std::pair<PortRef *, int>> toroute;
|
std::vector<std::pair<PortRef *, int>> toroute;
|
||||||
std::unordered_map<int, NetInfo *> clocks;
|
dict<int, NetInfo *> clocks;
|
||||||
for (auto &cell : ctx->cells) {
|
for (auto &cell : ctx->cells) {
|
||||||
CellInfo *ci = cell.second.get();
|
CellInfo *ci = cell.second.get();
|
||||||
if (ci->type == id_DCCA) {
|
if (ci->type == id_DCCA) {
|
||||||
@ -595,7 +595,7 @@ class Ecp5GlobalRouter
|
|||||||
WireId src = ctx->getNetinfoSourceWire(ni);
|
WireId src = ctx->getNetinfoSourceWire(ni);
|
||||||
WireId dst = ctx->getBelPinWire(ci->bel, pin);
|
WireId dst = ctx->getBelPinWire(ci->bel, pin);
|
||||||
std::queue<WireId> visit;
|
std::queue<WireId> visit;
|
||||||
std::unordered_map<WireId, PipId> backtrace;
|
dict<WireId, PipId> backtrace;
|
||||||
visit.push(dst);
|
visit.push(dst);
|
||||||
int iter = 0;
|
int iter = 0;
|
||||||
WireId cursor;
|
WireId cursor;
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <unordered_set>
|
|
||||||
|
|
||||||
#include "arch.h"
|
#include "arch.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
@ -27,7 +26,7 @@
|
|||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
static const std::unordered_set<std::string> sysconfig_keys = {
|
static const pool<std::string> sysconfig_keys = {
|
||||||
"SLAVE_SPI_PORT", "MASTER_SPI_PORT", "SLAVE_PARALLEL_PORT",
|
"SLAVE_SPI_PORT", "MASTER_SPI_PORT", "SLAVE_PARALLEL_PORT",
|
||||||
"BACKGROUND_RECONFIG", "DONE_EX", "DONE_OD",
|
"BACKGROUND_RECONFIG", "DONE_EX", "DONE_OD",
|
||||||
"DONE_PULL", "MCCLK_FREQ", "TRANSFR",
|
"DONE_PULL", "MCCLK_FREQ", "TRANSFR",
|
||||||
@ -35,7 +34,7 @@ static const std::unordered_set<std::string> sysconfig_keys = {
|
|||||||
"COMPRESS_CONFIG", "CONFIG_MODE", "INBUF",
|
"COMPRESS_CONFIG", "CONFIG_MODE", "INBUF",
|
||||||
};
|
};
|
||||||
|
|
||||||
static const std::unordered_set<std::string> iobuf_keys = {
|
static const pool<std::string> iobuf_keys = {
|
||||||
"IO_TYPE", "BANK", "BANK_VCC", "VREF", "PULLMODE", "DRIVE", "SLEWRATE",
|
"IO_TYPE", "BANK", "BANK_VCC", "VREF", "PULLMODE", "DRIVE", "SLEWRATE",
|
||||||
"CLAMP", "OPENDRAIN", "DIFFRESISTOR", "DIFFDRIVE", "HYSTERESIS", "TERMINATION",
|
"CLAMP", "OPENDRAIN", "DIFFRESISTOR", "DIFFDRIVE", "HYSTERESIS", "TERMINATION",
|
||||||
};
|
};
|
||||||
|
29
ecp5/pack.cc
29
ecp5/pack.cc
@ -21,7 +21,6 @@
|
|||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <unordered_set>
|
|
||||||
#include "cells.h"
|
#include "cells.h"
|
||||||
#include "chain_utils.h"
|
#include "chain_utils.h"
|
||||||
#include "design_utils.h"
|
#include "design_utils.h"
|
||||||
@ -261,7 +260,7 @@ class Ecp5Packer
|
|||||||
void pair_luts()
|
void pair_luts()
|
||||||
{
|
{
|
||||||
log_info("Finding LUT-LUT pairs...\n");
|
log_info("Finding LUT-LUT pairs...\n");
|
||||||
std::unordered_set<IdString> procdLuts;
|
pool<IdString> procdLuts;
|
||||||
for (auto &cell : ctx->cells) {
|
for (auto &cell : ctx->cells) {
|
||||||
CellInfo *ci = cell.second.get();
|
CellInfo *ci = cell.second.get();
|
||||||
if (is_lut(ctx, ci) && procdLuts.find(cell.first) == procdLuts.end()) {
|
if (is_lut(ctx, ci) && procdLuts.find(cell.first) == procdLuts.end()) {
|
||||||
@ -1134,7 +1133,7 @@ class Ecp5Packer
|
|||||||
// Used for packing an FF into a nearby SLICE
|
// Used for packing an FF into a nearby SLICE
|
||||||
template <typename TFunc> CellInfo *find_nearby_cell(CellInfo *origin, TFunc Func)
|
template <typename TFunc> CellInfo *find_nearby_cell(CellInfo *origin, TFunc Func)
|
||||||
{
|
{
|
||||||
std::unordered_set<CellInfo *> visited_cells;
|
pool<CellInfo *, hash_ptr_ops> visited_cells;
|
||||||
std::queue<CellInfo *> to_visit;
|
std::queue<CellInfo *> to_visit;
|
||||||
visited_cells.insert(origin);
|
visited_cells.insert(origin);
|
||||||
to_visit.push(origin);
|
to_visit.push(origin);
|
||||||
@ -1971,7 +1970,7 @@ class Ecp5Packer
|
|||||||
IdString global_name = ctx->id("G_BANK" + std::to_string(bank) + "ECLK" + std::to_string(found_eclk));
|
IdString global_name = ctx->id("G_BANK" + std::to_string(bank) + "ECLK" + std::to_string(found_eclk));
|
||||||
|
|
||||||
std::queue<WireId> upstream;
|
std::queue<WireId> upstream;
|
||||||
std::unordered_map<WireId, PipId> backtrace;
|
dict<WireId, PipId> backtrace;
|
||||||
upstream.push(userWire);
|
upstream.push(userWire);
|
||||||
WireId next;
|
WireId next;
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -2026,7 +2025,7 @@ class Ecp5Packer
|
|||||||
new_cells.push_back(std::move(zero_cell));
|
new_cells.push_back(std::move(zero_cell));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_map<IdString, std::pair<bool, int>> dqsbuf_dqsg;
|
dict<IdString, std::pair<bool, int>> dqsbuf_dqsg;
|
||||||
// Pack DQSBUFs
|
// Pack DQSBUFs
|
||||||
void pack_dqsbuf()
|
void pack_dqsbuf()
|
||||||
{
|
{
|
||||||
@ -2119,7 +2118,7 @@ class Ecp5Packer
|
|||||||
// Pack IOLOGIC
|
// Pack IOLOGIC
|
||||||
void pack_iologic()
|
void pack_iologic()
|
||||||
{
|
{
|
||||||
std::unordered_map<IdString, CellInfo *> pio_iologic;
|
dict<IdString, CellInfo *> pio_iologic;
|
||||||
|
|
||||||
auto set_iologic_sclk = [&](CellInfo *iol, CellInfo *prim, IdString port, bool input, bool disconnect = true) {
|
auto set_iologic_sclk = [&](CellInfo *iol, CellInfo *prim, IdString port, bool input, bool disconnect = true) {
|
||||||
NetInfo *sclk = nullptr;
|
NetInfo *sclk = nullptr;
|
||||||
@ -2779,7 +2778,7 @@ class Ecp5Packer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
flush_cells();
|
flush_cells();
|
||||||
std::unordered_set<BelId> used_eclksyncb;
|
pool<BelId> used_eclksyncb;
|
||||||
for (auto &cell : ctx->cells) {
|
for (auto &cell : ctx->cells) {
|
||||||
CellInfo *ci = cell.second.get();
|
CellInfo *ci = cell.second.get();
|
||||||
if (ci->type == id_CLKDIVF) {
|
if (ci->type == id_CLKDIVF) {
|
||||||
@ -2967,7 +2966,7 @@ class Ecp5Packer
|
|||||||
|
|
||||||
auto equals_epsilon = [](delay_t a, delay_t b) { return (std::abs(a - b) / std::max(double(b), 1.0)) < 1e-3; };
|
auto equals_epsilon = [](delay_t a, delay_t b) { return (std::abs(a - b) / std::max(double(b), 1.0)) < 1e-3; };
|
||||||
|
|
||||||
std::unordered_set<IdString> user_constrained, changed_nets;
|
pool<IdString> user_constrained, changed_nets;
|
||||||
for (auto &net : ctx->nets) {
|
for (auto &net : ctx->nets) {
|
||||||
if (net.second->clkconstr != nullptr)
|
if (net.second->clkconstr != nullptr)
|
||||||
user_constrained.insert(net.first);
|
user_constrained.insert(net.first);
|
||||||
@ -3041,7 +3040,7 @@ class Ecp5Packer
|
|||||||
const int itermax = 5000;
|
const int itermax = 5000;
|
||||||
while (!changed_nets.empty() && iter < itermax) {
|
while (!changed_nets.empty() && iter < itermax) {
|
||||||
++iter;
|
++iter;
|
||||||
std::unordered_set<IdString> changed_cells;
|
pool<IdString> changed_cells;
|
||||||
for (auto net : changed_nets) {
|
for (auto net : changed_nets) {
|
||||||
for (auto &user : ctx->nets.at(net)->users)
|
for (auto &user : ctx->nets.at(net)->users)
|
||||||
if (user.port == id_CLKI || user.port == id_ECLKI || user.port == id_CLK0 || user.port == id_CLK1)
|
if (user.port == id_CLKI || user.port == id_ECLKI || user.port == id_CLK0 || user.port == id_CLK1)
|
||||||
@ -3051,7 +3050,7 @@ class Ecp5Packer
|
|||||||
changed_cells.insert(drv.cell->name);
|
changed_cells.insert(drv.cell->name);
|
||||||
}
|
}
|
||||||
changed_nets.clear();
|
changed_nets.clear();
|
||||||
for (auto cell : sorted(changed_cells)) {
|
for (auto cell : changed_cells) {
|
||||||
CellInfo *ci = ctx->cells.at(cell).get();
|
CellInfo *ci = ctx->cells.at(cell).get();
|
||||||
if (ci->type == id_CLKDIVF) {
|
if (ci->type == id_CLKDIVF) {
|
||||||
std::string div = str_or_default(ci->params, ctx->id("DIV"), "2.0");
|
std::string div = str_or_default(ci->params, ctx->id("DIV"), "2.0");
|
||||||
@ -3152,7 +3151,7 @@ class Ecp5Packer
|
|||||||
private:
|
private:
|
||||||
Context *ctx;
|
Context *ctx;
|
||||||
|
|
||||||
std::unordered_set<IdString> packed_cells;
|
pool<IdString> packed_cells;
|
||||||
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
||||||
|
|
||||||
struct SliceUsage
|
struct SliceUsage
|
||||||
@ -3163,10 +3162,10 @@ class Ecp5Packer
|
|||||||
bool mux5_used = false, muxx_used = false;
|
bool mux5_used = false, muxx_used = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unordered_map<IdString, SliceUsage> sliceUsage;
|
dict<IdString, SliceUsage> sliceUsage;
|
||||||
std::unordered_map<IdString, IdString> lutffPairs;
|
dict<IdString, IdString> lutffPairs;
|
||||||
std::unordered_map<IdString, IdString> fflutPairs;
|
dict<IdString, IdString> fflutPairs;
|
||||||
std::unordered_map<IdString, IdString> lutPairs;
|
dict<IdString, IdString> lutPairs;
|
||||||
};
|
};
|
||||||
// Main pack function
|
// Main pack function
|
||||||
bool Arch::pack()
|
bool Arch::pack()
|
||||||
|
@ -63,21 +63,8 @@ struct SiteBelPair
|
|||||||
SiteBelPair(std::string site, IdString bel) : site(site), bel(bel) {}
|
SiteBelPair(std::string site, IdString bel) : site(site), bel(bel) {}
|
||||||
|
|
||||||
bool operator==(const SiteBelPair &other) const { return site == other.site && bel == other.bel; }
|
bool operator==(const SiteBelPair &other) const { return site == other.site && bel == other.bel; }
|
||||||
|
unsigned int hash() const { return mkhash(std::hash<std::string>()(site), bel.hash()); }
|
||||||
};
|
};
|
||||||
NEXTPNR_NAMESPACE_END
|
|
||||||
|
|
||||||
template <> struct std::hash<NEXTPNR_NAMESPACE_PREFIX SiteBelPair>
|
|
||||||
{
|
|
||||||
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX SiteBelPair &site_bel) const noexcept
|
|
||||||
{
|
|
||||||
std::size_t seed = 0;
|
|
||||||
boost::hash_combine(seed, std::hash<std::string>()(site_bel.site));
|
|
||||||
boost::hash_combine(seed, std::hash<NEXTPNR_NAMESPACE_PREFIX IdString>()(site_bel.bel));
|
|
||||||
return seed;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
|
||||||
|
|
||||||
static std::pair<std::string, std::string> split_identifier_name_dot(const std::string &name)
|
static std::pair<std::string, std::string> split_identifier_name_dot(const std::string &name)
|
||||||
{
|
{
|
||||||
@ -180,7 +167,7 @@ Arch::Arch(ArchArgs args) : args(args), disallow_site_routing(false)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_set<SiteBelPair> site_bel_pads;
|
pool<SiteBelPair> site_bel_pads;
|
||||||
for (const auto &package_pin : chip_info->packages[package_index].pins) {
|
for (const auto &package_pin : chip_info->packages[package_index].pins) {
|
||||||
IdString site(package_pin.site);
|
IdString site(package_pin.site);
|
||||||
IdString bel(package_pin.bel);
|
IdString bel(package_pin.bel);
|
||||||
@ -1951,7 +1938,7 @@ void Arch::unmask_bel_pins()
|
|||||||
|
|
||||||
void Arch::remove_site_routing()
|
void Arch::remove_site_routing()
|
||||||
{
|
{
|
||||||
HashTables::HashSet<WireId> wires_to_unbind;
|
pool<WireId> wires_to_unbind;
|
||||||
for (auto &net_pair : nets) {
|
for (auto &net_pair : nets) {
|
||||||
for (auto &wire_pair : net_pair.second->wires) {
|
for (auto &wire_pair : net_pair.second->wires) {
|
||||||
WireId wire = wire_pair.first;
|
WireId wire = wire_pair.first;
|
||||||
|
@ -103,14 +103,14 @@ struct Arch : ArchAPI<ArchRanges>
|
|||||||
// Guard initialization of "by_name" maps if accessed from multiple
|
// Guard initialization of "by_name" maps if accessed from multiple
|
||||||
// threads on a "const Context *".
|
// threads on a "const Context *".
|
||||||
mutable std::mutex by_name_mutex;
|
mutable std::mutex by_name_mutex;
|
||||||
mutable std::unordered_map<IdString, int> tile_by_name;
|
mutable dict<IdString, int> tile_by_name;
|
||||||
mutable std::unordered_map<IdString, std::pair<int, int>> site_by_name;
|
mutable dict<IdString, std::pair<int, int>> site_by_name;
|
||||||
|
|
||||||
std::unordered_map<WireId, NetInfo *> wire_to_net;
|
dict<WireId, NetInfo *> wire_to_net;
|
||||||
std::unordered_map<PipId, NetInfo *> pip_to_net;
|
dict<PipId, NetInfo *> pip_to_net;
|
||||||
|
|
||||||
DedicatedInterconnect dedicated_interconnect;
|
DedicatedInterconnect dedicated_interconnect;
|
||||||
HashTables::HashMap<int32_t, TileStatus> tileStatus;
|
dict<int32_t, TileStatus> tileStatus;
|
||||||
PseudoPipData pseudo_pip_data;
|
PseudoPipData pseudo_pip_data;
|
||||||
|
|
||||||
ArchArgs args;
|
ArchArgs args;
|
||||||
@ -685,8 +685,8 @@ struct Arch : ArchAPI<ArchRanges>
|
|||||||
|
|
||||||
// -------------------------------------------------
|
// -------------------------------------------------
|
||||||
|
|
||||||
void place_iobufs(WireId pad_wire, NetInfo *net, const std::unordered_set<CellInfo *> &tightly_attached_bels,
|
void place_iobufs(WireId pad_wire, NetInfo *net, const pool<CellInfo *, hash_ptr_ops> &tightly_attached_bels,
|
||||||
std::unordered_set<CellInfo *> *placed_cells);
|
pool<CellInfo *, hash_ptr_ops> *placed_cells);
|
||||||
void pack_ports();
|
void pack_ports();
|
||||||
void decode_lut_cells();
|
void decode_lut_cells();
|
||||||
|
|
||||||
@ -858,7 +858,7 @@ struct Arch : ArchAPI<ArchRanges>
|
|||||||
|
|
||||||
IdString get_bel_tiletype(BelId bel) const { return IdString(loc_info(chip_info, bel).name); }
|
IdString get_bel_tiletype(BelId bel) const { return IdString(loc_info(chip_info, bel).name); }
|
||||||
|
|
||||||
std::unordered_map<WireId, Loc> sink_locs, source_locs;
|
dict<WireId, Loc> sink_locs, source_locs;
|
||||||
// -------------------------------------------------
|
// -------------------------------------------------
|
||||||
void assignArchInfo() final {}
|
void assignArchInfo() final {}
|
||||||
|
|
||||||
@ -875,8 +875,8 @@ struct Arch : ArchAPI<ArchRanges>
|
|||||||
void write_physical_netlist(const std::string &filename) const;
|
void write_physical_netlist(const std::string &filename) const;
|
||||||
void parse_xdc(const std::string &filename);
|
void parse_xdc(const std::string &filename);
|
||||||
|
|
||||||
std::unordered_set<IdString> io_port_types;
|
pool<IdString> io_port_types;
|
||||||
std::unordered_set<BelId> pads;
|
pool<BelId> pads;
|
||||||
|
|
||||||
bool is_site_port(PipId pip) const
|
bool is_site_port(PipId pip) const
|
||||||
{
|
{
|
||||||
@ -1083,7 +1083,7 @@ struct Arch : ArchAPI<ArchRanges>
|
|||||||
IdString gnd_cell_pin;
|
IdString gnd_cell_pin;
|
||||||
IdString vcc_cell_pin;
|
IdString vcc_cell_pin;
|
||||||
std::vector<std::vector<LutElement>> lut_elements;
|
std::vector<std::vector<LutElement>> lut_elements;
|
||||||
std::unordered_map<IdString, const LutCellPOD *> lut_cells;
|
dict<IdString, const LutCellPOD *> lut_cells;
|
||||||
|
|
||||||
// Of the LUT cells, which is used for wires?
|
// Of the LUT cells, which is used for wires?
|
||||||
// Note: May be null in arch's without wire LUT types. Assumption is
|
// Note: May be null in arch's without wire LUT types. Assumption is
|
||||||
|
@ -24,8 +24,8 @@
|
|||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
void Arch::place_iobufs(WireId pad_wire, NetInfo *net, const std::unordered_set<CellInfo *> &tightly_attached_bels,
|
void Arch::place_iobufs(WireId pad_wire, NetInfo *net, const pool<CellInfo *, hash_ptr_ops> &tightly_attached_bels,
|
||||||
std::unordered_set<CellInfo *> *placed_cells)
|
pool<CellInfo *, hash_ptr_ops> *placed_cells)
|
||||||
{
|
{
|
||||||
for (BelPin bel_pin : getWireBelPins(pad_wire)) {
|
for (BelPin bel_pin : getWireBelPins(pad_wire)) {
|
||||||
BelId bel = bel_pin.bel;
|
BelId bel = bel_pin.bel;
|
||||||
@ -57,7 +57,7 @@ void Arch::place_iobufs(WireId pad_wire, NetInfo *net, const std::unordered_set<
|
|||||||
|
|
||||||
void Arch::pack_ports()
|
void Arch::pack_ports()
|
||||||
{
|
{
|
||||||
std::unordered_map<IdString, const TileInstInfoPOD *> tile_type_prototypes;
|
dict<IdString, const TileInstInfoPOD *> tile_type_prototypes;
|
||||||
for (size_t i = 0; i < chip_info->tiles.size(); ++i) {
|
for (size_t i = 0; i < chip_info->tiles.size(); ++i) {
|
||||||
const auto &tile = chip_info->tiles[i];
|
const auto &tile = chip_info->tiles[i];
|
||||||
const auto &tile_type = chip_info->tile_types[tile.type];
|
const auto &tile_type = chip_info->tile_types[tile.type];
|
||||||
@ -66,9 +66,9 @@ void Arch::pack_ports()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// set(site_types) for package pins
|
// set(site_types) for package pins
|
||||||
std::unordered_set<IdString> package_sites;
|
pool<IdString> package_sites;
|
||||||
// Package pin -> (Site type -> BelId)
|
// Package pin -> (Site type -> BelId)
|
||||||
std::unordered_map<IdString, std::vector<std::pair<IdString, BelId>>> package_pin_bels;
|
dict<IdString, std::vector<std::pair<IdString, BelId>>> package_pin_bels;
|
||||||
for (const PackagePinPOD &package_pin : chip_info->packages[package_index].pins) {
|
for (const PackagePinPOD &package_pin : chip_info->packages[package_index].pins) {
|
||||||
IdString pin(package_pin.package_pin);
|
IdString pin(package_pin.package_pin);
|
||||||
IdString bel(package_pin.bel);
|
IdString bel(package_pin.bel);
|
||||||
@ -78,7 +78,7 @@ void Arch::pack_ports()
|
|||||||
|
|
||||||
for (size_t i = 0; i < chip_info->tiles.size(); ++i) {
|
for (size_t i = 0; i < chip_info->tiles.size(); ++i) {
|
||||||
const auto &tile = chip_info->tiles[i];
|
const auto &tile = chip_info->tiles[i];
|
||||||
std::unordered_set<uint32_t> package_pin_sites;
|
pool<uint32_t> package_pin_sites;
|
||||||
for (size_t j = 0; j < tile.sites.size(); ++j) {
|
for (size_t j = 0; j < tile.sites.size(); ++j) {
|
||||||
auto &site_data = chip_info->sites[tile.sites[j]];
|
auto &site_data = chip_info->sites[tile.sites[j]];
|
||||||
if (site == id(site_data.site_name.get())) {
|
if (site == id(site_data.site_name.get())) {
|
||||||
@ -102,8 +102,8 @@ void Arch::pack_ports()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Determine for each package site type, which site types are possible.
|
// Determine for each package site type, which site types are possible.
|
||||||
std::unordered_set<IdString> package_pin_site_types;
|
pool<IdString> package_pin_site_types;
|
||||||
std::unordered_map<IdString, std::unordered_set<IdString>> possible_package_site_types;
|
dict<IdString, pool<IdString>> possible_package_site_types;
|
||||||
for (const TileInstInfoPOD &tile : chip_info->tiles) {
|
for (const TileInstInfoPOD &tile : chip_info->tiles) {
|
||||||
for (size_t site_index : tile.sites) {
|
for (size_t site_index : tile.sites) {
|
||||||
const SiteInstInfoPOD &site = chip_info->sites[site_index];
|
const SiteInstInfoPOD &site = chip_info->sites[site_index];
|
||||||
@ -121,7 +121,7 @@ void Arch::pack_ports()
|
|||||||
for (auto port_pair : port_cells) {
|
for (auto port_pair : port_cells) {
|
||||||
IdString port_name = port_pair.first;
|
IdString port_name = port_pair.first;
|
||||||
CellInfo *port_cell = port_pair.second;
|
CellInfo *port_cell = port_pair.second;
|
||||||
std::unordered_set<CellInfo *> tightly_attached_bels;
|
pool<CellInfo *, hash_ptr_ops> tightly_attached_bels;
|
||||||
|
|
||||||
for (auto port_pair : port_cell->ports) {
|
for (auto port_pair : port_cell->ports) {
|
||||||
const PortInfo &port_info = port_pair.second;
|
const PortInfo &port_info = port_pair.second;
|
||||||
@ -145,7 +145,7 @@ void Arch::pack_ports()
|
|||||||
}
|
}
|
||||||
|
|
||||||
NPNR_ASSERT(tightly_attached_bels.erase(port_cell) == 1);
|
NPNR_ASSERT(tightly_attached_bels.erase(port_cell) == 1);
|
||||||
std::unordered_set<IdString> cell_types_in_io_group;
|
pool<IdString> cell_types_in_io_group;
|
||||||
for (CellInfo *cell : tightly_attached_bels) {
|
for (CellInfo *cell : tightly_attached_bels) {
|
||||||
NPNR_ASSERT(port_cells.find(cell->name) == port_cells.end());
|
NPNR_ASSERT(port_cells.find(cell->name) == port_cells.end());
|
||||||
cell_types_in_io_group.emplace(cell->type);
|
cell_types_in_io_group.emplace(cell->type);
|
||||||
@ -153,7 +153,7 @@ void Arch::pack_ports()
|
|||||||
|
|
||||||
// Get possible placement locations for tightly coupled BELs with
|
// Get possible placement locations for tightly coupled BELs with
|
||||||
// port.
|
// port.
|
||||||
std::unordered_set<IdString> possible_site_types;
|
pool<IdString> possible_site_types;
|
||||||
for (const TileTypeInfoPOD &tile_type : chip_info->tile_types) {
|
for (const TileTypeInfoPOD &tile_type : chip_info->tile_types) {
|
||||||
IdString tile_type_name(tile_type.name);
|
IdString tile_type_name(tile_type.name);
|
||||||
for (const BelInfoPOD &bel_info : tile_type.bel_data) {
|
for (const BelInfoPOD &bel_info : tile_type.bel_data) {
|
||||||
@ -195,7 +195,7 @@ void Arch::pack_ports()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// std::unordered_map<IdString, std::unordered_map<IdString, BelId>> package_pin_bels;
|
// dict<IdString, dict<IdString, BelId>> package_pin_bels;
|
||||||
IdString package_pin_id = id(iter->second.as_string());
|
IdString package_pin_id = id(iter->second.as_string());
|
||||||
auto pin_iter = package_pin_bels.find(package_pin_id);
|
auto pin_iter = package_pin_bels.find(package_pin_id);
|
||||||
if (pin_iter == package_pin_bels.end()) {
|
if (pin_iter == package_pin_bels.end()) {
|
||||||
@ -233,7 +233,7 @@ void Arch::pack_ports()
|
|||||||
log_info("Binding port %s to BEL %s\n", port_name.c_str(getCtx()), getCtx()->nameOfBel(package_bel));
|
log_info("Binding port %s to BEL %s\n", port_name.c_str(getCtx()), getCtx()->nameOfBel(package_bel));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_set<CellInfo *> placed_cells;
|
pool<CellInfo *, hash_ptr_ops> placed_cells;
|
||||||
bindBel(package_bel, port_cell, STRENGTH_FIXED);
|
bindBel(package_bel, port_cell, STRENGTH_FIXED);
|
||||||
placed_cells.emplace(port_cell);
|
placed_cells.emplace(port_cell);
|
||||||
|
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
#include <boost/functional/hash.hpp>
|
#include <boost/functional/hash.hpp>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#include "hash_table.h"
|
|
||||||
#include "hashlib.h"
|
#include "hashlib.h"
|
||||||
#include "luts.h"
|
#include "luts.h"
|
||||||
#include "nextpnr_namespaces.h"
|
#include "nextpnr_namespaces.h"
|
||||||
@ -119,9 +118,9 @@ struct ArchNetInfo
|
|||||||
struct ArchCellInfo
|
struct ArchCellInfo
|
||||||
{
|
{
|
||||||
int32_t cell_mapping = -1;
|
int32_t cell_mapping = -1;
|
||||||
HashTables::HashMap<IdString, std::vector<IdString>> cell_bel_pins;
|
dict<IdString, std::vector<IdString>> cell_bel_pins;
|
||||||
HashTables::HashMap<IdString, std::vector<IdString>> masked_cell_bel_pins;
|
dict<IdString, std::vector<IdString>> masked_cell_bel_pins;
|
||||||
HashTables::HashSet<IdString> const_ports;
|
pool<IdString> const_ports;
|
||||||
LutCell lut_cell;
|
LutCell lut_cell;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
|
|
||||||
#include "chipdb.h"
|
#include "chipdb.h"
|
||||||
#include "dynamic_bitarray.h"
|
#include "dynamic_bitarray.h"
|
||||||
#include "hash_table.h"
|
|
||||||
#include "nextpnr_namespaces.h"
|
#include "nextpnr_namespaces.h"
|
||||||
#include "property.h"
|
#include "property.h"
|
||||||
|
|
||||||
@ -42,7 +41,7 @@ struct CellParameters
|
|||||||
bool compare_property(const Context *ctx, IdString cell_type, IdString parameter, const Property &property,
|
bool compare_property(const Context *ctx, IdString cell_type, IdString parameter, const Property &property,
|
||||||
IdString value_to_compare) const;
|
IdString value_to_compare) const;
|
||||||
|
|
||||||
HashTables::HashMap<std::pair<IdString, IdString>, const CellParameterPOD *, PairHash> parameters;
|
dict<std::pair<IdString, IdString>, const CellParameterPOD *> parameters;
|
||||||
|
|
||||||
std::regex verilog_binary_re;
|
std::regex verilog_binary_re;
|
||||||
std::regex verilog_hex_re;
|
std::regex verilog_hex_re;
|
||||||
|
@ -121,7 +121,7 @@ delay_t CostMap::get_delay(const Context *ctx, WireId src_wire, WireId dst_wire)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CostMap::set_cost_map(const Context *ctx, const TypeWirePair &wire_pair,
|
void CostMap::set_cost_map(const Context *ctx, const TypeWirePair &wire_pair,
|
||||||
const HashTables::HashMap<std::pair<int32_t, int32_t>, delay_t, PairHash> &delays)
|
const dict<std::pair<int32_t, int32_t>, delay_t> &delays)
|
||||||
{
|
{
|
||||||
CostMapEntry delay_matrix;
|
CostMapEntry delay_matrix;
|
||||||
|
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
#include <boost/multi_array.hpp>
|
#include <boost/multi_array.hpp>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
#include "hash_table.h"
|
|
||||||
#include "lookahead.capnp.h"
|
#include "lookahead.capnp.h"
|
||||||
#include "nextpnr_namespaces.h"
|
#include "nextpnr_namespaces.h"
|
||||||
#include "nextpnr_types.h"
|
#include "nextpnr_types.h"
|
||||||
@ -39,7 +38,7 @@ class CostMap
|
|||||||
public:
|
public:
|
||||||
delay_t get_delay(const Context *ctx, WireId src, WireId dst) const;
|
delay_t get_delay(const Context *ctx, WireId src, WireId dst) const;
|
||||||
void set_cost_map(const Context *ctx, const TypeWirePair &wire_pair,
|
void set_cost_map(const Context *ctx, const TypeWirePair &wire_pair,
|
||||||
const HashTables::HashMap<std::pair<int32_t, int32_t>, delay_t, PairHash> &delays);
|
const dict<std::pair<int32_t, int32_t>, delay_t> &delays);
|
||||||
|
|
||||||
void from_reader(lookahead_storage::CostMap::Reader reader);
|
void from_reader(lookahead_storage::CostMap::Reader reader);
|
||||||
void to_builder(lookahead_storage::CostMap::Builder builder) const;
|
void to_builder(lookahead_storage::CostMap::Builder builder) const;
|
||||||
@ -53,7 +52,7 @@ class CostMap
|
|||||||
};
|
};
|
||||||
|
|
||||||
std::mutex cost_map_mutex_;
|
std::mutex cost_map_mutex_;
|
||||||
HashTables::HashMap<TypeWirePair, CostMapEntry> cost_map_;
|
dict<TypeWirePair, CostMapEntry> cost_map_;
|
||||||
|
|
||||||
void fill_holes(const Context *ctx, const TypeWirePair &wire_pair, boost::multi_array<delay_t, 2> &matrix,
|
void fill_holes(const Context *ctx, const TypeWirePair &wire_pair, boost::multi_array<delay_t, 2> &matrix,
|
||||||
delay_t delay_penality);
|
delay_t delay_penality);
|
||||||
|
@ -496,7 +496,7 @@ void DedicatedInterconnect::find_dedicated_interconnect()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_set<TileTypeBelPin> seen_pins;
|
pool<TileTypeBelPin> seen_pins;
|
||||||
for (auto sink_pair : sinks) {
|
for (auto sink_pair : sinks) {
|
||||||
for (auto src : sink_pair.second) {
|
for (auto src : sink_pair.second) {
|
||||||
seen_pins.emplace(src.type_bel_pin);
|
seen_pins.emplace(src.type_bel_pin);
|
||||||
@ -558,7 +558,7 @@ void DedicatedInterconnect::expand_sink_bel(BelId sink_bel, IdString sink_pin, W
|
|||||||
nodes_to_expand.push_back(wire_node);
|
nodes_to_expand.push_back(wire_node);
|
||||||
|
|
||||||
Loc sink_loc = ctx->getBelLocation(sink_bel);
|
Loc sink_loc = ctx->getBelLocation(sink_bel);
|
||||||
std::unordered_set<DeltaTileTypeBelPin> srcs;
|
pool<DeltaTileTypeBelPin> srcs;
|
||||||
|
|
||||||
while (!nodes_to_expand.empty()) {
|
while (!nodes_to_expand.empty()) {
|
||||||
WireNode node_to_expand = nodes_to_expand.back();
|
WireNode node_to_expand = nodes_to_expand.back();
|
||||||
@ -701,7 +701,7 @@ void DedicatedInterconnect::expand_source_bel(BelId src_bel, IdString src_pin, W
|
|||||||
nodes_to_expand.push_back(wire_node);
|
nodes_to_expand.push_back(wire_node);
|
||||||
|
|
||||||
Loc src_loc = ctx->getBelLocation(src_bel);
|
Loc src_loc = ctx->getBelLocation(src_bel);
|
||||||
std::unordered_set<DeltaTileTypeBelPin> dsts;
|
pool<DeltaTileTypeBelPin> dsts;
|
||||||
|
|
||||||
while (!nodes_to_expand.empty()) {
|
while (!nodes_to_expand.empty()) {
|
||||||
WireNode node_to_expand = nodes_to_expand.back();
|
WireNode node_to_expand = nodes_to_expand.back();
|
||||||
|
@ -23,9 +23,9 @@
|
|||||||
|
|
||||||
#include <boost/functional/hash.hpp>
|
#include <boost/functional/hash.hpp>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
#include "archdefs.h"
|
#include "archdefs.h"
|
||||||
|
#include "hashlib.h"
|
||||||
#include "idstring.h"
|
#include "idstring.h"
|
||||||
#include "nextpnr_namespaces.h"
|
#include "nextpnr_namespaces.h"
|
||||||
|
|
||||||
@ -58,6 +58,7 @@ struct TileTypeBelPin
|
|||||||
{
|
{
|
||||||
return tile_type != other.tile_type || bel_index != other.bel_index || bel_pin != other.bel_pin;
|
return tile_type != other.tile_type || bel_index != other.bel_index || bel_pin != other.bel_pin;
|
||||||
}
|
}
|
||||||
|
unsigned int hash() const { return mkhash(mkhash(tile_type, bel_index), bel_pin.hash()); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DeltaTileTypeBelPin
|
struct DeltaTileTypeBelPin
|
||||||
@ -74,36 +75,9 @@ struct DeltaTileTypeBelPin
|
|||||||
{
|
{
|
||||||
return delta_x != other.delta_x || delta_y != other.delta_y || type_bel_pin != other.type_bel_pin;
|
return delta_x != other.delta_x || delta_y != other.delta_y || type_bel_pin != other.type_bel_pin;
|
||||||
}
|
}
|
||||||
|
unsigned int hash() const { return mkhash(mkhash(delta_x, delta_y), type_bel_pin.hash()); }
|
||||||
};
|
};
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
|
||||||
|
|
||||||
template <> struct std::hash<NEXTPNR_NAMESPACE_PREFIX TileTypeBelPin>
|
|
||||||
{
|
|
||||||
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX TileTypeBelPin &type_bel_pin) const noexcept
|
|
||||||
{
|
|
||||||
std::size_t seed = 0;
|
|
||||||
boost::hash_combine(seed, std::hash<int32_t>()(type_bel_pin.tile_type));
|
|
||||||
boost::hash_combine(seed, std::hash<int32_t>()(type_bel_pin.bel_index));
|
|
||||||
boost::hash_combine(seed, std::hash<NEXTPNR_NAMESPACE_PREFIX IdString>()(type_bel_pin.bel_pin));
|
|
||||||
return seed;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <> struct std::hash<NEXTPNR_NAMESPACE_PREFIX DeltaTileTypeBelPin>
|
|
||||||
{
|
|
||||||
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX DeltaTileTypeBelPin &delta_bel_pin) const noexcept
|
|
||||||
{
|
|
||||||
std::size_t seed = 0;
|
|
||||||
boost::hash_combine(seed, std::hash<int32_t>()(delta_bel_pin.delta_x));
|
|
||||||
boost::hash_combine(seed, std::hash<int32_t>()(delta_bel_pin.delta_y));
|
|
||||||
boost::hash_combine(seed, std::hash<NEXTPNR_NAMESPACE_PREFIX TileTypeBelPin>()(delta_bel_pin.type_bel_pin));
|
|
||||||
return seed;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
|
||||||
|
|
||||||
struct Context;
|
struct Context;
|
||||||
|
|
||||||
// This class models dedicated interconnect present in the given fabric.
|
// This class models dedicated interconnect present in the given fabric.
|
||||||
@ -123,8 +97,8 @@ struct DedicatedInterconnect
|
|||||||
{
|
{
|
||||||
const Context *ctx;
|
const Context *ctx;
|
||||||
|
|
||||||
std::unordered_map<TileTypeBelPin, std::unordered_set<DeltaTileTypeBelPin>> sinks;
|
dict<TileTypeBelPin, pool<DeltaTileTypeBelPin>> sinks;
|
||||||
std::unordered_map<TileTypeBelPin, std::unordered_set<DeltaTileTypeBelPin>> sources;
|
dict<TileTypeBelPin, pool<DeltaTileTypeBelPin>> sources;
|
||||||
|
|
||||||
void init(const Context *ctx);
|
void init(const Context *ctx);
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ static void write_message(::capnp::MallocMessageBuilder & message, const std::st
|
|||||||
|
|
||||||
struct StringEnumerator {
|
struct StringEnumerator {
|
||||||
std::vector<std::string> strings;
|
std::vector<std::string> strings;
|
||||||
std::unordered_map<std::string, size_t> string_to_index;
|
dict<std::string, size_t> string_to_index;
|
||||||
|
|
||||||
size_t get_index(const std::string &s) {
|
size_t get_index(const std::string &s) {
|
||||||
auto result = string_to_index.emplace(s, strings.size());
|
auto result = string_to_index.emplace(s, strings.size());
|
||||||
@ -59,7 +59,7 @@ struct StringEnumerator {
|
|||||||
static PhysicalNetlist::PhysNetlist::RouteBranch::Builder emit_branch(
|
static PhysicalNetlist::PhysNetlist::RouteBranch::Builder emit_branch(
|
||||||
const Context * ctx,
|
const Context * ctx,
|
||||||
StringEnumerator * strings,
|
StringEnumerator * strings,
|
||||||
const std::unordered_map<PipId, PlaceStrength> &pip_place_strength,
|
const dict<PipId, PlaceStrength> &pip_place_strength,
|
||||||
PipId pip,
|
PipId pip,
|
||||||
PhysicalNetlist::PhysNetlist::RouteBranch::Builder branch) {
|
PhysicalNetlist::PhysNetlist::RouteBranch::Builder branch) {
|
||||||
if(ctx->is_pip_synthetic(pip)) {
|
if(ctx->is_pip_synthetic(pip)) {
|
||||||
@ -264,10 +264,10 @@ static void init_bel_pin(
|
|||||||
static void emit_net(
|
static void emit_net(
|
||||||
const Context * ctx,
|
const Context * ctx,
|
||||||
StringEnumerator * strings,
|
StringEnumerator * strings,
|
||||||
const std::unordered_map<WireId, std::vector<PipId>> &pip_downhill,
|
const dict<WireId, std::vector<PipId>> &pip_downhill,
|
||||||
const std::unordered_map<WireId, std::vector<BelPin>> &sinks,
|
const dict<WireId, std::vector<BelPin>> &sinks,
|
||||||
std::unordered_set<PipId> *pips,
|
pool<PipId> *pips,
|
||||||
const std::unordered_map<PipId, PlaceStrength> &pip_place_strength,
|
const dict<PipId, PlaceStrength> &pip_place_strength,
|
||||||
WireId wire, PhysicalNetlist::PhysNetlist::RouteBranch::Builder branch) {
|
WireId wire, PhysicalNetlist::PhysNetlist::RouteBranch::Builder branch) {
|
||||||
size_t number_branches = 0;
|
size_t number_branches = 0;
|
||||||
|
|
||||||
@ -349,7 +349,7 @@ static PhysicalNetlist::PhysNetlist::RouteBranch::Builder init_local_source(
|
|||||||
StringEnumerator * strings,
|
StringEnumerator * strings,
|
||||||
PhysicalNetlist::PhysNetlist::RouteBranch::Builder source_branch,
|
PhysicalNetlist::PhysNetlist::RouteBranch::Builder source_branch,
|
||||||
PipId root,
|
PipId root,
|
||||||
const std::unordered_map<PipId, PlaceStrength> &pip_place_strength,
|
const dict<PipId, PlaceStrength> &pip_place_strength,
|
||||||
WireId *root_wire) {
|
WireId *root_wire) {
|
||||||
WireId source_wire = ctx->getPipSrcWire(root);
|
WireId source_wire = ctx->getPipSrcWire(root);
|
||||||
BelPin source_bel_pin = find_source(ctx, source_wire);
|
BelPin source_bel_pin = find_source(ctx, source_wire);
|
||||||
@ -365,7 +365,7 @@ static PhysicalNetlist::PhysNetlist::RouteBranch::Builder init_local_source(
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void find_non_synthetic_edges(const Context * ctx, WireId root_wire,
|
static void find_non_synthetic_edges(const Context * ctx, WireId root_wire,
|
||||||
const std::unordered_map<WireId, std::vector<PipId>> &pip_downhill,
|
const dict<WireId, std::vector<PipId>> &pip_downhill,
|
||||||
std::vector<PipId> *root_pips) {
|
std::vector<PipId> *root_pips) {
|
||||||
std::vector<WireId> wires_to_expand;
|
std::vector<WireId> wires_to_expand;
|
||||||
|
|
||||||
@ -403,7 +403,7 @@ void FpgaInterchange::write_physical_netlist(const Context * ctx, const std::str
|
|||||||
|
|
||||||
phys_netlist.setPart(ctx->get_part());
|
phys_netlist.setPart(ctx->get_part());
|
||||||
|
|
||||||
std::unordered_set<IdString> placed_cells;
|
pool<IdString> placed_cells;
|
||||||
for(const auto & cell_pair : ctx->cells) {
|
for(const auto & cell_pair : ctx->cells) {
|
||||||
const CellInfo & cell = *cell_pair.second;
|
const CellInfo & cell = *cell_pair.second;
|
||||||
if(cell.bel == BelId()) {
|
if(cell.bel == BelId()) {
|
||||||
@ -444,7 +444,7 @@ void FpgaInterchange::write_physical_netlist(const Context * ctx, const std::str
|
|||||||
|
|
||||||
std::vector<IdString> ports;
|
std::vector<IdString> ports;
|
||||||
|
|
||||||
std::unordered_map<std::string, std::string> sites;
|
dict<std::string, std::string> sites;
|
||||||
auto placements = phys_netlist.initPlacements(number_placements);
|
auto placements = phys_netlist.initPlacements(number_placements);
|
||||||
auto placement_iter = placements.begin();
|
auto placement_iter = placements.begin();
|
||||||
|
|
||||||
@ -556,9 +556,9 @@ void FpgaInterchange::write_physical_netlist(const Context * ctx, const std::str
|
|||||||
net_out.setName(strings.get_index(net.name.str(ctx)));
|
net_out.setName(strings.get_index(net.name.str(ctx)));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_map<WireId, BelPin> root_wires;
|
dict<WireId, BelPin> root_wires;
|
||||||
std::unordered_map<WireId, std::vector<PipId>> pip_downhill;
|
dict<WireId, std::vector<PipId>> pip_downhill;
|
||||||
std::unordered_set<PipId> pips;
|
pool<PipId> pips;
|
||||||
|
|
||||||
if (driver_cell != nullptr && driver_cell->bel != BelId() && ctx->isBelLocationValid(driver_cell->bel)) {
|
if (driver_cell != nullptr && driver_cell->bel != BelId() && ctx->isBelLocationValid(driver_cell->bel)) {
|
||||||
for(IdString bel_pin_name : driver_cell->cell_bel_pins.at(net.driver.port)) {
|
for(IdString bel_pin_name : driver_cell->cell_bel_pins.at(net.driver.port)) {
|
||||||
@ -573,7 +573,7 @@ void FpgaInterchange::write_physical_netlist(const Context * ctx, const std::str
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_map<WireId, std::vector<BelPin>> sinks;
|
dict<WireId, std::vector<BelPin>> sinks;
|
||||||
for(const auto &port_ref : net.users) {
|
for(const auto &port_ref : net.users) {
|
||||||
if(port_ref.cell != nullptr && port_ref.cell->bel != BelId() && ctx->isBelLocationValid(port_ref.cell->bel)) {
|
if(port_ref.cell != nullptr && port_ref.cell->bel != BelId() && ctx->isBelLocationValid(port_ref.cell->bel)) {
|
||||||
auto pin_iter = port_ref.cell->cell_bel_pins.find(port_ref.port);
|
auto pin_iter = port_ref.cell->cell_bel_pins.find(port_ref.port);
|
||||||
@ -598,7 +598,7 @@ void FpgaInterchange::write_physical_netlist(const Context * ctx, const std::str
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_map<PipId, PlaceStrength> pip_place_strength;
|
dict<PipId, PlaceStrength> pip_place_strength;
|
||||||
|
|
||||||
for(auto &wire_pair : net.wires) {
|
for(auto &wire_pair : net.wires) {
|
||||||
WireId downhill_wire = wire_pair.first;
|
WireId downhill_wire = wire_pair.first;
|
||||||
@ -723,23 +723,11 @@ struct PortKey {
|
|||||||
bool operator == (const PortKey &other) const {
|
bool operator == (const PortKey &other) const {
|
||||||
return inst_idx == other.inst_idx && port_idx == other.port_idx;
|
return inst_idx == other.inst_idx && port_idx == other.port_idx;
|
||||||
}
|
}
|
||||||
};
|
unsigned int hash() const {
|
||||||
|
return mkhash(inst_idx, port_idx);
|
||||||
NEXTPNR_NAMESPACE_END
|
|
||||||
|
|
||||||
template <> struct std::hash<NEXTPNR_NAMESPACE_PREFIX PortKey>
|
|
||||||
{
|
|
||||||
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX PortKey &key) const noexcept
|
|
||||||
{
|
|
||||||
std::size_t seed = 0;
|
|
||||||
boost::hash_combine(seed, std::hash<int32_t>()(key.inst_idx));
|
|
||||||
boost::hash_combine(seed, std::hash<uint32_t>()(key.port_idx));
|
|
||||||
return seed;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
|
||||||
|
|
||||||
struct ModuleReader {
|
struct ModuleReader {
|
||||||
const LogicalNetlistImpl *root;
|
const LogicalNetlistImpl *root;
|
||||||
|
|
||||||
@ -748,9 +736,9 @@ struct ModuleReader {
|
|||||||
LogicalNetlist::Netlist::Cell::Reader cell;
|
LogicalNetlist::Netlist::Cell::Reader cell;
|
||||||
LogicalNetlist::Netlist::CellDeclaration::Reader cell_decl;
|
LogicalNetlist::Netlist::CellDeclaration::Reader cell_decl;
|
||||||
|
|
||||||
std::unordered_map<int32_t, LogicalNetlist::Netlist::Net::Reader> net_indicies;
|
dict<int32_t, LogicalNetlist::Netlist::Net::Reader> net_indicies;
|
||||||
std::unordered_map<int32_t, std::string> disconnected_nets;
|
dict<int32_t, std::string> disconnected_nets;
|
||||||
std::unordered_map<PortKey, std::vector<int32_t>> connections;
|
dict<PortKey, std::vector<int32_t>> connections;
|
||||||
|
|
||||||
ModuleReader(const LogicalNetlistImpl *root,
|
ModuleReader(const LogicalNetlistImpl *root,
|
||||||
LogicalNetlist::Netlist::CellInstance::Reader cell_inst, bool is_top);
|
LogicalNetlist::Netlist::CellInstance::Reader cell_inst, bool is_top);
|
||||||
@ -834,7 +822,6 @@ struct LogicalNetlistImpl
|
|||||||
|
|
||||||
template <typename TFunc> void foreach_netname(const ModuleReader &mod, TFunc Func) const
|
template <typename TFunc> void foreach_netname(const ModuleReader &mod, TFunc Func) const
|
||||||
{
|
{
|
||||||
// std::unordered_map<int32_t, LogicalNetlist::Netlist::Net::Reader> net_indicies;
|
|
||||||
for(auto net_pair : mod.net_indicies) {
|
for(auto net_pair : mod.net_indicies) {
|
||||||
NetReader net_reader(&mod, net_pair.first);
|
NetReader net_reader(&mod, net_pair.first);
|
||||||
auto net = net_pair.second;
|
auto net = net_pair.second;
|
||||||
@ -842,7 +829,6 @@ struct LogicalNetlistImpl
|
|||||||
Func(strings.at(net.getName()), net_reader);
|
Func(strings.at(net.getName()), net_reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
// std::unordered_map<int32_t, IdString> disconnected_nets;
|
|
||||||
for(auto net_pair : mod.disconnected_nets) {
|
for(auto net_pair : mod.disconnected_nets) {
|
||||||
NetReader net_reader(&mod, net_pair.first);
|
NetReader net_reader(&mod, net_pair.first);
|
||||||
Func(net_pair.second, net_reader);
|
Func(net_pair.second, net_reader);
|
||||||
|
@ -67,7 +67,7 @@ static int route_global_arc(Context *ctx, NetInfo *net, size_t usr_idx, size_t p
|
|||||||
WireId startpoint;
|
WireId startpoint;
|
||||||
GlobalVist best_visit;
|
GlobalVist best_visit;
|
||||||
std::queue<WireId> visit_queue;
|
std::queue<WireId> visit_queue;
|
||||||
std::unordered_map<WireId, GlobalVist> visits;
|
dict<WireId, GlobalVist> visits;
|
||||||
|
|
||||||
visit_queue.push(dest);
|
visit_queue.push(dest);
|
||||||
visits[dest].downhill = PipId();
|
visits[dest].downhill = PipId();
|
||||||
|
@ -64,9 +64,9 @@ struct PipAndCost
|
|||||||
int32_t depth;
|
int32_t depth;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void expand_input(const Context *ctx, WireId input_wire, HashTables::HashMap<TypeWireId, delay_t> *input_costs)
|
static void expand_input(const Context *ctx, WireId input_wire, dict<TypeWireId, delay_t> *input_costs)
|
||||||
{
|
{
|
||||||
HashTables::HashSet<WireId> seen;
|
pool<WireId> seen;
|
||||||
std::priority_queue<RoutingNode> to_expand;
|
std::priority_queue<RoutingNode> to_expand;
|
||||||
|
|
||||||
RoutingNode initial;
|
RoutingNode initial;
|
||||||
@ -120,9 +120,8 @@ static void expand_input(const Context *ctx, WireId input_wire, HashTables::Hash
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void update_site_to_site_costs(const Context *ctx, WireId first_wire,
|
static void update_site_to_site_costs(const Context *ctx, WireId first_wire, const dict<WireId, PipAndCost> &best_path,
|
||||||
const HashTables::HashMap<WireId, PipAndCost> &best_path,
|
dict<TypeWirePair, delay_t> *site_to_site_cost)
|
||||||
HashTables::HashMap<TypeWirePair, delay_t> *site_to_site_cost)
|
|
||||||
{
|
{
|
||||||
for (auto &best_pair : best_path) {
|
for (auto &best_pair : best_path) {
|
||||||
WireId last_wire = best_pair.first;
|
WireId last_wire = best_pair.first;
|
||||||
@ -161,9 +160,9 @@ static void update_site_to_site_costs(const Context *ctx, WireId first_wire,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void expand_output(const Context *ctx, WireId output_wire, Lookahead::OutputSiteWireCost *output_cost,
|
static void expand_output(const Context *ctx, WireId output_wire, Lookahead::OutputSiteWireCost *output_cost,
|
||||||
HashTables::HashMap<TypeWirePair, delay_t> *site_to_site_cost)
|
dict<TypeWirePair, delay_t> *site_to_site_cost)
|
||||||
{
|
{
|
||||||
HashTables::HashSet<WireId> seen;
|
pool<WireId> seen;
|
||||||
std::priority_queue<RoutingNode> to_expand;
|
std::priority_queue<RoutingNode> to_expand;
|
||||||
|
|
||||||
RoutingNode initial;
|
RoutingNode initial;
|
||||||
@ -172,7 +171,7 @@ static void expand_output(const Context *ctx, WireId output_wire, Lookahead::Out
|
|||||||
|
|
||||||
to_expand.push(initial);
|
to_expand.push(initial);
|
||||||
|
|
||||||
HashTables::HashMap<WireId, PipAndCost> best_path;
|
dict<WireId, PipAndCost> best_path;
|
||||||
|
|
||||||
while (!to_expand.empty()) {
|
while (!to_expand.empty()) {
|
||||||
RoutingNode node = to_expand.top();
|
RoutingNode node = to_expand.top();
|
||||||
@ -228,7 +227,7 @@ static void expand_output(const Context *ctx, WireId output_wire, Lookahead::Out
|
|||||||
static void expand_input_type(const Context *ctx, DeterministicRNG *rng, const Sampler &tiles_of_type,
|
static void expand_input_type(const Context *ctx, DeterministicRNG *rng, const Sampler &tiles_of_type,
|
||||||
TypeWireId input_wire, std::vector<Lookahead::InputSiteWireCost> *input_costs)
|
TypeWireId input_wire, std::vector<Lookahead::InputSiteWireCost> *input_costs)
|
||||||
{
|
{
|
||||||
HashTables::HashMap<TypeWireId, delay_t> input_costs_map;
|
dict<TypeWireId, delay_t> input_costs_map;
|
||||||
for (size_t region = 0; region < tiles_of_type.number_of_regions(); ++region) {
|
for (size_t region = 0; region < tiles_of_type.number_of_regions(); ++region) {
|
||||||
size_t tile = tiles_of_type.get_sample_from_region(region, [rng]() -> int32_t { return rng->rng(); });
|
size_t tile = tiles_of_type.get_sample_from_region(region, [rng]() -> int32_t { return rng->rng(); });
|
||||||
|
|
||||||
@ -250,7 +249,7 @@ static void expand_input_type(const Context *ctx, DeterministicRNG *rng, const S
|
|||||||
|
|
||||||
struct DelayStorage
|
struct DelayStorage
|
||||||
{
|
{
|
||||||
HashTables::HashMap<TypeWirePair, HashTables::HashMap<std::pair<int32_t, int32_t>, delay_t, PairHash>> storage;
|
dict<TypeWirePair, dict<std::pair<int32_t, int32_t>, delay_t>> storage;
|
||||||
int32_t max_explore_depth;
|
int32_t max_explore_depth;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -290,7 +289,7 @@ static void update_results(const Context *ctx, const FlatWireMap<PipAndCost> &be
|
|||||||
// Starting from end of result, walk backwards and record the path into
|
// Starting from end of result, walk backwards and record the path into
|
||||||
// the delay storage.
|
// the delay storage.
|
||||||
WireId cursor = sink_wire;
|
WireId cursor = sink_wire;
|
||||||
HashTables::HashSet<WireId> seen;
|
pool<WireId> seen;
|
||||||
while (cursor != src_wire) {
|
while (cursor != src_wire) {
|
||||||
// No loops allowed in routing!
|
// No loops allowed in routing!
|
||||||
auto result = seen.emplace(cursor);
|
auto result = seen.emplace(cursor);
|
||||||
@ -335,7 +334,7 @@ static void update_results(const Context *ctx, const FlatWireMap<PipAndCost> &be
|
|||||||
static void expand_routing_graph_from_wire(const Context *ctx, WireId first_wire, FlatWireMap<PipAndCost> *best_path,
|
static void expand_routing_graph_from_wire(const Context *ctx, WireId first_wire, FlatWireMap<PipAndCost> *best_path,
|
||||||
DelayStorage *storage)
|
DelayStorage *storage)
|
||||||
{
|
{
|
||||||
HashTables::HashSet<WireId> seen;
|
pool<WireId> seen;
|
||||||
std::priority_queue<RoutingNode> to_expand;
|
std::priority_queue<RoutingNode> to_expand;
|
||||||
|
|
||||||
int src_tile;
|
int src_tile;
|
||||||
@ -436,11 +435,10 @@ static bool has_multiple_outputs(const Context *ctx, WireId wire)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void expand_routing_graph(const Context *ctx, DeterministicRNG *rng, const Sampler &tiles_of_type,
|
static void expand_routing_graph(const Context *ctx, DeterministicRNG *rng, const Sampler &tiles_of_type,
|
||||||
TypeWireId wire_type, HashTables::HashSet<TypeWireSet> *types_explored,
|
TypeWireId wire_type, pool<TypeWireSet> *types_explored, DelayStorage *storage,
|
||||||
DelayStorage *storage, HashTables::HashSet<TypeWireId> *types_deferred,
|
pool<TypeWireId> *types_deferred, FlatWireMap<PipAndCost> *best_path)
|
||||||
FlatWireMap<PipAndCost> *best_path)
|
|
||||||
{
|
{
|
||||||
HashTables::HashSet<TypeWireSet> new_types_explored;
|
pool<TypeWireSet> new_types_explored;
|
||||||
|
|
||||||
for (size_t region = 0; region < tiles_of_type.number_of_regions(); ++region) {
|
for (size_t region = 0; region < tiles_of_type.number_of_regions(); ++region) {
|
||||||
size_t tile = tiles_of_type.get_sample_from_region(region, [rng]() -> int32_t { return rng->rng(); });
|
size_t tile = tiles_of_type.get_sample_from_region(region, [rng]() -> int32_t { return rng->rng(); });
|
||||||
@ -562,10 +560,10 @@ static WireId follow_pip_chain_up(const Context *ctx, WireId wire, delay_t *dela
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void expand_deferred_routing_graph(const Context *ctx, DeterministicRNG *rng, const Sampler &tiles_of_type,
|
static void expand_deferred_routing_graph(const Context *ctx, DeterministicRNG *rng, const Sampler &tiles_of_type,
|
||||||
TypeWireId wire_type, HashTables::HashSet<TypeWireSet> *types_explored,
|
TypeWireId wire_type, pool<TypeWireSet> *types_explored,
|
||||||
DelayStorage *storage, FlatWireMap<PipAndCost> *best_path)
|
DelayStorage *storage, FlatWireMap<PipAndCost> *best_path)
|
||||||
{
|
{
|
||||||
HashTables::HashSet<TypeWireSet> new_types_explored;
|
pool<TypeWireSet> new_types_explored;
|
||||||
|
|
||||||
for (size_t region = 0; region < tiles_of_type.number_of_regions(); ++region) {
|
for (size_t region = 0; region < tiles_of_type.number_of_regions(); ++region) {
|
||||||
size_t tile = tiles_of_type.get_sample_from_region(region, [rng]() -> int32_t { return rng->rng(); });
|
size_t tile = tiles_of_type.get_sample_from_region(region, [rng]() -> int32_t { return rng->rng(); });
|
||||||
@ -603,7 +601,7 @@ static void expand_deferred_routing_graph(const Context *ctx, DeterministicRNG *
|
|||||||
|
|
||||||
static void expand_output_type(const Context *ctx, DeterministicRNG *rng, const Sampler &tiles_of_type,
|
static void expand_output_type(const Context *ctx, DeterministicRNG *rng, const Sampler &tiles_of_type,
|
||||||
TypeWireId output_wire, Lookahead::OutputSiteWireCost *output_cost,
|
TypeWireId output_wire, Lookahead::OutputSiteWireCost *output_cost,
|
||||||
HashTables::HashMap<TypeWirePair, delay_t> *site_to_site_cost)
|
dict<TypeWirePair, delay_t> *site_to_site_cost)
|
||||||
{
|
{
|
||||||
for (size_t region = 0; region < tiles_of_type.number_of_regions(); ++region) {
|
for (size_t region = 0; region < tiles_of_type.number_of_regions(); ++region) {
|
||||||
size_t tile = tiles_of_type.get_sample_from_region(region, [rng]() -> int32_t { return rng->rng(); });
|
size_t tile = tiles_of_type.get_sample_from_region(region, [rng]() -> int32_t { return rng->rng(); });
|
||||||
@ -651,8 +649,8 @@ struct ExpandLocals
|
|||||||
DeterministicRNG *rng;
|
DeterministicRNG *rng;
|
||||||
FlatWireMap<PipAndCost> *best_path;
|
FlatWireMap<PipAndCost> *best_path;
|
||||||
DelayStorage *storage;
|
DelayStorage *storage;
|
||||||
HashTables::HashSet<TypeWireSet> *explored;
|
pool<TypeWireSet> *explored;
|
||||||
HashTables::HashSet<TypeWireId> *deferred;
|
pool<TypeWireId> *deferred;
|
||||||
|
|
||||||
virtual void lock() {}
|
virtual void lock() {}
|
||||||
virtual void unlock() {}
|
virtual void unlock() {}
|
||||||
@ -698,8 +696,7 @@ static void expand_tile_type(const Context *ctx, int32_t tile_type, ExpandLocals
|
|||||||
static void expand_tile_type_serial(const Context *ctx, const std::vector<int32_t> &tile_types,
|
static void expand_tile_type_serial(const Context *ctx, const std::vector<int32_t> &tile_types,
|
||||||
const std::vector<Sampler> &tiles_of_type, DeterministicRNG *rng,
|
const std::vector<Sampler> &tiles_of_type, DeterministicRNG *rng,
|
||||||
FlatWireMap<PipAndCost> *best_path, DelayStorage *storage,
|
FlatWireMap<PipAndCost> *best_path, DelayStorage *storage,
|
||||||
HashTables::HashSet<TypeWireSet> *explored,
|
pool<TypeWireSet> *explored, pool<TypeWireId> *deferred, pool<int32_t> *tiles_left)
|
||||||
HashTables::HashSet<TypeWireId> *deferred, HashTables::HashSet<int32_t> *tiles_left)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
for (int32_t tile_type : tile_types) {
|
for (int32_t tile_type : tile_types) {
|
||||||
@ -725,9 +722,9 @@ struct TbbExpandLocals : public ExpandLocals
|
|||||||
std::mutex *all_costs_mutex;
|
std::mutex *all_costs_mutex;
|
||||||
|
|
||||||
DelayStorage *all_tiles_storage;
|
DelayStorage *all_tiles_storage;
|
||||||
HashTables::HashSet<TypeWireSet> *types_explored;
|
pool<TypeWireSet> *types_explored;
|
||||||
HashTables::HashSet<TypeWireId> *types_deferred;
|
pool<TypeWireId> *types_deferred;
|
||||||
HashTables::HashSet<int32_t> *tiles_left;
|
pool<int32_t> *tiles_left;
|
||||||
|
|
||||||
void lock() override { all_costs_mutex->lock(); }
|
void lock() override { all_costs_mutex->lock(); }
|
||||||
|
|
||||||
@ -785,16 +782,15 @@ struct TbbExpandLocals : public ExpandLocals
|
|||||||
// the data is joined with the global data.
|
// the data is joined with the global data.
|
||||||
static void expand_tile_type_parallel(const Context *ctx, int32_t tile_type, const std::vector<Sampler> &tiles_of_type,
|
static void expand_tile_type_parallel(const Context *ctx, int32_t tile_type, const std::vector<Sampler> &tiles_of_type,
|
||||||
DeterministicRNG *rng, std::mutex *all_costs_mutex,
|
DeterministicRNG *rng, std::mutex *all_costs_mutex,
|
||||||
DelayStorage *all_tiles_storage, HashTables::HashSet<TypeWireSet> *types_explored,
|
DelayStorage *all_tiles_storage, pool<TypeWireSet> *types_explored,
|
||||||
HashTables::HashSet<TypeWireId> *types_deferred,
|
pool<TypeWireId> *types_deferred, pool<int32_t> *tiles_left)
|
||||||
HashTables::HashSet<int32_t> *tiles_left)
|
|
||||||
{
|
{
|
||||||
TbbExpandLocals locals;
|
TbbExpandLocals locals;
|
||||||
|
|
||||||
DeterministicRNG rng_copy = *rng;
|
DeterministicRNG rng_copy = *rng;
|
||||||
FlatWireMap<PipAndCost> best_path(ctx);
|
FlatWireMap<PipAndCost> best_path(ctx);
|
||||||
HashTables::HashSet<TypeWireSet> explored;
|
pool<TypeWireSet> explored;
|
||||||
HashTables::HashSet<TypeWireId> deferred;
|
pool<TypeWireId> deferred;
|
||||||
DelayStorage storage;
|
DelayStorage storage;
|
||||||
storage.max_explore_depth = all_tiles_storage->max_explore_depth;
|
storage.max_explore_depth = all_tiles_storage->max_explore_depth;
|
||||||
|
|
||||||
@ -823,7 +819,7 @@ void Lookahead::build_lookahead(const Context *ctx, DeterministicRNG *rng)
|
|||||||
log_info("Building lookahead, first gathering input and output site wires\n");
|
log_info("Building lookahead, first gathering input and output site wires\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
HashTables::HashSet<TypeWireId> input_site_ports;
|
pool<TypeWireId> input_site_ports;
|
||||||
for (BelId bel : ctx->getBels()) {
|
for (BelId bel : ctx->getBels()) {
|
||||||
const auto &bel_data = bel_info(ctx->chip_info, bel);
|
const auto &bel_data = bel_info(ctx->chip_info, bel);
|
||||||
|
|
||||||
@ -917,15 +913,15 @@ void Lookahead::build_lookahead(const Context *ctx, DeterministicRNG *rng)
|
|||||||
all_tiles_storage.max_explore_depth = kInitialExploreDepth;
|
all_tiles_storage.max_explore_depth = kInitialExploreDepth;
|
||||||
|
|
||||||
// These are wire types that have been explored.
|
// These are wire types that have been explored.
|
||||||
HashTables::HashSet<TypeWireSet> types_explored;
|
pool<TypeWireSet> types_explored;
|
||||||
|
|
||||||
// These are wire types that have been deferred because they are trival
|
// These are wire types that have been deferred because they are trival
|
||||||
// copies of another wire type. These can be cheaply computed after the
|
// copies of another wire type. These can be cheaply computed after the
|
||||||
// graph has been explored.
|
// graph has been explored.
|
||||||
HashTables::HashSet<TypeWireId> types_deferred;
|
pool<TypeWireId> types_deferred;
|
||||||
|
|
||||||
std::vector<int32_t> tile_types;
|
std::vector<int32_t> tile_types;
|
||||||
HashTables::HashSet<int32_t> tiles_left;
|
pool<int32_t> tiles_left;
|
||||||
tile_types.reserve(ctx->chip_info->tile_types.size());
|
tile_types.reserve(ctx->chip_info->tile_types.size());
|
||||||
for (int32_t tile_type = 0; tile_type < ctx->chip_info->tile_types.ssize(); ++tile_type) {
|
for (int32_t tile_type = 0; tile_type < ctx->chip_info->tile_types.ssize(); ++tile_type) {
|
||||||
tile_types.push_back(tile_type);
|
tile_types.push_back(tile_type);
|
||||||
@ -994,10 +990,8 @@ void Lookahead::build_lookahead(const Context *ctx, DeterministicRNG *rng)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined(NEXTPNR_USE_TBB) // Run parallely
|
#if defined(NEXTPNR_USE_TBB) // Run parallely
|
||||||
tbb::parallel_for_each(
|
tbb::parallel_for_each(all_tiles_storage.storage,
|
||||||
all_tiles_storage.storage,
|
[&](const std::pair<TypeWirePair, dict<std::pair<int32_t, int32_t>, delay_t>> &type_pair) {
|
||||||
[&](const std::pair<TypeWirePair, HashTables::HashMap<std::pair<int32_t, int32_t>, delay_t, PairHash>>
|
|
||||||
&type_pair) {
|
|
||||||
#else
|
#else
|
||||||
for (const auto &type_pair : all_tiles_storage.storage) {
|
for (const auto &type_pair : all_tiles_storage.storage) {
|
||||||
#endif
|
#endif
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
|
|
||||||
#include "cost_map.h"
|
#include "cost_map.h"
|
||||||
#include "deterministic_rng.h"
|
#include "deterministic_rng.h"
|
||||||
#include "hash_table.h"
|
|
||||||
#include "lookahead.capnp.h"
|
#include "lookahead.capnp.h"
|
||||||
#include "nextpnr_namespaces.h"
|
#include "nextpnr_namespaces.h"
|
||||||
#include "type_wire.h"
|
#include "type_wire.h"
|
||||||
@ -88,9 +87,9 @@ struct Lookahead
|
|||||||
delay_t cost;
|
delay_t cost;
|
||||||
};
|
};
|
||||||
|
|
||||||
HashTables::HashMap<TypeWireId, std::vector<InputSiteWireCost>> input_site_wires;
|
dict<TypeWireId, std::vector<InputSiteWireCost>> input_site_wires;
|
||||||
HashTables::HashMap<TypeWireId, OutputSiteWireCost> output_site_wires;
|
dict<TypeWireId, OutputSiteWireCost> output_site_wires;
|
||||||
HashTables::HashMap<TypeWirePair, delay_t> site_to_site_cost;
|
dict<TypeWirePair, delay_t> site_to_site_cost;
|
||||||
CostMap cost_map;
|
CostMap cost_map;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -166,13 +166,13 @@ uint32_t LutMapper::check_wires(const Context *ctx) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HashTables::HashSet<const LutBel *> blocked_luts;
|
pool<const LutBel *, hash_ptr_ops> blocked_luts;
|
||||||
return check_wires(bel_to_cell_pin_remaps, lut_bels, used_pins, &blocked_luts);
|
return check_wires(bel_to_cell_pin_remaps, lut_bels, used_pins, &blocked_luts);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t LutMapper::check_wires(const std::vector<std::vector<int32_t>> &bel_to_cell_pin_remaps,
|
uint32_t LutMapper::check_wires(const std::vector<std::vector<int32_t>> &bel_to_cell_pin_remaps,
|
||||||
const std::vector<const LutBel *> &lut_bels, uint32_t used_pins,
|
const std::vector<const LutBel *> &lut_bels, uint32_t used_pins,
|
||||||
HashTables::HashSet<const LutBel *> *blocked_luts) const
|
pool<const LutBel *, hash_ptr_ops> *blocked_luts) const
|
||||||
{
|
{
|
||||||
std::vector<const LutBel *> unused_luts;
|
std::vector<const LutBel *> unused_luts;
|
||||||
for (auto &lut_bel_pair : element.lut_bels) {
|
for (auto &lut_bel_pair : element.lut_bels) {
|
||||||
@ -253,9 +253,9 @@ uint32_t LutMapper::check_wires(const std::vector<std::vector<int32_t>> &bel_to_
|
|||||||
return vcc_mask;
|
return vcc_mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LutMapper::remap_luts(const Context *ctx, HashTables::HashSet<const LutBel *> *blocked_luts)
|
bool LutMapper::remap_luts(const Context *ctx, pool<const LutBel *, hash_ptr_ops> *blocked_luts)
|
||||||
{
|
{
|
||||||
std::unordered_map<NetInfo *, LutPin> lut_pin_map;
|
dict<NetInfo *, LutPin, hash_ptr_ops> lut_pin_map;
|
||||||
std::vector<const LutBel *> lut_bels;
|
std::vector<const LutBel *> lut_bels;
|
||||||
lut_bels.resize(cells.size());
|
lut_bels.resize(cells.size());
|
||||||
|
|
||||||
@ -366,7 +366,7 @@ bool LutMapper::remap_luts(const Context *ctx, HashTables::HashSet<const LutBel
|
|||||||
CellInfo *cell = cells[cell_idx];
|
CellInfo *cell = cells[cell_idx];
|
||||||
auto &lut_bel = *lut_bels[cell_idx];
|
auto &lut_bel = *lut_bels[cell_idx];
|
||||||
|
|
||||||
std::unordered_map<IdString, IdString> cell_to_bel_map;
|
dict<IdString, IdString> cell_to_bel_map;
|
||||||
for (size_t pin_idx = 0; pin_idx < cell->lut_cell.pins.size(); ++pin_idx) {
|
for (size_t pin_idx = 0; pin_idx < cell->lut_cell.pins.size(); ++pin_idx) {
|
||||||
size_t bel_pin_idx = cell_to_bel_pin_remaps[cell_idx][pin_idx];
|
size_t bel_pin_idx = cell_to_bel_pin_remaps[cell_idx][pin_idx];
|
||||||
NPNR_ASSERT(bel_pin_idx < lut_bel.pins.size());
|
NPNR_ASSERT(bel_pin_idx < lut_bel.pins.size());
|
||||||
@ -452,8 +452,8 @@ bool LutMapper::remap_luts(const Context *ctx, HashTables::HashSet<const LutBel
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_equation(const LutCell &lut_cell, const std::unordered_map<IdString, IdString> &cell_to_bel_map,
|
void check_equation(const LutCell &lut_cell, const dict<IdString, IdString> &cell_to_bel_map, const LutBel &lut_bel,
|
||||||
const LutBel &lut_bel, const std::vector<LogicLevel> &equation, uint32_t used_pins)
|
const std::vector<LogicLevel> &equation, uint32_t used_pins)
|
||||||
{
|
{
|
||||||
std::vector<int8_t> pin_map;
|
std::vector<int8_t> pin_map;
|
||||||
pin_map.resize(lut_bel.pins.size(), -1);
|
pin_map.resize(lut_bel.pins.size(), -1);
|
||||||
|
@ -20,14 +20,11 @@
|
|||||||
#ifndef LUTS_H
|
#ifndef LUTS_H
|
||||||
#define LUTS_H
|
#define LUTS_H
|
||||||
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <unordered_set>
|
|
||||||
|
|
||||||
#include "idstring.h"
|
#include "idstring.h"
|
||||||
#include "nextpnr_namespaces.h"
|
#include "nextpnr_namespaces.h"
|
||||||
|
|
||||||
#include "dynamic_bitarray.h"
|
#include "dynamic_bitarray.h"
|
||||||
#include "hash_table.h"
|
#include "hashlib.h"
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
@ -45,8 +42,8 @@ struct LutCell
|
|||||||
{
|
{
|
||||||
// LUT cell pins for equation, LSB first.
|
// LUT cell pins for equation, LSB first.
|
||||||
std::vector<IdString> pins;
|
std::vector<IdString> pins;
|
||||||
std::unordered_set<IdString> lut_pins;
|
pool<IdString> lut_pins;
|
||||||
std::unordered_set<IdString> vcc_pins;
|
pool<IdString> vcc_pins;
|
||||||
DynamicBitarray<> equation;
|
DynamicBitarray<> equation;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -56,7 +53,7 @@ struct LutBel
|
|||||||
|
|
||||||
// LUT BEL pins to LUT array index.
|
// LUT BEL pins to LUT array index.
|
||||||
std::vector<IdString> pins;
|
std::vector<IdString> pins;
|
||||||
std::unordered_map<IdString, size_t> pin_to_index;
|
dict<IdString, size_t> pin_to_index;
|
||||||
|
|
||||||
IdString output_pin;
|
IdString output_pin;
|
||||||
|
|
||||||
@ -71,18 +68,18 @@ struct LutBel
|
|||||||
|
|
||||||
// Work forward from cell definition and cell -> bel pin map and check that
|
// Work forward from cell definition and cell -> bel pin map and check that
|
||||||
// equation is valid.
|
// equation is valid.
|
||||||
void check_equation(const LutCell &lut_cell, const std::unordered_map<IdString, IdString> &cell_to_bel_map,
|
void check_equation(const LutCell &lut_cell, const dict<IdString, IdString> &cell_to_bel_map, const LutBel &lut_bel,
|
||||||
const LutBel &lut_bel, const std::vector<LogicLevel> &equation, uint32_t used_pins);
|
const std::vector<LogicLevel> &equation, uint32_t used_pins);
|
||||||
|
|
||||||
struct LutElement
|
struct LutElement
|
||||||
{
|
{
|
||||||
size_t width;
|
size_t width;
|
||||||
std::unordered_map<IdString, LutBel> lut_bels;
|
dict<IdString, LutBel> lut_bels;
|
||||||
|
|
||||||
void compute_pin_order();
|
void compute_pin_order();
|
||||||
|
|
||||||
std::vector<IdString> pins;
|
std::vector<IdString> pins;
|
||||||
std::unordered_map<IdString, size_t> pin_to_index;
|
dict<IdString, size_t> pin_to_index;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LutMapper
|
struct LutMapper
|
||||||
@ -92,7 +89,7 @@ struct LutMapper
|
|||||||
|
|
||||||
std::vector<CellInfo *> cells;
|
std::vector<CellInfo *> cells;
|
||||||
|
|
||||||
bool remap_luts(const Context *ctx, HashTables::HashSet<const LutBel *> *blocked_luts);
|
bool remap_luts(const Context *ctx, pool<const LutBel *, hash_ptr_ops> *blocked_luts);
|
||||||
|
|
||||||
// Determine which wires given the current mapping must be tied to the
|
// Determine which wires given the current mapping must be tied to the
|
||||||
// default constant.
|
// default constant.
|
||||||
@ -101,7 +98,7 @@ struct LutMapper
|
|||||||
// the pin is free to be a signal.
|
// the pin is free to be a signal.
|
||||||
uint32_t check_wires(const std::vector<std::vector<int32_t>> &bel_to_cell_pin_remaps,
|
uint32_t check_wires(const std::vector<std::vector<int32_t>> &bel_to_cell_pin_remaps,
|
||||||
const std::vector<const LutBel *> &lut_bels, uint32_t used_pins,
|
const std::vector<const LutBel *> &lut_bels, uint32_t used_pins,
|
||||||
HashTables::HashSet<const LutBel *> *blocked_luts) const;
|
pool<const LutBel *, hash_ptr_ops> *blocked_luts) const;
|
||||||
|
|
||||||
// Version of check_wires that uses current state of cells based on pin
|
// Version of check_wires that uses current state of cells based on pin
|
||||||
// mapping in cells variable.
|
// mapping in cells variable.
|
||||||
|
@ -44,7 +44,7 @@ void PseudoPipData::init_tile_type(const Context *ctx, int32_t tile_type)
|
|||||||
max_pseudo_pip_index = pip_idx;
|
max_pseudo_pip_index = pip_idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
HashTables::HashSet<size_t> sites;
|
pool<size_t> sites;
|
||||||
std::vector<PseudoPipBel> pseudo_pip_bels;
|
std::vector<PseudoPipBel> pseudo_pip_bels;
|
||||||
for (int32_t wire_index : pip_data.pseudo_cell_wires) {
|
for (int32_t wire_index : pip_data.pseudo_cell_wires) {
|
||||||
const TileWireInfoPOD &wire_data = type_data.wire_data[wire_index];
|
const TileWireInfoPOD &wire_data = type_data.wire_data[wire_index];
|
||||||
@ -122,7 +122,7 @@ void PseudoPipData::init_tile_type(const Context *ctx, int32_t tile_type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!pseudo_pip_bels.empty()) {
|
if (!pseudo_pip_bels.empty()) {
|
||||||
HashTables::HashSet<int32_t> pseudo_cell_wires;
|
pool<int32_t> pseudo_cell_wires;
|
||||||
pseudo_cell_wires.insert(pip_data.pseudo_cell_wires.begin(), pip_data.pseudo_cell_wires.end());
|
pseudo_cell_wires.insert(pip_data.pseudo_cell_wires.begin(), pip_data.pseudo_cell_wires.end());
|
||||||
|
|
||||||
// For each BEL, find the input bel pin used, and attach it to
|
// For each BEL, find the input bel pin used, and attach it to
|
||||||
@ -195,7 +195,7 @@ void PseudoPipModel::prepare_for_routing(const Context *ctx, const std::vector<S
|
|||||||
{
|
{
|
||||||
// First determine which sites have placed cells, these sites are consider
|
// First determine which sites have placed cells, these sites are consider
|
||||||
// active.
|
// active.
|
||||||
HashTables::HashSet<size_t> active_sites;
|
pool<size_t> active_sites;
|
||||||
for (size_t site = 0; site < sites.size(); ++site) {
|
for (size_t site = 0; site < sites.size(); ++site) {
|
||||||
if (!sites[site].cells_in_site.empty()) {
|
if (!sites[site].cells_in_site.empty()) {
|
||||||
active_sites.emplace(site);
|
active_sites.emplace(site);
|
||||||
@ -309,7 +309,7 @@ void PseudoPipModel::update_site(const Context *ctx, size_t site)
|
|||||||
unused_pseudo_pips.clear();
|
unused_pseudo_pips.clear();
|
||||||
unused_pseudo_pips.reserve(pseudo_pips_for_site.size());
|
unused_pseudo_pips.reserve(pseudo_pips_for_site.size());
|
||||||
|
|
||||||
HashTables::HashMap<int32_t, PseudoPipBel> used_bels;
|
dict<int32_t, PseudoPipBel> used_bels;
|
||||||
for (int32_t pseudo_pip : pseudo_pips_for_site) {
|
for (int32_t pseudo_pip : pseudo_pips_for_site) {
|
||||||
if (!active_pseudo_pips.count(pseudo_pip)) {
|
if (!active_pseudo_pips.count(pseudo_pip)) {
|
||||||
unused_pseudo_pips.push_back(pseudo_pip);
|
unused_pseudo_pips.push_back(pseudo_pip);
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
#include "dynamic_bitarray.h"
|
#include "dynamic_bitarray.h"
|
||||||
#include "hash_table.h"
|
|
||||||
#include "nextpnr_namespaces.h"
|
#include "nextpnr_namespaces.h"
|
||||||
#include "nextpnr_types.h"
|
#include "nextpnr_types.h"
|
||||||
#include "site_router.h"
|
#include "site_router.h"
|
||||||
@ -58,28 +57,10 @@ struct LogicBelKey
|
|||||||
bool operator==(const LogicBelKey &other) const { return make_tuple() == other.make_tuple(); }
|
bool operator==(const LogicBelKey &other) const { return make_tuple() == other.make_tuple(); }
|
||||||
|
|
||||||
bool operator<(const LogicBelKey &other) const { return make_tuple() < other.make_tuple(); }
|
bool operator<(const LogicBelKey &other) const { return make_tuple() < other.make_tuple(); }
|
||||||
|
|
||||||
|
unsigned int hash() const { return mkhash(mkhash(tile_type, pip_index), site); }
|
||||||
};
|
};
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
|
||||||
|
|
||||||
namespace std {
|
|
||||||
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX LogicBelKey>
|
|
||||||
{
|
|
||||||
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX LogicBelKey &key) const noexcept
|
|
||||||
{
|
|
||||||
std::size_t seed = 0;
|
|
||||||
boost::hash_combine(seed, hash<int32_t>()(key.tile_type));
|
|
||||||
boost::hash_combine(seed, hash<int32_t>()(key.pip_index));
|
|
||||||
boost::hash_combine(seed, hash<int32_t>()(key.site));
|
|
||||||
|
|
||||||
return seed;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}; // namespace std
|
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
|
||||||
|
|
||||||
// Storage for tile type generic pseudo pip data and lookup.
|
// Storage for tile type generic pseudo pip data and lookup.
|
||||||
struct PseudoPipData
|
struct PseudoPipData
|
||||||
{
|
{
|
||||||
@ -97,9 +78,9 @@ struct PseudoPipData
|
|||||||
// This does **not** include site ports or site pips.
|
// This does **not** include site ports or site pips.
|
||||||
const std::vector<PseudoPipBel> &get_logic_bels_for_pip(const Context *ctx, int32_t site, PipId pip) const;
|
const std::vector<PseudoPipBel> &get_logic_bels_for_pip(const Context *ctx, int32_t site, PipId pip) const;
|
||||||
|
|
||||||
HashTables::HashMap<int32_t, size_t> max_pseudo_pip_for_tile_type;
|
dict<int32_t, size_t> max_pseudo_pip_for_tile_type;
|
||||||
HashTables::HashMap<std::pair<int32_t, int32_t>, std::vector<size_t>, PairHash> possibles_sites_for_pip;
|
dict<std::pair<int32_t, int32_t>, std::vector<size_t>> possibles_sites_for_pip;
|
||||||
HashTables::HashMap<LogicBelKey, std::vector<PseudoPipBel>> logic_bels_for_pip;
|
dict<LogicBelKey, std::vector<PseudoPipBel>> logic_bels_for_pip;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Tile instance fast pseudo pip lookup.
|
// Tile instance fast pseudo pip lookup.
|
||||||
@ -107,9 +88,9 @@ struct PseudoPipModel
|
|||||||
{
|
{
|
||||||
int32_t tile;
|
int32_t tile;
|
||||||
DynamicBitarray<> allowed_pseudo_pips;
|
DynamicBitarray<> allowed_pseudo_pips;
|
||||||
HashTables::HashMap<int32_t, size_t> pseudo_pip_sites;
|
dict<int32_t, size_t> pseudo_pip_sites;
|
||||||
HashTables::HashMap<size_t, std::vector<int32_t>> site_to_pseudo_pips;
|
dict<size_t, std::vector<int32_t>> site_to_pseudo_pips;
|
||||||
HashTables::HashSet<int32_t> active_pseudo_pips;
|
pool<int32_t> active_pseudo_pips;
|
||||||
std::vector<int32_t> scratch;
|
std::vector<int32_t> scratch;
|
||||||
|
|
||||||
// Call when a tile is initialized.
|
// Call when a tile is initialized.
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
SiteInformation::SiteInformation(const Context *ctx, int32_t tile, int32_t site,
|
SiteInformation::SiteInformation(const Context *ctx, int32_t tile, int32_t site,
|
||||||
const std::unordered_set<CellInfo *> &cells_in_site)
|
const pool<CellInfo *, hash_ptr_ops> &cells_in_site)
|
||||||
: ctx(ctx), tile(tile), tile_type(ctx->chip_info->tiles[tile].type), site(site), cells_in_site(cells_in_site)
|
: ctx(ctx), tile(tile), tile_type(ctx->chip_info->tiles[tile].type), site(site), cells_in_site(cells_in_site)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -22,13 +22,12 @@
|
|||||||
#define SITE_ARCH_H
|
#define SITE_ARCH_H
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <unordered_set>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "PhysicalNetlist.capnp.h"
|
#include "PhysicalNetlist.capnp.h"
|
||||||
#include "arch_iterators.h"
|
#include "arch_iterators.h"
|
||||||
#include "chipdb.h"
|
#include "chipdb.h"
|
||||||
#include "hash_table.h"
|
#include "hashlib.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "nextpnr_namespaces.h"
|
#include "nextpnr_namespaces.h"
|
||||||
#include "nextpnr_types.h"
|
#include "nextpnr_types.h"
|
||||||
@ -44,10 +43,10 @@ struct SiteInformation
|
|||||||
const int32_t tile;
|
const int32_t tile;
|
||||||
const int32_t tile_type;
|
const int32_t tile_type;
|
||||||
const int32_t site;
|
const int32_t site;
|
||||||
const std::unordered_set<CellInfo *> &cells_in_site;
|
const pool<CellInfo *, hash_ptr_ops> &cells_in_site;
|
||||||
|
|
||||||
SiteInformation(const Context *ctx, int32_t tile, int32_t site,
|
SiteInformation(const Context *ctx, int32_t tile, int32_t site,
|
||||||
const std::unordered_set<CellInfo *> &cells_in_site);
|
const pool<CellInfo *, hash_ptr_ops> &cells_in_site);
|
||||||
|
|
||||||
inline const ChipInfoPOD &chip_info() const NPNR_ALWAYS_INLINE;
|
inline const ChipInfoPOD &chip_info() const NPNR_ALWAYS_INLINE;
|
||||||
|
|
||||||
@ -143,6 +142,7 @@ struct SiteWire
|
|||||||
WireId wire;
|
WireId wire;
|
||||||
PipId pip;
|
PipId pip;
|
||||||
NetInfo *net = nullptr;
|
NetInfo *net = nullptr;
|
||||||
|
unsigned int hash() const { return mkhash(mkhash(int(type), wire.hash()), mkhash(pip.hash(), uintptr_t(net))); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SitePip
|
struct SitePip
|
||||||
@ -214,36 +214,8 @@ struct SitePip
|
|||||||
{
|
{
|
||||||
return type != other.type || pip != other.pip || wire != other.wire || other_pip != other.other_pip;
|
return type != other.type || pip != other.pip || wire != other.wire || other_pip != other.other_pip;
|
||||||
}
|
}
|
||||||
|
unsigned int hash() const { return mkhash(mkhash(int(type), pip.hash()), mkhash(wire.hash(), other_pip.hash())); }
|
||||||
};
|
};
|
||||||
NEXTPNR_NAMESPACE_END
|
|
||||||
|
|
||||||
template <> struct std::hash<NEXTPNR_NAMESPACE_PREFIX SiteWire>
|
|
||||||
{
|
|
||||||
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX SiteWire &site_wire) const noexcept
|
|
||||||
{
|
|
||||||
std::size_t seed = 0;
|
|
||||||
boost::hash_combine(seed, std::hash<NEXTPNR_NAMESPACE_PREFIX SiteWire::Type>()(site_wire.type));
|
|
||||||
boost::hash_combine(seed, std::hash<NEXTPNR_NAMESPACE_PREFIX WireId>()(site_wire.wire));
|
|
||||||
boost::hash_combine(seed, std::hash<NEXTPNR_NAMESPACE_PREFIX PipId>()(site_wire.pip));
|
|
||||||
boost::hash_combine(seed, std::hash<NEXTPNR_NAMESPACE_PREFIX NetInfo *>()(site_wire.net));
|
|
||||||
return seed;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <> struct std::hash<NEXTPNR_NAMESPACE_PREFIX SitePip>
|
|
||||||
{
|
|
||||||
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX SitePip &site_pip) const noexcept
|
|
||||||
{
|
|
||||||
std::size_t seed = 0;
|
|
||||||
boost::hash_combine(seed, std::hash<NEXTPNR_NAMESPACE_PREFIX SitePip::Type>()(site_pip.type));
|
|
||||||
boost::hash_combine(seed, std::hash<NEXTPNR_NAMESPACE_PREFIX PipId>()(site_pip.pip));
|
|
||||||
boost::hash_combine(seed, std::hash<NEXTPNR_NAMESPACE_PREFIX SiteWire>()(site_pip.wire));
|
|
||||||
boost::hash_combine(seed, std::hash<NEXTPNR_NAMESPACE_PREFIX PipId>()(site_pip.other_pip));
|
|
||||||
return seed;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
|
||||||
|
|
||||||
struct SitePipDownhillRange;
|
struct SitePipDownhillRange;
|
||||||
struct SitePipUphillRange;
|
struct SitePipUphillRange;
|
||||||
@ -266,9 +238,9 @@ struct SiteNetInfo
|
|||||||
{
|
{
|
||||||
NetInfo *net;
|
NetInfo *net;
|
||||||
SiteWire driver;
|
SiteWire driver;
|
||||||
HashTables::HashSet<SiteWire> users;
|
pool<SiteWire> users;
|
||||||
|
|
||||||
HashTables::HashMap<SiteWire, SitePipMap> wires;
|
dict<SiteWire, SitePipMap> wires;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SiteArch
|
struct SiteArch
|
||||||
@ -276,8 +248,8 @@ struct SiteArch
|
|||||||
const Context *const ctx;
|
const Context *const ctx;
|
||||||
const SiteInformation *const site_info;
|
const SiteInformation *const site_info;
|
||||||
|
|
||||||
HashTables::HashMap<NetInfo *, SiteNetInfo> nets;
|
dict<NetInfo *, SiteNetInfo, hash_ptr_ops> nets;
|
||||||
HashTables::HashMap<SiteWire, SiteNetMap> wire_to_nets;
|
dict<SiteWire, SiteNetMap> wire_to_nets;
|
||||||
|
|
||||||
NetInfo blocking_net;
|
NetInfo blocking_net;
|
||||||
SiteNetInfo blocking_site_net;
|
SiteNetInfo blocking_site_net;
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
|
|
||||||
#include "design_utils.h"
|
#include "design_utils.h"
|
||||||
#include "dynamic_bitarray.h"
|
#include "dynamic_bitarray.h"
|
||||||
#include "hash_table.h"
|
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "site_routing_cache.h"
|
#include "site_routing_cache.h"
|
||||||
|
|
||||||
@ -53,7 +52,7 @@ bool check_initial_wires(const Context *ctx, SiteInformation *site_info)
|
|||||||
{
|
{
|
||||||
// Propagate from BEL pins to first wire, checking for trivial routing
|
// Propagate from BEL pins to first wire, checking for trivial routing
|
||||||
// conflicts.
|
// conflicts.
|
||||||
HashTables::HashMap<WireId, NetInfo *> wires;
|
dict<WireId, NetInfo *> wires;
|
||||||
|
|
||||||
for (CellInfo *cell : site_info->cells_in_site) {
|
for (CellInfo *cell : site_info->cells_in_site) {
|
||||||
BelId bel = cell->bel;
|
BelId bel = cell->bel;
|
||||||
@ -132,7 +131,7 @@ struct SiteExpansionLoop
|
|||||||
|
|
||||||
bool expand_result;
|
bool expand_result;
|
||||||
SiteWire net_driver;
|
SiteWire net_driver;
|
||||||
HashTables::HashSet<SiteWire> net_users;
|
pool<SiteWire> net_users;
|
||||||
|
|
||||||
SiteRoutingSolution solution;
|
SiteRoutingSolution solution;
|
||||||
|
|
||||||
@ -206,7 +205,7 @@ struct SiteExpansionLoop
|
|||||||
|
|
||||||
auto node = new_node(net->driver, SitePip(), /*parent=*/nullptr);
|
auto node = new_node(net->driver, SitePip(), /*parent=*/nullptr);
|
||||||
|
|
||||||
HashTables::HashSet<SiteWire> targets;
|
pool<SiteWire> targets;
|
||||||
targets.insert(net->users.begin(), net->users.end());
|
targets.insert(net->users.begin(), net->users.end());
|
||||||
|
|
||||||
if (verbose_site_router(ctx)) {
|
if (verbose_site_router(ctx)) {
|
||||||
@ -722,7 +721,7 @@ static bool route_site(SiteArch *ctx, SiteRoutingCache *site_routing_cache, Rout
|
|||||||
|
|
||||||
// Create a flat sink list and map.
|
// Create a flat sink list and map.
|
||||||
std::vector<SiteWire> sinks;
|
std::vector<SiteWire> sinks;
|
||||||
HashTables::HashMap<SiteWire, size_t> sink_map;
|
dict<SiteWire, size_t> sink_map;
|
||||||
size_t number_solutions = 0;
|
size_t number_solutions = 0;
|
||||||
for (const auto *expansion : expansions) {
|
for (const auto *expansion : expansions) {
|
||||||
number_solutions += expansion->num_solutions();
|
number_solutions += expansion->num_solutions();
|
||||||
@ -963,8 +962,7 @@ static void apply_constant_routing(Context *ctx, const SiteArch &site_arch, NetI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void apply_routing(Context *ctx, const SiteArch &site_arch,
|
static void apply_routing(Context *ctx, const SiteArch &site_arch, pool<std::pair<IdString, int32_t>> &lut_thrus)
|
||||||
HashTables::HashSet<std::pair<IdString, int32_t>, PairHash> &lut_thrus)
|
|
||||||
{
|
{
|
||||||
IdString gnd_net_name(ctx->chip_info->constants->gnd_net_name);
|
IdString gnd_net_name(ctx->chip_info->constants->gnd_net_name);
|
||||||
NetInfo *gnd_net = ctx->nets.at(gnd_net_name).get();
|
NetInfo *gnd_net = ctx->nets.at(gnd_net_name).get();
|
||||||
@ -1019,8 +1017,7 @@ static void apply_routing(Context *ctx, const SiteArch &site_arch,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool map_luts_in_site(const SiteInformation &site_info,
|
static bool map_luts_in_site(const SiteInformation &site_info, pool<std::pair<IdString, IdString>> *blocked_wires)
|
||||||
HashTables::HashSet<std::pair<IdString, IdString>, PairHash> *blocked_wires)
|
|
||||||
{
|
{
|
||||||
const Context *ctx = site_info.ctx;
|
const Context *ctx = site_info.ctx;
|
||||||
const std::vector<LutElement> &lut_elements = ctx->lut_elements.at(site_info.tile_type);
|
const std::vector<LutElement> &lut_elements = ctx->lut_elements.at(site_info.tile_type);
|
||||||
@ -1048,7 +1045,7 @@ static bool map_luts_in_site(const SiteInformation &site_info,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
HashTables::HashSet<const LutBel *> blocked_luts;
|
pool<const LutBel *, hash_ptr_ops> blocked_luts;
|
||||||
if (!lut_mapper.remap_luts(ctx, &blocked_luts)) {
|
if (!lut_mapper.remap_luts(ctx, &blocked_luts)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1062,8 +1059,7 @@ static bool map_luts_in_site(const SiteInformation &site_info,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Block outputs of unavailable LUTs to prevent site router from using them.
|
// Block outputs of unavailable LUTs to prevent site router from using them.
|
||||||
static void block_lut_outputs(SiteArch *site_arch,
|
static void block_lut_outputs(SiteArch *site_arch, const pool<std::pair<IdString, IdString>> &blocked_wires)
|
||||||
const HashTables::HashSet<std::pair<IdString, IdString>, PairHash> &blocked_wires)
|
|
||||||
{
|
{
|
||||||
const Context *ctx = site_arch->site_info->ctx;
|
const Context *ctx = site_arch->site_info->ctx;
|
||||||
auto &tile_info = ctx->chip_info->tile_types[site_arch->site_info->tile_type];
|
auto &tile_info = ctx->chip_info->tile_types[site_arch->site_info->tile_type];
|
||||||
@ -1185,7 +1181,7 @@ bool SiteRouter::checkSiteRouting(const Context *ctx, const TileStatus &tile_sta
|
|||||||
}
|
}
|
||||||
|
|
||||||
SiteInformation site_info(ctx, tile, site, cells_in_site);
|
SiteInformation site_info(ctx, tile, site, cells_in_site);
|
||||||
HashTables::HashSet<std::pair<IdString, IdString>, PairHash> blocked_wires;
|
pool<std::pair<IdString, IdString>> blocked_wires;
|
||||||
if (!map_luts_in_site(site_info, &blocked_wires)) {
|
if (!map_luts_in_site(site_info, &blocked_wires)) {
|
||||||
site_ok = false;
|
site_ok = false;
|
||||||
return site_ok;
|
return site_ok;
|
||||||
@ -1263,7 +1259,7 @@ void SiteRouter::bindSiteRouting(Context *ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
SiteInformation site_info(ctx, tile, site, cells_in_site);
|
SiteInformation site_info(ctx, tile, site, cells_in_site);
|
||||||
HashTables::HashSet<std::pair<IdString, IdString>, PairHash> blocked_wires;
|
pool<std::pair<IdString, IdString>> blocked_wires;
|
||||||
NPNR_ASSERT(map_luts_in_site(site_info, &blocked_wires));
|
NPNR_ASSERT(map_luts_in_site(site_info, &blocked_wires));
|
||||||
|
|
||||||
SiteArch site_arch(&site_info);
|
SiteArch site_arch(&site_info);
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "hashlib.h"
|
||||||
#include "nextpnr_namespaces.h"
|
#include "nextpnr_namespaces.h"
|
||||||
#include "nextpnr_types.h"
|
#include "nextpnr_types.h"
|
||||||
#include "site_arch.h"
|
#include "site_arch.h"
|
||||||
@ -37,9 +38,9 @@ struct SiteRouter
|
|||||||
{
|
{
|
||||||
SiteRouter(int16_t site) : site(site), dirty(false), site_ok(true) {}
|
SiteRouter(int16_t site) : site(site), dirty(false), site_ok(true) {}
|
||||||
|
|
||||||
std::unordered_set<CellInfo *> cells_in_site;
|
pool<CellInfo *, hash_ptr_ops> cells_in_site;
|
||||||
std::vector<PipId> valid_pips;
|
std::vector<PipId> valid_pips;
|
||||||
HashTables::HashSet<std::pair<IdString, int32_t>, PairHash> lut_thrus;
|
pool<std::pair<IdString, int32_t>> lut_thrus;
|
||||||
const int16_t site;
|
const int16_t site;
|
||||||
|
|
||||||
mutable bool dirty;
|
mutable bool dirty;
|
||||||
|
@ -70,7 +70,7 @@ void SiteRoutingSolution::store_solution(const SiteArch *ctx, const RouteNodeSto
|
|||||||
|
|
||||||
void SiteRoutingSolution::verify(const SiteArch *ctx, const SiteNetInfo &net)
|
void SiteRoutingSolution::verify(const SiteArch *ctx, const SiteNetInfo &net)
|
||||||
{
|
{
|
||||||
HashTables::HashSet<SiteWire> seen_users;
|
pool<SiteWire> seen_users;
|
||||||
for (size_t i = 0; i < num_solutions(); ++i) {
|
for (size_t i = 0; i < num_solutions(); ++i) {
|
||||||
SiteWire cursor = solution_sink(i);
|
SiteWire cursor = solution_sink(i);
|
||||||
NPNR_ASSERT(net.users.count(cursor) == 1);
|
NPNR_ASSERT(net.users.count(cursor) == 1);
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
#define SITE_ROUTING_CACHE_H
|
#define SITE_ROUTING_CACHE_H
|
||||||
|
|
||||||
#include "PhysicalNetlist.capnp.h"
|
#include "PhysicalNetlist.capnp.h"
|
||||||
#include "hash_table.h"
|
|
||||||
#include "nextpnr_namespaces.h"
|
#include "nextpnr_namespaces.h"
|
||||||
#include "site_arch.h"
|
#include "site_arch.h"
|
||||||
#include "site_routing_storage.h"
|
#include "site_routing_storage.h"
|
||||||
@ -97,35 +96,25 @@ struct SiteRoutingKey
|
|||||||
}
|
}
|
||||||
|
|
||||||
static SiteRoutingKey make(const SiteArch *ctx, const SiteNetInfo &site_net);
|
static SiteRoutingKey make(const SiteArch *ctx, const SiteNetInfo &site_net);
|
||||||
};
|
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
unsigned int hash() const
|
||||||
|
|
||||||
template <> struct std::hash<NEXTPNR_NAMESPACE_PREFIX SiteRoutingKey>
|
|
||||||
{
|
|
||||||
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX SiteRoutingKey &key) const noexcept
|
|
||||||
{
|
{
|
||||||
std::size_t seed = 0;
|
unsigned int seed = 0;
|
||||||
boost::hash_combine(seed, std::hash<int32_t>()(key.tile_type));
|
seed = mkhash(seed, tile_type);
|
||||||
boost::hash_combine(seed, std::hash<int32_t>()(key.site));
|
seed = mkhash(seed, site);
|
||||||
boost::hash_combine(seed, std::hash<PhysicalNetlist::PhysNetlist::NetType>()(key.net_type));
|
seed = mkhash(seed, int(net_type));
|
||||||
boost::hash_combine(seed, std::hash<NEXTPNR_NAMESPACE_PREFIX SiteWire::Type>()(key.driver_type));
|
seed = mkhash(seed, int(driver_type));
|
||||||
boost::hash_combine(seed, std::hash<int32_t>()(key.driver_index));
|
seed = mkhash(seed, driver_index);
|
||||||
boost::hash_combine(seed, std::hash<std::size_t>()(key.user_types.size()));
|
seed = mkhash(seed, user_types.size());
|
||||||
for (NEXTPNR_NAMESPACE_PREFIX SiteWire::Type user_type : key.user_types) {
|
for (auto t : user_types)
|
||||||
boost::hash_combine(seed, std::hash<NEXTPNR_NAMESPACE_PREFIX SiteWire::Type>()(user_type));
|
seed = mkhash(seed, int(t));
|
||||||
}
|
seed = mkhash(seed, user_indicies.size());
|
||||||
|
for (auto i : user_indicies)
|
||||||
boost::hash_combine(seed, std::hash<std::size_t>()(key.user_indicies.size()));
|
seed = mkhash(seed, i);
|
||||||
for (int32_t index : key.user_indicies) {
|
|
||||||
boost::hash_combine(seed, std::hash<int32_t>()(index));
|
|
||||||
}
|
|
||||||
return seed;
|
return seed;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
|
||||||
|
|
||||||
// Provides an LRU cache for site routing solutions.
|
// Provides an LRU cache for site routing solutions.
|
||||||
class SiteRoutingCache
|
class SiteRoutingCache
|
||||||
{
|
{
|
||||||
@ -134,7 +123,7 @@ class SiteRoutingCache
|
|||||||
void add_solutions(const SiteArch *ctx, const SiteNetInfo &net, const SiteRoutingSolution &solution);
|
void add_solutions(const SiteArch *ctx, const SiteNetInfo &net, const SiteRoutingSolution &solution);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HashTables::HashMap<SiteRoutingKey, SiteRoutingSolution> cache_;
|
dict<SiteRoutingKey, SiteRoutingSolution> cache_;
|
||||||
};
|
};
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
@ -54,10 +54,9 @@ TypeWireSet::TypeWireSet(const Context *ctx, WireId wire)
|
|||||||
|
|
||||||
std::sort(wire_types_.begin(), wire_types_.end());
|
std::sort(wire_types_.begin(), wire_types_.end());
|
||||||
|
|
||||||
hash_ = 0;
|
hash_ = wire_types_.size();
|
||||||
boost::hash_combine(hash_, std::hash<size_t>()(wire_types_.size()));
|
|
||||||
for (const auto &wire : wire_types_) {
|
for (const auto &wire : wire_types_) {
|
||||||
boost::hash_combine(hash_, std::hash<NEXTPNR_NAMESPACE_PREFIX TypeWireId>()(wire));
|
hash_ = mkhash(hash_, wire.hash());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "hashlib.h"
|
||||||
#include "nextpnr_namespaces.h"
|
#include "nextpnr_namespaces.h"
|
||||||
#include "nextpnr_types.h"
|
#include "nextpnr_types.h"
|
||||||
|
|
||||||
@ -48,6 +49,8 @@ struct TypeWireId
|
|||||||
return type < other.type || (type == other.type && index < other.index);
|
return type < other.type || (type == other.type && index < other.index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int hash() const { return mkhash(type, index); }
|
||||||
|
|
||||||
int32_t type;
|
int32_t type;
|
||||||
int32_t index;
|
int32_t index;
|
||||||
};
|
};
|
||||||
@ -63,49 +66,24 @@ struct TypeWirePair
|
|||||||
|
|
||||||
bool operator==(const TypeWirePair &other) const { return src == other.src && dst == other.dst; }
|
bool operator==(const TypeWirePair &other) const { return src == other.src && dst == other.dst; }
|
||||||
bool operator!=(const TypeWirePair &other) const { return src != other.src || dst != other.dst; }
|
bool operator!=(const TypeWirePair &other) const { return src != other.src || dst != other.dst; }
|
||||||
|
|
||||||
|
unsigned int hash() const { return mkhash(src.hash(), dst.hash()); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TypeWireSet
|
struct TypeWireSet
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TypeWireSet(const Context *ctx, WireId wire);
|
TypeWireSet(const Context *ctx, WireId wire);
|
||||||
std::size_t hash() const { return hash_; }
|
unsigned int hash() const { return hash_; }
|
||||||
|
|
||||||
bool operator==(const TypeWireSet &other) const { return wire_types_ == other.wire_types_; }
|
bool operator==(const TypeWireSet &other) const { return wire_types_ == other.wire_types_; }
|
||||||
bool operator!=(const TypeWireSet &other) const { return wire_types_ != other.wire_types_; }
|
bool operator!=(const TypeWireSet &other) const { return wire_types_ != other.wire_types_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::size_t hash_;
|
unsigned int hash_;
|
||||||
std::vector<TypeWireId> wire_types_;
|
std::vector<TypeWireId> wire_types_;
|
||||||
};
|
};
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
|
||||||
template <> struct std::hash<NEXTPNR_NAMESPACE_PREFIX TypeWireId>
|
|
||||||
{
|
|
||||||
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX TypeWireId &wire) const noexcept
|
|
||||||
{
|
|
||||||
std::size_t seed = 0;
|
|
||||||
boost::hash_combine(seed, std::hash<int>()(wire.type));
|
|
||||||
boost::hash_combine(seed, std::hash<int>()(wire.index));
|
|
||||||
return seed;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <> struct std::hash<NEXTPNR_NAMESPACE_PREFIX TypeWirePair>
|
|
||||||
{
|
|
||||||
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX TypeWirePair &pair) const noexcept
|
|
||||||
{
|
|
||||||
std::size_t seed = 0;
|
|
||||||
boost::hash_combine(seed, std::hash<NEXTPNR_NAMESPACE_PREFIX TypeWireId>()(pair.src));
|
|
||||||
boost::hash_combine(seed, std::hash<NEXTPNR_NAMESPACE_PREFIX TypeWireId>()(pair.dst));
|
|
||||||
return seed;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <> struct std::hash<NEXTPNR_NAMESPACE_PREFIX TypeWireSet>
|
|
||||||
{
|
|
||||||
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX TypeWireSet &set) const noexcept { return set.hash(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* TYPE_WIRE_H */
|
#endif /* TYPE_WIRE_H */
|
||||||
|
@ -80,7 +80,7 @@ struct BelInfo
|
|||||||
IdString type;
|
IdString type;
|
||||||
std::map<IdString, std::string> attrs;
|
std::map<IdString, std::string> attrs;
|
||||||
CellInfo *bound_cell;
|
CellInfo *bound_cell;
|
||||||
std::unordered_map<IdString, PinInfo> pins;
|
dict<IdString, PinInfo> pins;
|
||||||
DecalXY decalxy;
|
DecalXY decalxy;
|
||||||
int x, y, z;
|
int x, y, z;
|
||||||
bool gb;
|
bool gb;
|
||||||
@ -101,27 +101,14 @@ struct CellDelayKey
|
|||||||
{
|
{
|
||||||
IdString from, to;
|
IdString from, to;
|
||||||
inline bool operator==(const CellDelayKey &other) const { return from == other.from && to == other.to; }
|
inline bool operator==(const CellDelayKey &other) const { return from == other.from && to == other.to; }
|
||||||
|
unsigned int hash() const { return mkhash(from.hash(), to.hash()); }
|
||||||
};
|
};
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
|
||||||
namespace std {
|
|
||||||
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX CellDelayKey>
|
|
||||||
{
|
|
||||||
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX CellDelayKey &dk) const noexcept
|
|
||||||
{
|
|
||||||
std::size_t seed = std::hash<NEXTPNR_NAMESPACE_PREFIX IdString>()(dk.from);
|
|
||||||
seed ^= std::hash<NEXTPNR_NAMESPACE_PREFIX IdString>()(dk.to) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
|
||||||
return seed;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // namespace std
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
|
||||||
|
|
||||||
struct CellTiming
|
struct CellTiming
|
||||||
{
|
{
|
||||||
std::unordered_map<IdString, TimingPortClass> portClasses;
|
dict<IdString, TimingPortClass> portClasses;
|
||||||
std::unordered_map<CellDelayKey, DelayQuad> combDelays;
|
dict<CellDelayKey, DelayQuad> combDelays;
|
||||||
std::unordered_map<IdString, std::vector<TimingClockingInfo>> clockingInfo;
|
dict<IdString, std::vector<TimingClockingInfo>> clockingInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ArchRanges
|
struct ArchRanges
|
||||||
@ -160,10 +147,10 @@ struct Arch : ArchAPI<ArchRanges>
|
|||||||
{
|
{
|
||||||
std::string chipName;
|
std::string chipName;
|
||||||
|
|
||||||
std::unordered_map<IdStringList, WireInfo> wires;
|
dict<IdStringList, WireInfo> wires;
|
||||||
std::unordered_map<IdStringList, PipInfo> pips;
|
dict<IdStringList, PipInfo> pips;
|
||||||
std::unordered_map<IdStringList, BelInfo> bels;
|
dict<IdStringList, BelInfo> bels;
|
||||||
std::unordered_map<GroupId, GroupInfo> groups;
|
dict<GroupId, GroupInfo> groups;
|
||||||
|
|
||||||
// These functions include useful errors if not found
|
// These functions include useful errors if not found
|
||||||
WireInfo &wire_info(IdStringList wire);
|
WireInfo &wire_info(IdStringList wire);
|
||||||
@ -172,16 +159,16 @@ struct Arch : ArchAPI<ArchRanges>
|
|||||||
|
|
||||||
std::vector<IdStringList> bel_ids, wire_ids, pip_ids;
|
std::vector<IdStringList> bel_ids, wire_ids, pip_ids;
|
||||||
|
|
||||||
std::unordered_map<Loc, BelId> bel_by_loc;
|
dict<Loc, BelId> bel_by_loc;
|
||||||
std::vector<std::vector<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;
|
dict<DecalId, std::vector<GraphicElement>> decal_graphics;
|
||||||
|
|
||||||
int gridDimX, gridDimY;
|
int gridDimX, gridDimY;
|
||||||
std::vector<std::vector<int>> tileBelDimZ;
|
std::vector<std::vector<int>> tileBelDimZ;
|
||||||
std::vector<std::vector<int>> tilePipDimZ;
|
std::vector<std::vector<int>> tilePipDimZ;
|
||||||
|
|
||||||
std::unordered_map<IdString, CellTiming> cellTiming;
|
dict<IdString, CellTiming> cellTiming;
|
||||||
|
|
||||||
void addWire(IdStringList name, IdString type, int x, int y);
|
void addWire(IdStringList name, IdString type, int x, int y);
|
||||||
void addPip(IdStringList name, IdString type, IdStringList srcWire, IdStringList dstWire, delay_t delay, Loc loc);
|
void addPip(IdStringList name, IdString type, IdStringList srcWire, IdStringList dstWire, delay_t delay, Loc loc);
|
||||||
@ -318,7 +305,7 @@ struct Arch : ArchAPI<ArchRanges>
|
|||||||
|
|
||||||
std::vector<IdString> getCellTypes() const override
|
std::vector<IdString> getCellTypes() const override
|
||||||
{
|
{
|
||||||
std::unordered_set<IdString> cell_types;
|
pool<IdString> cell_types;
|
||||||
for (auto bel : bels) {
|
for (auto bel : bels) {
|
||||||
cell_types.insert(bel.second.type);
|
cell_types.insert(bel.second.type);
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,7 @@
|
|||||||
#ifndef GENERIC_ARCHDEFS_H
|
#ifndef GENERIC_ARCHDEFS_H
|
||||||
#define GENERIC_ARCHDEFS_H
|
#define GENERIC_ARCHDEFS_H
|
||||||
|
|
||||||
#include <unordered_map>
|
#include "hashlib.h"
|
||||||
|
|
||||||
#include "idstringlist.h"
|
#include "idstringlist.h"
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
@ -52,7 +51,7 @@ struct ArchCellInfo
|
|||||||
// Only packing rule for slice type primitives is a single clock per tile
|
// Only packing rule for slice type primitives is a single clock per tile
|
||||||
const NetInfo *slice_clk;
|
const NetInfo *slice_clk;
|
||||||
// Cell to bel pin mapping
|
// Cell to bel pin mapping
|
||||||
std::unordered_map<IdString, std::vector<IdString>> bel_pins;
|
dict<IdString, std::vector<IdString>> bel_pins;
|
||||||
};
|
};
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
@ -106,7 +106,7 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_l
|
|||||||
replace_port(dff, ctx->id("Q"), lc, ctx->id("Q"));
|
replace_port(dff, ctx->id("Q"), lc, ctx->id("Q"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void nxio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *iob, std::unordered_set<IdString> &todelete_cells)
|
void nxio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *iob, pool<IdString> &todelete_cells)
|
||||||
{
|
{
|
||||||
if (nxio->type == ctx->id("$nextpnr_ibuf")) {
|
if (nxio->type == ctx->id("$nextpnr_ibuf")) {
|
||||||
iob->params[ctx->id("INPUT_USED")] = 1;
|
iob->params[ctx->id("INPUT_USED")] = 1;
|
||||||
|
@ -48,7 +48,7 @@ void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff = tr
|
|||||||
void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut = false);
|
void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut = false);
|
||||||
|
|
||||||
// Convert a nextpnr IO buffer to a GENERIC_IOB
|
// Convert a nextpnr IO buffer to a GENERIC_IOB
|
||||||
void nxio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *sbio, std::unordered_set<IdString> &todelete_cells);
|
void nxio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *sbio, pool<IdString> &todelete_cells);
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <unordered_set>
|
|
||||||
#include "cells.h"
|
#include "cells.h"
|
||||||
#include "design_utils.h"
|
#include "design_utils.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
@ -32,7 +31,7 @@ static void pack_lut_lutffs(Context *ctx)
|
|||||||
{
|
{
|
||||||
log_info("Packing LUT-FFs..\n");
|
log_info("Packing LUT-FFs..\n");
|
||||||
|
|
||||||
std::unordered_set<IdString> packed_cells;
|
pool<IdString> packed_cells;
|
||||||
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
||||||
for (auto &cell : ctx->cells) {
|
for (auto &cell : ctx->cells) {
|
||||||
CellInfo *ci = cell.second.get();
|
CellInfo *ci = cell.second.get();
|
||||||
@ -89,7 +88,7 @@ static void pack_nonlut_ffs(Context *ctx)
|
|||||||
{
|
{
|
||||||
log_info("Packing non-LUT FFs..\n");
|
log_info("Packing non-LUT FFs..\n");
|
||||||
|
|
||||||
std::unordered_set<IdString> packed_cells;
|
pool<IdString> packed_cells;
|
||||||
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
||||||
|
|
||||||
for (auto &cell : ctx->cells) {
|
for (auto &cell : ctx->cells) {
|
||||||
@ -203,8 +202,8 @@ static bool is_generic_iob(const Context *ctx, const CellInfo *cell) { return ce
|
|||||||
// Pack IO buffers
|
// Pack IO buffers
|
||||||
static void pack_io(Context *ctx)
|
static void pack_io(Context *ctx)
|
||||||
{
|
{
|
||||||
std::unordered_set<IdString> packed_cells;
|
pool<IdString> packed_cells;
|
||||||
std::unordered_set<IdString> delete_nets;
|
pool<IdString> delete_nets;
|
||||||
|
|
||||||
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
||||||
log_info("Packing IOs..\n");
|
log_info("Packing IOs..\n");
|
||||||
|
37
gowin/arch.h
37
gowin/arch.h
@ -209,7 +209,7 @@ struct BelInfo
|
|||||||
IdString name, type;
|
IdString name, type;
|
||||||
std::map<IdString, std::string> attrs;
|
std::map<IdString, std::string> attrs;
|
||||||
CellInfo *bound_cell;
|
CellInfo *bound_cell;
|
||||||
std::unordered_map<IdString, PinInfo> pins;
|
dict<IdString, PinInfo> pins;
|
||||||
DecalXY decalxy;
|
DecalXY decalxy;
|
||||||
int x, y, z;
|
int x, y, z;
|
||||||
bool gb;
|
bool gb;
|
||||||
@ -229,27 +229,14 @@ struct CellDelayKey
|
|||||||
{
|
{
|
||||||
IdString from, to;
|
IdString from, to;
|
||||||
inline bool operator==(const CellDelayKey &other) const { return from == other.from && to == other.to; }
|
inline bool operator==(const CellDelayKey &other) const { return from == other.from && to == other.to; }
|
||||||
|
unsigned int hash() const { return mkhash(from.hash(), to.hash()); }
|
||||||
};
|
};
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
|
||||||
namespace std {
|
|
||||||
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX CellDelayKey>
|
|
||||||
{
|
|
||||||
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX CellDelayKey &dk) const noexcept
|
|
||||||
{
|
|
||||||
std::size_t seed = std::hash<NEXTPNR_NAMESPACE_PREFIX IdString>()(dk.from);
|
|
||||||
seed ^= std::hash<NEXTPNR_NAMESPACE_PREFIX IdString>()(dk.to) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
|
||||||
return seed;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // namespace std
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
|
||||||
|
|
||||||
struct CellTiming
|
struct CellTiming
|
||||||
{
|
{
|
||||||
std::unordered_map<IdString, TimingPortClass> portClasses;
|
dict<IdString, TimingPortClass> portClasses;
|
||||||
std::unordered_map<CellDelayKey, DelayQuad> combDelays;
|
dict<CellDelayKey, DelayQuad> combDelays;
|
||||||
std::unordered_map<IdString, std::vector<TimingClockingInfo>> clockingInfo;
|
dict<IdString, std::vector<TimingClockingInfo>> clockingInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ArchRanges : BaseArchRanges
|
struct ArchRanges : BaseArchRanges
|
||||||
@ -287,10 +274,10 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
const PackagePOD *package;
|
const PackagePOD *package;
|
||||||
const TimingGroupsPOD *speed;
|
const TimingGroupsPOD *speed;
|
||||||
|
|
||||||
std::unordered_map<IdString, WireInfo> wires;
|
dict<IdString, WireInfo> wires;
|
||||||
std::unordered_map<IdString, PipInfo> pips;
|
dict<IdString, PipInfo> pips;
|
||||||
std::unordered_map<IdString, BelInfo> bels;
|
dict<IdString, BelInfo> bels;
|
||||||
std::unordered_map<GroupId, GroupInfo> groups;
|
dict<GroupId, GroupInfo> groups;
|
||||||
|
|
||||||
// These functions include useful errors if not found
|
// These functions include useful errors if not found
|
||||||
WireInfo &wire_info(IdString wire);
|
WireInfo &wire_info(IdString wire);
|
||||||
@ -299,16 +286,16 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
|
|
||||||
std::vector<IdString> bel_ids, wire_ids, pip_ids;
|
std::vector<IdString> bel_ids, wire_ids, pip_ids;
|
||||||
|
|
||||||
std::unordered_map<Loc, BelId> bel_by_loc;
|
dict<Loc, BelId> bel_by_loc;
|
||||||
std::vector<std::vector<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;
|
dict<DecalId, std::vector<GraphicElement>> decal_graphics;
|
||||||
|
|
||||||
int gridDimX, gridDimY;
|
int gridDimX, gridDimY;
|
||||||
std::vector<std::vector<int>> tileBelDimZ;
|
std::vector<std::vector<int>> tileBelDimZ;
|
||||||
std::vector<std::vector<int>> tilePipDimZ;
|
std::vector<std::vector<int>> tilePipDimZ;
|
||||||
|
|
||||||
std::unordered_map<IdString, CellTiming> cellTiming;
|
dict<IdString, CellTiming> cellTiming;
|
||||||
|
|
||||||
void addWire(IdString name, IdString type, int x, int y);
|
void addWire(IdString name, IdString type, int x, int y);
|
||||||
void addPip(IdString name, IdString type, IdString srcWire, IdString dstWire, DelayQuad delay, Loc loc);
|
void addPip(IdString name, IdString type, IdString srcWire, IdString dstWire, DelayQuad delay, Loc loc);
|
||||||
|
@ -114,7 +114,7 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_l
|
|||||||
replace_port(dff, id_Q, lc, id_Q);
|
replace_port(dff, id_Q, lc, id_Q);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gwio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *iob, std::unordered_set<IdString> &todelete_cells)
|
void gwio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *iob, pool<IdString> &todelete_cells)
|
||||||
{
|
{
|
||||||
if (nxio->type == id_IBUF) {
|
if (nxio->type == id_IBUF) {
|
||||||
iob->params[id_INPUT_USED] = 1;
|
iob->params[id_INPUT_USED] = 1;
|
||||||
|
@ -87,7 +87,7 @@ void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff = tr
|
|||||||
void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut = false);
|
void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut = false);
|
||||||
|
|
||||||
// Convert a Gowin IO buffer to a IOB bel
|
// Convert a Gowin IO buffer to a IOB bel
|
||||||
void gwio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *sbio, std::unordered_set<IdString> &todelete_cells);
|
void gwio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *sbio, pool<IdString> &todelete_cells);
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <unordered_set>
|
|
||||||
#include "cells.h"
|
#include "cells.h"
|
||||||
#include "design_utils.h"
|
#include "design_utils.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
@ -34,7 +33,7 @@ static void pack_lut_lutffs(Context *ctx)
|
|||||||
{
|
{
|
||||||
log_info("Packing LUT-FFs..\n");
|
log_info("Packing LUT-FFs..\n");
|
||||||
|
|
||||||
std::unordered_set<IdString> packed_cells;
|
pool<IdString> packed_cells;
|
||||||
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
||||||
for (auto &cell : ctx->cells) {
|
for (auto &cell : ctx->cells) {
|
||||||
CellInfo *ci = cell.second.get();
|
CellInfo *ci = cell.second.get();
|
||||||
@ -90,7 +89,7 @@ static void pack_nonlut_ffs(Context *ctx)
|
|||||||
{
|
{
|
||||||
log_info("Packing non-LUT FFs..\n");
|
log_info("Packing non-LUT FFs..\n");
|
||||||
|
|
||||||
std::unordered_set<IdString> packed_cells;
|
pool<IdString> packed_cells;
|
||||||
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
||||||
|
|
||||||
for (auto &cell : ctx->cells) {
|
for (auto &cell : ctx->cells) {
|
||||||
@ -212,8 +211,8 @@ static bool is_gowin_iob(const Context *ctx, const CellInfo *cell)
|
|||||||
// Pack IO buffers
|
// Pack IO buffers
|
||||||
static void pack_io(Context *ctx)
|
static void pack_io(Context *ctx)
|
||||||
{
|
{
|
||||||
std::unordered_set<IdString> packed_cells;
|
pool<IdString> packed_cells;
|
||||||
std::unordered_set<IdString> delete_nets;
|
pool<IdString> delete_nets;
|
||||||
|
|
||||||
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
||||||
log_info("Packing IOs..\n");
|
log_info("Packing IOs..\n");
|
||||||
|
10
ice40/arch.h
10
ice40/arch.h
@ -400,10 +400,10 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
const ChipInfoPOD *chip_info;
|
const ChipInfoPOD *chip_info;
|
||||||
const PackageInfoPOD *package_info;
|
const PackageInfoPOD *package_info;
|
||||||
|
|
||||||
mutable std::unordered_map<IdStringList, int> bel_by_name;
|
mutable dict<IdStringList, int> bel_by_name;
|
||||||
mutable std::unordered_map<IdStringList, int> wire_by_name;
|
mutable dict<IdStringList, int> wire_by_name;
|
||||||
mutable std::unordered_map<IdStringList, int> pip_by_name;
|
mutable dict<IdStringList, int> pip_by_name;
|
||||||
mutable std::unordered_map<Loc, int> bel_by_loc;
|
mutable dict<Loc, int> bel_by_loc;
|
||||||
|
|
||||||
std::vector<bool> bel_carry;
|
std::vector<bool> bel_carry;
|
||||||
std::vector<CellInfo *> bel_to_cell;
|
std::vector<CellInfo *> bel_to_cell;
|
||||||
@ -414,7 +414,7 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
// fast access to X and Y IdStrings for building object names
|
// fast access to X and Y IdStrings for building object names
|
||||||
std::vector<IdString> x_ids, y_ids;
|
std::vector<IdString> x_ids, y_ids;
|
||||||
// inverse of the above for name->object mapping
|
// inverse of the above for name->object mapping
|
||||||
std::unordered_map<IdString, int> id_to_x, id_to_y;
|
dict<IdString, int> id_to_x, id_to_y;
|
||||||
|
|
||||||
ArchArgs args;
|
ArchArgs args;
|
||||||
Arch(ArchArgs args);
|
Arch(ArchArgs args);
|
||||||
|
@ -252,7 +252,7 @@ static BelPin get_one_bel_pin(const Context *ctx, WireId wire)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Permute LUT init value given map (LUT input -> ext input)
|
// Permute LUT init value given map (LUT input -> ext input)
|
||||||
unsigned permute_lut(unsigned orig_init, const std::unordered_map<int, int> &input_permute)
|
unsigned permute_lut(unsigned orig_init, const dict<int, int> &input_permute)
|
||||||
{
|
{
|
||||||
unsigned new_init = 0;
|
unsigned new_init = 0;
|
||||||
|
|
||||||
@ -387,8 +387,8 @@ void write_asc(const Context *ctx, std::ostream &out)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scan for PLL and collects the affected SB_IOs
|
// Scan for PLL and collects the affected SB_IOs
|
||||||
std::unordered_set<Loc> sb_io_used_by_pll_out;
|
pool<Loc> sb_io_used_by_pll_out;
|
||||||
std::unordered_set<Loc> sb_io_used_by_pll_pad;
|
pool<Loc> sb_io_used_by_pll_pad;
|
||||||
|
|
||||||
for (auto &cell : ctx->cells) {
|
for (auto &cell : ctx->cells) {
|
||||||
if (cell.second->type != ctx->id("ICESTORM_PLL"))
|
if (cell.second->type != ctx->id("ICESTORM_PLL"))
|
||||||
@ -447,7 +447,7 @@ void write_asc(const Context *ctx, std::ostream &out)
|
|||||||
std::vector<bool> lc(20, false);
|
std::vector<bool> lc(20, false);
|
||||||
|
|
||||||
// Discover permutation
|
// Discover permutation
|
||||||
std::unordered_map<int, int> input_perm;
|
dict<int, int> input_perm;
|
||||||
std::set<int> unused;
|
std::set<int> unused;
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
unused.insert(i);
|
unused.insert(i);
|
||||||
|
@ -412,7 +412,7 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_l
|
|||||||
replace_port(dff, ctx->id("Q"), lc, ctx->id("O"));
|
replace_port(dff, ctx->id("Q"), lc, ctx->id("O"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio, std::unordered_set<IdString> &todelete_cells)
|
void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio, pool<IdString> &todelete_cells)
|
||||||
{
|
{
|
||||||
if (nxio->type == ctx->id("$nextpnr_ibuf")) {
|
if (nxio->type == ctx->id("$nextpnr_ibuf")) {
|
||||||
sbio->params[ctx->id("PIN_TYPE")] = 1;
|
sbio->params[ctx->id("PIN_TYPE")] = 1;
|
||||||
|
@ -130,7 +130,7 @@ void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff = tr
|
|||||||
void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut = false);
|
void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut = false);
|
||||||
|
|
||||||
// Convert a nextpnr IO buffer to a SB_IO
|
// Convert a nextpnr IO buffer to a SB_IO
|
||||||
void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio, std::unordered_set<IdString> &todelete_cells);
|
void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio, pool<IdString> &todelete_cells);
|
||||||
|
|
||||||
// Return true if a port is a clock port
|
// Return true if a port is a clock port
|
||||||
bool is_clock_port(const BaseCtx *ctx, const PortRef &port);
|
bool is_clock_port(const BaseCtx *ctx, const PortRef &port);
|
||||||
|
@ -253,7 +253,7 @@ class ChainConstrainer
|
|||||||
return i3_next;
|
return i3_next;
|
||||||
return (CellInfo *)nullptr;
|
return (CellInfo *)nullptr;
|
||||||
});
|
});
|
||||||
std::unordered_set<IdString> chained;
|
pool<IdString> chained;
|
||||||
for (auto &base_chain : carry_chains) {
|
for (auto &base_chain : carry_chains) {
|
||||||
for (auto c : base_chain.cells)
|
for (auto c : base_chain.cells)
|
||||||
chained.insert(c->name);
|
chained.insert(c->name);
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <unordered_set>
|
|
||||||
#include "cells.h"
|
#include "cells.h"
|
||||||
#include "chains.h"
|
#include "chains.h"
|
||||||
#include "design_utils.h"
|
#include "design_utils.h"
|
||||||
@ -35,7 +34,7 @@ static void pack_lut_lutffs(Context *ctx)
|
|||||||
{
|
{
|
||||||
log_info("Packing LUT-FFs..\n");
|
log_info("Packing LUT-FFs..\n");
|
||||||
int lut_only = 0, lut_and_ff = 0;
|
int lut_only = 0, lut_and_ff = 0;
|
||||||
std::unordered_set<IdString> packed_cells;
|
pool<IdString> packed_cells;
|
||||||
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
||||||
for (auto &cell : ctx->cells) {
|
for (auto &cell : ctx->cells) {
|
||||||
CellInfo *ci = cell.second.get();
|
CellInfo *ci = cell.second.get();
|
||||||
@ -100,7 +99,7 @@ static void pack_nonlut_ffs(Context *ctx)
|
|||||||
{
|
{
|
||||||
log_info("Packing non-LUT FFs..\n");
|
log_info("Packing non-LUT FFs..\n");
|
||||||
|
|
||||||
std::unordered_set<IdString> packed_cells;
|
pool<IdString> packed_cells;
|
||||||
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
||||||
int ff_only = 0;
|
int ff_only = 0;
|
||||||
|
|
||||||
@ -144,8 +143,8 @@ static bool net_is_constant(const Context *ctx, NetInfo *net, bool &value)
|
|||||||
static void pack_carries(Context *ctx)
|
static void pack_carries(Context *ctx)
|
||||||
{
|
{
|
||||||
log_info("Packing carries..\n");
|
log_info("Packing carries..\n");
|
||||||
std::unordered_set<IdString> exhausted_cells;
|
pool<IdString> exhausted_cells;
|
||||||
std::unordered_set<IdString> packed_cells;
|
pool<IdString> packed_cells;
|
||||||
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
||||||
int carry_only = 0;
|
int carry_only = 0;
|
||||||
|
|
||||||
@ -274,7 +273,7 @@ static void pack_ram(Context *ctx)
|
|||||||
{
|
{
|
||||||
log_info("Packing RAMs..\n");
|
log_info("Packing RAMs..\n");
|
||||||
|
|
||||||
std::unordered_set<IdString> packed_cells;
|
pool<IdString> packed_cells;
|
||||||
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
||||||
|
|
||||||
for (auto &cell : ctx->cells) {
|
for (auto &cell : ctx->cells) {
|
||||||
@ -466,8 +465,8 @@ static bool is_ice_iob(const Context *ctx, const CellInfo *cell)
|
|||||||
// Pack IO buffers
|
// Pack IO buffers
|
||||||
static void pack_io(Context *ctx)
|
static void pack_io(Context *ctx)
|
||||||
{
|
{
|
||||||
std::unordered_set<IdString> packed_cells;
|
pool<IdString> packed_cells;
|
||||||
std::unordered_set<IdString> delete_nets;
|
pool<IdString> delete_nets;
|
||||||
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
||||||
log_info("Packing IOs..\n");
|
log_info("Packing IOs..\n");
|
||||||
|
|
||||||
@ -1119,7 +1118,7 @@ static void pack_special(Context *ctx)
|
|||||||
{
|
{
|
||||||
log_info("Packing special functions..\n");
|
log_info("Packing special functions..\n");
|
||||||
|
|
||||||
std::unordered_set<IdString> packed_cells;
|
pool<IdString> packed_cells;
|
||||||
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
||||||
|
|
||||||
// Handle LED_DRV_CUR first to set the ledCurConnected flag before RGB_DRV is handled below.
|
// Handle LED_DRV_CUR first to set the ledCurConnected flag before RGB_DRV is handled below.
|
||||||
@ -1299,7 +1298,7 @@ void pack_plls(Context *ctx)
|
|||||||
{
|
{
|
||||||
log_info("Packing PLLs..\n");
|
log_info("Packing PLLs..\n");
|
||||||
|
|
||||||
std::unordered_set<IdString> packed_cells;
|
pool<IdString> packed_cells;
|
||||||
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
||||||
for (auto &cell : ctx->cells) {
|
for (auto &cell : ctx->cells) {
|
||||||
CellInfo *ci = cell.second.get();
|
CellInfo *ci = cell.second.get();
|
||||||
|
@ -403,12 +403,12 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
const ChipInfoPOD *chip_info;
|
const ChipInfoPOD *chip_info;
|
||||||
const PackageInfoPOD *package_info;
|
const PackageInfoPOD *package_info;
|
||||||
|
|
||||||
mutable std::unordered_map<IdStringList, PipId> pip_by_name;
|
mutable dict<IdStringList, PipId> pip_by_name;
|
||||||
|
|
||||||
// fast access to X and Y IdStrings for building object names
|
// fast access to X and Y IdStrings for building object names
|
||||||
std::vector<IdString> x_ids, y_ids;
|
std::vector<IdString> x_ids, y_ids;
|
||||||
// inverse of the above for name->object mapping
|
// inverse of the above for name->object mapping
|
||||||
std::unordered_map<IdString, int> id_to_x, id_to_y;
|
dict<IdString, int> id_to_x, id_to_y;
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
template <typename Id> const TileTypePOD *tile_info(Id &id) const
|
template <typename Id> const TileTypePOD *tile_info(Id &id) const
|
||||||
|
@ -175,6 +175,6 @@ void dff_to_lc(Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void nxio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *iob, std::unordered_set<IdString> &todelete_cells) {}
|
void nxio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *iob, pool<IdString> &todelete_cells) {}
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
@ -49,7 +49,7 @@ void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff = tr
|
|||||||
void dff_to_lc(Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut = false);
|
void dff_to_lc(Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut = false);
|
||||||
|
|
||||||
// Convert a nextpnr IO buffer to a GENERIC_IOB
|
// Convert a nextpnr IO buffer to a GENERIC_IOB
|
||||||
void nxio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *sbio, std::unordered_set<IdString> &todelete_cells);
|
void nxio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *sbio, pool<IdString> &todelete_cells);
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <unordered_set>
|
|
||||||
#include "cells.h"
|
#include "cells.h"
|
||||||
#include "design_utils.h"
|
#include "design_utils.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
@ -33,7 +32,7 @@ static void pack_lut_lutffs(Context *ctx)
|
|||||||
{
|
{
|
||||||
log_info("Packing LUT-FFs..\n");
|
log_info("Packing LUT-FFs..\n");
|
||||||
|
|
||||||
std::unordered_set<IdString> packed_cells;
|
pool<IdString> packed_cells;
|
||||||
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
||||||
for (auto &cell : ctx->cells) {
|
for (auto &cell : ctx->cells) {
|
||||||
CellInfo *ci = cell.second.get();
|
CellInfo *ci = cell.second.get();
|
||||||
@ -91,7 +90,7 @@ static void pack_remaining_ffs(Context *ctx)
|
|||||||
{
|
{
|
||||||
log_info("Packing remaining FFs..\n");
|
log_info("Packing remaining FFs..\n");
|
||||||
|
|
||||||
std::unordered_set<IdString> packed_cells;
|
pool<IdString> packed_cells;
|
||||||
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
||||||
|
|
||||||
for (auto &cell : ctx->cells) {
|
for (auto &cell : ctx->cells) {
|
||||||
@ -130,7 +129,7 @@ static void set_net_constant(Context *ctx, NetInfo *orig, NetInfo *constnet, boo
|
|||||||
{
|
{
|
||||||
(void)constval;
|
(void)constval;
|
||||||
|
|
||||||
std::unordered_set<IdString> packed_cells;
|
pool<IdString> packed_cells;
|
||||||
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
||||||
|
|
||||||
orig->driver.cell = nullptr;
|
orig->driver.cell = nullptr;
|
||||||
@ -233,7 +232,7 @@ static bool is_facade_iob(const Context *ctx, const CellInfo *cell) { return cel
|
|||||||
// attributes.
|
// attributes.
|
||||||
static void pack_io(Context *ctx)
|
static void pack_io(Context *ctx)
|
||||||
{
|
{
|
||||||
std::unordered_set<IdString> packed_cells;
|
pool<IdString> packed_cells;
|
||||||
|
|
||||||
log_info("Packing IOs..\n");
|
log_info("Packing IOs..\n");
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ struct BelInfo
|
|||||||
// For cases where we need to determine an original block index, due to multiple bels at the same tile this
|
// For cases where we need to determine an original block index, due to multiple bels at the same tile this
|
||||||
// might not be the same as the nextpnr z-coordinate
|
// might not be the same as the nextpnr z-coordinate
|
||||||
int block_index;
|
int block_index;
|
||||||
std::unordered_map<IdString, PinInfo> pins;
|
dict<IdString, PinInfo> pins;
|
||||||
// Info for different kinds of bels
|
// Info for different kinds of bels
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
@ -153,7 +153,7 @@ struct UpDownhillPipRange
|
|||||||
UpDownhillPipIterator b, e;
|
UpDownhillPipIterator b, e;
|
||||||
|
|
||||||
UpDownhillPipRange(const std::vector<WireId> &v, WireId other_wire, bool is_uphill)
|
UpDownhillPipRange(const std::vector<WireId> &v, WireId other_wire, bool is_uphill)
|
||||||
: b(v.cbegin(), other_wire, is_uphill), e(v.cend(), other_wire, is_uphill){};
|
: b(v.begin(), other_wire, is_uphill), e(v.end(), other_wire, is_uphill){};
|
||||||
|
|
||||||
UpDownhillPipIterator begin() const { return b; }
|
UpDownhillPipIterator begin() const { return b; }
|
||||||
UpDownhillPipIterator end() const { return e; }
|
UpDownhillPipIterator end() const { return e; }
|
||||||
@ -161,7 +161,7 @@ struct UpDownhillPipRange
|
|||||||
|
|
||||||
// This iterates over the list of wires, and for each wire yields its uphill pips, as an efficient way of going over
|
// This iterates over the list of wires, and for each wire yields its uphill pips, as an efficient way of going over
|
||||||
// all the pips in the device
|
// all the pips in the device
|
||||||
using WireMapIterator = std::unordered_map<WireId, WireInfo>::const_iterator;
|
using WireMapIterator = dict<WireId, WireInfo>::const_iterator;
|
||||||
struct AllPipIterator
|
struct AllPipIterator
|
||||||
{
|
{
|
||||||
WireMapIterator base, end;
|
WireMapIterator base, end;
|
||||||
@ -196,8 +196,7 @@ struct AllPipRange
|
|||||||
{
|
{
|
||||||
AllPipIterator b, e;
|
AllPipIterator b, e;
|
||||||
|
|
||||||
AllPipRange(const std::unordered_map<WireId, WireInfo> &wires)
|
AllPipRange(const dict<WireId, WireInfo> &wires) : b(wires.begin(), wires.end(), -1), e(wires.end(), wires.end(), 0)
|
||||||
: b(wires.cbegin(), wires.cend(), -1), e(wires.cend(), wires.cend(), 0)
|
|
||||||
{
|
{
|
||||||
// Starting the begin iterator at index -1 and incrementing it ensures we skip over the first wire if it has no
|
// Starting the begin iterator at index -1 and incrementing it ensures we skip over the first wire if it has no
|
||||||
// uphill pips
|
// uphill pips
|
||||||
@ -211,7 +210,7 @@ struct AllPipRange
|
|||||||
// This transforms a map to a range of keys, used as the wire iterator
|
// This transforms a map to a range of keys, used as the wire iterator
|
||||||
template <typename T> struct key_range
|
template <typename T> struct key_range
|
||||||
{
|
{
|
||||||
key_range(const T &t) : b(t.cbegin()), e(t.cend()){};
|
key_range(const T &t) : b(t.begin()), e(t.end()){};
|
||||||
typename T::const_iterator b, e;
|
typename T::const_iterator b, e;
|
||||||
|
|
||||||
struct xformed_iterator : public T::const_iterator
|
struct xformed_iterator : public T::const_iterator
|
||||||
@ -224,7 +223,7 @@ template <typename T> struct key_range
|
|||||||
xformed_iterator end() const { return xformed_iterator(e); }
|
xformed_iterator end() const { return xformed_iterator(e); }
|
||||||
};
|
};
|
||||||
|
|
||||||
using AllWireRange = key_range<std::unordered_map<WireId, WireInfo>>;
|
using AllWireRange = key_range<dict<WireId, WireInfo>>;
|
||||||
|
|
||||||
struct ArchRanges : BaseArchRanges
|
struct ArchRanges : BaseArchRanges
|
||||||
{
|
{
|
||||||
@ -489,7 +488,7 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
static const std::string defaultRouter;
|
static const std::string defaultRouter;
|
||||||
static const std::vector<std::string> availableRouters;
|
static const std::vector<std::string> availableRouters;
|
||||||
|
|
||||||
std::unordered_map<WireId, WireInfo> wires;
|
dict<WireId, WireInfo> wires;
|
||||||
|
|
||||||
// List of LABs
|
// List of LABs
|
||||||
std::vector<LABInfo> labs;
|
std::vector<LABInfo> labs;
|
||||||
@ -499,13 +498,13 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
|
|
||||||
// Conversion between numbers and rnode types and IdString, for fast wire name implementation
|
// Conversion between numbers and rnode types and IdString, for fast wire name implementation
|
||||||
std::vector<IdString> int2id;
|
std::vector<IdString> int2id;
|
||||||
std::unordered_map<IdString, int> id2int;
|
dict<IdString, int> id2int;
|
||||||
|
|
||||||
std::vector<IdString> rn_t2id;
|
std::vector<IdString> rn_t2id;
|
||||||
std::unordered_map<IdString, CycloneV::rnode_type_t> id2rn_t;
|
dict<IdString, CycloneV::rnode_type_t> id2rn_t;
|
||||||
|
|
||||||
// This structure is only used for nextpnr-created wires
|
// This structure is only used for nextpnr-created wires
|
||||||
std::unordered_map<IdStringList, WireId> npnr_wirebyname;
|
dict<IdStringList, WireId> npnr_wirebyname;
|
||||||
|
|
||||||
std::vector<std::vector<BelInfo>> bels_by_tile;
|
std::vector<std::vector<BelInfo>> bels_by_tile;
|
||||||
std::vector<BelId> all_bels;
|
std::vector<BelId> all_bels;
|
||||||
@ -525,18 +524,18 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
// -------------------------------------------------
|
// -------------------------------------------------
|
||||||
|
|
||||||
void assign_default_pinmap(CellInfo *cell);
|
void assign_default_pinmap(CellInfo *cell);
|
||||||
static const std::unordered_map<IdString, IdString> comb_pinmap;
|
static const dict<IdString, IdString> comb_pinmap;
|
||||||
|
|
||||||
// -------------------------------------------------
|
// -------------------------------------------------
|
||||||
|
|
||||||
typedef std::unordered_map<IdString, CellPinStyle> CellPinsData; // pins.cc
|
typedef dict<IdString, CellPinStyle> CellPinsData; // pins.cc
|
||||||
static const std::unordered_map<IdString, CellPinsData> cell_pins_db; // pins.cc
|
static const dict<IdString, CellPinsData> cell_pins_db; // pins.cc
|
||||||
CellPinStyle get_cell_pin_style(const CellInfo *cell, IdString port) const; // pins.cc
|
CellPinStyle get_cell_pin_style(const CellInfo *cell, IdString port) const; // pins.cc
|
||||||
|
|
||||||
// -------------------------------------------------
|
// -------------------------------------------------
|
||||||
|
|
||||||
// List of IO constraints, used by QSF parser
|
// List of IO constraints, used by QSF parser
|
||||||
std::unordered_map<IdString, std::unordered_map<IdString, Property>> io_attr;
|
dict<IdString, dict<IdString, Property>> io_attr;
|
||||||
void read_qsf(std::istream &in); // qsf.cc
|
void read_qsf(std::istream &in); // qsf.cc
|
||||||
|
|
||||||
// -------------------------------------------------
|
// -------------------------------------------------
|
||||||
|
@ -203,7 +203,7 @@ struct ArchCellInfo : BaseClusterInfo
|
|||||||
} ffInfo;
|
} ffInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unordered_map<IdString, ArchPinInfo> pin_data;
|
dict<IdString, ArchPinInfo> pin_data;
|
||||||
|
|
||||||
CellPinState get_pin_state(IdString pin) const;
|
CellPinState get_pin_state(IdString pin) const;
|
||||||
};
|
};
|
||||||
|
@ -718,7 +718,7 @@ void Arch::reassign_alm_inputs(uint32_t lab, uint8_t alm)
|
|||||||
// - C, E0, and F0 are exclusive to the top LUT5 secion
|
// - C, E0, and F0 are exclusive to the top LUT5 secion
|
||||||
// - D, E1, and F1 are exclusive to the bottom LUT5 section
|
// - D, E1, and F1 are exclusive to the bottom LUT5 section
|
||||||
// First find up to two shared inputs
|
// First find up to two shared inputs
|
||||||
std::unordered_map<IdString, int> shared_nets;
|
dict<IdString, int> shared_nets;
|
||||||
if (luts[0] && luts[1]) {
|
if (luts[0] && luts[1]) {
|
||||||
for (int i = 0; i < luts[0]->combInfo.lut_input_count; i++) {
|
for (int i = 0; i < luts[0]->combInfo.lut_input_count; i++) {
|
||||||
for (int j = 0; j < luts[1]->combInfo.lut_input_count; j++) {
|
for (int j = 0; j < luts[1]->combInfo.lut_input_count; j++) {
|
||||||
@ -826,7 +826,7 @@ void Arch::reassign_alm_inputs(uint32_t lab, uint8_t alm)
|
|||||||
|
|
||||||
// This default cell-bel pin mapping is used to provide estimates during placement only. It will have errors and
|
// This default cell-bel pin mapping is used to provide estimates during placement only. It will have errors and
|
||||||
// overlaps and a correct mapping will be resolved twixt placement and routing
|
// overlaps and a correct mapping will be resolved twixt placement and routing
|
||||||
const std::unordered_map<IdString, IdString> Arch::comb_pinmap = {
|
const dict<IdString, IdString> Arch::comb_pinmap = {
|
||||||
{id_A, id_F0}, // fastest input first
|
{id_A, id_F0}, // fastest input first
|
||||||
{id_B, id_E0}, {id_C, id_D}, {id_D, id_C}, {id_D0, id_C}, {id_D1, id_B},
|
{id_B, id_E0}, {id_C, id_D}, {id_D, id_C}, {id_D0, id_C}, {id_D1, id_B},
|
||||||
{id_E, id_B}, {id_F, id_A}, {id_Q, id_COMBOUT}, {id_SO, id_COMBOUT},
|
{id_E, id_B}, {id_F, id_A}, {id_Q, id_COMBOUT}, {id_SO, id_COMBOUT},
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
const std::unordered_map<IdString, Arch::CellPinsData> Arch::cell_pins_db = {
|
const dict<IdString, Arch::CellPinsData> Arch::cell_pins_db = {
|
||||||
// For combinational cells, inversion and tieing can be implemented by manipulating the LUT function
|
// For combinational cells, inversion and tieing can be implemented by manipulating the LUT function
|
||||||
{id_MISTRAL_ALUT2, {{{}, PINSTYLE_COMB}}},
|
{id_MISTRAL_ALUT2, {{{}, PINSTYLE_COMB}}},
|
||||||
{id_MISTRAL_ALUT3, {{{}, PINSTYLE_COMB}}},
|
{id_MISTRAL_ALUT3, {{{}, PINSTYLE_COMB}}},
|
||||||
|
@ -34,7 +34,7 @@ struct QsfOption
|
|||||||
bool required; // error out if this option isn't passed
|
bool required; // error out if this option isn't passed
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::unordered_map<std::string, std::vector<std::string>> option_map_t;
|
typedef dict<std::string, std::vector<std::string>> option_map_t;
|
||||||
|
|
||||||
struct QsfCommand
|
struct QsfCommand
|
||||||
{
|
{
|
||||||
|
12
nexus/arch.h
12
nexus/arch.h
@ -916,7 +916,7 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
// fast access to X and Y IdStrings for building object names
|
// fast access to X and Y IdStrings for building object names
|
||||||
std::vector<IdString> x_ids, y_ids;
|
std::vector<IdString> x_ids, y_ids;
|
||||||
// inverse of the above for name->object mapping
|
// inverse of the above for name->object mapping
|
||||||
std::unordered_map<IdString, int> id_to_x, id_to_y;
|
dict<IdString, int> id_to_x, id_to_y;
|
||||||
|
|
||||||
// -------------------------------------------------
|
// -------------------------------------------------
|
||||||
|
|
||||||
@ -1181,7 +1181,7 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
|
|
||||||
// for better DSP bounding boxes
|
// for better DSP bounding boxes
|
||||||
void pre_routing();
|
void pre_routing();
|
||||||
std::unordered_set<WireId> dsp_wires, lram_wires;
|
pool<WireId> dsp_wires, lram_wires;
|
||||||
|
|
||||||
// -------------------------------------------------
|
// -------------------------------------------------
|
||||||
|
|
||||||
@ -1271,9 +1271,9 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
|
|
||||||
// -------------------------------------------------
|
// -------------------------------------------------
|
||||||
|
|
||||||
typedef std::unordered_map<IdString, CellPinStyle> CellPinsData;
|
typedef dict<IdString, CellPinStyle> CellPinsData;
|
||||||
|
|
||||||
std::unordered_map<IdString, CellPinsData> cell_pins_db;
|
dict<IdString, CellPinsData> cell_pins_db;
|
||||||
CellPinStyle get_cell_pin_style(const CellInfo *cell, IdString port) const;
|
CellPinStyle get_cell_pin_style(const CellInfo *cell, IdString port) const;
|
||||||
|
|
||||||
void init_cell_pin_data();
|
void init_cell_pin_data();
|
||||||
@ -1361,7 +1361,7 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
|
|
||||||
// -------------------------------------------------
|
// -------------------------------------------------
|
||||||
// Data about different IO standard, mostly used by bitgen
|
// Data about different IO standard, mostly used by bitgen
|
||||||
static const std::unordered_map<std::string, IOTypeData> io_types;
|
static const dict<std::string, IOTypeData> io_types;
|
||||||
int get_io_type_vcc(const std::string &io_type) const;
|
int get_io_type_vcc(const std::string &io_type) const;
|
||||||
bool is_io_type_diff(const std::string &io_type) const;
|
bool is_io_type_diff(const std::string &io_type) const;
|
||||||
bool is_io_type_ref(const std::string &io_type) const;
|
bool is_io_type_ref(const std::string &io_type) const;
|
||||||
@ -1388,7 +1388,7 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
// -------------------------------------------------
|
// -------------------------------------------------
|
||||||
|
|
||||||
// List of IO constraints, used by PDC parser
|
// List of IO constraints, used by PDC parser
|
||||||
std::unordered_map<IdString, std::unordered_map<IdString, Property>> io_attr;
|
dict<IdString, dict<IdString, Property>> io_attr;
|
||||||
|
|
||||||
void read_pdc(std::istream &in);
|
void read_pdc(std::istream &in);
|
||||||
|
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
#define NEXUS_ARCHDEFS_H
|
#define NEXUS_ARCHDEFS_H
|
||||||
|
|
||||||
#include <boost/functional/hash.hpp>
|
#include <boost/functional/hash.hpp>
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
#include "base_clusterinfo.h"
|
#include "base_clusterinfo.h"
|
||||||
#include "hashlib.h"
|
#include "hashlib.h"
|
||||||
@ -184,7 +183,7 @@ struct ArchCellInfo : BaseClusterInfo
|
|||||||
|
|
||||||
int tmg_index = -1;
|
int tmg_index = -1;
|
||||||
// Map from cell/bel ports to logical timing ports
|
// Map from cell/bel ports to logical timing ports
|
||||||
std::unordered_map<IdString, IdString> tmg_portmap;
|
dict<IdString, IdString> tmg_portmap;
|
||||||
};
|
};
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
@ -336,7 +336,7 @@ struct NexusFasmWriter
|
|||||||
pop(2);
|
pop(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_set<BelId> used_io;
|
pool<BelId> used_io;
|
||||||
|
|
||||||
struct BankConfig
|
struct BankConfig
|
||||||
{
|
{
|
||||||
@ -556,7 +556,7 @@ struct NexusFasmWriter
|
|||||||
|
|
||||||
// Which PLL params are 'word' values
|
// Which PLL params are 'word' values
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
const std::unordered_map<std::string, int> pll_word_params = {
|
const dict<std::string, int> pll_word_params = {
|
||||||
{"DIVA", 7}, {"DELA", 7}, {"PHIA", 3}, {"DIVB", 7},
|
{"DIVA", 7}, {"DELA", 7}, {"PHIA", 3}, {"DIVB", 7},
|
||||||
{"DELB", 7}, {"PHIB", 3}, {"DIVC", 7}, {"DELC", 7},
|
{"DELB", 7}, {"PHIB", 3}, {"DIVC", 7}, {"DELC", 7},
|
||||||
{"PHIC", 3}, {"DIVD", 7}, {"DELD", 7}, {"PHID", 3},
|
{"PHIC", 3}, {"DIVD", 7}, {"DELD", 7}, {"PHID", 3},
|
||||||
@ -582,7 +582,7 @@ struct NexusFasmWriter
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Which MIPI params are 'word' values
|
// Which MIPI params are 'word' values
|
||||||
const std::unordered_map<std::string, int> dphy_word_params = {
|
const dict<std::string, int> dphy_word_params = {
|
||||||
{"CM", 8}, {"CN", 5}, {"CO", 3}, {"RSEL", 2}, {"RXCDRP", 2},
|
{"CM", 8}, {"CN", 5}, {"CO", 3}, {"RSEL", 2}, {"RXCDRP", 2},
|
||||||
{"RXDATAWIDTHHS", 2}, {"RXLPRP", 3}, {"TEST_ENBL", 6},
|
{"RXDATAWIDTHHS", 2}, {"RXLPRP", 3}, {"TEST_ENBL", 6},
|
||||||
{"TEST_PATTERN", 32}, {"TST", 4}, {"TXDATAWIDTHHS", 2},
|
{"TEST_PATTERN", 32}, {"TST", 4}, {"TXDATAWIDTHHS", 2},
|
||||||
@ -683,7 +683,7 @@ struct NexusFasmWriter
|
|||||||
write_comment("# Unused bels");
|
write_comment("# Unused bels");
|
||||||
|
|
||||||
// DSP primitives are configured to a default mode; even if unused
|
// DSP primitives are configured to a default mode; even if unused
|
||||||
static const std::unordered_map<IdString, std::vector<std::string>> dsp_defconf = {
|
static const dict<IdString, std::vector<std::string>> dsp_defconf = {
|
||||||
{id_MULT9_CORE,
|
{id_MULT9_CORE,
|
||||||
{
|
{
|
||||||
"GSR.ENABLED",
|
"GSR.ENABLED",
|
||||||
@ -733,7 +733,7 @@ struct NexusFasmWriter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::unordered_map<int, int> bank_vcco;
|
dict<int, int> bank_vcco;
|
||||||
// bank VccO in mV
|
// bank VccO in mV
|
||||||
int get_bank_vcco(const std::string &iostd)
|
int get_bank_vcco(const std::string &iostd)
|
||||||
{
|
{
|
||||||
|
@ -49,7 +49,7 @@ struct NexusGlobalRouter
|
|||||||
// Queue of wires to visit
|
// Queue of wires to visit
|
||||||
std::queue<WireId> visit;
|
std::queue<WireId> visit;
|
||||||
// Wire -> upstream pip
|
// Wire -> upstream pip
|
||||||
std::unordered_map<WireId, PipId> backtrace;
|
dict<WireId, PipId> backtrace;
|
||||||
|
|
||||||
// Lookup source and destination wires
|
// Lookup source and destination wires
|
||||||
WireId src = ctx->getNetinfoSourceWire(net);
|
WireId src = ctx->getNetinfoSourceWire(net);
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
const std::unordered_map<std::string, IOTypeData> Arch::io_types = {
|
const dict<std::string, IOTypeData> Arch::io_types = {
|
||||||
{"LVCMOS33", {IOSTYLE_SE_WR, 330}}, {"LVCMOS25", {IOSTYLE_SE_WR, 250}},
|
{"LVCMOS33", {IOSTYLE_SE_WR, 330}}, {"LVCMOS25", {IOSTYLE_SE_WR, 250}},
|
||||||
{"LVCMOS18", {IOSTYLE_SE_WR, 180}}, {"LVCMOS15", {IOSTYLE_SE_WR, 150}},
|
{"LVCMOS18", {IOSTYLE_SE_WR, 180}}, {"LVCMOS15", {IOSTYLE_SE_WR, 150}},
|
||||||
{"LVCMOS12", {IOSTYLE_SE_WR, 120}}, {"LVCMOS10", {IOSTYLE_SE_WR, 120}},
|
{"LVCMOS12", {IOSTYLE_SE_WR, 120}}, {"LVCMOS10", {IOSTYLE_SE_WR, 120}},
|
||||||
|
@ -106,16 +106,16 @@ struct NexusPacker
|
|||||||
struct XFormRule
|
struct XFormRule
|
||||||
{
|
{
|
||||||
IdString new_type;
|
IdString new_type;
|
||||||
std::unordered_map<IdString, IdString> port_xform;
|
dict<IdString, IdString> port_xform;
|
||||||
std::unordered_map<IdString, std::vector<IdString>> port_multixform;
|
dict<IdString, std::vector<IdString>> port_multixform;
|
||||||
std::unordered_map<IdString, IdString> param_xform;
|
dict<IdString, IdString> param_xform;
|
||||||
std::vector<std::pair<IdString, std::string>> set_attrs;
|
std::vector<std::pair<IdString, std::string>> set_attrs;
|
||||||
std::vector<std::pair<IdString, Property>> set_params;
|
std::vector<std::pair<IdString, Property>> set_params;
|
||||||
std::vector<std::pair<IdString, Property>> default_params;
|
std::vector<std::pair<IdString, Property>> default_params;
|
||||||
std::vector<std::tuple<IdString, IdString, int, int64_t>> parse_params;
|
std::vector<std::tuple<IdString, IdString, int, int64_t>> parse_params;
|
||||||
};
|
};
|
||||||
|
|
||||||
void xform_cell(const std::unordered_map<IdString, XFormRule> &rules, CellInfo *ci)
|
void xform_cell(const dict<IdString, XFormRule> &rules, CellInfo *ci)
|
||||||
{
|
{
|
||||||
auto &rule = rules.at(ci->type);
|
auto &rule = rules.at(ci->type);
|
||||||
ci->type = rule.new_type;
|
ci->type = rule.new_type;
|
||||||
@ -178,7 +178,7 @@ struct NexusPacker
|
|||||||
ci->params[param.first] = param.second;
|
ci->params[param.first] = param.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
void generic_xform(const std::unordered_map<IdString, XFormRule> &rules, bool print_summary = false)
|
void generic_xform(const dict<IdString, XFormRule> &rules, bool print_summary = false)
|
||||||
{
|
{
|
||||||
std::map<std::string, int> cell_count;
|
std::map<std::string, int> cell_count;
|
||||||
std::map<std::string, int> new_types;
|
std::map<std::string, int> new_types;
|
||||||
@ -205,7 +205,7 @@ struct NexusPacker
|
|||||||
void pack_luts()
|
void pack_luts()
|
||||||
{
|
{
|
||||||
log_info("Packing LUTs...\n");
|
log_info("Packing LUTs...\n");
|
||||||
std::unordered_map<IdString, XFormRule> lut_rules;
|
dict<IdString, XFormRule> lut_rules;
|
||||||
lut_rules[id_LUT4].new_type = id_OXIDE_COMB;
|
lut_rules[id_LUT4].new_type = id_OXIDE_COMB;
|
||||||
lut_rules[id_LUT4].port_xform[id_Z] = id_F;
|
lut_rules[id_LUT4].port_xform[id_Z] = id_F;
|
||||||
lut_rules[id_LUT4].parse_params.emplace_back(id_INIT, id_INIT, 16, 0);
|
lut_rules[id_LUT4].parse_params.emplace_back(id_INIT, id_INIT, 16, 0);
|
||||||
@ -229,7 +229,7 @@ struct NexusPacker
|
|||||||
void pack_ffs()
|
void pack_ffs()
|
||||||
{
|
{
|
||||||
log_info("Packing FFs...\n");
|
log_info("Packing FFs...\n");
|
||||||
std::unordered_map<IdString, XFormRule> ff_rules;
|
dict<IdString, XFormRule> ff_rules;
|
||||||
for (auto type : {id_FD1P3BX, id_FD1P3DX, id_FD1P3IX, id_FD1P3JX}) {
|
for (auto type : {id_FD1P3BX, id_FD1P3DX, id_FD1P3IX, id_FD1P3JX}) {
|
||||||
ff_rules[type].new_type = id_OXIDE_FF;
|
ff_rules[type].new_type = id_OXIDE_FF;
|
||||||
ff_rules[type].port_xform[id_CK] = id_CLK;
|
ff_rules[type].port_xform[id_CK] = id_CLK;
|
||||||
@ -262,7 +262,7 @@ struct NexusPacker
|
|||||||
generic_xform(ff_rules, true);
|
generic_xform(ff_rules, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_map<IdString, BelId> reference_bels;
|
dict<IdString, BelId> reference_bels;
|
||||||
|
|
||||||
void autocreate_ports(CellInfo *cell)
|
void autocreate_ports(CellInfo *cell)
|
||||||
{
|
{
|
||||||
@ -549,11 +549,10 @@ struct NexusPacker
|
|||||||
|
|
||||||
void pack_io()
|
void pack_io()
|
||||||
{
|
{
|
||||||
std::unordered_set<IdString> iob_types = {id_IB, id_OB, id_OBZ, id_BB,
|
pool<IdString> iob_types = {id_IB, id_OB, id_OBZ, id_BB, id_BB_I3C_A, id_SEIO33,
|
||||||
id_BB_I3C_A, id_SEIO33, id_SEIO18, id_DIFFIO18,
|
id_SEIO18, id_DIFFIO18, id_SEIO33_CORE, id_SEIO18_CORE, id_DIFFIO18_CORE};
|
||||||
id_SEIO33_CORE, id_SEIO18_CORE, id_DIFFIO18_CORE};
|
|
||||||
|
|
||||||
std::unordered_map<IdString, XFormRule> io_rules;
|
dict<IdString, XFormRule> io_rules;
|
||||||
|
|
||||||
// For the low level primitives, make sure we always preserve their type
|
// For the low level primitives, make sure we always preserve their type
|
||||||
io_rules[id_SEIO33_CORE].new_type = id_SEIO33_CORE;
|
io_rules[id_SEIO33_CORE].new_type = id_SEIO33_CORE;
|
||||||
@ -567,12 +566,12 @@ struct NexusPacker
|
|||||||
io_rules[id_SEIO33].port_xform[id_PADDT] = id_T;
|
io_rules[id_SEIO33].port_xform[id_PADDT] = id_T;
|
||||||
io_rules[id_SEIO33].port_xform[id_IOPAD] = id_B;
|
io_rules[id_SEIO33].port_xform[id_IOPAD] = id_B;
|
||||||
|
|
||||||
io_rules[id_BB_I3C_A] = io_rules[id_SEIO33];
|
io_rules[id_BB_I3C_A] = XFormRule(io_rules[id_SEIO33]);
|
||||||
|
|
||||||
io_rules[id_SEIO18] = io_rules[id_SEIO33];
|
io_rules[id_SEIO18] = XFormRule(io_rules[id_SEIO33]);
|
||||||
io_rules[id_SEIO18].new_type = id_SEIO18_CORE;
|
io_rules[id_SEIO18].new_type = id_SEIO18_CORE;
|
||||||
|
|
||||||
io_rules[id_DIFFIO18] = io_rules[id_SEIO33];
|
io_rules[id_DIFFIO18] = XFormRule(io_rules[id_SEIO33]);
|
||||||
io_rules[id_DIFFIO18].new_type = id_DIFFIO18_CORE;
|
io_rules[id_DIFFIO18].new_type = id_DIFFIO18_CORE;
|
||||||
|
|
||||||
// Stage 0: deal with top level inserted IO buffers
|
// Stage 0: deal with top level inserted IO buffers
|
||||||
@ -677,8 +676,8 @@ struct NexusPacker
|
|||||||
{
|
{
|
||||||
int iter = 0;
|
int iter = 0;
|
||||||
std::queue<WireId> visit;
|
std::queue<WireId> visit;
|
||||||
std::unordered_set<WireId> seen_wires;
|
pool<WireId> seen_wires;
|
||||||
std::unordered_set<BelId> seen_bels;
|
pool<BelId> seen_bels;
|
||||||
|
|
||||||
BelId bel = get_bel_attr(cell);
|
BelId bel = get_bel_attr(cell);
|
||||||
if (bel == BelId())
|
if (bel == BelId())
|
||||||
@ -751,7 +750,7 @@ struct NexusPacker
|
|||||||
return best_bel;
|
return best_bel;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_set<BelId> used_bels;
|
pool<BelId> used_bels;
|
||||||
|
|
||||||
// Pre-place a primitive based on routeability first and distance second
|
// Pre-place a primitive based on routeability first and distance second
|
||||||
bool preplace_prim(CellInfo *cell, IdString pin, bool strict_routing)
|
bool preplace_prim(CellInfo *cell, IdString pin, bool strict_routing)
|
||||||
@ -1024,7 +1023,7 @@ struct NexusPacker
|
|||||||
void convert_prims()
|
void convert_prims()
|
||||||
{
|
{
|
||||||
// Convert primitives from their non-CORE variant to their CORE variant
|
// Convert primitives from their non-CORE variant to their CORE variant
|
||||||
static const std::unordered_map<IdString, IdString> prim_map = {
|
static const dict<IdString, IdString> prim_map = {
|
||||||
{id_OSCA, id_OSC_CORE}, {id_DP16K, id_DP16K_MODE}, {id_PDP16K, id_PDP16K_MODE},
|
{id_OSCA, id_OSC_CORE}, {id_DP16K, id_DP16K_MODE}, {id_PDP16K, id_PDP16K_MODE},
|
||||||
{id_PDPSC16K, id_PDPSC16K_MODE}, {id_SP16K, id_SP16K_MODE}, {id_FIFO16K, id_FIFO16K_MODE},
|
{id_PDPSC16K, id_PDPSC16K_MODE}, {id_SP16K, id_SP16K_MODE}, {id_FIFO16K, id_FIFO16K_MODE},
|
||||||
{id_SP512K, id_SP512K_MODE}, {id_DPSC512K, id_DPSC512K_MODE}, {id_PDPSC512K, id_PDPSC512K_MODE},
|
{id_SP512K, id_SP512K_MODE}, {id_DPSC512K, id_DPSC512K_MODE}, {id_PDPSC512K, id_PDPSC512K_MODE},
|
||||||
@ -1048,7 +1047,7 @@ struct NexusPacker
|
|||||||
|
|
||||||
void pack_bram()
|
void pack_bram()
|
||||||
{
|
{
|
||||||
std::unordered_map<IdString, XFormRule> bram_rules;
|
dict<IdString, XFormRule> bram_rules;
|
||||||
bram_rules[id_DP16K_MODE].new_type = id_OXIDE_EBR;
|
bram_rules[id_DP16K_MODE].new_type = id_OXIDE_EBR;
|
||||||
bram_rules[id_DP16K_MODE].set_params.emplace_back(id_MODE, std::string("DP16K"));
|
bram_rules[id_DP16K_MODE].set_params.emplace_back(id_MODE, std::string("DP16K"));
|
||||||
bram_rules[id_DP16K_MODE].parse_params.emplace_back(id_CSDECODE_A, id_CSDECODE_A, 3, 7);
|
bram_rules[id_DP16K_MODE].parse_params.emplace_back(id_CSDECODE_A, id_CSDECODE_A, 3, 7);
|
||||||
@ -1074,7 +1073,7 @@ struct NexusPacker
|
|||||||
add_bus_xform(bram_rules[id_PDP16K_MODE], "DO", "DOA", 18, 18, 0);
|
add_bus_xform(bram_rules[id_PDP16K_MODE], "DO", "DOA", 18, 18, 0);
|
||||||
|
|
||||||
// Pseudo dual port; single clock
|
// Pseudo dual port; single clock
|
||||||
bram_rules[id_PDPSC16K_MODE] = bram_rules[id_PDP16K_MODE];
|
bram_rules[id_PDPSC16K_MODE] = XFormRule(bram_rules[id_PDP16K_MODE]);
|
||||||
bram_rules[id_PDPSC16K_MODE].set_params.clear();
|
bram_rules[id_PDPSC16K_MODE].set_params.clear();
|
||||||
bram_rules[id_PDPSC16K_MODE].set_params.emplace_back(id_MODE, std::string("PDPSC16K"));
|
bram_rules[id_PDPSC16K_MODE].set_params.emplace_back(id_MODE, std::string("PDPSC16K"));
|
||||||
bram_rules[id_PDPSC16K_MODE].set_params.emplace_back(id_WEAMUX, std::string("1"));
|
bram_rules[id_PDPSC16K_MODE].set_params.emplace_back(id_WEAMUX, std::string("1"));
|
||||||
@ -1096,7 +1095,7 @@ struct NexusPacker
|
|||||||
|
|
||||||
void pack_lram()
|
void pack_lram()
|
||||||
{
|
{
|
||||||
std::unordered_map<IdString, XFormRule> lram_rules;
|
dict<IdString, XFormRule> lram_rules;
|
||||||
lram_rules[id_SP512K_MODE].new_type = id_LRAM_CORE;
|
lram_rules[id_SP512K_MODE].new_type = id_LRAM_CORE;
|
||||||
lram_rules[id_SP512K_MODE].set_params.emplace_back(id_EBR_SP_EN, std::string("ENABLE"));
|
lram_rules[id_SP512K_MODE].set_params.emplace_back(id_EBR_SP_EN, std::string("ENABLE"));
|
||||||
lram_rules[id_SP512K_MODE].port_xform[id_CE] = id_CEA;
|
lram_rules[id_SP512K_MODE].port_xform[id_CE] = id_CEA;
|
||||||
@ -1296,7 +1295,7 @@ struct NexusPacker
|
|||||||
|
|
||||||
// Automatically generate cascade connections downstream of a cell
|
// Automatically generate cascade connections downstream of a cell
|
||||||
// using the temporary placement that we use solely to access the routing graph
|
// using the temporary placement that we use solely to access the routing graph
|
||||||
void auto_cascade_cell(CellInfo *cell, BelId bel, const std::unordered_map<BelId, CellInfo *> &bel2cell)
|
void auto_cascade_cell(CellInfo *cell, BelId bel, const dict<BelId, CellInfo *> &bel2cell)
|
||||||
{
|
{
|
||||||
// Create outputs based on the actual bel
|
// Create outputs based on the actual bel
|
||||||
for (auto bp : ctx->getBelPins(bel)) {
|
for (auto bp : ctx->getBelPins(bel)) {
|
||||||
@ -1322,7 +1321,7 @@ struct NexusPacker
|
|||||||
|
|
||||||
// Standard BFS-type exploration
|
// Standard BFS-type exploration
|
||||||
std::queue<WireId> visit;
|
std::queue<WireId> visit;
|
||||||
std::unordered_set<WireId> in_queue;
|
pool<WireId> in_queue;
|
||||||
visit.push(start_wire);
|
visit.push(start_wire);
|
||||||
in_queue.insert(start_wire);
|
in_queue.insert(start_wire);
|
||||||
int iter = 0;
|
int iter = 0;
|
||||||
@ -1403,8 +1402,8 @@ struct NexusPacker
|
|||||||
|
|
||||||
// We first create a temporary placement so we can access the routing graph
|
// We first create a temporary placement so we can access the routing graph
|
||||||
bool found = false;
|
bool found = false;
|
||||||
std::unordered_map<BelId, CellInfo *> bel2cell;
|
dict<BelId, CellInfo *> bel2cell;
|
||||||
std::unordered_map<IdString, BelId> cell2bel;
|
dict<IdString, BelId> cell2bel;
|
||||||
|
|
||||||
for (BelId root_bel : ctx->getBels()) {
|
for (BelId root_bel : ctx->getBels()) {
|
||||||
if (ctx->getBelType(root_bel) != root->type)
|
if (ctx->getBelType(root_bel) != root->type)
|
||||||
@ -1592,7 +1591,7 @@ struct NexusPacker
|
|||||||
int wide; // DSP is a "wide" (dot-product) variant
|
int wide; // DSP is a "wide" (dot-product) variant
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::unordered_map<IdString, DSPMacroType> dsp_types = {
|
const dict<IdString, DSPMacroType> dsp_types = {
|
||||||
{id_MULT9X9, {9, 9, 0, 18, 1, 0, 0, false, false, -1}},
|
{id_MULT9X9, {9, 9, 0, 18, 1, 0, 0, false, false, -1}},
|
||||||
{id_MULT18X18, {18, 18, 0, 36, 2, 1, 0, false, false, -1}},
|
{id_MULT18X18, {18, 18, 0, 36, 2, 1, 0, false, false, -1}},
|
||||||
{id_MULT18X36, {18, 36, 0, 54, 4, 2, 1, false, false, -1}},
|
{id_MULT18X36, {18, 36, 0, 54, 4, 2, 1, false, false, -1}},
|
||||||
@ -1805,7 +1804,7 @@ struct NexusPacker
|
|||||||
|
|
||||||
auto equals_epsilon = [](delay_t a, delay_t b) { return (std::abs(a - b) / std::max(double(b), 1.0)) < 1e-3; };
|
auto equals_epsilon = [](delay_t a, delay_t b) { return (std::abs(a - b) / std::max(double(b), 1.0)) < 1e-3; };
|
||||||
|
|
||||||
std::unordered_set<IdString> user_constrained, changed_nets;
|
pool<IdString> user_constrained, changed_nets;
|
||||||
for (auto &net : ctx->nets) {
|
for (auto &net : ctx->nets) {
|
||||||
if (net.second->clkconstr != nullptr)
|
if (net.second->clkconstr != nullptr)
|
||||||
user_constrained.insert(net.first);
|
user_constrained.insert(net.first);
|
||||||
@ -1883,7 +1882,7 @@ struct NexusPacker
|
|||||||
const int itermax = 5000;
|
const int itermax = 5000;
|
||||||
while (!changed_nets.empty() && iter < itermax) {
|
while (!changed_nets.empty() && iter < itermax) {
|
||||||
++iter;
|
++iter;
|
||||||
std::unordered_set<IdString> changed_cells;
|
pool<IdString> changed_cells;
|
||||||
for (auto net : changed_nets) {
|
for (auto net : changed_nets) {
|
||||||
for (auto &user : ctx->nets.at(net)->users)
|
for (auto &user : ctx->nets.at(net)->users)
|
||||||
if (user.port == id_CLKI || user.port == id_REFCK)
|
if (user.port == id_CLKI || user.port == id_REFCK)
|
||||||
@ -1893,7 +1892,7 @@ struct NexusPacker
|
|||||||
changed_cells.insert(drv.cell->name);
|
changed_cells.insert(drv.cell->name);
|
||||||
}
|
}
|
||||||
changed_nets.clear();
|
changed_nets.clear();
|
||||||
for (auto cell : sorted(changed_cells)) {
|
for (auto cell : changed_cells) {
|
||||||
CellInfo *ci = ctx->cells.at(cell).get();
|
CellInfo *ci = ctx->cells.at(cell).get();
|
||||||
if (ci->type == id_DCC) {
|
if (ci->type == id_DCC) {
|
||||||
copy_constraint(ci, id_CLKI, id_CLKO, 1);
|
copy_constraint(ci, id_CLKI, id_CLKO, 1);
|
||||||
@ -1945,7 +1944,7 @@ struct NexusPacker
|
|||||||
|
|
||||||
void pack_plls()
|
void pack_plls()
|
||||||
{
|
{
|
||||||
const std::unordered_map<IdString, std::string> pll_defaults = {
|
const dict<IdString, std::string> pll_defaults = {
|
||||||
{id_FLOCK_CTRL, "2X"}, {id_FLOCK_EN, "ENABLED"}, {id_FLOCK_SRC_SEL, "REFCLK"},
|
{id_FLOCK_CTRL, "2X"}, {id_FLOCK_EN, "ENABLED"}, {id_FLOCK_SRC_SEL, "REFCLK"},
|
||||||
{id_DIV_DEL, "0b0000001"}, {id_FBK_PI_RC, "0b1100"}, {id_FBK_PR_IC, "0b1000"},
|
{id_DIV_DEL, "0b0000001"}, {id_FBK_PI_RC, "0b1100"}, {id_FBK_PR_IC, "0b1000"},
|
||||||
};
|
};
|
||||||
@ -1966,7 +1965,7 @@ struct NexusPacker
|
|||||||
// Map LOC attribute on DPHY_CORE to a bel
|
// Map LOC attribute on DPHY_CORE to a bel
|
||||||
// TDPHY_CORE2 is Radiant 2.0 style, DPHY0 is Radiant 2.2
|
// TDPHY_CORE2 is Radiant 2.0 style, DPHY0 is Radiant 2.2
|
||||||
// TODO: LIFCL-17 (perhaps remove the hardcoded map)
|
// TODO: LIFCL-17 (perhaps remove the hardcoded map)
|
||||||
const std::unordered_map<std::string, std::string> dphy_loc_map = {
|
const dict<std::string, std::string> dphy_loc_map = {
|
||||||
{"TDPHY_CORE2", "X4/Y0/TDPHY_CORE2"},
|
{"TDPHY_CORE2", "X4/Y0/TDPHY_CORE2"},
|
||||||
{"DPHY0", "X4/Y0/TDPHY_CORE2"},
|
{"DPHY0", "X4/Y0/TDPHY_CORE2"},
|
||||||
{"TDPHY_CORE26", "X28/Y0/TDPHY_CORE26"},
|
{"TDPHY_CORE26", "X28/Y0/TDPHY_CORE26"},
|
||||||
|
@ -406,7 +406,7 @@ struct PDCParser
|
|||||||
|
|
||||||
TCLValue cmd_ldc_set_port(const std::vector<TCLValue> &arguments)
|
TCLValue cmd_ldc_set_port(const std::vector<TCLValue> &arguments)
|
||||||
{
|
{
|
||||||
std::unordered_map<IdString, Property> args;
|
dict<IdString, Property> args;
|
||||||
for (int i = 1; i < int(arguments.size()); i++) {
|
for (int i = 1; i < int(arguments.size()); i++) {
|
||||||
auto &arg = arguments.at(i);
|
auto &arg = arguments.at(i);
|
||||||
if (arg.is_string) {
|
if (arg.is_string) {
|
||||||
|
@ -24,7 +24,7 @@ NEXTPNR_NAMESPACE_BEGIN
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
static const std::unordered_map<IdString, Arch::CellPinsData> base_cell_pin_data = {
|
static const dict<IdString, Arch::CellPinsData> base_cell_pin_data = {
|
||||||
{id_OXIDE_COMB,
|
{id_OXIDE_COMB,
|
||||||
{
|
{
|
||||||
{id_WCK, PINSTYLE_DEDI},
|
{id_WCK, PINSTYLE_DEDI},
|
||||||
|
Loading…
Reference in New Issue
Block a user