Merge pull request #718 from YosysHQ/gatecat/hashlib

Moving from unordered_{map, set} to hashlib
This commit is contained in:
gatecat 2021-06-03 09:04:34 +01:00 committed by GitHub
commit a3d8b4f9d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
137 changed files with 2155 additions and 1662 deletions

View File

@ -57,7 +57,7 @@ function build_nextpnr {
build_capnp build_capnp
mkdir build mkdir build
pushd build pushd build
cmake .. -DARCH=fpga_interchange -DRAPIDWRIGHT_PATH=${RAPIDWRIGHT_PATH} -DPYTHON_INTERCHANGE_PATH=${PYTHON_INTERCHANGE_PATH} -DUSE_ABSEIL=on cmake .. -DARCH=fpga_interchange -DRAPIDWRIGHT_PATH=${RAPIDWRIGHT_PATH} -DPYTHON_INTERCHANGE_PATH=${PYTHON_INTERCHANGE_PATH}
make nextpnr-fpga_interchange -j`nproc` make nextpnr-fpga_interchange -j`nproc`
popd popd
} }

3
.gitmodules vendored
View File

@ -4,6 +4,3 @@
[submodule "fpga-interchange-schema"] [submodule "fpga-interchange-schema"]
path = 3rdparty/fpga-interchange-schema path = 3rdparty/fpga-interchange-schema
url = https://github.com/SymbiFlow/fpga-interchange-schema.git url = https://github.com/SymbiFlow/fpga-interchange-schema.git
[submodule "3rdparty/abseil-cpp"]
path = 3rdparty/abseil-cpp
url = https://github.com/abseil/abseil-cpp.git

1
3rdparty/abseil-cpp vendored

@ -1 +0,0 @@
Subproject commit a76698790753d2ec71f655cdc84d61bcb27780d4

View File

@ -20,7 +20,6 @@ option(EXTERNAL_CHIPDB "Create build with pre-built chipdb binaries" OFF)
option(WERROR "pass -Werror to compiler (used for CI)" OFF) option(WERROR "pass -Werror to compiler (used for CI)" OFF)
option(PROFILER "Link against libprofiler" OFF) option(PROFILER "Link against libprofiler" OFF)
option(USE_IPO "Compile nextpnr with IPO" ON) option(USE_IPO "Compile nextpnr with IPO" ON)
option(USE_ABSEIL "Compile nextpnr with Abseil for faster hash map" OFF)
if (USE_IPO) if (USE_IPO)
if (ipo_supported) if (ipo_supported)
@ -199,10 +198,6 @@ if (NOT DEFINED CURRENT_GIT_VERSION)
) )
endif() endif()
if (USE_ABSEIL)
add_subdirectory(3rdparty/abseil-cpp EXCLUDE_FROM_ALL)
endif()
if (BUILD_TESTS) if (BUILD_TESTS)
add_subdirectory(3rdparty/googletest/googletest ${CMAKE_CURRENT_BINARY_DIR}/generated/3rdparty/googletest EXCLUDE_FROM_ALL) add_subdirectory(3rdparty/googletest/googletest ${CMAKE_CURRENT_BINARY_DIR}/generated/3rdparty/googletest EXCLUDE_FROM_ALL)
enable_testing() enable_testing()
@ -252,13 +247,7 @@ else()
endif() endif()
set(EXTRA_LIB_DEPS) set(EXTRA_LIB_DEPS)
if (USE_ABSEIL)
if (NOT USE_THREADS)
message(FATAL_ERROR "Abseil without threads is not supported")
endif()
list(APPEND EXTRA_LIB_DEPS absl::flat_hash_map)
list(APPEND EXTRA_LIB_DEPS absl::flat_hash_set)
endif()
if(PROFILER) if(PROFILER)
list(APPEND EXTRA_LIB_DEPS profiler) list(APPEND EXTRA_LIB_DEPS profiler)
endif() endif()
@ -336,9 +325,6 @@ foreach (family ${ARCH})
target_compile_definitions(${target} PRIVATE QT_NO_KEYWORDS) target_compile_definitions(${target} PRIVATE QT_NO_KEYWORDS)
target_link_libraries(${target} LINK_PUBLIC gui_${family} ${GUI_LIBRARY_FILES_${ufamily}}) target_link_libraries(${target} LINK_PUBLIC gui_${family} ${GUI_LIBRARY_FILES_${ufamily}})
endif() endif()
if (USE_ABSEIL)
target_compile_definitions(${target} PRIVATE USE_ABSEIL)
endif()
if (BUILD_PYTHON) if (BUILD_PYTHON)
target_link_libraries(${target} LINK_PUBLIC ${PYTHON_LIBRARIES}) target_link_libraries(${target} LINK_PUBLIC ${PYTHON_LIBRARIES})
if (STATIC_BUILD) if (STATIC_BUILD)

View File

@ -108,7 +108,7 @@ void archcheck_locs(const Context *ctx)
for (int x = 0; x < ctx->getGridDimX(); x++) for (int x = 0; x < ctx->getGridDimX(); x++)
for (int y = 0; y < ctx->getGridDimY(); y++) { for (int y = 0; y < ctx->getGridDimY(); y++) {
dbg("> %d %d\n", x, y); dbg("> %d %d\n", x, y);
std::unordered_set<int> usedz; pool<int> usedz;
for (int z = 0; z < ctx->getTileBelDimZ(x, y); z++) { for (int z = 0; z < ctx->getTileBelDimZ(x, y); z++) {
BelId bel = ctx->getBelByLocation(Loc(x, y, z)); BelId bel = ctx->getBelByLocation(Loc(x, y, z));
@ -162,10 +162,10 @@ struct LruWireCacheMap
// list is oldest wire in cache. // list is oldest wire in cache.
std::list<WireId> last_access_list; std::list<WireId> last_access_list;
// Quick wire -> list element lookup. // Quick wire -> list element lookup.
std::unordered_map<WireId, std::list<WireId>::iterator> last_access_map; dict<WireId, std::list<WireId>::iterator> last_access_map;
std::unordered_map<PipId, WireId> pips_downhill; dict<PipId, WireId> pips_downhill;
std::unordered_map<PipId, WireId> pips_uphill; dict<PipId, WireId> pips_uphill;
void removeWireFromCache(WireId wire_to_remove) void removeWireFromCache(WireId wire_to_remove)
{ {
@ -255,8 +255,8 @@ void archcheck_conn(const Context *ctx)
log_info("Checking all wires...\n"); log_info("Checking all wires...\n");
#ifndef USING_LRU_CACHE #ifndef USING_LRU_CACHE
std::unordered_map<PipId, WireId> pips_downhill; dict<PipId, WireId> pips_downhill;
std::unordered_map<PipId, WireId> pips_uphill; dict<PipId, WireId> pips_uphill;
#endif #endif
for (WireId wire : ctx->getWires()) { for (WireId wire : ctx->getWires()) {
@ -347,7 +347,7 @@ void archcheck_buckets(const Context *ctx)
for (BelBucketId bucket : ctx->getBelBuckets()) { for (BelBucketId bucket : ctx->getBelBuckets()) {
// Find out which cell types are in this bucket. // Find out which cell types are in this bucket.
std::unordered_set<IdString> cell_types_in_bucket; pool<IdString> cell_types_in_bucket;
for (IdString cell_type : ctx->getCellTypes()) { for (IdString cell_type : ctx->getCellTypes()) {
if (ctx->getBelBucketForCellType(cell_type) == bucket) { if (ctx->getBelBucketForCellType(cell_type) == bucket) {
cell_types_in_bucket.insert(cell_type); cell_types_in_bucket.insert(cell_type);
@ -356,9 +356,9 @@ void archcheck_buckets(const Context *ctx)
// Make sure that all cell types in this bucket have at least one // Make sure that all cell types in this bucket have at least one
// BelId they can be placed at. // BelId they can be placed at.
std::unordered_set<IdString> cell_types_unused; pool<IdString> cell_types_unused;
std::unordered_set<BelId> bels_in_bucket; pool<BelId> bels_in_bucket;
for (BelId bel : ctx->getBelsInBucket(bucket)) { for (BelId bel : ctx->getBelsInBucket(bucket)) {
BelBucketId bucket2 = ctx->getBelBucketForBel(bel); BelBucketId bucket2 = ctx->getBelBucketForBel(bel);
log_assert(bucket == bucket2); log_assert(bucket == bucket2);

View File

@ -148,7 +148,7 @@ template <typename R> struct BaseArch : ArchAPI<R>
virtual char getNameDelimiter() const override { return ' '; } virtual char getNameDelimiter() const override { return ' '; }
// Bel methods // Bel methods
virtual uint32_t getBelChecksum(BelId bel) const override { return uint32_t(std::hash<BelId>()(bel)); } virtual uint32_t getBelChecksum(BelId bel) const override { return bel.hash(); }
virtual void bindBel(BelId bel, CellInfo *cell, PlaceStrength strength) override virtual void bindBel(BelId bel, CellInfo *cell, PlaceStrength strength) override
{ {
NPNR_ASSERT(bel != BelId()); NPNR_ASSERT(bel != BelId());
@ -196,7 +196,7 @@ template <typename R> struct BaseArch : ArchAPI<R>
{ {
return empty_if_possible<typename R::WireAttrsRangeT>(); return empty_if_possible<typename R::WireAttrsRangeT>();
} }
virtual uint32_t getWireChecksum(WireId wire) const override { return uint32_t(std::hash<WireId>()(wire)); } virtual uint32_t getWireChecksum(WireId wire) const override { return wire.hash(); }
virtual void bindWire(WireId wire, NetInfo *net, PlaceStrength strength) override virtual void bindWire(WireId wire, NetInfo *net, PlaceStrength strength) override
{ {
@ -244,7 +244,7 @@ template <typename R> struct BaseArch : ArchAPI<R>
{ {
return empty_if_possible<typename R::PipAttrsRangeT>(); return empty_if_possible<typename R::PipAttrsRangeT>();
} }
virtual uint32_t getPipChecksum(PipId pip) const override { return uint32_t(std::hash<PipId>()(pip)); } virtual uint32_t getPipChecksum(PipId pip) const override { return pip.hash(); }
virtual void bindPip(PipId pip, NetInfo *net, PlaceStrength strength) override virtual void bindPip(PipId pip, NetInfo *net, PlaceStrength strength) override
{ {
NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip != PipId());
@ -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));

View File

@ -28,6 +28,7 @@
#include <boost/thread.hpp> #include <boost/thread.hpp>
#endif #endif
#include "hashlib.h"
#include "idstring.h" #include "idstring.h"
#include "nextpnr_namespaces.h" #include "nextpnr_namespaces.h"
#include "nextpnr_types.h" #include "nextpnr_types.h"
@ -59,29 +60,29 @@ struct BaseCtx
mutable StrRingBuffer log_strs; mutable StrRingBuffer log_strs;
// Project settings and config switches // Project settings and config switches
std::unordered_map<IdString, Property> settings; dict<IdString, Property> settings;
// Placed nets and cells. // Placed nets and cells.
std::unordered_map<IdString, std::unique_ptr<NetInfo>> nets; dict<IdString, std::unique_ptr<NetInfo>> nets;
std::unordered_map<IdString, std::unique_ptr<CellInfo>> cells; dict<IdString, std::unique_ptr<CellInfo>> cells;
// Hierarchical (non-leaf) cells by full path // Hierarchical (non-leaf) cells by full path
std::unordered_map<IdString, HierarchicalCell> hierarchy; dict<IdString, HierarchicalCell> hierarchy;
// This is the root of the above structure // This is the root of the above structure
IdString top_module; IdString top_module;
// Aliases for nets, which may have more than one name due to assignments and hierarchy // Aliases for nets, which may have more than one name due to assignments and hierarchy
std::unordered_map<IdString, IdString> net_aliases; dict<IdString, IdString> net_aliases;
// Top-level ports // Top-level ports
std::unordered_map<IdString, PortInfo> ports; dict<IdString, PortInfo> ports;
std::unordered_map<IdString, CellInfo *> port_cells; dict<IdString, CellInfo *> port_cells;
// Floorplanning regions // Floorplanning regions
std::unordered_map<IdString, std::unique_ptr<Region>> region; dict<IdString, std::unique_ptr<Region>> region;
// Context meta data // Context meta data
std::unordered_map<IdString, Property> attrs; dict<IdString, Property> attrs;
Context *as_ctx = nullptr; Context *as_ctx = nullptr;
@ -186,10 +187,10 @@ struct BaseCtx
bool allUiReload = true; bool allUiReload = true;
bool frameUiReload = false; bool frameUiReload = false;
std::unordered_set<BelId> belUiReload; pool<BelId> belUiReload;
std::unordered_set<WireId> wireUiReload; pool<WireId> wireUiReload;
std::unordered_set<PipId> pipUiReload; pool<PipId> pipUiReload;
std::unordered_set<GroupId> groupUiReload; pool<GroupId> groupUiReload;
void refreshUi() { allUiReload = true; } void refreshUi() { allUiReload = true; }

View File

@ -37,10 +37,10 @@ std::vector<CellChain> find_chains(const Context *ctx, F1 cell_type_predicate, F
{ {
std::set<IdString> chained; std::set<IdString> chained;
std::vector<CellChain> chains; std::vector<CellChain> chains;
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
if (chained.find(cell.first) != chained.end()) if (chained.find(cell.first) != chained.end())
continue; continue;
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (cell_type_predicate(ctx, ci)) { if (cell_type_predicate(ctx, ci)) {
CellInfo *start = ci; CellInfo *start = ci;
CellInfo *prev_start = ci; CellInfo *prev_start = ci;

View File

@ -458,7 +458,7 @@ int CommandHandler::exec()
if (executeBeforeContext()) if (executeBeforeContext())
return 0; return 0;
std::unordered_map<std::string, Property> values; dict<std::string, Property> values;
std::unique_ptr<Context> ctx = createContext(values); std::unique_ptr<Context> ctx = createContext(values);
setupContext(ctx.get()); setupContext(ctx.get());
setupArchContext(ctx.get()); setupArchContext(ctx.get());
@ -475,7 +475,7 @@ int CommandHandler::exec()
std::unique_ptr<Context> CommandHandler::load_json(std::string filename) std::unique_ptr<Context> CommandHandler::load_json(std::string filename)
{ {
std::unordered_map<std::string, Property> values; dict<std::string, Property> values;
std::unique_ptr<Context> ctx = createContext(values); std::unique_ptr<Context> ctx = createContext(values);
setupContext(ctx.get()); setupContext(ctx.get());
setupArchContext(ctx.get()); setupArchContext(ctx.get());

View File

@ -42,7 +42,7 @@ class CommandHandler
protected: protected:
virtual void setupArchContext(Context *ctx) = 0; virtual void setupArchContext(Context *ctx) = 0;
virtual std::unique_ptr<Context> createContext(std::unordered_map<std::string, Property> &values) = 0; virtual std::unique_ptr<Context> createContext(dict<std::string, Property> &values) = 0;
virtual po::options_description getArchOptions() = 0; virtual po::options_description getArchOptions() = 0;
virtual void validate(){}; virtual void validate(){};
virtual void customAfterLoad(Context *ctx){}; virtual void customAfterLoad(Context *ctx){};

View File

@ -21,11 +21,11 @@
#define CONSTRAINTS_H #define CONSTRAINTS_H
#include <cstdint> #include <cstdint>
#include <unordered_map>
#include <vector> #include <vector>
#include "archdefs.h" #include "archdefs.h"
#include "exclusive_state_groups.h" #include "exclusive_state_groups.h"
#include "hashlib.h"
#include "idstring.h" #include "idstring.h"
#include "nextpnr_namespaces.h" #include "nextpnr_namespaces.h"
@ -53,7 +53,7 @@ template <std::size_t StateCount, typename StateType = int8_t, typename CountTyp
}; };
typedef ExclusiveStateGroup<StateCount, StateType, CountType> TagState; typedef ExclusiveStateGroup<StateCount, StateType, CountType> TagState;
std::unordered_map<uint32_t, std::vector<typename TagState::Definition>> definitions; dict<uint32_t, std::vector<typename TagState::Definition>> definitions;
template <typename ConstraintRange> void bindBel(TagState *tags, const ConstraintRange constraints); template <typename ConstraintRange> void bindBel(TagState *tags, const ConstraintRange constraints);

View File

@ -389,8 +389,8 @@ struct FixupHierarchyWorker
// Update hierarchy structure for nets and cells that have hiercell set // Update hierarchy structure for nets and cells that have hiercell set
void rebuild_hierarchy() void rebuild_hierarchy()
{ {
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (ci->hierpath == IdString()) if (ci->hierpath == IdString())
ci->hierpath = ctx->top_module; ci->hierpath = ctx->top_module;
auto &hc = ctx->hierarchy.at(ci->hierpath); auto &hc = ctx->hierarchy.at(ci->hierpath);

View File

@ -50,7 +50,7 @@ struct Context : Arch, DeterministicRNG
// provided by router1.cc // provided by router1.cc
bool checkRoutedDesign() const; bool checkRoutedDesign() const;
bool getActualRouteDelay(WireId src_wire, WireId dst_wire, delay_t *delay = nullptr, bool getActualRouteDelay(WireId src_wire, WireId dst_wire, delay_t *delay = nullptr,
std::unordered_map<WireId, PipId> *route = nullptr, bool useEstimate = true); dict<WireId, PipId> *route = nullptr, bool useEstimate = true);
// -------------------------------------------------------------- // --------------------------------------------------------------
// call after changing hierpath or adding/removing nets and cells // call after changing hierpath or adding/removing nets and cells

View File

@ -178,10 +178,10 @@ struct FastBels
const bool check_bel_available; const bool check_bel_available;
const int minBelsForGridPick; const int minBelsForGridPick;
std::unordered_map<IdString, TypeData> cell_types; dict<IdString, TypeData> cell_types;
std::vector<std::unique_ptr<FastBelsData>> fast_bels_by_cell_type; std::vector<std::unique_ptr<FastBelsData>> fast_bels_by_cell_type;
std::unordered_map<BelBucketId, TypeData> partition_types; dict<BelBucketId, TypeData> partition_types;
std::vector<std::unique_ptr<FastBelsData>> fast_bels_by_partition_type; std::vector<std::unique_ptr<FastBelsData>> fast_bels_by_partition_type;
}; };

View File

@ -1,63 +0,0 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2021 Symbiflow Authors
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#ifndef HASH_TABLE_H
#define HASH_TABLE_H
#if defined(USE_ABSEIL)
#include <absl/container/flat_hash_map.h>
#include <absl/container/flat_hash_set.h>
#else
#include <unordered_map>
#include <unordered_set>
#endif
#include <boost/functional/hash.hpp>
#include "nextpnr_namespaces.h"
NEXTPNR_NAMESPACE_BEGIN
namespace HashTables {
#if defined(USE_ABSEIL)
template <typename Key, typename Value, typename Hash = std::hash<Key>>
using HashMap = absl::flat_hash_map<Key, Value, Hash>;
template <typename Value, typename Hash = std::hash<Value>> using HashSet = absl::flat_hash_set<Value, Hash>;
#else
template <typename Key, typename Value, typename Hash = std::hash<Key>>
using HashMap = std::unordered_map<Key, Value, Hash>;
template <typename Value, typename Hash = std::hash<Value>> using HashSet = std::unordered_set<Value, Hash>;
#endif
}; // namespace HashTables
struct PairHash
{
template <typename T1, typename T2> std::size_t operator()(const std::pair<T1, T2> &idp) const noexcept
{
std::size_t seed = 0;
boost::hash_combine(seed, std::hash<T1>()(idp.first));
boost::hash_combine(seed, std::hash<T2>()(idp.second));
return seed;
}
};
NEXTPNR_NAMESPACE_END
#endif /* HASH_TABLE_H */

1196
common/hashlib.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -56,18 +56,10 @@ struct IdString
bool operator!=(const IdString &other) const { return index != other.index; } bool operator!=(const IdString &other) const { return index != other.index; }
bool empty() const { return index == 0; } bool empty() const { return index == 0; }
unsigned int hash() const { return index; }
}; };
NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_END
namespace std {
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX IdString>
{
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX IdString &obj) const noexcept
{
return std::hash<int>()(obj.index);
}
};
} // namespace std
#endif /* IDSTRING_H */ #endif /* IDSTRING_H */

View File

@ -22,6 +22,7 @@
#define IDSTRING_LIST_H #define IDSTRING_LIST_H
#include <boost/functional/hash.hpp> #include <boost/functional/hash.hpp>
#include "hashlib.h"
#include "idstring.h" #include "idstring.h"
#include "nextpnr_namespaces.h" #include "nextpnr_namespaces.h"
#include "sso_array.h" #include "sso_array.h"
@ -67,22 +68,16 @@ struct IdStringList
static IdStringList concat(IdStringList a, IdStringList b); static IdStringList concat(IdStringList a, IdStringList b);
IdStringList slice(size_t s, size_t e) const; IdStringList slice(size_t s, size_t e) const;
unsigned int hash() const
{
unsigned int h = mkhash_init;
for (const auto &val : ids)
h = mkhash(h, val.hash());
return h;
}
}; };
NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_END
namespace std {
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX IdStringList>
{
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX IdStringList &obj) const noexcept
{
std::size_t seed = 0;
boost::hash_combine(seed, hash<size_t>()(obj.size()));
for (auto &id : obj)
boost::hash_combine(seed, hash<NEXTPNR_NAMESPACE_PREFIX IdString>()(id));
return seed;
}
};
} // namespace std
#endif /* IDSTRING_LIST_H */ #endif /* IDSTRING_LIST_H */

View File

@ -38,7 +38,7 @@ log_write_type log_write_function = nullptr;
std::string log_last_error; std::string log_last_error;
void (*log_error_atexit)() = NULL; void (*log_error_atexit)() = NULL;
std::unordered_map<LogLevel, int> message_count_by_level; dict<LogLevel, int, loglevel_hash_ops> message_count_by_level;
static int log_newline_count = 0; static int log_newline_count = 0;
bool had_nonfatal_error = false; bool had_nonfatal_error = false;

View File

@ -26,8 +26,8 @@
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <string> #include <string>
#include <unordered_map>
#include <vector> #include <vector>
#include "hashlib.h"
#include "nextpnr_namespaces.h" #include "nextpnr_namespaces.h"
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
@ -51,13 +51,19 @@ enum class LogLevel
ALWAYS_MSG ALWAYS_MSG
}; };
struct loglevel_hash_ops
{
static inline bool cmp(LogLevel a, LogLevel b) { return a == b; }
static inline unsigned int hash(LogLevel a) { return unsigned(a); }
};
extern std::vector<std::pair<std::ostream *, LogLevel>> log_streams; extern std::vector<std::pair<std::ostream *, LogLevel>> log_streams;
extern log_write_type log_write_function; extern log_write_type log_write_function;
extern std::string log_last_error; extern std::string log_last_error;
extern void (*log_error_atexit)(); extern void (*log_error_atexit)();
extern bool had_nonfatal_error; extern bool had_nonfatal_error;
extern std::unordered_map<LogLevel, int> message_count_by_level; extern dict<LogLevel, int, loglevel_hash_ops> message_count_by_level;
std::string stringf(const char *fmt, ...); std::string stringf(const char *fmt, ...);
std::string vstringf(const char *fmt, va_list ap); std::string vstringf(const char *fmt, va_list ap);
@ -83,14 +89,4 @@ static inline void log_assert_worker(bool cond, const char *expr, const char *fi
NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_END
namespace std {
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX LogLevel>
{
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX LogLevel &loglevel) const noexcept
{
return std::hash<int>()((int)loglevel);
}
};
} // namespace std
#endif #endif

View File

@ -30,6 +30,7 @@
#include <boost/functional/hash.hpp> #include <boost/functional/hash.hpp>
#include <string> #include <string>
#include "hashlib.h"
#include "idstring.h" #include "idstring.h"
#include "nextpnr_namespaces.h" #include "nextpnr_namespaces.h"
@ -89,6 +90,7 @@ struct Loc
bool operator==(const Loc &other) const { return (x == other.x) && (y == other.y) && (z == other.z); } bool operator==(const Loc &other) const { return (x == other.x) && (y == other.y) && (z == other.z); }
bool operator!=(const Loc &other) const { return (x != other.x) || (y != other.y) || (z != other.z); } bool operator!=(const Loc &other) const { return (x != other.x) || (y != other.y) || (z != other.z); }
unsigned int hash() const { return mkhash(x, mkhash(y, z)); }
}; };
struct ArcBounds struct ArcBounds
@ -128,19 +130,4 @@ enum PlaceStrength
NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_END
namespace std {
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX Loc>
{
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX Loc &obj) const noexcept
{
std::size_t seed = 0;
boost::hash_combine(seed, hash<int>()(obj.x));
boost::hash_combine(seed, hash<int>()(obj.y));
boost::hash_combine(seed, hash<int>()(obj.z));
return seed;
}
};
} // namespace std
#endif /* NEXTPNR_BASE_TYPES_H */ #endif /* NEXTPNR_BASE_TYPES_H */

View File

@ -28,6 +28,7 @@
#include <unordered_set> #include <unordered_set>
#include "archdefs.h" #include "archdefs.h"
#include "hashlib.h"
#include "nextpnr_base_types.h" #include "nextpnr_base_types.h"
#include "nextpnr_namespaces.h" #include "nextpnr_namespaces.h"
#include "property.h" #include "property.h"
@ -56,9 +57,9 @@ struct Region
bool constr_wires = false; bool constr_wires = false;
bool constr_pips = false; bool constr_pips = false;
std::unordered_set<BelId> bels; pool<BelId> bels;
std::unordered_set<WireId> wires; pool<WireId> wires;
std::unordered_set<Loc> piplocs; pool<Loc> piplocs;
}; };
struct PipMap struct PipMap
@ -128,10 +129,10 @@ struct NetInfo : ArchNetInfo
PortRef driver; PortRef driver;
std::vector<PortRef> users; std::vector<PortRef> users;
std::unordered_map<IdString, Property> attrs; dict<IdString, Property> attrs;
// wire -> uphill_pip // wire -> uphill_pip
std::unordered_map<WireId, PipMap> wires; dict<WireId, PipMap> wires;
std::vector<IdString> aliases; // entries in net_aliases that point to this net std::vector<IdString> aliases; // entries in net_aliases that point to this net
@ -159,8 +160,8 @@ struct CellInfo : ArchCellInfo
IdString name, type, hierpath; IdString name, type, hierpath;
int32_t udata; int32_t udata;
std::unordered_map<IdString, PortInfo> ports; dict<IdString, PortInfo> ports;
std::unordered_map<IdString, Property> attrs, params; dict<IdString, Property> attrs, params;
BelId bel; BelId bel;
PlaceStrength belStrength = STRENGTH_NONE; PlaceStrength belStrength = STRENGTH_NONE;
@ -232,13 +233,13 @@ struct HierarchicalCell
{ {
IdString name, type, parent, fullpath; IdString name, type, parent, fullpath;
// Name inside cell instance -> global name // Name inside cell instance -> global name
std::unordered_map<IdString, IdString> leaf_cells, nets; dict<IdString, IdString> leaf_cells, nets;
// Global name -> name inside cell instance // Global name -> name inside cell instance
std::unordered_map<IdString, IdString> leaf_cells_by_gname, nets_by_gname; dict<IdString, IdString> leaf_cells_by_gname, nets_by_gname;
// Cell port to net // Cell port to net
std::unordered_map<IdString, HierarchicalPort> ports; dict<IdString, HierarchicalPort> ports;
// Name inside cell instance -> global name // Name inside cell instance -> global name
std::unordered_map<IdString, IdString> hier_cells; dict<IdString, IdString> hier_cells;
}; };
NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_END

View File

@ -178,8 +178,8 @@ class ConstraintLegaliseWorker
private: private:
Context *ctx; Context *ctx;
std::set<IdString> rippedCells; std::set<IdString> rippedCells;
std::unordered_map<IdString, Loc> oldLocations; dict<IdString, Loc> oldLocations;
std::unordered_map<ClusterId, std::vector<CellInfo *>> cluster2cells; dict<ClusterId, std::vector<CellInfo *>> cluster2cells;
class IncreasingDiameterSearch class IncreasingDiameterSearch
{ {
@ -227,10 +227,10 @@ class ConstraintLegaliseWorker
int sign = 0; int sign = 0;
}; };
typedef std::unordered_map<IdString, Loc> CellLocations; typedef dict<IdString, Loc> CellLocations;
// Check if a location would be suitable for a cell and all its constrained children // Check if a location would be suitable for a cell and all its constrained children
bool valid_loc_for(const CellInfo *cell, Loc loc, CellLocations &solution, std::unordered_set<Loc> &usedLocations) bool valid_loc_for(const CellInfo *cell, Loc loc, CellLocations &solution, pool<Loc> &usedLocations)
{ {
BelId locBel = ctx->getBelByLocation(loc); BelId locBel = ctx->getBelByLocation(loc);
if (locBel == BelId()) if (locBel == BelId())
@ -324,7 +324,7 @@ class ConstraintLegaliseWorker
} }
CellLocations solution; CellLocations solution;
std::unordered_set<Loc> used; pool<Loc> used;
if (valid_loc_for(cell, rootLoc, solution, used)) { if (valid_loc_for(cell, rootLoc, solution, used)) {
for (auto cp : solution) { for (auto cp : solution) {
// First unbind all cells // First unbind all cells
@ -377,9 +377,9 @@ class ConstraintLegaliseWorker
public: public:
ConstraintLegaliseWorker(Context *ctx) : ctx(ctx) ConstraintLegaliseWorker(Context *ctx) : ctx(ctx)
{ {
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
if (cell.second->cluster != ClusterId()) if (cell.second->cluster != ClusterId())
cluster2cells[cell.second->cluster].push_back(cell.second); cluster2cells[cell.second->cluster].push_back(cell.second.get());
} }
}; };
@ -414,11 +414,11 @@ class ConstraintLegaliseWorker
int legalise_constraints() int legalise_constraints()
{ {
log_info("Legalising relative constraints...\n"); log_info("Legalising relative constraints...\n");
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
oldLocations[cell.first] = ctx->getBelLocation(cell.second->bel); oldLocations[cell.first] = ctx->getBelLocation(cell.second->bel);
} }
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
bool res = legalise_cell(cell.second); bool res = legalise_cell(cell.second.get());
if (!res) { if (!res) {
log_error("failed to place chain starting at cell '%s'\n", cell.first.c_str(ctx)); log_error("failed to place chain starting at cell '%s'\n", cell.first.c_str(ctx));
return -1; return -1;
@ -434,8 +434,8 @@ class ConstraintLegaliseWorker
} }
} }
auto score = print_stats("replacing ripped up cells"); auto score = print_stats("replacing ripped up cells");
for (auto cell : sorted(ctx->cells)) for (auto &cell : ctx->cells)
if (get_constraints_distance(ctx, cell.second) != 0) if (get_constraints_distance(ctx, cell.second.get()) != 0)
log_error("constraint satisfaction check failed for cell '%s' at Bel '%s'\n", cell.first.c_str(ctx), log_error("constraint satisfaction check failed for cell '%s' at Bel '%s'\n", cell.first.c_str(ctx),
ctx->nameOfBel(cell.second->bel)); ctx->nameOfBel(cell.second->bel));
return score; return score;

View File

@ -46,19 +46,6 @@
#include "timing.h" #include "timing.h"
#include "util.h" #include "util.h"
namespace std {
template <> struct hash<std::pair<NEXTPNR_NAMESPACE_PREFIX IdString, std::size_t>>
{
std::size_t operator()(const std::pair<NEXTPNR_NAMESPACE_PREFIX IdString, std::size_t> &idp) const noexcept
{
std::size_t seed = 0;
boost::hash_combine(seed, hash<NEXTPNR_NAMESPACE_PREFIX IdString>()(idp.first));
boost::hash_combine(seed, hash<std::size_t>()(idp.second));
return seed;
}
};
} // namespace std
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
class SAPlacer class SAPlacer
@ -87,8 +74,8 @@ class SAPlacer
} }
diameter = std::max(max_x, max_y) + 1; diameter = std::max(max_x, max_y) + 1;
std::unordered_set<IdString> cell_types_in_use; pool<IdString> cell_types_in_use;
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
IdString cell_type = cell.second->type; IdString cell_type = cell.second->type;
cell_types_in_use.insert(cell_type); cell_types_in_use.insert(cell_type);
} }
@ -108,8 +95,8 @@ class SAPlacer
net.second->udata = n++; net.second->udata = n++;
net_by_udata.push_back(net.second.get()); net_by_udata.push_back(net.second.get());
} }
for (auto &region : sorted(ctx->region)) { for (auto &region : ctx->region) {
Region *r = region.second; Region *r = region.second.get();
BoundingBox bb; BoundingBox bb;
if (r->constr_bels) { if (r->constr_bels) {
bb.x0 = std::numeric_limits<int>::max(); bb.x0 = std::numeric_limits<int>::max();
@ -360,12 +347,12 @@ class SAPlacer
// Only increase temperature if something was moved // Only increase temperature if something was moved
autoplaced.clear(); autoplaced.clear();
chain_basis.clear(); chain_basis.clear();
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
if (cell.second->belStrength <= STRENGTH_STRONG && cell.second->cluster != ClusterId() && if (cell.second->belStrength <= STRENGTH_STRONG && cell.second->cluster != ClusterId() &&
ctx->getClusterRootCell(cell.second->cluster) == cell.second) ctx->getClusterRootCell(cell.second->cluster) == cell.second.get())
chain_basis.push_back(cell.second); chain_basis.push_back(cell.second.get());
else if (cell.second->belStrength < STRENGTH_STRONG) else if (cell.second->belStrength < STRENGTH_STRONG)
autoplaced.push_back(cell.second); autoplaced.push_back(cell.second.get());
} }
// temp = post_legalise_temp; // temp = post_legalise_temp;
// diameter = std::min<int>(M, diameter * post_legalise_dia_scale); // diameter = std::min<int>(M, diameter * post_legalise_dia_scale);
@ -421,8 +408,8 @@ class SAPlacer
} }
} }
} }
for (auto cell : sorted(ctx->cells)) for (auto &cell : ctx->cells)
if (get_constraints_distance(ctx, cell.second) != 0) if (get_constraints_distance(ctx, cell.second.get()) != 0)
log_error("constraint satisfaction check failed for cell '%s' at Bel '%s'\n", cell.first.c_str(ctx), log_error("constraint satisfaction check failed for cell '%s' at Bel '%s'\n", cell.first.c_str(ctx),
ctx->nameOfBel(cell.second->bel)); ctx->nameOfBel(cell.second->bel));
timing_analysis(ctx); timing_analysis(ctx);
@ -629,7 +616,7 @@ class SAPlacer
bool try_swap_chain(CellInfo *cell, BelId newBase) bool try_swap_chain(CellInfo *cell, BelId newBase)
{ {
std::vector<std::pair<CellInfo *, Loc>> cell_rel; std::vector<std::pair<CellInfo *, Loc>> cell_rel;
std::unordered_set<IdString> cells; pool<IdString> cells;
std::vector<std::pair<CellInfo *, BelId>> moves_made; std::vector<std::pair<CellInfo *, BelId>> moves_made;
std::vector<std::pair<CellInfo *, BelId>> dest_bels; std::vector<std::pair<CellInfo *, BelId>> dest_bels;
double delta = 0; double delta = 0;
@ -831,8 +818,8 @@ class SAPlacer
// Set up the cost maps // Set up the cost maps
void setup_costs() void setup_costs()
{ {
for (auto net : sorted(ctx->nets)) { for (auto &net : ctx->nets) {
NetInfo *ni = net.second; NetInfo *ni = net.second.get();
if (ignore_net(ni)) if (ignore_net(ni))
continue; continue;
net_bounds[ni->udata] = get_net_bounds(ni); net_bounds[ni->udata] = get_net_bounds(ni);
@ -1065,7 +1052,7 @@ class SAPlacer
mc.already_changed_arcs[pn->udata][i] = true; mc.already_changed_arcs[pn->udata][i] = true;
} }
} else if (port.second.type == PORT_IN) { } else if (port.second.type == PORT_IN) {
auto usr = fast_port_to_user.at(&port.second); auto usr = fast_port_to_user.at(std::make_pair(cell->name, port.first));
if (!mc.already_changed_arcs[pn->udata][usr]) { if (!mc.already_changed_arcs[pn->udata][usr]) {
mc.changed_arcs.emplace_back(std::make_pair(pn->udata, usr)); mc.changed_arcs.emplace_back(std::make_pair(pn->udata, usr));
mc.already_changed_arcs[pn->udata][usr] = true; mc.already_changed_arcs[pn->udata][usr] = true;
@ -1118,11 +1105,11 @@ class SAPlacer
// Build the cell port -> user index // Build the cell port -> user index
void build_port_index() void build_port_index()
{ {
for (auto net : sorted(ctx->nets)) { for (auto &net : ctx->nets) {
NetInfo *ni = net.second; NetInfo *ni = net.second.get();
for (size_t i = 0; i < ni->users.size(); i++) { for (size_t i = 0; i < ni->users.size(); i++) {
auto &usr = ni->users.at(i); auto &usr = ni->users.at(i);
fast_port_to_user[&(usr.cell->ports.at(usr.port))] = i; fast_port_to_user[std::make_pair(usr.cell->name, usr.port)] = i;
} }
} }
} }
@ -1130,13 +1117,13 @@ class SAPlacer
// Simple routeability driven placement // Simple routeability driven placement
const int large_cell_thresh = 50; const int large_cell_thresh = 50;
int total_net_share = 0; int total_net_share = 0;
std::vector<std::vector<std::unordered_map<IdString, int>>> nets_by_tile; std::vector<std::vector<dict<IdString, int>>> nets_by_tile;
void setup_nets_by_tile() void setup_nets_by_tile()
{ {
total_net_share = 0; total_net_share = 0;
nets_by_tile.resize(max_x + 1, std::vector<std::unordered_map<IdString, int>>(max_y + 1)); nets_by_tile.resize(max_x + 1, std::vector<dict<IdString, int>>(max_y + 1));
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (int(ci->ports.size()) > large_cell_thresh) if (int(ci->ports.size()) > large_cell_thresh)
continue; continue;
Loc loc = ctx->getBelLocation(ci->bel); Loc loc = ctx->getBelLocation(ci->bel);
@ -1194,7 +1181,7 @@ class SAPlacer
std::vector<std::vector<double>> net_arc_tcost; std::vector<std::vector<double>> net_arc_tcost;
// Fast lookup for cell port to net user index // Fast lookup for cell port to net user index
std::unordered_map<const PortInfo *, size_t> fast_port_to_user; dict<std::pair<IdString, IdString>, size_t> fast_port_to_user;
// Wirelength and timing cost at last and current iteration // Wirelength and timing cost at last and current iteration
wirelen_t last_wirelen_cost, curr_wirelen_cost; wirelen_t last_wirelen_cost, curr_wirelen_cost;
@ -1207,10 +1194,10 @@ class SAPlacer
bool improved = false; bool improved = false;
int n_move, n_accept; int n_move, n_accept;
int diameter = 35, max_x = 1, max_y = 1; int diameter = 35, max_x = 1, max_y = 1;
std::unordered_map<IdString, std::tuple<int, int>> bel_types; dict<IdString, std::tuple<int, int>> bel_types;
std::unordered_map<IdString, BoundingBox> region_bounds; dict<IdString, BoundingBox> region_bounds;
FastBels fast_bels; FastBels fast_bels;
std::unordered_set<BelId> locked_bels; pool<BelId> locked_bels;
std::vector<NetInfo *> net_by_udata; std::vector<NetInfo *> net_by_udata;
std::vector<decltype(NetInfo::udata)> old_udata; std::vector<decltype(NetInfo::udata)> old_udata;
bool require_legal = true; bool require_legal = true;

View File

@ -43,7 +43,6 @@
#include <numeric> #include <numeric>
#include <queue> #include <queue>
#include <tuple> #include <tuple>
#include <unordered_map>
#include "fast_bels.h" #include "fast_bels.h"
#include "log.h" #include "log.h"
#include "nextpnr.h" #include "nextpnr.h"
@ -146,9 +145,9 @@ class HeAPPlacer
tmg.setup_only = true; tmg.setup_only = true;
tmg.setup(); tmg.setup();
for (auto cell : sorted(ctx->cells)) for (auto &cell : ctx->cells)
if (cell.second->cluster != ClusterId()) if (cell.second->cluster != ClusterId())
cluster2cells[cell.second->cluster].push_back(cell.second); cluster2cells[cell.second->cluster].push_back(cell.second.get());
} }
bool place() bool place()
@ -188,14 +187,14 @@ class HeAPPlacer
std::vector<std::tuple<CellInfo *, BelId, PlaceStrength>> solution; std::vector<std::tuple<CellInfo *, BelId, PlaceStrength>> solution;
std::vector<std::unordered_set<BelBucketId>> heap_runs; std::vector<pool<BelBucketId>> heap_runs;
std::unordered_set<BelBucketId> all_buckets; pool<BelBucketId> all_buckets;
std::unordered_map<BelBucketId, int> bucket_count; dict<BelBucketId, int> bucket_count;
for (auto cell : place_cells) { for (auto cell : place_cells) {
BelBucketId bucket = ctx->getBelBucketForCellType(cell->type); BelBucketId bucket = ctx->getBelBucketForCellType(cell->type);
if (!all_buckets.count(bucket)) { if (!all_buckets.count(bucket)) {
heap_runs.push_back(std::unordered_set<BelBucketId>{bucket}); heap_runs.push_back(pool<BelBucketId>{bucket});
all_buckets.insert(bucket); all_buckets.insert(bucket);
} }
bucket_count[bucket]++; bucket_count[bucket]++;
@ -253,9 +252,9 @@ class HeAPPlacer
for (const auto &group : cfg.cellGroups) for (const auto &group : cfg.cellGroups)
CutSpreader(this, group).run(); CutSpreader(this, group).run();
for (auto type : sorted(run)) for (auto type : run)
if (std::all_of(cfg.cellGroups.begin(), cfg.cellGroups.end(), if (std::all_of(cfg.cellGroups.begin(), cfg.cellGroups.end(),
[type](const std::unordered_set<BelBucketId> &grp) { return !grp.count(type); })) [type](const pool<BelBucketId> &grp) { return !grp.count(type); }))
CutSpreader(this, {type}).run(); CutSpreader(this, {type}).run();
// Run strict legalisation to find a valid bel for all cells // Run strict legalisation to find a valid bel for all cells
@ -283,8 +282,8 @@ class HeAPPlacer
stalled = 0; stalled = 0;
// Save solution // Save solution
solution.clear(); solution.clear();
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
solution.emplace_back(cell.second, cell.second->bel, cell.second->belStrength); solution.emplace_back(cell.second.get(), cell.second->bel, cell.second->belStrength);
} }
} else { } else {
++stalled; ++stalled;
@ -311,10 +310,10 @@ class HeAPPlacer
ctx->bindBel(bel, cell, strength); ctx->bindBel(bel, cell, strength);
} }
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
if (cell.second->bel == BelId()) if (cell.second->bel == BelId())
log_error("Found unbound cell %s\n", cell.first.c_str(ctx)); log_error("Found unbound cell %s\n", cell.first.c_str(ctx));
if (ctx->getBoundBelCell(cell.second->bel) != cell.second) if (ctx->getBoundBelCell(cell.second->bel) != cell.second.get())
log_error("Found cell %s with mismatched binding\n", cell.first.c_str(ctx)); log_error("Found cell %s with mismatched binding\n", cell.first.c_str(ctx));
if (ctx->debug) if (ctx->debug)
log_info("AP soln: %s -> %s\n", cell.first.c_str(ctx), ctx->nameOfBel(cell.second->bel)); log_info("AP soln: %s -> %s\n", cell.first.c_str(ctx), ctx->nameOfBel(cell.second->bel));
@ -360,7 +359,7 @@ class HeAPPlacer
int max_x = 0, max_y = 0; int max_x = 0, max_y = 0;
FastBels fast_bels; FastBels fast_bels;
std::unordered_map<IdString, std::tuple<int, int>> bel_types; dict<IdString, std::tuple<int, int>> bel_types;
TimingAnalyser tmg; TimingAnalyser tmg;
@ -370,7 +369,7 @@ class HeAPPlacer
int x0 = 0, x1 = 0, y0 = 0, y1 = 0; int x0 = 0, x1 = 0, y0 = 0, y1 = 0;
}; };
std::unordered_map<IdString, BoundingBox> constraint_region_bounds; dict<IdString, BoundingBox> constraint_region_bounds;
// In some cases, we can't use bindBel because we allow overlap in the earlier stages. So we use this custom // In some cases, we can't use bindBel because we allow overlap in the earlier stages. So we use this custom
// structure instead // structure instead
@ -381,7 +380,7 @@ class HeAPPlacer
double rawx, rawy; double rawx, rawy;
bool locked, global; bool locked, global;
}; };
std::unordered_map<IdString, CellLocation> cell_locs; dict<IdString, CellLocation> cell_locs;
// The set of cells that we will actually place. This excludes locked cells and children cells of macros/chains // The set of cells that we will actually place. This excludes locked cells and children cells of macros/chains
// (only the root of each macro is placed.) // (only the root of each macro is placed.)
std::vector<CellInfo *> place_cells; std::vector<CellInfo *> place_cells;
@ -390,8 +389,8 @@ class HeAPPlacer
// cells of a certain type) // cells of a certain type)
std::vector<CellInfo *> solve_cells; std::vector<CellInfo *> solve_cells;
std::unordered_map<ClusterId, std::vector<CellInfo *>> cluster2cells; dict<ClusterId, std::vector<CellInfo *>> cluster2cells;
std::unordered_map<ClusterId, int> chain_size; dict<ClusterId, int> chain_size;
// Performance counting // Performance counting
double solve_time = 0, cl_time = 0, sl_time = 0; double solve_time = 0, cl_time = 0, sl_time = 0;
@ -448,9 +447,9 @@ class HeAPPlacer
max_y = std::max(max_y, loc.y); max_y = std::max(max_y, loc.y);
} }
std::unordered_set<IdString> cell_types_in_use; pool<IdString> cell_types_in_use;
std::unordered_set<BelBucketId> buckets_in_use; pool<BelBucketId> buckets_in_use;
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
IdString cell_type = cell.second->type; IdString cell_type = cell.second->type;
cell_types_in_use.insert(cell_type); cell_types_in_use.insert(cell_type);
BelBucketId bucket = ctx->getBelBucketForCellType(cell_type); BelBucketId bucket = ctx->getBelBucketForCellType(cell_type);
@ -465,8 +464,8 @@ class HeAPPlacer
} }
// Determine bounding boxes of region constraints // Determine bounding boxes of region constraints
for (auto &region : sorted(ctx->region)) { for (auto &region : ctx->region) {
Region *r = region.second; Region *r = region.second.get();
BoundingBox bb; BoundingBox bb;
if (r->constr_bels) { if (r->constr_bels) {
bb.x0 = std::numeric_limits<int>::max(); bb.x0 = std::numeric_limits<int>::max();
@ -515,13 +514,13 @@ class HeAPPlacer
// FIXME: Are there better approaches to the initial placement (e.g. greedy?) // FIXME: Are there better approaches to the initial placement (e.g. greedy?)
void seed_placement() void seed_placement()
{ {
std::unordered_set<IdString> cell_types; pool<IdString> cell_types;
for (const auto &cell : ctx->cells) { for (const auto &cell : ctx->cells) {
cell_types.insert(cell.second->type); cell_types.insert(cell.second->type);
} }
std::unordered_set<BelId> bels_used; pool<BelId> bels_used;
std::unordered_map<IdString, std::deque<BelId>> available_bels; dict<IdString, std::deque<BelId>> available_bels;
for (auto bel : ctx->getBels()) { for (auto bel : ctx->getBels()) {
if (!ctx->checkBelAvail(bel)) { if (!ctx->checkBelAvail(bel)) {
@ -539,8 +538,8 @@ class HeAPPlacer
ctx->shuffle(t.second.begin(), t.second.end()); ctx->shuffle(t.second.begin(), t.second.end());
} }
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (ci->bel != BelId()) { if (ci->bel != BelId()) {
Loc loc = ctx->getBelLocation(ci->bel); Loc loc = ctx->getBelLocation(ci->bel);
cell_locs[cell.first].x = loc.x; cell_locs[cell.first].x = loc.x;
@ -591,7 +590,7 @@ class HeAPPlacer
cell_locs[cell.first].global = ctx->getBelGlobalBuf(bel); cell_locs[cell.first].global = ctx->getBelGlobalBuf(bel);
// FIXME // FIXME
if (has_connectivity(cell.second) && !cfg.ioBufTypes.count(ci->type)) { if (has_connectivity(cell.second.get()) && !cfg.ioBufTypes.count(ci->type)) {
bels_used.insert(bel); bels_used.insert(bel);
place_cells.push_back(ci); place_cells.push_back(ci);
placed = true; placed = true;
@ -612,12 +611,12 @@ class HeAPPlacer
} }
// Setup the cells to be solved, returns the number of rows // Setup the cells to be solved, returns the number of rows
int setup_solve_cells(std::unordered_set<BelBucketId> *buckets = nullptr) int setup_solve_cells(pool<BelBucketId> *buckets = nullptr)
{ {
int row = 0; int row = 0;
solve_cells.clear(); solve_cells.clear();
// First clear the udata of all cells // First clear the udata of all cells
for (auto cell : sorted(ctx->cells)) for (auto &cell : ctx->cells)
cell.second->udata = dont_solve; cell.second->udata = dont_solve;
// Then update cells to be placed, which excludes cell children // Then update cells to be placed, which excludes cell children
for (auto cell : place_cells) { for (auto cell : place_cells) {
@ -671,8 +670,8 @@ class HeAPPlacer
es.reset(); es.reset();
for (auto net : sorted(ctx->nets)) { for (auto &net : ctx->nets) {
NetInfo *ni = net.second; NetInfo *ni = net.second.get();
if (ni->driver.cell == nullptr) if (ni->driver.cell == nullptr)
continue; continue;
if (ni->users.empty()) if (ni->users.empty())
@ -783,8 +782,8 @@ class HeAPPlacer
wirelen_t total_hpwl() wirelen_t total_hpwl()
{ {
wirelen_t hpwl = 0; wirelen_t hpwl = 0;
for (auto net : sorted(ctx->nets)) { for (auto &net : ctx->nets) {
NetInfo *ni = net.second; NetInfo *ni = net.second.get();
if (ni->driver.cell == nullptr) if (ni->driver.cell == nullptr)
continue; continue;
CellLocation &drvloc = cell_locs.at(ni->driver.cell->name); CellLocation &drvloc = cell_locs.at(ni->driver.cell->name);
@ -809,8 +808,8 @@ class HeAPPlacer
auto startt = std::chrono::high_resolution_clock::now(); auto startt = std::chrono::high_resolution_clock::now();
// Unbind all cells placed in this solution // Unbind all cells placed in this solution
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (ci->bel != BelId() && if (ci->bel != BelId() &&
(ci->udata != dont_solve || (ci->udata != dont_solve ||
(ci->cluster != ClusterId() && ctx->getClusterRootCell(ci->cluster)->udata != dont_solve))) (ci->cluster != ClusterId() && ctx->getClusterRootCell(ci->cluster)->udata != dont_solve)))
@ -1106,11 +1105,11 @@ class HeAPPlacer
class CutSpreader class CutSpreader
{ {
public: public:
CutSpreader(HeAPPlacer *p, const std::unordered_set<BelBucketId> &buckets) : p(p), ctx(p->ctx), buckets(buckets) CutSpreader(HeAPPlacer *p, const pool<BelBucketId> &buckets) : p(p), ctx(p->ctx), buckets(buckets)
{ {
// Get fast BELs data for all buckets being Cut/Spread. // Get fast BELs data for all buckets being Cut/Spread.
size_t idx = 0; size_t idx = 0;
for (BelBucketId bucket : sorted(buckets)) { for (BelBucketId bucket : buckets) {
type_index[bucket] = idx; type_index[bucket] = idx;
FastBels::FastBelsData *fast_bels; FastBels::FastBelsData *fast_bels;
p->fast_bels.getBelsForBelBucket(bucket, &fast_bels); p->fast_bels.getBelsForBelBucket(bucket, &fast_bels);
@ -1198,8 +1197,8 @@ class HeAPPlacer
private: private:
HeAPPlacer *p; HeAPPlacer *p;
Context *ctx; Context *ctx;
std::unordered_set<BelBucketId> buckets; pool<BelBucketId> buckets;
std::unordered_map<BelBucketId, size_t> type_index; dict<BelBucketId, size_t> type_index;
std::vector<std::vector<std::vector<int>>> occupancy; std::vector<std::vector<std::vector<int>>> occupancy;
std::vector<std::vector<int>> groups; std::vector<std::vector<int>> groups;
std::vector<std::vector<ChainExtent>> chaines; std::vector<std::vector<ChainExtent>> chaines;
@ -1208,7 +1207,7 @@ class HeAPPlacer
std::vector<std::vector<std::vector<std::vector<BelId>>> *> fb; std::vector<std::vector<std::vector<std::vector<BelId>>> *> fb;
std::vector<SpreaderRegion> regions; std::vector<SpreaderRegion> regions;
std::unordered_set<int> merged_regions; pool<int> merged_regions;
// Cells at a location, sorted by real (not integer) x and y // Cells at a location, sorted by real (not integer) x and y
std::vector<std::vector<std::vector<CellInfo *>>> cells_at_location; std::vector<std::vector<std::vector<CellInfo *>>> cells_at_location;
@ -1490,7 +1489,7 @@ class HeAPPlacer
} }
} }
if (!changed) { if (!changed) {
for (auto bucket : sorted(buckets)) { for (auto bucket : buckets) {
if (reg.cells > reg.bels) { if (reg.cells > reg.bels) {
IdString bucket_name = ctx->getBelBucketName(bucket); IdString bucket_name = ctx->getBelBucketName(bucket);
log_error("Failed to expand region (%d, %d) |_> (%d, %d) of %d %ss\n", reg.x0, reg.y0, log_error("Failed to expand region (%d, %d) |_> (%d, %d) of %d %ss\n", reg.x0, reg.y0,

View File

@ -46,10 +46,10 @@ struct PlacerHeapCfg
int spread_scale_x, spread_scale_y; int spread_scale_x, spread_scale_y;
// These cell types will be randomly locked to prevent singular matrices // These cell types will be randomly locked to prevent singular matrices
std::unordered_set<IdString> ioBufTypes; pool<IdString> ioBufTypes;
// These cell types are part of the same unit (e.g. slices split into // These cell types are part of the same unit (e.g. slices split into
// components) so will always be spread together // components) so will always be spread together
std::vector<std::unordered_set<BelBucketId>> cellGroups; std::vector<pool<BelBucketId>> cellGroups;
}; };
extern bool placer_heap(Context *ctx, PlacerHeapCfg cfg); extern bool placer_heap(Context *ctx, PlacerHeapCfg cfg);

View File

@ -164,10 +164,10 @@ PYBIND11_EMBEDDED_MODULE(MODULE_NAME, m)
.def("maxFallDelay", &DelayQuad::maxFallDelay) .def("maxFallDelay", &DelayQuad::maxFallDelay)
.def("delayPair", &DelayQuad::delayPair); .def("delayPair", &DelayQuad::delayPair);
typedef std::unordered_map<IdString, Property> AttrMap; typedef dict<IdString, Property> AttrMap;
typedef std::unordered_map<IdString, PortInfo> PortMap; typedef dict<IdString, PortInfo> PortMap;
typedef std::unordered_map<IdString, IdString> IdIdMap; typedef dict<IdString, IdString> IdIdMap;
typedef std::unordered_map<IdString, std::unique_ptr<Region>> RegionMap; typedef dict<IdString, std::unique_ptr<Region>> RegionMap;
py::class_<BaseCtx>(m, "BaseCtx"); py::class_<BaseCtx>(m, "BaseCtx");
@ -218,9 +218,9 @@ PYBIND11_EMBEDDED_MODULE(MODULE_NAME, m)
pass_through<PortType>>::def_wrap(pi_cls, "type"); pass_through<PortType>>::def_wrap(pi_cls, "type");
typedef std::vector<PortRef> PortRefVector; typedef std::vector<PortRef> PortRefVector;
typedef std::unordered_map<WireId, PipMap> WireMap; typedef dict<WireId, PipMap> WireMap;
typedef std::unordered_set<BelId> BelSet; typedef pool<BelId> BelSet;
typedef std::unordered_set<WireId> WireSet; typedef pool<WireId> WireSet;
auto ni_cls = py::class_<ContextualWrapper<NetInfo &>>(m, "NetInfo"); auto ni_cls = py::class_<ContextualWrapper<NetInfo &>>(m, "NetInfo");
readwrite_wrapper<NetInfo &, decltype(&NetInfo::name), &NetInfo::name, conv_to_str<IdString>, readwrite_wrapper<NetInfo &, decltype(&NetInfo::name), &NetInfo::name, conv_to_str<IdString>,

View File

@ -49,16 +49,13 @@ struct arc_key
: net_info->name < other.net_info->name; : net_info->name < other.net_info->name;
} }
struct Hash unsigned int hash() const
{ {
std::size_t operator()(const arc_key &arg) const noexcept std::size_t seed = std::hash<NetInfo *>()(net_info);
{ seed ^= std::hash<int>()(user_idx) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
std::size_t seed = std::hash<NetInfo *>()(arg.net_info); seed ^= std::hash<int>()(phys_idx) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
seed ^= std::hash<int>()(arg.user_idx) + 0x9e3779b9 + (seed << 6) + (seed >> 2); return seed;
seed ^= std::hash<int>()(arg.phys_idx) + 0x9e3779b9 + (seed << 6) + (seed >> 2); }
return seed;
}
};
}; };
struct arc_entry struct arc_entry
@ -107,15 +104,15 @@ struct Router1
const Router1Cfg &cfg; const Router1Cfg &cfg;
std::priority_queue<arc_entry, std::vector<arc_entry>, arc_entry::Less> arc_queue; std::priority_queue<arc_entry, std::vector<arc_entry>, arc_entry::Less> arc_queue;
std::unordered_map<WireId, std::unordered_set<arc_key, arc_key::Hash>> wire_to_arcs; dict<WireId, pool<arc_key>> wire_to_arcs;
std::unordered_map<arc_key, std::unordered_set<WireId>, arc_key::Hash> arc_to_wires; dict<arc_key, pool<WireId>> arc_to_wires;
std::unordered_set<arc_key, arc_key::Hash> queued_arcs; pool<arc_key> queued_arcs;
std::unordered_map<WireId, QueuedWire> visited; dict<WireId, QueuedWire> visited;
std::priority_queue<QueuedWire, std::vector<QueuedWire>, QueuedWire::Greater> queue; std::priority_queue<QueuedWire, std::vector<QueuedWire>, QueuedWire::Greater> queue;
std::unordered_map<WireId, int> wireScores; dict<WireId, int> wireScores;
std::unordered_map<NetInfo *, int> netScores; dict<NetInfo *, int, hash_ptr_ops> netScores;
int arcs_with_ripup = 0; int arcs_with_ripup = 0;
int arcs_without_ripup = 0; int arcs_without_ripup = 0;
@ -295,11 +292,11 @@ struct Router1
void check() void check()
{ {
std::unordered_set<arc_key, arc_key::Hash> valid_arcs; pool<arc_key> valid_arcs;
for (auto &net_it : ctx->nets) { for (auto &net_it : ctx->nets) {
NetInfo *net_info = net_it.second.get(); NetInfo *net_info = net_it.second.get();
std::unordered_set<WireId> valid_wires_for_net; pool<WireId> valid_wires_for_net;
if (skip_net(net_info)) if (skip_net(net_info))
continue; continue;
@ -357,8 +354,8 @@ struct Router1
void setup() void setup()
{ {
std::unordered_map<WireId, NetInfo *> src_to_net; dict<WireId, NetInfo *> src_to_net;
std::unordered_map<WireId, arc_key> dst_to_arc; dict<WireId, arc_key> dst_to_arc;
std::vector<IdString> net_names; std::vector<IdString> net_names;
for (auto &net_it : ctx->nets) for (auto &net_it : ctx->nets)
@ -472,7 +469,7 @@ struct Router1
// unbind wires that are currently used exclusively by this arc // unbind wires that are currently used exclusively by this arc
std::unordered_set<WireId> old_arc_wires; pool<WireId> old_arc_wires;
old_arc_wires.swap(arc_to_wires[arc]); old_arc_wires.swap(arc_to_wires[arc]);
for (WireId wire : old_arc_wires) { for (WireId wire : old_arc_wires) {
@ -720,7 +717,7 @@ struct Router1
// bind resulting route (and maybe unroute other nets) // bind resulting route (and maybe unroute other nets)
std::unordered_set<WireId> unassign_wires = arc_to_wires[arc]; pool<WireId> unassign_wires = arc_to_wires[arc];
WireId cursor = dst_wire; WireId cursor = dst_wire;
delay_t accumulated_path_delay = 0; delay_t accumulated_path_delay = 0;
@ -919,10 +916,10 @@ bool Context::checkRoutedDesign() const
struct ExtraWireInfo struct ExtraWireInfo
{ {
int order_num = 0; int order_num = 0;
std::unordered_set<WireId> children; pool<WireId> children;
}; };
std::unordered_map<WireId, ExtraWireInfo> db; dict<WireId, std::unique_ptr<ExtraWireInfo>> db;
for (auto &it : net_info->wires) { for (auto &it : net_info->wires) {
WireId w = it.first; WireId w = it.first;
@ -930,7 +927,7 @@ bool Context::checkRoutedDesign() const
if (p != PipId()) { if (p != PipId()) {
log_assert(ctx->getPipDstWire(p) == w); log_assert(ctx->getPipDstWire(p) == w);
db[ctx->getPipSrcWire(p)].children.insert(w); db.emplace(ctx->getPipSrcWire(p), std::make_unique<ExtraWireInfo>()).first->second->children.insert(w);
} }
} }
@ -948,7 +945,7 @@ bool Context::checkRoutedDesign() const
found_unrouted = true; found_unrouted = true;
} }
std::unordered_map<WireId, int> dest_wires; dict<WireId, int> dest_wires;
for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) { for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) {
for (auto dst_wire : ctx->getNetinfoSinkWires(net_info, net_info->users[user_idx])) { for (auto dst_wire : ctx->getNetinfoSinkWires(net_info, net_info->users[user_idx])) {
log_assert(dst_wire != WireId()); log_assert(dst_wire != WireId());
@ -963,10 +960,10 @@ bool Context::checkRoutedDesign() const
} }
std::function<void(WireId, int)> setOrderNum; std::function<void(WireId, int)> setOrderNum;
std::unordered_set<WireId> logged_wires; pool<WireId> logged_wires;
setOrderNum = [&](WireId w, int num) { setOrderNum = [&](WireId w, int num) {
auto &db_entry = db[w]; auto &db_entry = *db.emplace(w, std::make_unique<ExtraWireInfo>()).first->second;
if (db_entry.order_num != 0) { if (db_entry.order_num != 0) {
found_loop = true; found_loop = true;
log(" %*s=> loop\n", 2 * num, ""); log(" %*s=> loop\n", 2 * num, "");
@ -998,10 +995,10 @@ bool Context::checkRoutedDesign() const
} }
setOrderNum(src_wire, 1); setOrderNum(src_wire, 1);
std::unordered_set<WireId> dangling_wires; pool<WireId> dangling_wires;
for (auto &it : db) { for (auto &it : db) {
auto &db_entry = it.second; auto &db_entry = *it.second;
if (db_entry.order_num == 0) if (db_entry.order_num == 0)
dangling_wires.insert(it.first); dangling_wires.insert(it.first);
} }
@ -1010,10 +1007,10 @@ bool Context::checkRoutedDesign() const
if (dangling_wires.empty()) { if (dangling_wires.empty()) {
log(" no dangling wires.\n"); log(" no dangling wires.\n");
} else { } else {
std::unordered_set<WireId> root_wires = dangling_wires; pool<WireId> root_wires = dangling_wires;
for (WireId w : dangling_wires) { for (WireId w : dangling_wires) {
for (WireId c : db[w].children) for (WireId c : db[w]->children)
root_wires.erase(c); root_wires.erase(c);
} }
@ -1064,8 +1061,8 @@ bool Context::checkRoutedDesign() const
return true; return true;
} }
bool Context::getActualRouteDelay(WireId src_wire, WireId dst_wire, delay_t *delay, bool Context::getActualRouteDelay(WireId src_wire, WireId dst_wire, delay_t *delay, dict<WireId, PipId> *route,
std::unordered_map<WireId, PipId> *route, bool useEstimate) bool useEstimate)
{ {
// FIXME // FIXME
return false; return false;

View File

@ -35,7 +35,6 @@
#include <fstream> #include <fstream>
#include <queue> #include <queue>
#include "hash_table.h"
#include "log.h" #include "log.h"
#include "nextpnr.h" #include "nextpnr.h"
#include "router1.h" #include "router1.h"
@ -131,8 +130,8 @@ struct Router2
nets.resize(ctx->nets.size()); nets.resize(ctx->nets.size());
nets_by_udata.resize(ctx->nets.size()); nets_by_udata.resize(ctx->nets.size());
size_t i = 0; size_t i = 0;
for (auto net : sorted(ctx->nets)) { for (auto &net : ctx->nets) {
NetInfo *ni = net.second; NetInfo *ni = net.second.get();
ni->udata = i; ni->udata = i;
nets_by_udata.at(i) = ni; nets_by_udata.at(i) = ni;
nets.at(i).arcs.resize(ni->users.size()); nets.at(i).arcs.resize(ni->users.size());
@ -198,7 +197,7 @@ struct Router2
} }
} }
HashTables::HashMap<WireId, int> wire_to_idx; dict<WireId, int> wire_to_idx;
std::vector<PerWireData> flat_wires; std::vector<PerWireData> flat_wires;
PerWireData &wire_data(WireId w) { return flat_wires[wire_to_idx.at(w)]; } PerWireData &wire_data(WireId w) { return flat_wires[wire_to_idx.at(w)]; }
@ -231,8 +230,8 @@ struct Router2
flat_wires.push_back(pwd); flat_wires.push_back(pwd);
} }
for (auto net_pair : sorted(ctx->nets)) { for (auto &net_pair : ctx->nets) {
auto *net = net_pair.second; auto *net = net_pair.second.get();
auto &nd = nets.at(net->udata); auto &nd = nets.at(net->udata);
for (size_t usr = 0; usr < net->users.size(); usr++) { for (size_t usr = 0; usr < net->users.size(); usr++) {
auto &ad = nd.arcs.at(usr); auto &ad = nd.arcs.at(usr);
@ -284,7 +283,7 @@ struct Router2
std::priority_queue<QueuedWire, std::vector<QueuedWire>, QueuedWire::Greater> queue; std::priority_queue<QueuedWire, std::vector<QueuedWire>, QueuedWire::Greater> queue;
// Special case where one net has multiple logical arcs to the same physical sink // Special case where one net has multiple logical arcs to the same physical sink
std::unordered_set<WireId> processed_sinks; pool<WireId> processed_sinks;
// Backwards routing // Backwards routing
std::queue<int> backwards_queue; std::queue<int> backwards_queue;
@ -465,7 +464,7 @@ struct Router2
bool did_something = false; bool did_something = false;
WireId src = ctx->getNetinfoSourceWire(net); WireId src = ctx->getNetinfoSourceWire(net);
for (auto sink : ctx->getNetinfoSinkWires(net, net->users.at(i))) { for (auto sink : ctx->getNetinfoSinkWires(net, net->users.at(i))) {
std::unordered_set<WireId> rsv; pool<WireId> rsv;
WireId cursor = sink; WireId cursor = sink;
bool done = false; bool done = false;
if (ctx->debug) if (ctx->debug)
@ -1083,7 +1082,7 @@ struct Router2
void write_wiretype_heatmap(std::ostream &out) void write_wiretype_heatmap(std::ostream &out)
{ {
std::unordered_map<IdString, std::vector<int>> cong_by_type; dict<IdString, std::vector<int>> cong_by_type;
size_t max_cong = 0; size_t max_cong = 0;
// Build histogram // Build histogram
for (auto &wd : flat_wires) { for (auto &wd : flat_wires) {
@ -1099,7 +1098,7 @@ struct Router2
for (size_t i = 0; i <= max_cong; i++) for (size_t i = 0; i <= max_cong; i++)
out << "bound=" << i << ","; out << "bound=" << i << ",";
out << std::endl; out << std::endl;
for (auto &ty : sorted_ref(cong_by_type)) { for (auto &ty : cong_by_type) {
out << ctx->nameOf(ty.first) << ","; out << ctx->nameOf(ty.first) << ",";
for (int count : ty.second) for (int count : ty.second)
out << count << ","; out << count << ",";

View File

@ -254,9 +254,9 @@ void Context::writeSDF(std::ostream &out, bool cvc_mode) const
return rf; return rf;
}; };
for (auto cell : sorted(cells)) { for (const auto &cell : cells) {
Cell sc; Cell sc;
const CellInfo *ci = cell.second; const CellInfo *ci = cell.second.get();
sc.instance = ci->name.str(this); sc.instance = ci->name.str(this);
sc.celltype = ci->type.str(this); sc.celltype = ci->type.str(this);
for (auto port : ci->ports) { for (auto port : ci->ports) {
@ -313,8 +313,8 @@ void Context::writeSDF(std::ostream &out, bool cvc_mode) const
wr.cells.push_back(sc); wr.cells.push_back(sc);
} }
for (auto net : sorted(nets)) { for (auto &net : nets) {
NetInfo *ni = net.second; NetInfo *ni = net.second.get();
if (ni->driver.cell == nullptr) if (ni->driver.cell == nullptr)
continue; continue;
for (auto &usr : ni->users) { for (auto &usr : ni->users) {

View File

@ -23,7 +23,6 @@
#include <boost/range/adaptor/reversed.hpp> #include <boost/range/adaptor/reversed.hpp>
#include <deque> #include <deque>
#include <map> #include <map>
#include <unordered_map>
#include <utility> #include <utility>
#include "log.h" #include "log.h"
#include "util.h" #include "util.h"
@ -52,17 +51,17 @@ void TimingAnalyser::run()
void TimingAnalyser::init_ports() void TimingAnalyser::init_ports()
{ {
// Per cell port structures // Per cell port structures
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
for (auto port : sorted_ref(ci->ports)) { for (auto &port : ci->ports) {
auto &data = ports[CellPortKey(ci->name, port.first)]; auto &data = ports[CellPortKey(ci->name, port.first)];
data.type = port.second.type; data.type = port.second.type;
data.cell_port = CellPortKey(ci->name, port.first); data.cell_port = CellPortKey(ci->name, port.first);
} }
} }
// Cell port to net port mapping // Cell port to net port mapping
for (auto net : sorted(ctx->nets)) { for (auto &net : ctx->nets) {
NetInfo *ni = net.second; NetInfo *ni = net.second.get();
if (ni->driver.cell != nullptr) if (ni->driver.cell != nullptr)
ports[CellPortKey(ni->driver)].net_port = NetPortKey(ni->name); ports[CellPortKey(ni->driver)].net_port = NetPortKey(ni->name);
for (size_t i = 0; i < ni->users.size(); i++) for (size_t i = 0; i < ni->users.size(); i++)
@ -138,8 +137,8 @@ void TimingAnalyser::get_cell_delays()
void TimingAnalyser::get_route_delays() void TimingAnalyser::get_route_delays()
{ {
for (auto net : sorted(ctx->nets)) { for (auto &net : ctx->nets) {
NetInfo *ni = net.second; NetInfo *ni = net.second.get();
if (ni->driver.cell == nullptr || ni->driver.cell->bel == BelId()) if (ni->driver.cell == nullptr || ni->driver.cell->bel == BelId())
continue; continue;
for (auto &usr : ni->users) { for (auto &usr : ni->users) {
@ -272,7 +271,7 @@ void TimingAnalyser::setup_port_domains()
void TimingAnalyser::reset_times() void TimingAnalyser::reset_times()
{ {
for (auto &port : ports) { for (auto &port : ports) {
auto do_reset = [&](std::unordered_map<domain_id_t, ArrivReqTime> &times) { auto do_reset = [&](dict<domain_id_t, ArrivReqTime> &times) {
for (auto &t : times) { for (auto &t : times) {
t.second.value = init_delay; t.second.value = init_delay;
t.second.path_length = 0; t.second.path_length = 0;
@ -426,7 +425,7 @@ void TimingAnalyser::walk_backward()
void TimingAnalyser::print_fmax() void TimingAnalyser::print_fmax()
{ {
// Temporary testing code for comparison only // Temporary testing code for comparison only
std::unordered_map<int, double> domain_fmax; dict<int, double> domain_fmax;
for (auto p : topological_order) { for (auto p : topological_order) {
auto &pd = ports.at(p); auto &pd = ports.at(p);
for (auto &req : pd.required) { for (auto &req : pd.required) {
@ -591,6 +590,7 @@ struct ClockEvent
ClockEdge edge; ClockEdge edge;
bool operator==(const ClockEvent &other) const { return clock == other.clock && edge == other.edge; } bool operator==(const ClockEvent &other) const { return clock == other.clock && edge == other.edge; }
unsigned int hash() const { return mkhash(clock.hash(), int(edge)); }
}; };
struct ClockPair struct ClockPair
@ -598,37 +598,10 @@ struct ClockPair
ClockEvent start, end; ClockEvent start, end;
bool operator==(const ClockPair &other) const { return start == other.start && end == other.end; } bool operator==(const ClockPair &other) const { return start == other.start && end == other.end; }
unsigned int hash() const { return mkhash(start.hash(), end.hash()); }
}; };
} // namespace } // namespace
NEXTPNR_NAMESPACE_END
namespace std {
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX ClockEvent>
{
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX ClockEvent &obj) const noexcept
{
std::size_t seed = 0;
boost::hash_combine(seed, hash<NEXTPNR_NAMESPACE_PREFIX IdString>()(obj.clock));
boost::hash_combine(seed, hash<int>()(int(obj.edge)));
return seed;
}
};
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX ClockPair>
{
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX ClockPair &obj) const noexcept
{
std::size_t seed = 0;
boost::hash_combine(seed, hash<NEXTPNR_NAMESPACE_PREFIX ClockEvent>()(obj.start));
boost::hash_combine(seed, hash<NEXTPNR_NAMESPACE_PREFIX ClockEvent>()(obj.start));
return seed;
}
};
} // namespace std
NEXTPNR_NAMESPACE_BEGIN
typedef std::vector<const PortRef *> PortRefVector; typedef std::vector<const PortRef *> PortRefVector;
typedef std::map<int, unsigned> DelayFrequency; typedef std::map<int, unsigned> DelayFrequency;
@ -639,7 +612,7 @@ struct CriticalPath
delay_t path_period; delay_t path_period;
}; };
typedef std::unordered_map<ClockPair, CriticalPath> CriticalPathMap; typedef dict<ClockPair, CriticalPath> CriticalPathMap;
struct Timing struct Timing
{ {
@ -660,7 +633,7 @@ struct Timing
delay_t min_remaining_budget; delay_t min_remaining_budget;
bool false_startpoint = false; bool false_startpoint = false;
std::vector<delay_t> min_required; std::vector<delay_t> min_required;
std::unordered_map<ClockEvent, delay_t> arrival_time; dict<ClockEvent, delay_t> arrival_time;
}; };
Timing(Context *ctx, bool net_delays, bool update, CriticalPathMap *crit_path = nullptr, Timing(Context *ctx, bool net_delays, bool update, CriticalPathMap *crit_path = nullptr,
@ -677,14 +650,14 @@ struct Timing
// First, compute the topological order of nets to walk through the circuit, assuming it is a _acyclic_ graph // First, compute the topological order of nets to walk through the circuit, assuming it is a _acyclic_ graph
// TODO(eddieh): Handle the case where it is cyclic, e.g. combinatorial loops // TODO(eddieh): Handle the case where it is cyclic, e.g. combinatorial loops
std::vector<NetInfo *> topological_order; std::vector<NetInfo *> topological_order;
std::unordered_map<const NetInfo *, std::unordered_map<ClockEvent, TimingData>> net_data; dict<const NetInfo *, dict<ClockEvent, TimingData>, hash_ptr_ops> net_data;
// In lieu of deleting edges from the graph, simply count the number of fanins to each output port // In lieu of deleting edges from the graph, simply count the number of fanins to each output port
std::unordered_map<const PortInfo *, unsigned> port_fanin; dict<const PortInfo *, unsigned, hash_ptr_ops> port_fanin;
std::vector<IdString> input_ports; std::vector<IdString> input_ports;
std::vector<const PortInfo *> output_ports; std::vector<const PortInfo *> output_ports;
std::unordered_set<IdString> ooc_port_nets; pool<IdString> ooc_port_nets;
// In out-of-context mode, top-level inputs look floating but aren't // In out-of-context mode, top-level inputs look floating but aren't
if (bool_or_default(ctx->settings, ctx->id("arch.ooc"))) { if (bool_or_default(ctx->settings, ctx->id("arch.ooc"))) {
@ -880,7 +853,7 @@ struct Timing
} }
} }
std::unordered_map<ClockPair, std::pair<delay_t, NetInfo *>> crit_nets; dict<ClockPair, std::pair<delay_t, NetInfo *>> crit_nets;
// Now go backwards topologically to determine the minimum path slack, and to distribute all path slack evenly // Now go backwards topologically to determine the minimum path slack, and to distribute all path slack evenly
// between all nets on the path // between all nets on the path

View File

@ -35,15 +35,7 @@ struct CellPortKey
port = pr.port; port = pr.port;
} }
IdString cell, port; IdString cell, port;
struct Hash unsigned int hash() const { return mkhash(cell.hash(), port.hash()); }
{
inline std::size_t operator()(const CellPortKey &arg) const noexcept
{
std::size_t seed = std::hash<IdString>()(arg.cell);
seed ^= std::hash<IdString>()(arg.port) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
return seed;
}
};
inline bool operator==(const CellPortKey &other) const { return (cell == other.cell) && (port == other.port); } inline bool operator==(const CellPortKey &other) const { return (cell == other.cell) && (port == other.port); }
inline bool operator!=(const CellPortKey &other) const { return (cell != other.cell) || (port != other.port); } inline bool operator!=(const CellPortKey &other) const { return (cell != other.cell) || (port != other.port); }
inline bool operator<(const CellPortKey &other) const inline bool operator<(const CellPortKey &other) const
@ -69,15 +61,8 @@ struct NetPortKey
return idx; return idx;
} }
struct Hash unsigned int hash() const { return mkhash(net.hash(), idx); }
{
std::size_t operator()(const NetPortKey &arg) const noexcept
{
std::size_t seed = std::hash<IdString>()(arg.net);
seed ^= std::hash<size_t>()(arg.idx) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
return seed;
}
};
inline bool operator==(const NetPortKey &other) const { return (net == other.net) && (idx == other.idx); } inline bool operator==(const NetPortKey &other) const { return (net == other.net) && (idx == other.idx); }
}; };
@ -89,15 +74,8 @@ struct ClockDomainKey
// probably also need something here to deal with constraints // probably also need something here to deal with constraints
inline bool is_async() const { return clock == IdString(); } inline bool is_async() const { return clock == IdString(); }
struct Hash unsigned int hash() const { return mkhash(clock.hash(), int(edge)); }
{
std::size_t operator()(const ClockDomainKey &arg) const noexcept
{
std::size_t seed = std::hash<IdString>()(arg.clock);
seed ^= std::hash<int>()(int(arg.edge)) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
return seed;
}
};
inline bool operator==(const ClockDomainKey &other) const { return (clock == other.clock) && (edge == other.edge); } inline bool operator==(const ClockDomainKey &other) const { return (clock == other.clock) && (edge == other.edge); }
}; };
@ -111,15 +89,7 @@ struct ClockDomainPairKey
{ {
return (launch == other.launch) && (capture == other.capture); return (launch == other.launch) && (capture == other.capture);
} }
struct Hash unsigned int hash() const { return mkhash(launch, capture); }
{
std::size_t operator()(const ClockDomainPairKey &arg) const noexcept
{
std::size_t seed = std::hash<domain_id_t>()(arg.launch);
seed ^= std::hash<domain_id_t>()(arg.capture) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
return seed;
}
};
}; };
struct TimingAnalyser struct TimingAnalyser
@ -223,16 +193,17 @@ struct TimingAnalyser
NetPortKey net_port; NetPortKey net_port;
PortType type; PortType type;
// per domain timings // per domain timings
std::unordered_map<domain_id_t, ArrivReqTime> arrival; dict<domain_id_t, ArrivReqTime> arrival;
std::unordered_map<domain_id_t, ArrivReqTime> required; dict<domain_id_t, ArrivReqTime> required;
std::unordered_map<domain_id_t, PortDomainPairData> domain_pairs; dict<domain_id_t, PortDomainPairData> domain_pairs;
// cell timing arcs to (outputs)/from (inputs) from this port // cell timing arcs to (outputs)/from (inputs) from this port
std::vector<CellArc> cell_arcs; std::vector<CellArc> cell_arcs;
// routing delay into this port (input ports only) // routing delay into this port (input ports only)
DelayPair route_delay; DelayPair route_delay{0};
// worst criticality and slack across domain pairs // worst criticality and slack across domain pairs
float worst_crit; float worst_crit = 0;
delay_t worst_setup_slack, worst_hold_slack; delay_t worst_setup_slack = std::numeric_limits<delay_t>::max(),
worst_hold_slack = std::numeric_limits<delay_t>::max();
}; };
struct PerDomain struct PerDomain
@ -260,9 +231,9 @@ struct TimingAnalyser
void copy_domains(const CellPortKey &from, const CellPortKey &to, bool backwards); void copy_domains(const CellPortKey &from, const CellPortKey &to, bool backwards);
std::unordered_map<CellPortKey, PerPort, CellPortKey::Hash> ports; dict<CellPortKey, PerPort> ports;
std::unordered_map<ClockDomainKey, domain_id_t, ClockDomainKey::Hash> domain_to_id; dict<ClockDomainKey, domain_id_t> domain_to_id;
std::unordered_map<ClockDomainPairKey, domain_id_t, ClockDomainPairKey::Hash> pair_to_id; dict<ClockDomainPairKey, domain_id_t> pair_to_id;
std::vector<PerDomain> domains; std::vector<PerDomain> domains;
std::vector<PerDomainPair> domain_pairs; std::vector<PerDomainPair> domain_pairs;

View File

@ -35,8 +35,6 @@
#include "timing.h" #include "timing.h"
#include "util.h" #include "util.h"
#include "hash_table.h"
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
class TimingOptimiser class TimingOptimiser
@ -68,8 +66,8 @@ class TimingOptimiser
void setup_delay_limits() void setup_delay_limits()
{ {
max_net_delay.clear(); max_net_delay.clear();
for (auto net : sorted(ctx->nets)) { for (auto &net : ctx->nets) {
NetInfo *ni = net.second; NetInfo *ni = net.second.get();
if (ni->driver.cell == nullptr) if (ni->driver.cell == nullptr)
continue; continue;
for (auto usr : ni->users) { for (auto usr : ni->users) {
@ -167,7 +165,7 @@ class TimingOptimiser
BelId curr = cell->bel; BelId curr = cell->bel;
Loc curr_loc = ctx->getBelLocation(curr); Loc curr_loc = ctx->getBelLocation(curr);
int found_count = 0; int found_count = 0;
cell_neighbour_bels[cell->name] = std::unordered_set<BelId>{}; cell_neighbour_bels[cell->name] = pool<BelId>{};
for (int dy = -d; dy <= d; dy++) { for (int dy = -d; dy <= d; dy++) {
for (int dx = -d; dx <= d; dx++) { for (int dx = -d; dx <= d; dx++) {
// Go through all the Bels at this location // Go through all the Bels at this location
@ -239,7 +237,7 @@ class TimingOptimiser
std::vector<std::pair<NetInfo *, int>> crit_nets; std::vector<std::pair<NetInfo *, int>> crit_nets;
std::vector<IdString> netnames; std::vector<IdString> netnames;
std::transform(ctx->nets.begin(), ctx->nets.end(), std::back_inserter(netnames), std::transform(ctx->nets.begin(), ctx->nets.end(), std::back_inserter(netnames),
[](const std::pair<const IdString, std::unique_ptr<NetInfo>> &kv) { return kv.first; }); [](const std::pair<IdString, std::unique_ptr<NetInfo>> &kv) { return kv.first; });
ctx->sorted_shuffle(netnames); ctx->sorted_shuffle(netnames);
for (auto net : netnames) { for (auto net : netnames) {
if (crit_nets.size() >= max_count) if (crit_nets.size() >= max_count)
@ -267,7 +265,7 @@ class TimingOptimiser
} }
NPNR_ASSERT_FALSE("port user not found on net"); NPNR_ASSERT_FALSE("port user not found on net");
}; };
std::unordered_set<PortRef *> used_ports; pool<PortRef *, hash_ptr_ops> used_ports;
for (auto crit_net : crit_nets) { for (auto crit_net : crit_nets) {
@ -439,10 +437,10 @@ class TimingOptimiser
} }
// Actual BFS path optimisation algorithm // Actual BFS path optimisation algorithm
std::unordered_map<IdString, std::unordered_map<BelId, delay_t>> cumul_costs; dict<IdString, dict<BelId, delay_t>> cumul_costs;
std::unordered_map<std::pair<IdString, BelId>, std::pair<IdString, BelId>, PairHash> backtrace; dict<std::pair<IdString, BelId>, std::pair<IdString, BelId>> backtrace;
std::queue<std::pair<int, BelId>> visit; std::queue<std::pair<int, BelId>> visit;
std::unordered_set<std::pair<int, BelId>, PairHash> to_visit; pool<std::pair<int, BelId>> to_visit;
for (auto startbel : cell_neighbour_bels[path_cells.front()]) { for (auto startbel : cell_neighbour_bels[path_cells.front()]) {
// Swap for legality check // Swap for legality check
@ -568,10 +566,10 @@ class TimingOptimiser
// Current candidate Bels for cells (linked in both direction> // Current candidate Bels for cells (linked in both direction>
std::vector<IdString> path_cells; std::vector<IdString> path_cells;
std::unordered_map<IdString, std::unordered_set<BelId>> cell_neighbour_bels; dict<IdString, pool<BelId>> cell_neighbour_bels;
std::unordered_map<BelId, std::unordered_set<IdString>> bel_candidate_cells; dict<BelId, pool<IdString>> bel_candidate_cells;
// Map cell ports to net delay limit // Map cell ports to net delay limit
std::unordered_map<std::pair<IdString, IdString>, delay_t, PairHash> max_net_delay; dict<std::pair<IdString, IdString>, delay_t> max_net_delay;
Context *ctx; Context *ctx;
TimingOptCfg cfg; TimingOptCfg cfg;
TimingAnalyser tmg; TimingAnalyser tmg;

View File

@ -29,7 +29,7 @@ struct TimingOptCfg
// The timing optimiser will *only* optimise cells of these types // The timing optimiser will *only* optimise cells of these types
// Normally these would only be logic cells (or tiles if applicable), the algorithm makes little sense // Normally these would only be logic cells (or tiles if applicable), the algorithm makes little sense
// for other cell types // for other cell types
std::unordered_set<IdString> cellTypes; pool<IdString> cellTypes;
}; };
extern bool timing_opt(Context *ctx, TimingOptCfg cfg); extern bool timing_opt(Context *ctx, TimingOptCfg cfg);

View File

@ -55,7 +55,7 @@ std::string str_or_default(const Container &ct, const KeyType &key, std::string
}; };
template <typename KeyType> template <typename KeyType>
std::string str_or_default(const std::unordered_map<KeyType, Property> &ct, const KeyType &key, std::string def = "") std::string str_or_default(const dict<KeyType, Property> &ct, const KeyType &key, std::string def = "")
{ {
auto found = ct.find(key); auto found = ct.find(key);
if (found == ct.end()) if (found == ct.end())
@ -78,8 +78,7 @@ template <typename Container, typename KeyType> int int_or_default(const Contain
return std::stoi(found->second); return std::stoi(found->second);
}; };
template <typename KeyType> template <typename KeyType> int int_or_default(const dict<KeyType, Property> &ct, const KeyType &key, int def = 0)
int int_or_default(const std::unordered_map<KeyType, Property> &ct, const KeyType &key, int def = 0)
{ {
auto found = ct.find(key); auto found = ct.find(key);
if (found == ct.end()) if (found == ct.end())
@ -103,42 +102,6 @@ bool bool_or_default(const Container &ct, const KeyType &key, bool def = false)
return bool(int_or_default(ct, key, int(def))); return bool(int_or_default(ct, key, int(def)));
}; };
// Wrap an unordered_map, and allow it to be iterated over sorted by key
template <typename K, typename V> std::map<K, V *> sorted(const std::unordered_map<K, std::unique_ptr<V>> &orig)
{
std::map<K, V *> retVal;
for (auto &item : orig)
retVal.emplace(std::make_pair(item.first, item.second.get()));
return retVal;
};
// Wrap an unordered_map, and allow it to be iterated over sorted by key
template <typename K, typename V> std::map<K, V &> sorted_ref(std::unordered_map<K, V> &orig)
{
std::map<K, V &> retVal;
for (auto &item : orig)
retVal.emplace(std::make_pair(item.first, std::ref(item.second)));
return retVal;
};
// Wrap an unordered_map, and allow it to be iterated over sorted by key
template <typename K, typename V> std::map<K, const V &> sorted_cref(const std::unordered_map<K, V> &orig)
{
std::map<K, const V &> retVal;
for (auto &item : orig)
retVal.emplace(std::make_pair(item.first, std::ref(item.second)));
return retVal;
};
// Wrap an unordered_set, and allow it to be iterated over sorted by key
template <typename K> std::set<K> sorted(const std::unordered_set<K> &orig)
{
std::set<K> retVal;
for (auto &item : orig)
retVal.insert(item);
return retVal;
};
// Return a net if port exists, or nullptr // Return a net if port exists, or nullptr
inline const NetInfo *get_net_or_empty(const CellInfo *cell, const IdString port) inline const NetInfo *get_net_or_empty(const CellInfo *cell, const IdString port)
{ {

View File

@ -45,31 +45,31 @@ A scalar type that is used to represent delays. May be an integer or float type
### BelId ### BelId
A type representing a bel name. `BelId()` must construct a unique null-value. Must provide `==`, `!=`, and `<` operators and a specialization for `std::hash<BelId>`. A type representing a bel name. `BelId()` must construct a unique null-value. Must provide `==`, `!=`, and `<` operators and a `unsigned int hash() const` member function.
### WireId ### WireId
A type representing a wire name. `WireId()` must construct a unique null-value. Must provide `==`, `!=`, and `<` operators and a specialization for `std::hash<WireId>`. A type representing a wire name. `WireId()` must construct a unique null-value. Must provide `==`, `!=`, and `<` operators and a `unsigned int hash() const` member function.
### PipId ### PipId
A type representing a pip name. `PipId()` must construct a unique null-value. Must provide `==`, `!=`, and `<` operators and a specialization for `std::hash<PipId>`. A type representing a pip name. `PipId()` must construct a unique null-value. Must provide `==`, `!=`, and `<` operators and a `unsigned int hash() const` member function.
### BelBucketId ### BelBucketId
A type representing a bel bucket. `BelBucketId()` must construct a unique null-value. Must provide `==`, `!=`, and `<` operators and a specialization for `std::hash<BelBucketId>`. A type representing a bel bucket. `BelBucketId()` must construct a unique null-value. Must provide `==`, `!=`, and `<` operators and a `unsigned int hash() const` member function.
### GroupId ### GroupId
A type representing a group name. `GroupId()` must construct a unique null-value. Must provide `==` and `!=` operators and a specialization for `std::hash<GroupId>`. A type representing a group name. `GroupId()` must construct a unique null-value. Must provide `==` and `!=` operators and a `unsigned int hash() const` member function.
### DecalId ### DecalId
A type representing a reference to a graphical decal. `DecalId()` must construct a unique null-value. Must provide `==` and `!=` operators and a specialization for `std::hash<DecalId>`. A type representing a reference to a graphical decal. `DecalId()` must construct a unique null-value. Must provide `==` and `!=` operators and a `unsigned int hash() const` member function.
### ClusterId ### ClusterId
A type representing a reference to a constrained cluster of cells. `ClusterId()` must construct a unique null-value. Must provide `==` and `!=` operators and a specialization for `std::hash<ClusterId>`. A type representing a reference to a constrained cluster of cells. `ClusterId()` must construct a unique null-value. Must provide `==` and `!=` operators and `unsigned int hash() const` member function.
### ArchNetInfo ### ArchNetInfo
@ -171,7 +171,7 @@ Returns true if the given bel is a global buffer. A global buffer does not "pull
Return a (preferably unique) number that represents this bel. This is used in design state checksum calculations. Return a (preferably unique) number that represents this bel. This is used in design state checksum calculations.
*BaseArch default: returns `std::hash` of `BelId` cast to `uint32_t`* *BaseArch default: returns `bel.hash()`*
### void bindBel(BelId bel, CellInfo \*cell, PlaceStrength strength) ### void bindBel(BelId bel, CellInfo \*cell, PlaceStrength strength)
@ -276,7 +276,7 @@ unused. An implementation may simply return an empty range.
Return a (preferably unique) number that represents this wire. This is used in design state checksum calculations. Return a (preferably unique) number that represents this wire. This is used in design state checksum calculations.
*BaseArch default: returns `std::hash` of `WireId` cast to `uint32_t`* *BaseArch default: returns `wire.hash()`*
### void bindWire(WireId wire, NetInfo \*net, PlaceStrength strength) ### void bindWire(WireId wire, NetInfo \*net, PlaceStrength strength)
@ -374,7 +374,7 @@ for pips a X/Y/Z location refers to a group of pips, not an individual pip.
Return a (preferably unique) number that represents this pip. This is used in design state checksum calculations. Return a (preferably unique) number that represents this pip. This is used in design state checksum calculations.
*BaseArch default: returns `std::hash` of `WireId` cast to `uint32_t`* *BaseArch default: returns `pip.hash()`*
### void bindPip(PipId pip, NetInfo \*net, PlaceStrength strength) ### void bindPip(PipId pip, NetInfo \*net, PlaceStrength strength)

View File

@ -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;

View File

@ -98,15 +98,6 @@ void Arch::permute_luts()
TimingAnalyser tmg(getCtx()); TimingAnalyser tmg(getCtx());
tmg.setup(); tmg.setup();
std::unordered_map<PortInfo *, size_t> port_to_user;
for (auto net : sorted(nets)) {
NetInfo *ni = net.second;
for (size_t i = 0; i < ni->users.size(); i++) {
auto &usr = ni->users.at(i);
port_to_user[&(usr.cell->ports.at(usr.port))] = i;
}
}
auto proc_lut = [&](CellInfo *ci, int lut) { auto proc_lut = [&](CellInfo *ci, int lut) {
std::vector<IdString> port_names; std::vector<IdString> port_names;
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
@ -157,8 +148,8 @@ void Arch::permute_luts()
ci->params[id("LUT" + std::to_string(lut) + "_INITVAL")] = Property(new_init, 16); ci->params[id("LUT" + std::to_string(lut) + "_INITVAL")] = Property(new_init, 16);
}; };
for (auto cell : sorted(cells)) { for (auto &cell : cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (ci->type == id_TRELLIS_SLICE && str_or_default(ci->params, id("MODE"), "LOGIC") == "LOGIC") { if (ci->type == id_TRELLIS_SLICE && str_or_default(ci->params, id("MODE"), "LOGIC") == "LOGIC") {
proc_lut(ci, 0); proc_lut(ci, 0);
proc_lut(ci, 1); proc_lut(ci, 1);
@ -169,8 +160,8 @@ void Arch::permute_luts()
void Arch::setup_wire_locations() void Arch::setup_wire_locations()
{ {
wire_loc_overrides.clear(); wire_loc_overrides.clear();
for (auto cell : sorted(cells)) { for (auto &cell : cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (ci->bel == BelId()) if (ci->bel == BelId())
continue; continue;
if (ci->type == id_MULT18X18D || ci->type == id_DCUA || ci->type == id_DDRDLL || ci->type == id_DQSBUFM || if (ci->type == id_MULT18X18D || ci->type == id_DCUA || ci->type == id_DDRDLL || ci->type == id_DQSBUFM ||

View File

@ -44,10 +44,10 @@ void arch_wrap_python(py::module &m)
.def("place", &Context::place) .def("place", &Context::place)
.def("route", &Context::route); .def("route", &Context::route);
typedef std::unordered_map<IdString, std::unique_ptr<CellInfo>> CellMap; typedef dict<IdString, std::unique_ptr<CellInfo>> CellMap;
typedef std::unordered_map<IdString, std::unique_ptr<NetInfo>> NetMap; typedef dict<IdString, std::unique_ptr<NetInfo>> NetMap;
typedef std::unordered_map<IdString, IdString> AliasMap; typedef dict<IdString, IdString> AliasMap;
typedef std::unordered_map<IdString, HierarchicalCell> HierarchyMap; typedef dict<IdString, HierarchicalCell> HierarchyMap;
auto belpin_cls = py::class_<ContextualWrapper<BelPin>>(m, "BelPin"); auto belpin_cls = py::class_<ContextualWrapper<BelPin>>(m, "BelPin");
readonly_wrapper<BelPin, decltype(&BelPin::bel), &BelPin::bel, conv_to_str<BelId>>::def_wrap(belpin_cls, "bel"); readonly_wrapper<BelPin, decltype(&BelPin::bel), &BelPin::bel, conv_to_str<BelId>>::def_wrap(belpin_cls, "bel");

View File

@ -21,9 +21,8 @@
#ifndef ECP5_ARCHDEFS_H #ifndef ECP5_ARCHDEFS_H
#define ECP5_ARCHDEFS_H #define ECP5_ARCHDEFS_H
#include <boost/functional/hash.hpp>
#include "base_clusterinfo.h" #include "base_clusterinfo.h"
#include "hashlib.h"
#include "idstring.h" #include "idstring.h"
#include "nextpnr_namespaces.h" #include "nextpnr_namespaces.h"
@ -63,6 +62,7 @@ struct Location
bool operator==(const Location &other) const { return x == other.x && y == other.y; } bool operator==(const Location &other) const { return x == other.x && y == other.y; }
bool operator!=(const Location &other) const { return x != other.x || y != other.y; } bool operator!=(const Location &other) const { return x != other.x || y != other.y; }
bool operator<(const Location &other) const { return y == other.y ? x < other.x : y < other.y; } bool operator<(const Location &other) const { return y == other.y ? x < other.x : y < other.y; }
unsigned int hash() const { return mkhash(x, y); }
}; };
inline Location operator+(const Location &a, const Location &b) { return Location(a.x + b.x, a.y + b.y); } inline Location operator+(const Location &a, const Location &b) { return Location(a.x + b.x, a.y + b.y); }
@ -78,6 +78,7 @@ struct BelId
{ {
return location == other.location ? index < other.index : location < other.location; return location == other.location ? index < other.index : location < other.location;
} }
unsigned int hash() const { return mkhash(location.hash(), index); }
}; };
struct WireId struct WireId
@ -91,6 +92,7 @@ struct WireId
{ {
return location == other.location ? index < other.index : location < other.location; return location == other.location ? index < other.index : location < other.location;
} }
unsigned int hash() const { return mkhash(location.hash(), index); }
}; };
struct PipId struct PipId
@ -104,6 +106,7 @@ struct PipId
{ {
return location == other.location ? index < other.index : location < other.location; return location == other.location ? index < other.index : location < other.location;
} }
unsigned int hash() const { return mkhash(location.hash(), index); }
}; };
typedef IdString BelBucketId; typedef IdString BelBucketId;
@ -119,6 +122,7 @@ struct GroupId
bool operator==(const GroupId &other) const { return (type == other.type) && (location == other.location); } bool operator==(const GroupId &other) const { return (type == other.type) && (location == other.location); }
bool operator!=(const GroupId &other) const { return (type != other.type) || (location != other.location); } bool operator!=(const GroupId &other) const { return (type != other.type) || (location != other.location); }
unsigned int hash() const { return mkhash(location.hash(), int(type)); }
}; };
struct DecalId struct DecalId
@ -142,6 +146,7 @@ struct DecalId
{ {
return type != other.type || location != other.location || z != other.z || active != other.active; return type != other.type || location != other.location || z != other.z || active != other.active;
} }
unsigned int hash() const { return mkhash(location.hash(), mkhash(z, int(type))); }
}; };
struct ArchNetInfo struct ArchNetInfo
@ -180,72 +185,4 @@ struct ArchCellInfo : BaseClusterInfo
}; };
NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_END
namespace std {
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX Location>
{
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX Location &loc) const noexcept
{
std::size_t seed = std::hash<int>()(loc.x);
seed ^= std::hash<int>()(loc.y) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
return seed;
}
};
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX BelId>
{
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX BelId &bel) const noexcept
{
std::size_t seed = std::hash<NEXTPNR_NAMESPACE_PREFIX Location>()(bel.location);
seed ^= std::hash<int>()(bel.index) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
return seed;
}
};
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX WireId>
{
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX WireId &wire) const noexcept
{
std::size_t seed = std::hash<NEXTPNR_NAMESPACE_PREFIX Location>()(wire.location);
seed ^= std::hash<int>()(wire.index) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
return seed;
}
};
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX PipId>
{
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX PipId &pip) const noexcept
{
std::size_t seed = std::hash<NEXTPNR_NAMESPACE_PREFIX Location>()(pip.location);
seed ^= std::hash<int>()(pip.index) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
return seed;
}
};
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX GroupId>
{
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX GroupId &group) const noexcept
{
std::size_t seed = 0;
boost::hash_combine(seed, hash<int>()(group.type));
boost::hash_combine(seed, hash<NEXTPNR_NAMESPACE_PREFIX Location>()(group.location));
return seed;
}
};
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX DecalId>
{
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX DecalId &decal) const noexcept
{
std::size_t seed = 0;
boost::hash_combine(seed, hash<int>()(decal.type));
boost::hash_combine(seed, hash<NEXTPNR_NAMESPACE_PREFIX Location>()(decal.location));
boost::hash_combine(seed, hash<int>()(decal.z));
boost::hash_combine(seed, hash<bool>()(decal.active));
return seed;
}
};
} // namespace std
#endif /* ECP5_ARCHDEFS_H */ #endif /* ECP5_ARCHDEFS_H */

View File

@ -569,8 +569,7 @@ static std::vector<bool> parse_config_str(const Property &p, int length)
return word; return word;
} }
std::string intstr_or_default(const std::unordered_map<IdString, Property> &ct, const IdString &key, std::string intstr_or_default(const dict<IdString, Property> &ct, const IdString &key, std::string def = "0")
std::string def = "0")
{ {
auto found = ct.find(key); auto found = ct.find(key);
if (found == ct.end()) if (found == ct.end())
@ -670,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();

View File

@ -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");

View File

@ -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

View File

@ -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"))
@ -91,8 +91,8 @@ class Ecp5GlobalRouter
} }
// DCCAs must always drive globals // DCCAs must always drive globals
std::vector<NetInfo *> clocks; std::vector<NetInfo *> clocks;
for (auto &cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (ci->type == id_DCCA) { if (ci->type == id_DCCA) {
NetInfo *glb = ci->ports.at(id_CLKO).net; NetInfo *glb = ci->ports.at(id_CLKO).net;
if (glb != nullptr) { if (glb != nullptr) {
@ -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,9 +535,9 @@ 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 : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (ci->type == id_DCCA) { if (ci->type == id_DCCA) {
NetInfo *clock = ci->ports.at(id_CLKO).net; NetInfo *clock = ci->ports.at(id_CLKO).net;
NPNR_ASSERT(clock != nullptr); NPNR_ASSERT(clock != nullptr);
@ -577,8 +577,8 @@ class Ecp5GlobalRouter
void route_eclk_sources() void route_eclk_sources()
{ {
// Try and use dedicated paths if possible // Try and use dedicated paths if possible
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (ci->type == id_ECLKSYNCB || ci->type == id_TRELLIS_ECLKBUF || ci->type == id_ECLKBRIDGECS) { if (ci->type == id_ECLKSYNCB || ci->type == id_TRELLIS_ECLKBUF || ci->type == id_ECLKBRIDGECS) {
std::vector<IdString> pins; std::vector<IdString> pins;
if (ci->type == id_ECLKSYNCB || ci->type == id_TRELLIS_ECLKBUF) { if (ci->type == id_ECLKSYNCB || ci->type == id_TRELLIS_ECLKBUF) {
@ -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;

View File

@ -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",
}; };

View File

@ -34,7 +34,7 @@ class ECP5CommandHandler : public CommandHandler
public: public:
ECP5CommandHandler(int argc, char **argv); ECP5CommandHandler(int argc, char **argv);
virtual ~ECP5CommandHandler(){}; virtual ~ECP5CommandHandler(){};
std::unique_ptr<Context> createContext(std::unordered_map<std::string, Property> &values) override; std::unique_ptr<Context> createContext(dict<std::string, Property> &values) override;
void setupArchContext(Context *ctx) override{}; void setupArchContext(Context *ctx) override{};
void customAfterLoad(Context *ctx) override; void customAfterLoad(Context *ctx) override;
void validate() override; void validate() override;
@ -132,7 +132,7 @@ static std::string speedString(ArchArgs::SpeedGrade speed)
return ""; return "";
} }
std::unique_ptr<Context> ECP5CommandHandler::createContext(std::unordered_map<std::string, Property> &values) std::unique_ptr<Context> ECP5CommandHandler::createContext(dict<std::string, Property> &values)
{ {
ArchArgs chipArgs; ArchArgs chipArgs;
chipArgs.type = ArchArgs::NONE; chipArgs.type = ArchArgs::NONE;
@ -270,8 +270,8 @@ void ECP5CommandHandler::customAfterLoad(Context *ctx)
log_error("failed to parse LPF file '%s'\n", filename.c_str()); log_error("failed to parse LPF file '%s'\n", filename.c_str());
} }
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (ci->type == ctx->id("$nextpnr_ibuf") || ci->type == ctx->id("$nextpnr_obuf") || if (ci->type == ctx->id("$nextpnr_ibuf") || ci->type == ctx->id("$nextpnr_obuf") ||
ci->type == ctx->id("$nextpnr_iobuf")) { ci->type == ctx->id("$nextpnr_iobuf")) {
if (!ci->attrs.count(ctx->id("LOC"))) { if (!ci->attrs.count(ctx->id("LOC"))) {

View File

@ -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"
@ -106,8 +105,8 @@ class Ecp5Packer
void find_lutff_pairs() void find_lutff_pairs()
{ {
log_info("Finding LUTFF pairs...\n"); log_info("Finding LUTFF pairs...\n");
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (is_lut(ctx, ci) || is_pfumx(ctx, ci) || is_l6mux(ctx, ci)) { if (is_lut(ctx, ci) || is_pfumx(ctx, ci) || is_l6mux(ctx, ci)) {
NetInfo *znet = ci->ports.at(ctx->id("Z")).net; NetInfo *znet = ci->ports.at(ctx->id("Z")).net;
if (znet != nullptr) { if (znet != nullptr) {
@ -261,9 +260,9 @@ 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 : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; 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()) {
NetInfo *znet = ci->ports.at(ctx->id("Z")).net; NetInfo *znet = ci->ports.at(ctx->id("Z")).net;
std::vector<NetInfo *> inpnets; std::vector<NetInfo *> inpnets;
@ -392,8 +391,8 @@ class Ecp5Packer
} }
if (ctx->debug) { if (ctx->debug) {
log_info("Singleton LUTs (packer QoR debug): \n"); log_info("Singleton LUTs (packer QoR debug): \n");
for (auto cell : sorted(ctx->cells)) for (auto &cell : ctx->cells)
if (is_lut(ctx, cell.second) && !procdLuts.count(cell.first)) if (is_lut(ctx, cell.second.get()) && !procdLuts.count(cell.first))
log_info(" %s\n", cell.first.c_str(ctx)); log_info(" %s\n", cell.first.c_str(ctx));
} }
} }
@ -443,8 +442,8 @@ class Ecp5Packer
{ {
log_info("Packing IOs..\n"); log_info("Packing IOs..\n");
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (is_nextpnr_iob(ctx, ci)) { if (is_nextpnr_iob(ctx, ci)) {
CellInfo *trio = nullptr; CellInfo *trio = nullptr;
NetInfo *ionet = nullptr; NetInfo *ionet = nullptr;
@ -536,8 +535,8 @@ class Ecp5Packer
void pack_lut5xs() void pack_lut5xs()
{ {
log_info("Packing LUT5-7s...\n"); log_info("Packing LUT5-7s...\n");
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (is_pfumx(ctx, ci)) { if (is_pfumx(ctx, ci)) {
std::unique_ptr<CellInfo> packed = std::unique_ptr<CellInfo> packed =
create_ecp5_cell(ctx, ctx->id("TRELLIS_SLICE"), ci->name.str(ctx) + "_SLICE"); create_ecp5_cell(ctx, ctx->id("TRELLIS_SLICE"), ci->name.str(ctx) + "_SLICE");
@ -593,8 +592,8 @@ class Ecp5Packer
} }
flush_cells(); flush_cells();
// Pack LUT6s // Pack LUT6s
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (is_l6mux(ctx, ci)) { if (is_l6mux(ctx, ci)) {
NetInfo *ofx0_0 = ci->ports.at(ctx->id("D0")).net; NetInfo *ofx0_0 = ci->ports.at(ctx->id("D0")).net;
if (ofx0_0 == nullptr) if (ofx0_0 == nullptr)
@ -651,8 +650,8 @@ class Ecp5Packer
} }
flush_cells(); flush_cells();
// Pack LUT7s // Pack LUT7s
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (is_l6mux(ctx, ci)) { if (is_l6mux(ctx, ci)) {
NetInfo *ofx1_0 = ci->ports.at(ctx->id("D0")).net; NetInfo *ofx1_0 = ci->ports.at(ctx->id("D0")).net;
if (ofx1_0 == nullptr) if (ofx1_0 == nullptr)
@ -975,8 +974,8 @@ class Ecp5Packer
// Pack distributed RAM // Pack distributed RAM
void pack_dram() void pack_dram()
{ {
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (is_dpram(ctx, ci)) { if (is_dpram(ctx, ci)) {
// Create RAMW slice // Create RAMW slice
@ -1108,8 +1107,8 @@ class Ecp5Packer
void pack_remaining_luts() void pack_remaining_luts()
{ {
log_info("Packing unpaired LUTs into a SLICE...\n"); log_info("Packing unpaired LUTs into a SLICE...\n");
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (is_lut(ctx, ci)) { if (is_lut(ctx, ci)) {
std::unique_ptr<CellInfo> slice = std::unique_ptr<CellInfo> slice =
create_ecp5_cell(ctx, ctx->id("TRELLIS_SLICE"), ci->name.str(ctx) + "_SLICE"); create_ecp5_cell(ctx, ctx->id("TRELLIS_SLICE"), ci->name.str(ctx) + "_SLICE");
@ -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);
@ -1181,8 +1180,8 @@ class Ecp5Packer
++used_slices; ++used_slices;
log_info("Packing unpaired FFs into a SLICE...\n"); log_info("Packing unpaired FFs into a SLICE...\n");
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (is_ff(ctx, ci)) { if (is_ff(ctx, ci)) {
bool pack_dense = used_slices > (dense_pack_mode_thresh * available_slices); bool pack_dense = used_slices > (dense_pack_mode_thresh * available_slices);
bool requires_m = get_net_or_empty(ci, ctx->id("M")) != nullptr; bool requires_m = get_net_or_empty(ci, ctx->id("M")) != nullptr;
@ -1403,8 +1402,8 @@ class Ecp5Packer
bool gnd_used = false, vcc_used = false; bool gnd_used = false, vcc_used = false;
for (auto net : sorted(ctx->nets)) { for (auto &net : ctx->nets) {
NetInfo *ni = net.second; NetInfo *ni = net.second.get();
if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("GND")) { if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("GND")) {
IdString drv_cell = ni->driver.cell->name; IdString drv_cell = ni->driver.cell->name;
set_net_constant(ctx, ni, gnd_net.get(), false); set_net_constant(ctx, ni, gnd_net.get(), false);
@ -1461,8 +1460,8 @@ class Ecp5Packer
c->params[n] = c->params[o]; c->params[n] = c->params[o];
c->params.erase(o); c->params.erase(o);
}; };
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
// Convert 36-bit PDP RAMs to regular 18-bit DP ones that match the Bel // Convert 36-bit PDP RAMs to regular 18-bit DP ones that match the Bel
if (ci->type == ctx->id("PDPW16KD")) { if (ci->type == ctx->id("PDPW16KD")) {
ci->params[ctx->id("DATA_WIDTH_A")] = 36; // force PDP mode ci->params[ctx->id("DATA_WIDTH_A")] = 36; // force PDP mode
@ -1503,8 +1502,8 @@ class Ecp5Packer
ci->type = id_DP16KD; ci->type = id_DP16KD;
} }
} }
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (ci->type == id_DP16KD) { if (ci->type == id_DP16KD) {
// Add ports, even if disconnected, to ensure correct tie-offs // Add ports, even if disconnected, to ensure correct tie-offs
for (int i = 0; i < 14; i++) { for (int i = 0; i < 14; i++) {
@ -1544,8 +1543,8 @@ class Ecp5Packer
// Pack DSPs // Pack DSPs
void pack_dsps() void pack_dsps()
{ {
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (ci->type == id_MULT18X18D) { if (ci->type == id_MULT18X18D) {
// Add ports, even if disconnected, to ensure correct tie-offs // Add ports, even if disconnected, to ensure correct tie-offs
for (auto sig : {"CLK", "CE", "RST"}) for (auto sig : {"CLK", "CE", "RST"})
@ -1708,8 +1707,8 @@ class Ecp5Packer
// "Pack" DCUs // "Pack" DCUs
void pack_dcus() void pack_dcus()
{ {
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (ci->type == id_DCUA) { if (ci->type == id_DCUA) {
if (ci->attrs.count(ctx->id("LOC"))) { if (ci->attrs.count(ctx->id("LOC"))) {
std::string loc = ci->attrs.at(ctx->id("LOC")).as_string(); std::string loc = ci->attrs.at(ctx->id("LOC")).as_string();
@ -1759,8 +1758,8 @@ class Ecp5Packer
} }
} }
} }
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (ci->type == id_EXTREFB) { if (ci->type == id_EXTREFB) {
const NetInfo *refo = net_or_nullptr(ci, id_REFCLKO); const NetInfo *refo = net_or_nullptr(ci, id_REFCLKO);
CellInfo *dcu = nullptr; CellInfo *dcu = nullptr;
@ -1800,8 +1799,8 @@ class Ecp5Packer
// Miscellaneous packer tasks // Miscellaneous packer tasks
void pack_misc() void pack_misc()
{ {
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (ci->type == id_USRMCLK) { if (ci->type == id_USRMCLK) {
rename_port(ctx, ci, ctx->id("USRMCLKI"), id_PADDO); rename_port(ctx, ci, ctx->id("USRMCLKI"), id_PADDO);
rename_port(ctx, ci, ctx->id("USRMCLKTS"), id_PADDT); rename_port(ctx, ci, ctx->id("USRMCLKTS"), id_PADDT);
@ -1829,14 +1828,14 @@ class Ecp5Packer
if (ctx->getBelType(bel) == id_EHXPLLL && ctx->checkBelAvail(bel)) if (ctx->getBelType(bel) == id_EHXPLLL && ctx->checkBelAvail(bel))
available_plls.insert(bel); available_plls.insert(bel);
} }
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (ci->type == id_EHXPLLL && ci->attrs.count(ctx->id("BEL"))) if (ci->type == id_EHXPLLL && ci->attrs.count(ctx->id("BEL")))
available_plls.erase(ctx->getBelByNameStr(ci->attrs.at(ctx->id("BEL")).as_string())); available_plls.erase(ctx->getBelByNameStr(ci->attrs.at(ctx->id("BEL")).as_string()));
} }
// Place PLL connected to fixed drivers such as IO close to their source // Place PLL connected to fixed drivers such as IO close to their source
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (ci->type == id_EHXPLLL && !ci->attrs.count(ctx->id("BEL"))) { if (ci->type == id_EHXPLLL && !ci->attrs.count(ctx->id("BEL"))) {
const NetInfo *drivernet = net_or_nullptr(ci, id_CLKI); const NetInfo *drivernet = net_or_nullptr(ci, id_CLKI);
if (drivernet == nullptr || drivernet->driver.cell == nullptr) if (drivernet == nullptr || drivernet->driver.cell == nullptr)
@ -1863,8 +1862,8 @@ class Ecp5Packer
} }
} }
// Place PLLs driven by logic, etc, randomly // Place PLLs driven by logic, etc, randomly
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (ci->type == id_EHXPLLL && !ci->attrs.count(ctx->id("BEL"))) { if (ci->type == id_EHXPLLL && !ci->attrs.count(ctx->id("BEL"))) {
if (available_plls.empty()) if (available_plls.empty())
log_error("failed to place PLL '%s'\n", ci->name.c_str(ctx)); log_error("failed to place PLL '%s'\n", ci->name.c_str(ctx));
@ -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,12 +2025,12 @@ 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()
{ {
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (ci->type == id_DQSBUFM) { if (ci->type == id_DQSBUFM) {
CellInfo *pio = net_driven_by(ctx, ci->ports.at(ctx->id("DQSI")).net, is_trellis_io, id_O); CellInfo *pio = net_driven_by(ctx, ci->ports.at(ctx->id("DQSI")).net, is_trellis_io, id_O);
if (pio == nullptr || ci->ports.at(ctx->id("DQSI")).net->users.size() > 1) if (pio == nullptr || ci->ports.at(ctx->id("DQSI")).net->users.size() > 1)
@ -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;
@ -2265,8 +2264,8 @@ class Ecp5Packer
} }
}; };
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (ci->type == ctx->id("DELAYF") || ci->type == ctx->id("DELAYG")) { if (ci->type == ctx->id("DELAYF") || ci->type == ctx->id("DELAYG")) {
CellInfo *i_pio = net_driven_by(ctx, ci->ports.at(ctx->id("A")).net, is_trellis_io, id_O); CellInfo *i_pio = net_driven_by(ctx, ci->ports.at(ctx->id("A")).net, is_trellis_io, id_O);
CellInfo *o_pio = net_only_drives(ctx, ci->ports.at(ctx->id("Z")).net, is_trellis_io, id_I, true); CellInfo *o_pio = net_only_drives(ctx, ci->ports.at(ctx->id("Z")).net, is_trellis_io, id_I, true);
@ -2349,8 +2348,8 @@ class Ecp5Packer
} }
} }
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (ci->type == ctx->id("IDDRX1F")) { if (ci->type == ctx->id("IDDRX1F")) {
CellInfo *pio = net_driven_by(ctx, ci->ports.at(ctx->id("D")).net, is_trellis_io, id_O); CellInfo *pio = net_driven_by(ctx, ci->ports.at(ctx->id("D")).net, is_trellis_io, id_O);
if (pio == nullptr || ci->ports.at(ctx->id("D")).net->users.size() > 1) if (pio == nullptr || ci->ports.at(ctx->id("D")).net->users.size() > 1)
@ -2692,8 +2691,8 @@ class Ecp5Packer
} }
flush_cells(); flush_cells();
// Constrain ECLK-related cells // Constrain ECLK-related cells
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (ci->type == id_ECLKBRIDGECS) { if (ci->type == id_ECLKBRIDGECS) {
Loc loc; Loc loc;
NetInfo *i0 = get_net_or_empty(ci, id_CLK0), *i1 = get_net_or_empty(ci, id_CLK1), NetInfo *i0 = get_net_or_empty(ci, id_CLK0), *i1 = get_net_or_empty(ci, id_CLK1),
@ -2760,8 +2759,8 @@ class Ecp5Packer
} }
} }
// Promote/route edge clocks // Promote/route edge clocks
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (ci->type == id_IOLOGIC || ci->type == id_DQSBUFM) { if (ci->type == id_IOLOGIC || ci->type == id_DQSBUFM) {
if (!ci->ports.count(id_ECLK) || ci->ports.at(id_ECLK).net == nullptr) if (!ci->ports.count(id_ECLK) || ci->ports.at(id_ECLK).net == nullptr)
continue; continue;
@ -2779,9 +2778,9 @@ class Ecp5Packer
} }
} }
flush_cells(); flush_cells();
std::unordered_set<BelId> used_eclksyncb; pool<BelId> used_eclksyncb;
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (ci->type == id_CLKDIVF) { if (ci->type == id_CLKDIVF) {
const NetInfo *clki = net_or_nullptr(ci, id_CLKI); const NetInfo *clki = net_or_nullptr(ci, id_CLKI);
for (auto &eclk : eclks) { for (auto &eclk : eclks) {
@ -2896,8 +2895,8 @@ class Ecp5Packer
} }
} }
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (ci->type == id_ECLKSYNCB) { if (ci->type == id_ECLKSYNCB) {
// **All** ECLKSYNCBs must be constrained // **All** ECLKSYNCBs must be constrained
// Most will be dealt with above, but there might be some rogue cases // Most will be dealt with above, but there might be some rogue cases
@ -2921,8 +2920,8 @@ class Ecp5Packer
} }
} }
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (ci->type == id_CLKDIVF) { if (ci->type == id_CLKDIVF) {
if (ci->attrs.count(ctx->id("BEL"))) if (ci->attrs.count(ctx->id("BEL")))
continue; continue;
@ -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");
@ -3114,8 +3113,8 @@ class Ecp5Packer
{ {
// Check for legacy-style JSON (use CEMUX as a clue) and error out, avoiding a confusing assertion failure // Check for legacy-style JSON (use CEMUX as a clue) and error out, avoiding a confusing assertion failure
// later // later
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
if (is_ff(ctx, cell.second) && cell.second->params.count(ctx->id("CEMUX")) && if (is_ff(ctx, cell.second.get()) && cell.second->params.count(ctx->id("CEMUX")) &&
!cell.second->params[ctx->id("CEMUX")].is_string) !cell.second->params[ctx->id("CEMUX")].is_string)
log_error("Found netlist using legacy-style JSON parameter values, please update your Yosys.\n"); log_error("Found netlist using legacy-style JSON parameter values, please update your Yosys.\n");
} }
@ -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()
@ -3188,8 +3187,8 @@ bool Arch::pack()
void Arch::assignArchInfo() void Arch::assignArchInfo()
{ {
for (auto cell : sorted(cells)) { for (auto &cell : cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (ci->type == id_TRELLIS_SLICE) { if (ci->type == id_TRELLIS_SLICE) {
ci->sliceInfo.using_dff = false; ci->sliceInfo.using_dff = false;
@ -3301,7 +3300,7 @@ void Arch::assignArchInfo()
ci->multInfo.is_clocked = ci->multInfo.timing_id != id_MULT18X18D_REGS_NONE; ci->multInfo.is_clocked = ci->multInfo.timing_id != id_MULT18X18D_REGS_NONE;
} }
} }
for (auto net : sorted(nets)) { for (auto &net : nets) {
net.second->is_global = bool_or_default(net.second->attrs, id("ECP5_IS_GLOBAL")); net.second->is_global = bool_or_default(net.second->attrs, id("ECP5_IS_GLOBAL"));
} }
} }

View File

@ -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;
@ -2047,8 +2034,8 @@ void Arch::pack_default_conns()
std::vector<IdString> dead_nets; std::vector<IdString> dead_nets;
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
const DefaultCellConnsPOD *conns = get_default_conns(ci->type); const DefaultCellConnsPOD *conns = get_default_conns(ci->type);
if (conns == nullptr) if (conns == nullptr)
continue; continue;

View File

@ -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

View File

@ -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);

View File

@ -49,10 +49,10 @@ void arch_wrap_python(py::module &m)
fn_wrapper_1a_v<Context, decltype(&Context::explain_bel_status), &Context::explain_bel_status, fn_wrapper_1a_v<Context, decltype(&Context::explain_bel_status), &Context::explain_bel_status,
conv_from_str<BelId>>::def_wrap(ctx_cls, "explain_bel_status"); conv_from_str<BelId>>::def_wrap(ctx_cls, "explain_bel_status");
typedef std::unordered_map<IdString, std::unique_ptr<CellInfo>> CellMap; typedef dict<IdString, std::unique_ptr<CellInfo>> CellMap;
typedef std::unordered_map<IdString, std::unique_ptr<NetInfo>> NetMap; typedef dict<IdString, std::unique_ptr<NetInfo>> NetMap;
typedef std::unordered_map<IdString, IdString> AliasMap; typedef dict<IdString, IdString> AliasMap;
typedef std::unordered_map<IdString, HierarchicalCell> HierarchyMap; typedef dict<IdString, HierarchicalCell> HierarchyMap;
auto belpin_cls = py::class_<ContextualWrapper<BelPin>>(m, "BelPin"); auto belpin_cls = py::class_<ContextualWrapper<BelPin>>(m, "BelPin");
readonly_wrapper<BelPin, decltype(&BelPin::bel), &BelPin::bel, conv_to_str<BelId>>::def_wrap(belpin_cls, "bel"); readonly_wrapper<BelPin, decltype(&BelPin::bel), &BelPin::bel, conv_to_str<BelId>>::def_wrap(belpin_cls, "bel");

View File

@ -21,10 +21,9 @@
#ifndef FPGA_INTERCHANGE_ARCHDEFS_H #ifndef FPGA_INTERCHANGE_ARCHDEFS_H
#define FPGA_INTERCHANGE_ARCHDEFS_H #define FPGA_INTERCHANGE_ARCHDEFS_H
#include <boost/functional/hash.hpp>
#include <cstdint> #include <cstdint>
#include "hash_table.h" #include "hashlib.h"
#include "luts.h" #include "luts.h"
#include "nextpnr_namespaces.h" #include "nextpnr_namespaces.h"
@ -48,6 +47,7 @@ struct BelId
{ {
return tile < other.tile || (tile == other.tile && index < other.index); return tile < other.tile || (tile == other.tile && index < other.index);
} }
unsigned int hash() const { return mkhash(tile, index); }
}; };
struct WireId struct WireId
@ -62,6 +62,7 @@ struct WireId
{ {
return tile < other.tile || (tile == other.tile && index < other.index); return tile < other.tile || (tile == other.tile && index < other.index);
} }
unsigned int hash() const { return mkhash(tile, index); }
}; };
struct PipId struct PipId
@ -75,18 +76,21 @@ struct PipId
{ {
return tile < other.tile || (tile == other.tile && index < other.index); return tile < other.tile || (tile == other.tile && index < other.index);
} }
unsigned int hash() const { return mkhash(tile, index); }
}; };
struct GroupId struct GroupId
{ {
bool operator==(const GroupId &other) const { return true; } bool operator==(const GroupId &other) const { return true; }
bool operator!=(const GroupId &other) const { return false; } bool operator!=(const GroupId &other) const { return false; }
unsigned int hash() const { return 0; }
}; };
struct DecalId struct DecalId
{ {
bool operator==(const DecalId &other) const { return true; } bool operator==(const DecalId &other) const { return true; }
bool operator!=(const DecalId &other) const { return false; } bool operator!=(const DecalId &other) const { return false; }
unsigned int hash() const { return 0; }
}; };
struct BelBucketId struct BelBucketId
@ -96,6 +100,7 @@ struct BelBucketId
bool operator==(const BelBucketId &other) const { return (name == other.name); } bool operator==(const BelBucketId &other) const { return (name == other.name); }
bool operator!=(const BelBucketId &other) const { return (name != other.name); } bool operator!=(const BelBucketId &other) const { return (name != other.name); }
bool operator<(const BelBucketId &other) const { return name < other.name; } bool operator<(const BelBucketId &other) const { return name < other.name; }
unsigned int hash() const { return name.hash(); }
}; };
typedef IdString ClusterId; typedef IdString ClusterId;
@ -112,76 +117,12 @@ 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;
}; };
NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_END
namespace std {
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX BelId>
{
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX BelId &bel) const noexcept
{
std::size_t seed = 0;
boost::hash_combine(seed, hash<int>()(bel.tile));
boost::hash_combine(seed, hash<int>()(bel.index));
return seed;
}
};
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX WireId>
{
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX WireId &wire) const noexcept
{
std::size_t seed = 0;
boost::hash_combine(seed, hash<int>()(wire.tile));
boost::hash_combine(seed, hash<int>()(wire.index));
return seed;
}
};
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX PipId>
{
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX PipId &pip) const noexcept
{
std::size_t seed = 0;
boost::hash_combine(seed, hash<int>()(pip.tile));
boost::hash_combine(seed, hash<int>()(pip.index));
return seed;
}
};
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX GroupId>
{
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX GroupId &group) const noexcept
{
std::size_t seed = 0;
return seed;
}
};
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX DecalId>
{
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX DecalId &decal) const noexcept
{
std::size_t seed = 0;
return seed;
}
};
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX BelBucketId>
{
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX BelBucketId &bucket) const noexcept
{
std::size_t seed = 0;
boost::hash_combine(seed, hash<NEXTPNR_NAMESPACE_PREFIX IdString>()(bucket.name));
return seed;
}
};
} // namespace std
#endif /* FPGA_INTERCHANGE_ARCHDEFS_H */ #endif /* FPGA_INTERCHANGE_ARCHDEFS_H */

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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();

View File

@ -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);

View File

@ -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);

View File

@ -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();
@ -160,8 +160,8 @@ void Arch::place_globals()
// TODO: for more complex PLL type setups, we might want a toposort or iterative loop as the PLL must be placed // TODO: for more complex PLL type setups, we might want a toposort or iterative loop as the PLL must be placed
// before the GBs it drives // before the GBs it drives
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
const GlobalCellPOD *glb_cell = global_cell_info(ci->type); const GlobalCellPOD *glb_cell = global_cell_info(ci->type);
if (glb_cell == nullptr) if (glb_cell == nullptr)
continue; continue;
@ -239,8 +239,8 @@ void Arch::route_globals()
IdString gnd_net_name(chip_info->constants->gnd_net_name); IdString gnd_net_name(chip_info->constants->gnd_net_name);
IdString vcc_net_name(chip_info->constants->vcc_net_name); IdString vcc_net_name(chip_info->constants->vcc_net_name);
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
const GlobalCellPOD *glb_cell = global_cell_info(ci->type); const GlobalCellPOD *glb_cell = global_cell_info(ci->type);
if (glb_cell == nullptr) if (glb_cell == nullptr)
continue; continue;

View File

@ -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,16 +990,14 @@ 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
cost_map.set_cost_map(ctx, type_pair.first, type_pair.second); cost_map.set_cost_map(ctx, type_pair.first, type_pair.second);
#if defined(NEXTPNR_USE_TBB) // Run parallely #if defined(NEXTPNR_USE_TBB) // Run parallely
}); });
#else #else
} }
#endif #endif

View File

@ -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;
}; };

View File

@ -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);

View File

@ -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.

View File

@ -53,8 +53,8 @@ void Arch::expand_macros()
// Make up a list of cells, so we don't have modify-while-iterating issues // Make up a list of cells, so we don't have modify-while-iterating issues
Context *ctx = getCtx(); Context *ctx = getCtx();
std::vector<CellInfo *> cells; std::vector<CellInfo *> cells;
for (auto cell : sorted(ctx->cells)) for (auto &cell : ctx->cells)
cells.push_back(cell.second); cells.push_back(cell.second.get());
std::vector<CellInfo *> next_cells; std::vector<CellInfo *> next_cells;

View File

@ -36,7 +36,7 @@ class FpgaInterchangeCommandHandler : public CommandHandler
public: public:
FpgaInterchangeCommandHandler(int argc, char **argv); FpgaInterchangeCommandHandler(int argc, char **argv);
virtual ~FpgaInterchangeCommandHandler(){}; virtual ~FpgaInterchangeCommandHandler(){};
std::unique_ptr<Context> createContext(std::unordered_map<std::string, Property> &values) override; std::unique_ptr<Context> createContext(dict<std::string, Property> &values) override;
void setupArchContext(Context *ctx) override{}; void setupArchContext(Context *ctx) override{};
void customBitstream(Context *ctx) override; void customBitstream(Context *ctx) override;
void customAfterLoad(Context *ctx) override; void customAfterLoad(Context *ctx) override;
@ -69,7 +69,7 @@ void FpgaInterchangeCommandHandler::customBitstream(Context *ctx)
} }
} }
std::unique_ptr<Context> FpgaInterchangeCommandHandler::createContext(std::unordered_map<std::string, Property> &values) std::unique_ptr<Context> FpgaInterchangeCommandHandler::createContext(dict<std::string, Property> &values)
{ {
auto start = std::chrono::high_resolution_clock::now(); auto start = std::chrono::high_resolution_clock::now();

View File

@ -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);

View File

@ -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.

View File

@ -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)
{ {
} }

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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());
} }
} }

View File

@ -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 */

View File

@ -118,7 +118,7 @@ struct ModuleInfo
{ {
bool is_top = false, is_blackbox = false, is_whitebox = false; bool is_top = false, is_blackbox = false, is_whitebox = false;
inline bool is_box() const { return is_blackbox || is_whitebox; } inline bool is_box() const { return is_blackbox || is_whitebox; }
std::unordered_set<IdString> instantiated_celltypes; pool<IdString> instantiated_celltypes;
}; };
template <typename FrontendType> struct GenericFrontend template <typename FrontendType> struct GenericFrontend
@ -134,7 +134,7 @@ template <typename FrontendType> struct GenericFrontend
m.path = top; m.path = top;
ctx->top_module = top; ctx->top_module = top;
// Do the actual import, starting from the top level module // Do the actual import, starting from the top level module
import_module(m, top.str(ctx), top.str(ctx), mod_refs.at(top)); import_module(m, top.str(ctx), top.str(ctx), mod_refs.at(top.str(ctx)));
ctx->design_loaded = true; ctx->design_loaded = true;
} }
@ -148,8 +148,8 @@ template <typename FrontendType> struct GenericFrontend
using netname_dat_t = typename FrontendType::NetnameDataType; using netname_dat_t = typename FrontendType::NetnameDataType;
using bitvector_t = typename FrontendType::BitVectorDataType; using bitvector_t = typename FrontendType::BitVectorDataType;
std::unordered_map<IdString, ModuleInfo> mods; dict<IdString, ModuleInfo> mods;
std::unordered_map<IdString, const mod_dat_t> mod_refs; std::unordered_map<std::string, const mod_dat_t> mod_refs;
IdString top; IdString top;
// Process the list of modules and determine // Process the list of modules and determine
@ -159,7 +159,7 @@ template <typename FrontendType> struct GenericFrontend
impl.foreach_module([&](const std::string &name, const mod_dat_t &mod) { impl.foreach_module([&](const std::string &name, const mod_dat_t &mod) {
IdString mod_id = ctx->id(name); IdString mod_id = ctx->id(name);
auto &mi = mods[mod_id]; auto &mi = mods[mod_id];
mod_refs.emplace(mod_id, mod); mod_refs.emplace(name, mod);
impl.foreach_attr(mod, [&](const std::string &name, const Property &value) { impl.foreach_attr(mod, [&](const std::string &name, const Property &value) {
if (name == "top") if (name == "top")
mi.is_top = (value.intval != 0); mi.is_top = (value.intval != 0);
@ -196,7 +196,7 @@ template <typename FrontendType> struct GenericFrontend
} }
// Finally, attempt to autodetect the top module using hierarchy // Finally, attempt to autodetect the top module using hierarchy
// (a module that is not a box and is not used as a cell by any other module) // (a module that is not a box and is not used as a cell by any other module)
std::unordered_set<IdString> candidate_top; pool<IdString> candidate_top;
for (auto &mod : mods) for (auto &mod : mods)
if (!mod.second.is_box()) if (!mod.second.is_box())
candidate_top.insert(mod.first); candidate_top.insert(mod.first);
@ -207,7 +207,7 @@ template <typename FrontendType> struct GenericFrontend
if (candidate_top.size() == 0) if (candidate_top.size() == 0)
log_info("No candidate top level modules.\n"); log_info("No candidate top level modules.\n");
else else
for (auto ctp : sorted(candidate_top)) for (auto ctp : candidate_top)
log_info("Candidate top module: '%s'\n", ctx->nameOf(ctp)); log_info("Candidate top module: '%s'\n", ctx->nameOf(ctp));
log_error("Failed to autodetect top module, please specify using --top.\n"); log_error("Failed to autodetect top module, please specify using --top.\n");
} }
@ -256,7 +256,7 @@ template <typename FrontendType> struct GenericFrontend
index_to_net_flatindex.resize(idx + 1, -1); index_to_net_flatindex.resize(idx + 1, -1);
return index_to_net_flatindex.at(idx); return index_to_net_flatindex.at(idx);
} }
std::unordered_map<IdString, std::vector<int>> port_to_bus; dict<IdString, std::vector<int>> port_to_bus;
// All of the names given to a net // All of the names given to a net
std::vector<std::vector<std::string>> net_names; std::vector<std::vector<std::string>> net_names;
}; };
@ -453,7 +453,7 @@ template <typename FrontendType> struct GenericFrontend
CellInfo *ci = ctx->createCell(inst_name, ctx->id(impl.get_cell_type(cd))); CellInfo *ci = ctx->createCell(inst_name, ctx->id(impl.get_cell_type(cd)));
ci->hierpath = m.path; ci->hierpath = m.path;
// Import port directions // Import port directions
std::unordered_map<IdString, PortType> port_dirs; dict<IdString, PortType> port_dirs;
impl.foreach_port_dir(cd, [&](const std::string &port, PortType dir) { port_dirs[ctx->id(port)] = dir; }); impl.foreach_port_dir(cd, [&](const std::string &port, PortType dir) { port_dirs[ctx->id(port)] = dir; });
// Import port connectivity // Import port connectivity
impl.foreach_port_conn(cd, [&](const std::string &name, const bitvector_t &bits) { impl.foreach_port_conn(cd, [&](const std::string &name, const bitvector_t &bits) {
@ -531,7 +531,7 @@ template <typename FrontendType> struct GenericFrontend
ctx->hierarchy[m.path].hier_cells[ctx->id(name)] = submod.path; ctx->hierarchy[m.path].hier_cells[ctx->id(name)] = submod.path;
// Do the submodule import // Do the submodule import
auto type = impl.get_cell_type(cd); auto type = impl.get_cell_type(cd);
import_module(submod, name, type, mod_refs.at(ctx->id(type))); import_module(submod, name, type, mod_refs.at(type));
} }
// Import the cells section of a module // Import the cells section of a module

View File

@ -553,8 +553,8 @@ bool Arch::place()
std::string placer = str_or_default(settings, id("placer"), defaultPlacer); std::string placer = str_or_default(settings, id("placer"), defaultPlacer);
if (placer == "heap") { if (placer == "heap") {
bool have_iobuf_or_constr = false; bool have_iobuf_or_constr = false;
for (auto cell : sorted(cells)) { for (auto &cell : cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (ci->type == id("GENERIC_IOB") || ci->bel != BelId() || ci->attrs.count(id("BEL"))) { if (ci->type == id("GENERIC_IOB") || ci->bel != BelId() || ci->attrs.count(id("BEL"))) {
have_iobuf_or_constr = true; have_iobuf_or_constr = true;
break; break;

View File

@ -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);
} }

View File

@ -138,9 +138,9 @@ void arch_wrap_python(py::module &m)
fn_wrapper_3a<Context, decltype(&Context::constructDecalXY), &Context::constructDecalXY, wrap_context<DecalXY>, fn_wrapper_3a<Context, decltype(&Context::constructDecalXY), &Context::constructDecalXY, wrap_context<DecalXY>,
conv_from_str<DecalId>, pass_through<float>, pass_through<float>>::def_wrap(ctx_cls, "DecalXY"); conv_from_str<DecalId>, pass_through<float>, pass_through<float>>::def_wrap(ctx_cls, "DecalXY");
typedef std::unordered_map<IdString, std::unique_ptr<CellInfo>> CellMap; typedef dict<IdString, std::unique_ptr<CellInfo>> CellMap;
typedef std::unordered_map<IdString, std::unique_ptr<NetInfo>> NetMap; typedef dict<IdString, std::unique_ptr<NetInfo>> NetMap;
typedef std::unordered_map<IdString, HierarchicalCell> HierarchyMap; typedef dict<IdString, HierarchicalCell> HierarchyMap;
readonly_wrapper<Context, decltype(&Context::cells), &Context::cells, wrap_context<CellMap &>>::def_wrap(ctx_cls, readonly_wrapper<Context, decltype(&Context::cells), &Context::cells, wrap_context<CellMap &>>::def_wrap(ctx_cls,
"cells"); "cells");

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -32,7 +32,7 @@ class GenericCommandHandler : public CommandHandler
public: public:
GenericCommandHandler(int argc, char **argv); GenericCommandHandler(int argc, char **argv);
virtual ~GenericCommandHandler(){}; virtual ~GenericCommandHandler(){};
std::unique_ptr<Context> createContext(std::unordered_map<std::string, Property> &values) override; std::unique_ptr<Context> createContext(dict<std::string, Property> &values) override;
void setupArchContext(Context *ctx) override{}; void setupArchContext(Context *ctx) override{};
void customBitstream(Context *ctx) override; void customBitstream(Context *ctx) override;
@ -52,7 +52,7 @@ po::options_description GenericCommandHandler::getArchOptions()
void GenericCommandHandler::customBitstream(Context *ctx) {} void GenericCommandHandler::customBitstream(Context *ctx) {}
std::unique_ptr<Context> GenericCommandHandler::createContext(std::unordered_map<std::string, Property> &values) std::unique_ptr<Context> GenericCommandHandler::createContext(dict<std::string, Property> &values)
{ {
ArchArgs chipArgs; ArchArgs chipArgs;
if (values.find("arch.name") != values.end()) { if (values.find("arch.name") != values.end()) {

View File

@ -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,16 +31,17 @@ 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 : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (ctx->verbose) if (ctx->verbose)
log_info("cell '%s' is of type '%s'\n", ci->name.c_str(ctx), ci->type.c_str(ctx)); log_info("cell '%s' is of type '%s'\n", ci->name.c_str(ctx), ci->type.c_str(ctx));
if (is_lut(ctx, ci)) { if (is_lut(ctx, ci)) {
std::unique_ptr<CellInfo> packed = std::unique_ptr<CellInfo> packed =
create_generic_cell(ctx, ctx->id("GENERIC_SLICE"), ci->name.str(ctx) + "_LC"); create_generic_cell(ctx, ctx->id("GENERIC_SLICE"), ci->name.str(ctx) + "_LC");
std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(packed->attrs, packed->attrs.begin())); for (auto &attr : ci->attrs)
packed->attrs[attr.first] = attr.second;
packed_cells.insert(ci->name); packed_cells.insert(ci->name);
if (ctx->verbose) if (ctx->verbose)
log_info("packed cell %s into %s\n", ci->name.c_str(ctx), packed->name.c_str(ctx)); log_info("packed cell %s into %s\n", ci->name.c_str(ctx), packed->name.c_str(ctx));
@ -88,15 +88,16 @@ 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 : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (is_ff(ctx, ci)) { if (is_ff(ctx, ci)) {
std::unique_ptr<CellInfo> packed = std::unique_ptr<CellInfo> packed =
create_generic_cell(ctx, ctx->id("GENERIC_SLICE"), ci->name.str(ctx) + "_DFFLC"); create_generic_cell(ctx, ctx->id("GENERIC_SLICE"), ci->name.str(ctx) + "_DFFLC");
std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(packed->attrs, packed->attrs.begin())); for (auto &attr : ci->attrs)
packed->attrs[attr.first] = attr.second;
if (ctx->verbose) if (ctx->verbose)
log_info("packed cell %s into %s\n", ci->name.c_str(ctx), packed->name.c_str(ctx)); log_info("packed cell %s into %s\n", ci->name.c_str(ctx), packed->name.c_str(ctx));
packed_cells.insert(ci->name); packed_cells.insert(ci->name);
@ -158,8 +159,8 @@ static void pack_constants(Context *ctx)
bool gnd_used = false, vcc_used = false; bool gnd_used = false, vcc_used = false;
for (auto net : sorted(ctx->nets)) { for (auto &net : ctx->nets) {
NetInfo *ni = net.second; NetInfo *ni = net.second.get();
if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("GND")) { if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("GND")) {
IdString drv_cell = ni->driver.cell->name; IdString drv_cell = ni->driver.cell->name;
set_net_constant(ctx, ni, gnd_net.get(), false); set_net_constant(ctx, ni, gnd_net.get(), false);
@ -201,14 +202,14 @@ 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");
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (is_nextpnr_iob(ctx, ci)) { if (is_nextpnr_iob(ctx, ci)) {
CellInfo *iob = nullptr; CellInfo *iob = nullptr;
if (ci->type == ctx->id("$nextpnr_ibuf") || ci->type == ctx->id("$nextpnr_iobuf")) { if (ci->type == ctx->id("$nextpnr_ibuf") || ci->type == ctx->id("$nextpnr_iobuf")) {
@ -254,7 +255,8 @@ static void pack_io(Context *ctx)
} }
packed_cells.insert(ci->name); packed_cells.insert(ci->name);
if (iob != nullptr) if (iob != nullptr)
std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(iob->attrs, iob->attrs.begin())); for (auto &attr : ci->attrs)
iob->attrs[attr.first] = attr.second;
} }
} }
for (auto pcell : packed_cells) { for (auto pcell : packed_cells) {

View File

@ -1009,8 +1009,8 @@ bool Arch::place()
std::string placer = str_or_default(settings, id("placer"), defaultPlacer); std::string placer = str_or_default(settings, id("placer"), defaultPlacer);
if (placer == "heap") { if (placer == "heap") {
bool have_iobuf_or_constr = false; bool have_iobuf_or_constr = false;
for (auto cell : sorted(cells)) { for (auto &cell : cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (ci->type == id("IOB") || ci->bel != BelId() || ci->attrs.count(id("BEL"))) { if (ci->type == id("IOB") || ci->bel != BelId() || ci->attrs.count(id("BEL"))) {
have_iobuf_or_constr = true; have_iobuf_or_constr = true;
break; break;

View File

@ -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);

View File

@ -137,9 +137,9 @@ void arch_wrap_python(py::module &m)
fn_wrapper_3a<Context, decltype(&Context::constructDecalXY), &Context::constructDecalXY, wrap_context<DecalXY>, fn_wrapper_3a<Context, decltype(&Context::constructDecalXY), &Context::constructDecalXY, wrap_context<DecalXY>,
conv_from_str<DecalId>, pass_through<float>, pass_through<float>>::def_wrap(ctx_cls, "DecalXY"); conv_from_str<DecalId>, pass_through<float>, pass_through<float>>::def_wrap(ctx_cls, "DecalXY");
typedef std::unordered_map<IdString, std::unique_ptr<CellInfo>> CellMap; typedef dict<IdString, std::unique_ptr<CellInfo>> CellMap;
typedef std::unordered_map<IdString, std::unique_ptr<NetInfo>> NetMap; typedef dict<IdString, std::unique_ptr<NetInfo>> NetMap;
typedef std::unordered_map<IdString, HierarchicalCell> HierarchyMap; typedef dict<IdString, HierarchicalCell> HierarchyMap;
readonly_wrapper<Context, decltype(&Context::cells), &Context::cells, wrap_context<CellMap &>>::def_wrap(ctx_cls, readonly_wrapper<Context, decltype(&Context::cells), &Context::cells, wrap_context<CellMap &>>::def_wrap(ctx_cls,
"cells"); "cells");

View File

@ -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;

View File

@ -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

View File

@ -34,7 +34,7 @@ class GowinCommandHandler : public CommandHandler
public: public:
GowinCommandHandler(int argc, char **argv); GowinCommandHandler(int argc, char **argv);
virtual ~GowinCommandHandler(){}; virtual ~GowinCommandHandler(){};
std::unique_ptr<Context> createContext(std::unordered_map<std::string, Property> &values) override; std::unique_ptr<Context> createContext(dict<std::string, Property> &values) override;
void setupArchContext(Context *ctx) override{}; void setupArchContext(Context *ctx) override{};
void customAfterLoad(Context *ctx) override; void customAfterLoad(Context *ctx) override;
@ -52,7 +52,7 @@ po::options_description GowinCommandHandler::getArchOptions()
return specific; return specific;
} }
std::unique_ptr<Context> GowinCommandHandler::createContext(std::unordered_map<std::string, Property> &values) std::unique_ptr<Context> GowinCommandHandler::createContext(dict<std::string, Property> &values)
{ {
std::regex devicere = std::regex("GW1N([A-Z]*)-(LV|UV)([0-9])([A-Z]{2}[0-9]+)(C[0-9]/I[0-9])"); std::regex devicere = std::regex("GW1N([A-Z]*)-(LV|UV)([0-9])([A-Z]{2}[0-9]+)(C[0-9]/I[0-9])");
std::smatch match; std::smatch match;

View File

@ -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,15 +33,16 @@ 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 : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (ctx->verbose) if (ctx->verbose)
log_info("cell '%s' is of type '%s'\n", ctx->nameOf(ci), ci->type.c_str(ctx)); log_info("cell '%s' is of type '%s'\n", ctx->nameOf(ci), ci->type.c_str(ctx));
if (is_lut(ctx, ci)) { if (is_lut(ctx, ci)) {
std::unique_ptr<CellInfo> packed = create_generic_cell(ctx, ctx->id("SLICE"), ci->name.str(ctx) + "_LC"); std::unique_ptr<CellInfo> packed = create_generic_cell(ctx, ctx->id("SLICE"), ci->name.str(ctx) + "_LC");
std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(packed->attrs, packed->attrs.begin())); for (auto &attr : ci->attrs)
packed->attrs[attr.first] = attr.second;
packed_cells.insert(ci->name); packed_cells.insert(ci->name);
if (ctx->verbose) if (ctx->verbose)
log_info("packed cell %s into %s\n", ctx->nameOf(ci), ctx->nameOf(packed.get())); log_info("packed cell %s into %s\n", ctx->nameOf(ci), ctx->nameOf(packed.get()));
@ -89,14 +89,15 @@ 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 : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (is_ff(ctx, ci)) { if (is_ff(ctx, ci)) {
std::unique_ptr<CellInfo> packed = create_generic_cell(ctx, ctx->id("SLICE"), ci->name.str(ctx) + "_DFFLC"); std::unique_ptr<CellInfo> packed = create_generic_cell(ctx, ctx->id("SLICE"), ci->name.str(ctx) + "_DFFLC");
std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(packed->attrs, packed->attrs.begin())); for (auto &attr : ci->attrs)
packed->attrs[attr.first] = attr.second;
if (ctx->verbose) if (ctx->verbose)
log_info("packed cell %s into %s\n", ctx->nameOf(ci), ctx->nameOf(packed.get())); log_info("packed cell %s into %s\n", ctx->nameOf(ci), ctx->nameOf(packed.get()));
packed_cells.insert(ci->name); packed_cells.insert(ci->name);
@ -158,8 +159,8 @@ static void pack_constants(Context *ctx)
bool gnd_used = false; bool gnd_used = false;
for (auto net : sorted(ctx->nets)) { for (auto &net : ctx->nets) {
NetInfo *ni = net.second; NetInfo *ni = net.second.get();
if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("GND")) { if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("GND")) {
IdString drv_cell = ni->driver.cell->name; IdString drv_cell = ni->driver.cell->name;
set_net_constant(ctx, ni, gnd_net.get(), false); set_net_constant(ctx, ni, gnd_net.get(), false);
@ -210,14 +211,14 @@ 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");
for (auto cell : sorted(ctx->cells)) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second.get();
if (is_gowin_iob(ctx, ci)) { if (is_gowin_iob(ctx, ci)) {
CellInfo *iob = nullptr; CellInfo *iob = nullptr;
switch (ci->type.index) { switch (ci->type.index) {
@ -251,7 +252,8 @@ static void pack_io(Context *ctx)
packed_cells.insert(ci->name); packed_cells.insert(ci->name);
if (iob != nullptr) if (iob != nullptr)
std::copy(iob->attrs.begin(), iob->attrs.end(), std::inserter(gwiob->attrs, gwiob->attrs.begin())); for (auto &attr : iob->attrs)
gwiob->attrs[attr.first] = attr.second;
} }
} }
for (auto pcell : packed_cells) { for (auto pcell : packed_cells) {

View File

@ -40,10 +40,6 @@ endif()
target_compile_definitions(gui_${family} PRIVATE NEXTPNR_NAMESPACE=nextpnr_${family} ARCH_${ufamily} ARCHNAME=${family} QT_NO_KEYWORDS) target_compile_definitions(gui_${family} PRIVATE NEXTPNR_NAMESPACE=nextpnr_${family} ARCH_${ufamily} ARCHNAME=${family} QT_NO_KEYWORDS)
if (USE_ABSEIL)
target_compile_definitions(gui_${family} PRIVATE USE_ABSEIL)
endif()
target_link_libraries(gui_${family} Qt5::Widgets) target_link_libraries(gui_${family} Qt5::Widgets)
foreach(lib_dep ${EXTRA_LIB_DEPS}) foreach(lib_dep ${EXTRA_LIB_DEPS})

View File

@ -58,7 +58,7 @@ void IdList::updateElements(Context *ctx, std::vector<IdStringList> elements)
bool changed = false; bool changed = false;
// For any elements that are not yet in managed_, created them. // For any elements that are not yet in managed_, created them.
std::unordered_set<IdStringList> element_set; pool<IdStringList> element_set;
for (auto elem : elements) { for (auto elem : elements) {
element_set.insert(elem); element_set.insert(elem);
auto existing = managed_.find(elem); auto existing = managed_.find(elem);

View File

@ -140,7 +140,7 @@ class IdList : public Item
private: private:
// Children that we manage the memory for, stored for quick lookup from // Children that we manage the memory for, stored for quick lookup from
// IdString to child. // IdString to child.
std::unordered_map<IdStringList, std::unique_ptr<IdStringItem>> managed_; dict<IdStringList, std::unique_ptr<IdStringItem>> managed_;
// Type of children that the list creates. // Type of children that the list creates.
ElementType child_type_; ElementType child_type_;
@ -184,7 +184,7 @@ template <typename ElementT> class ElementList : public Item
ElementGetter getter_; ElementGetter getter_;
// Children that we manage the memory for, stored for quick lookup from // Children that we manage the memory for, stored for quick lookup from
// IdString to child. // IdString to child.
std::unordered_map<IdStringList, std::unique_ptr<Item>> managed_; dict<IdStringList, std::unique_ptr<Item>> managed_;
// Type of children that he list creates. // Type of children that he list creates.
ElementType child_type_; ElementType child_type_;

View File

@ -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);

View File

@ -60,10 +60,10 @@ void arch_wrap_python(py::module &m)
.def("place", &Context::place) .def("place", &Context::place)
.def("route", &Context::route); .def("route", &Context::route);
typedef std::unordered_map<IdString, std::unique_ptr<CellInfo>> CellMap; typedef dict<IdString, std::unique_ptr<CellInfo>> CellMap;
typedef std::unordered_map<IdString, std::unique_ptr<NetInfo>> NetMap; typedef dict<IdString, std::unique_ptr<NetInfo>> NetMap;
typedef std::unordered_map<IdString, IdString> AliasMap; typedef dict<IdString, IdString> AliasMap;
typedef std::unordered_map<IdString, HierarchicalCell> HierarchyMap; typedef dict<IdString, HierarchicalCell> HierarchyMap;
auto belpin_cls = py::class_<ContextualWrapper<BelPin>>(m, "BelPin"); auto belpin_cls = py::class_<ContextualWrapper<BelPin>>(m, "BelPin");
readonly_wrapper<BelPin, decltype(&BelPin::bel), &BelPin::bel, conv_to_str<BelId>>::def_wrap(belpin_cls, "bel"); readonly_wrapper<BelPin, decltype(&BelPin::bel), &BelPin::bel, conv_to_str<BelId>>::def_wrap(belpin_cls, "bel");

View File

@ -20,9 +20,8 @@
#ifndef ICE40_ARCHDEFS_H #ifndef ICE40_ARCHDEFS_H
#define ICE40_ARCHDEFS_H #define ICE40_ARCHDEFS_H
#include <boost/functional/hash.hpp>
#include "base_clusterinfo.h" #include "base_clusterinfo.h"
#include "hashlib.h"
#include "idstring.h" #include "idstring.h"
#include "nextpnr_namespaces.h" #include "nextpnr_namespaces.h"
@ -55,6 +54,7 @@ struct BelId
bool operator==(const BelId &other) const { return index == other.index; } bool operator==(const BelId &other) const { return index == other.index; }
bool operator!=(const BelId &other) const { return index != other.index; } bool operator!=(const BelId &other) const { return index != other.index; }
bool operator<(const BelId &other) const { return index < other.index; } bool operator<(const BelId &other) const { return index < other.index; }
unsigned int hash() const { return index; }
}; };
struct WireId struct WireId
@ -64,6 +64,7 @@ struct WireId
bool operator==(const WireId &other) const { return index == other.index; } bool operator==(const WireId &other) const { return index == other.index; }
bool operator!=(const WireId &other) const { return index != other.index; } bool operator!=(const WireId &other) const { return index != other.index; }
bool operator<(const WireId &other) const { return index < other.index; } bool operator<(const WireId &other) const { return index < other.index; }
unsigned int hash() const { return index; }
}; };
struct PipId struct PipId
@ -73,6 +74,7 @@ struct PipId
bool operator==(const PipId &other) const { return index == other.index; } bool operator==(const PipId &other) const { return index == other.index; }
bool operator!=(const PipId &other) const { return index != other.index; } bool operator!=(const PipId &other) const { return index != other.index; }
bool operator<(const PipId &other) const { return index < other.index; } bool operator<(const PipId &other) const { return index < other.index; }
unsigned int hash() const { return index; }
}; };
struct GroupId struct GroupId
@ -96,6 +98,7 @@ struct GroupId
bool operator==(const GroupId &other) const { return (type == other.type) && (x == other.x) && (y == other.y); } bool operator==(const GroupId &other) const { return (type == other.type) && (x == other.x) && (y == other.y); }
bool operator!=(const GroupId &other) const { return (type != other.type) || (x != other.x) || (y == other.y); } bool operator!=(const GroupId &other) const { return (type != other.type) || (x != other.x) || (y == other.y); }
unsigned int hash() const { return mkhash(mkhash(x, y), int(type)); }
}; };
struct DecalId struct DecalId
@ -113,6 +116,7 @@ struct DecalId
bool operator==(const DecalId &other) const { return (type == other.type) && (index == other.index); } bool operator==(const DecalId &other) const { return (type == other.type) && (index == other.index); }
bool operator!=(const DecalId &other) const { return (type != other.type) || (index != other.index); } bool operator!=(const DecalId &other) const { return (type != other.type) || (index != other.index); }
unsigned int hash() const { return mkhash(index, int(type)); }
}; };
struct ArchNetInfo struct ArchNetInfo
@ -159,48 +163,4 @@ typedef IdString ClusterId;
NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_END
namespace std {
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX BelId>
{
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX BelId &bel) const noexcept { return hash<int>()(bel.index); }
};
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX WireId>
{
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX WireId &wire) const noexcept
{
return hash<int>()(wire.index);
}
};
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX PipId>
{
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX PipId &pip) const noexcept { return hash<int>()(pip.index); }
};
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX GroupId>
{
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX GroupId &group) const noexcept
{
std::size_t seed = 0;
boost::hash_combine(seed, hash<int>()(group.type));
boost::hash_combine(seed, hash<int>()(group.x));
boost::hash_combine(seed, hash<int>()(group.y));
return seed;
}
};
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX DecalId>
{
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX DecalId &decal) const noexcept
{
std::size_t seed = 0;
boost::hash_combine(seed, hash<int>()(decal.type));
boost::hash_combine(seed, hash<int>()(decal.index));
return seed;
}
};
} // namespace std
#endif /* ICE40_ARCHDEFS_H */ #endif /* ICE40_ARCHDEFS_H */

View File

@ -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);

View File

@ -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;

View File

@ -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);

Some files were not shown because too many files have changed in this diff Show More