aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgatecat <gatecat@ds0.me>2021-06-03 09:04:34 +0100
committerGitHub <noreply@github.com>2021-06-03 09:04:34 +0100
commita3d8b4f9d198226ec0903e34a8d290b376b45c0b (patch)
treeada2c6a5d48e766fa523e633aaa28179baea3273
parent589ca8ded5da2012e4388a3ec4c8fae74dff75e4 (diff)
parentdcbb322447a7fb59cabe197ec1dd2307acfa3681 (diff)
downloadnextpnr-a3d8b4f9d198226ec0903e34a8d290b376b45c0b.tar.gz
nextpnr-a3d8b4f9d198226ec0903e34a8d290b376b45c0b.tar.bz2
nextpnr-a3d8b4f9d198226ec0903e34a8d290b376b45c0b.zip
Merge pull request #718 from YosysHQ/gatecat/hashlib
Moving from unordered_{map, set} to hashlib
-rwxr-xr-x.github/ci/build_interchange.sh2
-rw-r--r--.gitmodules3
m---------3rdparty/abseil-cpp0
-rw-r--r--CMakeLists.txt16
-rw-r--r--common/archcheck.cc18
-rw-r--r--common/base_arch.h18
-rw-r--r--common/basectx.h27
-rw-r--r--common/chain_utils.h4
-rw-r--r--common/command.cc4
-rw-r--r--common/command.h2
-rw-r--r--common/constraints.h4
-rw-r--r--common/context.cc4
-rw-r--r--common/context.h2
-rw-r--r--common/fast_bels.h4
-rw-r--r--common/hash_table.h63
-rw-r--r--common/hashlib.h1196
-rw-r--r--common/idstring.h12
-rw-r--r--common/idstringlist.h21
-rw-r--r--common/log.cc2
-rw-r--r--common/log.h20
-rw-r--r--common/nextpnr_base_types.h17
-rw-r--r--common/nextpnr_types.h23
-rw-r--r--common/place_common.cc24
-rw-r--r--common/placer1.cc63
-rw-r--r--common/placer_heap.cc85
-rw-r--r--common/placer_heap.h4
-rw-r--r--common/pybindings.cc14
-rw-r--r--common/router1.cc63
-rw-r--r--common/router2.cc19
-rw-r--r--common/sdf.cc8
-rw-r--r--common/timing.cc61
-rw-r--r--common/timing.h61
-rw-r--r--common/timing_opt.cc24
-rw-r--r--common/timing_opt.h2
-rw-r--r--common/util.h41
-rw-r--r--docs/archapi.md20
-rw-r--r--ecp5/arch.h26
-rw-r--r--ecp5/arch_place.cc17
-rw-r--r--ecp5/arch_pybindings.cc8
-rw-r--r--ecp5/archdefs.h77
-rw-r--r--ecp5/bitstream.cc7
-rw-r--r--ecp5/cells.cc2
-rw-r--r--ecp5/cells.h2
-rw-r--r--ecp5/globals.cc26
-rw-r--r--ecp5/lpf.cc5
-rw-r--r--ecp5/main.cc8
-rw-r--r--ecp5/pack.cc151
-rw-r--r--fpga_interchange/arch.cc23
-rw-r--r--fpga_interchange/arch.h22
-rw-r--r--fpga_interchange/arch_pack_io.cc26
-rw-r--r--fpga_interchange/arch_pybindings.cc8
-rw-r--r--fpga_interchange/archdefs.h79
-rw-r--r--fpga_interchange/cell_parameters.h3
-rw-r--r--fpga_interchange/cost_map.cc2
-rw-r--r--fpga_interchange/cost_map.h5
-rw-r--r--fpga_interchange/dedicated_interconnect.cc6
-rw-r--r--fpga_interchange/dedicated_interconnect.h36
-rw-r--r--fpga_interchange/fpga_interchange.cpp54
-rw-r--r--fpga_interchange/globals.cc10
-rw-r--r--fpga_interchange/lookahead.cc76
-rw-r--r--fpga_interchange/lookahead.h7
-rw-r--r--fpga_interchange/luts.cc14
-rw-r--r--fpga_interchange/luts.h23
-rw-r--r--fpga_interchange/macros.cc4
-rw-r--r--fpga_interchange/main.cc4
-rw-r--r--fpga_interchange/pseudo_pip_model.cc8
-rw-r--r--fpga_interchange/pseudo_pip_model.h33
-rw-r--r--fpga_interchange/site_arch.cc2
-rw-r--r--fpga_interchange/site_arch.h46
-rw-r--r--fpga_interchange/site_router.cc24
-rw-r--r--fpga_interchange/site_router.h5
-rw-r--r--fpga_interchange/site_routing_cache.cc2
-rw-r--r--fpga_interchange/site_routing_cache.h39
-rw-r--r--fpga_interchange/type_wire.cc5
-rw-r--r--fpga_interchange/type_wire.h36
-rw-r--r--frontend/frontend_base.h20
-rw-r--r--generic/arch.cc4
-rw-r--r--generic/arch.h39
-rw-r--r--generic/arch_pybindings.cc6
-rw-r--r--generic/archdefs.h5
-rw-r--r--generic/cells.cc2
-rw-r--r--generic/cells.h2
-rw-r--r--generic/main.cc4
-rw-r--r--generic/pack.cc34
-rw-r--r--gowin/arch.cc4
-rw-r--r--gowin/arch.h37
-rw-r--r--gowin/arch_pybindings.cc6
-rw-r--r--gowin/cells.cc2
-rw-r--r--gowin/cells.h2
-rw-r--r--gowin/main.cc4
-rw-r--r--gowin/pack.cc34
-rw-r--r--gui/CMakeLists.txt4
-rw-r--r--gui/treemodel.cc2
-rw-r--r--gui/treemodel.h4
-rw-r--r--ice40/arch.h10
-rw-r--r--ice40/arch_pybindings.cc8
-rw-r--r--ice40/archdefs.h52
-rw-r--r--ice40/bitstream.cc8
-rw-r--r--ice40/cells.cc2
-rw-r--r--ice40/cells.h2
-rw-r--r--ice40/chains.cc6
-rw-r--r--ice40/delay.cc2
-rw-r--r--ice40/main.cc4
-rw-r--r--ice40/pack.cc84
-rw-r--r--ice40/pcf.cc4
-rw-r--r--json/jsonwrite.cc7
-rw-r--r--machxo2/arch.h4
-rw-r--r--machxo2/arch_pybindings.cc8
-rw-r--r--machxo2/archdefs.h48
-rw-r--r--machxo2/bitstream.cc3
-rw-r--r--machxo2/cells.cc2
-rw-r--r--machxo2/cells.h2
-rw-r--r--machxo2/main.cc4
-rw-r--r--machxo2/pack.cc34
-rw-r--r--mistral/arch.cc4
-rw-r--r--mistral/arch.h29
-rw-r--r--mistral/arch_pybindings.cc8
-rw-r--r--mistral/archdefs.h37
-rw-r--r--mistral/bitstream.cc10
-rw-r--r--mistral/lab.cc4
-rw-r--r--mistral/main.cc4
-rw-r--r--mistral/pack.cc28
-rw-r--r--mistral/pins.cc2
-rw-r--r--mistral/qsf.cc2
-rw-r--r--nexus/arch.cc8
-rw-r--r--nexus/arch.h12
-rw-r--r--nexus/arch_pybindings.cc8
-rw-r--r--nexus/archdefs.h70
-rw-r--r--nexus/fasm.cc30
-rw-r--r--nexus/global.cc6
-rw-r--r--nexus/io.cc2
-rw-r--r--nexus/main.cc4
-rw-r--r--nexus/pack.cc143
-rw-r--r--nexus/pdc.cc2
-rw-r--r--nexus/pins.cc2
-rw-r--r--nexus/post_place.cc4
m---------tests0
137 files changed, 2152 insertions, 1658 deletions
diff --git a/.github/ci/build_interchange.sh b/.github/ci/build_interchange.sh
index ed6e82bd..8168d519 100755
--- a/.github/ci/build_interchange.sh
+++ b/.github/ci/build_interchange.sh
@@ -57,7 +57,7 @@ function build_nextpnr {
build_capnp
mkdir 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`
popd
}
diff --git a/.gitmodules b/.gitmodules
index c0c178bf..a22fbc41 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -4,6 +4,3 @@
[submodule "fpga-interchange-schema"]
path = 3rdparty/fpga-interchange-schema
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
diff --git a/3rdparty/abseil-cpp b/3rdparty/abseil-cpp
deleted file mode 160000
-Subproject a76698790753d2ec71f655cdc84d61bcb27780d
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 233d5797..42d55a97 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -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(PROFILER "Link against libprofiler" OFF)
option(USE_IPO "Compile nextpnr with IPO" ON)
-option(USE_ABSEIL "Compile nextpnr with Abseil for faster hash map" OFF)
if (USE_IPO)
if (ipo_supported)
@@ -199,10 +198,6 @@ if (NOT DEFINED CURRENT_GIT_VERSION)
)
endif()
-if (USE_ABSEIL)
- add_subdirectory(3rdparty/abseil-cpp EXCLUDE_FROM_ALL)
-endif()
-
if (BUILD_TESTS)
add_subdirectory(3rdparty/googletest/googletest ${CMAKE_CURRENT_BINARY_DIR}/generated/3rdparty/googletest EXCLUDE_FROM_ALL)
enable_testing()
@@ -252,13 +247,7 @@ else()
endif()
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)
list(APPEND EXTRA_LIB_DEPS profiler)
endif()
@@ -336,9 +325,6 @@ foreach (family ${ARCH})
target_compile_definitions(${target} PRIVATE QT_NO_KEYWORDS)
target_link_libraries(${target} LINK_PUBLIC gui_${family} ${GUI_LIBRARY_FILES_${ufamily}})
endif()
- if (USE_ABSEIL)
- target_compile_definitions(${target} PRIVATE USE_ABSEIL)
- endif()
if (BUILD_PYTHON)
target_link_libraries(${target} LINK_PUBLIC ${PYTHON_LIBRARIES})
if (STATIC_BUILD)
diff --git a/common/archcheck.cc b/common/archcheck.cc
index f46db95c..89a61007 100644
--- a/common/archcheck.cc
+++ b/common/archcheck.cc
@@ -108,7 +108,7 @@ void archcheck_locs(const Context *ctx)
for (int x = 0; x < ctx->getGridDimX(); x++)
for (int y = 0; y < ctx->getGridDimY(); y++) {
dbg("> %d %d\n", x, y);
- std::unordered_set<int> usedz;
+ pool<int> usedz;
for (int z = 0; z < ctx->getTileBelDimZ(x, y); z++) {
BelId bel = ctx->getBelByLocation(Loc(x, y, z));
@@ -162,10 +162,10 @@ struct LruWireCacheMap
// list is oldest wire in cache.
std::list<WireId> last_access_list;
// 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;
- std::unordered_map<PipId, WireId> pips_uphill;
+ dict<PipId, WireId> pips_downhill;
+ dict<PipId, WireId> pips_uphill;
void removeWireFromCache(WireId wire_to_remove)
{
@@ -255,8 +255,8 @@ void archcheck_conn(const Context *ctx)
log_info("Checking all wires...\n");
#ifndef USING_LRU_CACHE
- std::unordered_map<PipId, WireId> pips_downhill;
- std::unordered_map<PipId, WireId> pips_uphill;
+ dict<PipId, WireId> pips_downhill;
+ dict<PipId, WireId> pips_uphill;
#endif
for (WireId wire : ctx->getWires()) {
@@ -347,7 +347,7 @@ void archcheck_buckets(const Context *ctx)
for (BelBucketId bucket : ctx->getBelBuckets()) {
// 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()) {
if (ctx->getBelBucketForCellType(cell_type) == bucket) {
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
// 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)) {
BelBucketId bucket2 = ctx->getBelBucketForBel(bel);
log_assert(bucket == bucket2);
diff --git a/common/base_arch.h b/common/base_arch.h
index fbafee99..457e6582 100644
--- a/common/base_arch.h
+++ b/common/base_arch.h
@@ -148,7 +148,7 @@ template <typename R> struct BaseArch : ArchAPI<R>
virtual char getNameDelimiter() const override { return ' '; }
// 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
{
NPNR_ASSERT(bel != BelId());
@@ -196,7 +196,7 @@ template <typename R> struct BaseArch : ArchAPI<R>
{
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
{
@@ -244,7 +244,7 @@ template <typename R> struct BaseArch : ArchAPI<R>
{
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
{
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
- // 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
- std::unordered_map<BelId, CellInfo *> base_bel2cell;
- std::unordered_map<WireId, NetInfo *> base_wire2net;
- std::unordered_map<PipId, NetInfo *> base_pip2net;
+ dict<BelId, CellInfo *> base_bel2cell;
+ dict<WireId, NetInfo *> base_wire2net;
+ dict<PipId, NetInfo *> base_pip2net;
// For the default cell/bel bucket implementations
std::vector<IdString> cell_types;
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
bool cell_types_initialised = false;
bool bel_buckets_initialised = false;
void init_cell_types()
{
- std::unordered_set<IdString> bel_types;
+ pool<IdString> bel_types;
for (auto bel : this->getBels())
bel_types.insert(this->getBelType(bel));
std::copy(bel_types.begin(), bel_types.end(), std::back_inserter(cell_types));
diff --git a/common/basectx.h b/common/basectx.h
index fccd12af..12f63f98 100644
--- a/common/basectx.h
+++ b/common/basectx.h
@@ -28,6 +28,7 @@
#include <boost/thread.hpp>
#endif
+#include "hashlib.h"
#include "idstring.h"
#include "nextpnr_namespaces.h"
#include "nextpnr_types.h"
@@ -59,29 +60,29 @@ struct BaseCtx
mutable StrRingBuffer log_strs;
// Project settings and config switches
- std::unordered_map<IdString, Property> settings;
+ dict<IdString, Property> settings;
// Placed nets and cells.
- std::unordered_map<IdString, std::unique_ptr<NetInfo>> nets;
- std::unordered_map<IdString, std::unique_ptr<CellInfo>> cells;
+ dict<IdString, std::unique_ptr<NetInfo>> nets;
+ dict<IdString, std::unique_ptr<CellInfo>> cells;
// 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
IdString top_module;
// 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
- std::unordered_map<IdString, PortInfo> ports;
- std::unordered_map<IdString, CellInfo *> port_cells;
+ dict<IdString, PortInfo> ports;
+ dict<IdString, CellInfo *> port_cells;
// Floorplanning regions
- std::unordered_map<IdString, std::unique_ptr<Region>> region;
+ dict<IdString, std::unique_ptr<Region>> region;
// Context meta data
- std::unordered_map<IdString, Property> attrs;
+ dict<IdString, Property> attrs;
Context *as_ctx = nullptr;
@@ -186,10 +187,10 @@ struct BaseCtx
bool allUiReload = true;
bool frameUiReload = false;
- std::unordered_set<BelId> belUiReload;
- std::unordered_set<WireId> wireUiReload;
- std::unordered_set<PipId> pipUiReload;
- std::unordered_set<GroupId> groupUiReload;
+ pool<BelId> belUiReload;
+ pool<WireId> wireUiReload;
+ pool<PipId> pipUiReload;
+ pool<GroupId> groupUiReload;
void refreshUi() { allUiReload = true; }
diff --git a/common/chain_utils.h b/common/chain_utils.h
index 300d96a1..1bd95c9e 100644
--- a/common/chain_utils.h
+++ b/common/chain_utils.h
@@ -37,10 +37,10 @@ std::vector<CellChain> find_chains(const Context *ctx, F1 cell_type_predicate, F
{
std::set<IdString> chained;
std::vector<CellChain> chains;
- for (auto cell : sorted(ctx->cells)) {
+ for (auto &cell : ctx->cells) {
if (chained.find(cell.first) != chained.end())
continue;
- CellInfo *ci = cell.second;
+ CellInfo *ci = cell.second.get();
if (cell_type_predicate(ctx, ci)) {
CellInfo *start = ci;
CellInfo *prev_start = ci;
diff --git a/common/command.cc b/common/command.cc
index f48d6adf..27e59260 100644
--- a/common/command.cc
+++ b/common/command.cc
@@ -458,7 +458,7 @@ int CommandHandler::exec()
if (executeBeforeContext())
return 0;
- std::unordered_map<std::string, Property> values;
+ dict<std::string, Property> values;
std::unique_ptr<Context> ctx = createContext(values);
setupContext(ctx.get());
setupArchContext(ctx.get());
@@ -475,7 +475,7 @@ int CommandHandler::exec()
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);
setupContext(ctx.get());
setupArchContext(ctx.get());
diff --git a/common/command.h b/common/command.h
index 36b6d8ab..ba606ea2 100644
--- a/common/command.h
+++ b/common/command.h
@@ -42,7 +42,7 @@ class CommandHandler
protected:
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 void validate(){};
virtual void customAfterLoad(Context *ctx){};
diff --git a/common/constraints.h b/common/constraints.h
index 9ec8372d..65abf12c 100644
--- a/common/constraints.h
+++ b/common/constraints.h
@@ -21,11 +21,11 @@
#define CONSTRAINTS_H
#include <cstdint>
-#include <unordered_map>
#include <vector>
#include "archdefs.h"
#include "exclusive_state_groups.h"
+#include "hashlib.h"
#include "idstring.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;
- 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);
diff --git a/common/context.cc b/common/context.cc
index 05c1e094..115b333a 100644
--- a/common/context.cc
+++ b/common/context.cc
@@ -389,8 +389,8 @@ struct FixupHierarchyWorker
// Update hierarchy structure for nets and cells that have hiercell set
void rebuild_hierarchy()
{
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->hierpath == IdString())
ci->hierpath = ctx->top_module;
auto &hc = ctx->hierarchy.at(ci->hierpath);
diff --git a/common/context.h b/common/context.h
index a5553422..102dc221 100644
--- a/common/context.h
+++ b/common/context.h
@@ -50,7 +50,7 @@ struct Context : Arch, DeterministicRNG
// provided by router1.cc
bool checkRoutedDesign() const;
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
diff --git a/common/fast_bels.h b/common/fast_bels.h
index 0425f92a..b49c4c6c 100644
--- a/common/fast_bels.h
+++ b/common/fast_bels.h
@@ -178,10 +178,10 @@ struct FastBels
const bool check_bel_available;
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::unordered_map<BelBucketId, TypeData> partition_types;
+ dict<BelBucketId, TypeData> partition_types;
std::vector<std::unique_ptr<FastBelsData>> fast_bels_by_partition_type;
};
diff --git a/common/hash_table.h b/common/hash_table.h
deleted file mode 100644
index 21ca8887..00000000
--- a/common/hash_table.h
+++ /dev/null
@@ -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 */
diff --git a/common/hashlib.h b/common/hashlib.h
new file mode 100644
index 00000000..063df78f
--- /dev/null
+++ b/common/hashlib.h
@@ -0,0 +1,1196 @@
+// This is free and unencumbered software released into the public domain.
+//
+// Anyone is free to copy, modify, publish, use, compile, sell, or
+// distribute this software, either in source code form or as a compiled
+// binary, for any purpose, commercial or non-commercial, and by any
+// means.
+
+// -------------------------------------------------------
+// Written by Claire Xen <claire@clairexen.net> in 2014
+// -------------------------------------------------------
+
+#ifndef HASHLIB_H
+#define HASHLIB_H
+
+#include <algorithm>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+#include "nextpnr_assertions.h"
+#include "nextpnr_namespaces.h"
+
+NEXTPNR_NAMESPACE_BEGIN
+
+const int hashtable_size_trigger = 2;
+const int hashtable_size_factor = 3;
+
+// The XOR version of DJB2
+inline unsigned int mkhash(unsigned int a, unsigned int b) { return ((a << 5) + a) ^ b; }
+
+// traditionally 5381 is used as starting value for the djb2 hash
+const unsigned int mkhash_init = 5381;
+
+// The ADD version of DJB2
+// (use this version for cache locality in b)
+inline unsigned int mkhash_add(unsigned int a, unsigned int b) { return ((a << 5) + a) + b; }
+
+inline unsigned int mkhash_xorshift(unsigned int a)
+{
+ if (sizeof(a) == 4) {
+ a ^= a << 13;
+ a ^= a >> 17;
+ a ^= a << 5;
+ } else if (sizeof(a) == 8) {
+ a ^= a << 13;
+ a ^= a >> 7;
+ a ^= a << 17;
+ } else
+ NPNR_ASSERT_FALSE("mkhash_xorshift() only implemented for 32 bit and 64 bit ints");
+ return a;
+}
+
+template <typename T> struct hash_ops
+{
+ static inline bool cmp(const T &a, const T &b) { return a == b; }
+ static inline unsigned int hash(const T &a) { return a.hash(); }
+};
+
+struct hash_int_ops
+{
+ template <typename T> static inline bool cmp(T a, T b) { return a == b; }
+};
+
+template <> struct hash_ops<bool> : hash_int_ops
+{
+ static inline unsigned int hash(bool a) { return a ? 1 : 0; }
+};
+template <> struct hash_ops<int32_t> : hash_int_ops
+{
+ static inline unsigned int hash(int32_t a) { return a; }
+};
+template <> struct hash_ops<int64_t> : hash_int_ops
+{
+ static inline unsigned int hash(int64_t a) { return mkhash((unsigned int)(a), (unsigned int)(a >> 32)); }
+};
+
+template <> struct hash_ops<uint32_t> : hash_int_ops
+{
+ static inline unsigned int hash(uint32_t a) { return a; }
+};
+template <> struct hash_ops<uint64_t> : hash_int_ops
+{
+ static inline unsigned int hash(uint64_t a) { return mkhash((unsigned int)(a), (unsigned int)(a >> 32)); }
+};
+
+template <> struct hash_ops<std::string>
+{
+ static inline bool cmp(const std::string &a, const std::string &b) { return a == b; }
+ static inline unsigned int hash(const std::string &a)
+ {
+ unsigned int v = 0;
+ for (auto c : a)
+ v = mkhash(v, c);
+ return v;
+ }
+};
+
+template <typename P, typename Q> struct hash_ops<std::pair<P, Q>>
+{
+ static inline bool cmp(std::pair<P, Q> a, std::pair<P, Q> b) { return a == b; }
+ static inline unsigned int hash(std::pair<P, Q> a)
+ {
+ return mkhash(hash_ops<P>::hash(a.first), hash_ops<Q>::hash(a.second));
+ }
+};
+
+template <typename... T> struct hash_ops<std::tuple<T...>>
+{
+ static inline bool cmp(std::tuple<T...> a, std::tuple<T...> b) { return a == b; }
+ template <size_t I = 0>
+ static inline typename std::enable_if<I == sizeof...(T), unsigned int>::type hash(std::tuple<T...>)
+ {
+ return mkhash_init;
+ }
+ template <size_t I = 0>
+ static inline typename std::enable_if<I != sizeof...(T), unsigned int>::type hash(std::tuple<T...> a)
+ {
+ typedef hash_ops<typename std::tuple_element<I, std::tuple<T...>>::type> element_ops_t;
+ return mkhash(hash<I + 1>(a), element_ops_t::hash(std::get<I>(a)));
+ }
+};
+
+template <typename T> struct hash_ops<std::vector<T>>
+{
+ static inline bool cmp(std::vector<T> a, std::vector<T> b) { return a == b; }
+ static inline unsigned int hash(std::vector<T> a)
+ {
+ unsigned int h = mkhash_init;
+ for (auto k : a)
+ h = mkhash(h, hash_ops<T>::hash(k));
+ return h;
+ }
+};
+
+struct hash_cstr_ops
+{
+ static inline bool cmp(const char *a, const char *b)
+ {
+ for (int i = 0; a[i] || b[i]; i++)
+ if (a[i] != b[i])
+ return false;
+ return true;
+ }
+ static inline unsigned int hash(const char *a)
+ {
+ unsigned int hash = mkhash_init;
+ while (*a)
+ hash = mkhash(hash, *(a++));
+ return hash;
+ }
+};
+
+struct hash_ptr_ops
+{
+ static inline bool cmp(const void *a, const void *b) { return a == b; }
+ static inline unsigned int hash(const void *a) { return (uintptr_t)a; }
+};
+
+struct hash_obj_ops
+{
+ static inline bool cmp(const void *a, const void *b) { return a == b; }
+ template <typename T> static inline unsigned int hash(const T *a) { return a ? a->hash() : 0; }
+};
+
+template <typename T> inline unsigned int mkhash(const T &v) { return hash_ops<T>().hash(v); }
+
+inline int hashtable_size(int min_size)
+{
+ static std::vector<int> zero_and_some_primes = {
+ 0, 23, 29, 37, 47, 59, 79, 101, 127, 163,
+ 211, 269, 337, 431, 541, 677, 853, 1069, 1361, 1709,
+ 2137, 2677, 3347, 4201, 5261, 6577, 8231, 10289, 12889, 16127,
+ 20161, 25219, 31531, 39419, 49277, 61603, 77017, 96281, 120371, 150473,
+ 188107, 235159, 293957, 367453, 459317, 574157, 717697, 897133, 1121423, 1401791,
+ 1752239, 2190299, 2737937, 3422429, 4278037, 5347553, 6684443, 8355563, 10444457, 13055587,
+ 16319519, 20399411, 25499291, 31874149, 39842687, 49803361, 62254207, 77817767, 97272239, 121590311,
+ 151987889, 189984863, 237481091, 296851369, 371064217};
+
+ for (auto p : zero_and_some_primes)
+ if (p >= min_size)
+ return p;
+
+ if (sizeof(int) == 4)
+ throw std::length_error("hash table exceeded maximum size. use a ILP64 abi for larger tables.");
+
+ for (auto p : zero_and_some_primes)
+ if (100129 * p > min_size)
+ return 100129 * p;
+
+ throw std::length_error("hash table exceeded maximum size.");
+}
+
+template <typename K, typename T, typename OPS = hash_ops<K>> class dict;
+template <typename K, int offset = 0, typename OPS = hash_ops<K>> class idict;
+template <typename K, typename OPS = hash_ops<K>> class pool;
+template <typename K, typename OPS = hash_ops<K>> class mfp;
+
+template <typename K, typename T, typename OPS> class dict
+{
+ struct entry_t
+ {
+ std::pair<K, T> udata;
+ int next;
+
+ entry_t() {}
+ entry_t(const std::pair<K, T> &udata, int next) : udata(udata), next(next) {}
+ entry_t(std::pair<K, T> &&udata, int next) : udata(std::move(udata)), next(next) {}
+ bool operator<(const entry_t &other) const { return udata.first < other.udata.first; }
+ };
+
+ std::vector<int> hashtable;
+ std::vector<entry_t> entries;
+ OPS ops;
+
+#ifdef NDEBUG
+ static inline void do_assert(bool) {}
+#else
+ static inline void do_assert(bool cond) { NPNR_ASSERT(cond); }
+#endif
+
+ int do_hash(const K &key) const
+ {
+ unsigned int hash = 0;
+ if (!hashtable.empty())
+ hash = ops.hash(key) % (unsigned int)(hashtable.size());
+ return hash;
+ }
+
+ void do_rehash()
+ {
+ hashtable.clear();
+ hashtable.resize(hashtable_size(entries.capacity() * hashtable_size_factor), -1);
+
+ for (int i = 0; i < int(entries.size()); i++) {
+ do_assert(-1 <= entries[i].next && entries[i].next < int(entries.size()));
+ int hash = do_hash(entries[i].udata.first);
+ entries[i].next = hashtable[hash];
+ hashtable[hash] = i;
+ }
+ }
+
+ int do_erase(int index, int hash)
+ {
+ do_assert(index < int(entries.size()));
+ if (hashtable.empty() || index < 0)
+ return 0;
+
+ int k = hashtable[hash];
+ do_assert(0 <= k && k < int(entries.size()));
+
+ if (k == index) {
+ hashtable[hash] = entries[index].next;
+ } else {
+ while (entries[k].next != index) {
+ k = entries[k].next;
+ do_assert(0 <= k && k < int(entries.size()));
+ }
+ entries[k].next = entries[index].next;
+ }
+
+ int back_idx = entries.size() - 1;
+
+ if (index != back_idx) {
+ int back_hash = do_hash(entries[back_idx].udata.first);
+
+ k = hashtable[back_hash];
+ do_assert(0 <= k && k < int(entries.size()));
+
+ if (k == back_idx) {
+ hashtable[back_hash] = index;
+ } else {
+ while (entries[k].next != back_idx) {
+ k = entries[k].next;
+ do_assert(0 <= k && k < int(entries.size()));
+ }
+ entries[k].next = index;
+ }
+
+ entries[index] = std::move(entries[back_idx]);
+ }
+
+ entries.pop_back();
+
+ if (entries.empty())
+ hashtable.clear();
+
+ return 1;
+ }
+
+ int do_lookup(const K &key, int &hash) const
+ {
+ if (hashtable.empty())
+ return -1;
+
+ if (entries.size() * hashtable_size_trigger > hashtable.size()) {
+ ((dict *)this)->do_rehash();
+ hash = do_hash(key);
+ }
+
+ int index = hashtable[hash];
+
+ while (index >= 0 && !ops.cmp(entries[index].udata.first, key)) {
+ index = entries[index].next;
+ do_assert(-1 <= index && index < int(entries.size()));
+ }
+
+ return index;
+ }
+
+ int do_insert(const K &key, int &hash)
+ {
+ if (hashtable.empty()) {
+ entries.emplace_back(std::pair<K, T>(key, T()), -1);
+ do_rehash();
+ hash = do_hash(key);
+ } else {
+ entries.emplace_back(std::pair<K, T>(key, T()), hashtable[hash]);
+ hashtable[hash] = entries.size() - 1;
+ }
+ return entries.size() - 1;
+ }
+
+ int do_insert(const std::pair<K, T> &value, int &hash)
+ {
+ if (hashtable.empty()) {
+ entries.emplace_back(value, -1);
+ do_rehash();
+ hash = do_hash(value.first);
+ } else {
+ entries.emplace_back(value, hashtable[hash]);
+ hashtable[hash] = entries.size() - 1;
+ }
+ return entries.size() - 1;
+ }
+
+ int do_insert(std::pair<K, T> &&rvalue, int &hash)
+ {
+ if (hashtable.empty()) {
+ auto key = rvalue.first;
+ entries.emplace_back(std::forward<std::pair<K, T>>(rvalue), -1);
+ do_rehash();
+ hash = do_hash(key);
+ } else {
+ entries.emplace_back(std::forward<std::pair<K, T>>(rvalue), hashtable[hash]);
+ hashtable[hash] = entries.size() - 1;
+ }
+ return entries.size() - 1;
+ }
+
+ public:
+ using key_type = K;
+ using mapped_type = T;
+ using value_type = std::pair<K, T>;
+
+ class const_iterator : public std::iterator<std::forward_iterator_tag, std::pair<K, T>>
+ {
+ friend class dict;
+
+ protected:
+ const dict *ptr;
+ int index;
+ const_iterator(const dict *ptr, int index) : ptr(ptr), index(index) {}
+
+ public:
+ const_iterator() {}
+ const_iterator operator++()
+ {
+ index--;
+ return *this;
+ }
+ const_iterator operator+=(int amt)
+ {
+ index -= amt;
+ return *this;
+ }
+ bool operator<(const const_iterator &other) const { return index > other.index; }
+ bool operator==(const const_iterator &other) const { return index == other.index; }
+ bool operator!=(const const_iterator &other) const { return index != other.index; }
+ const std::pair<K, T> &operator*() const { return ptr->entries[index].udata; }
+ const std::pair<K, T> *operator->() const { return &ptr->entries[index].udata; }
+ };
+
+ class iterator : public std::iterator<std::forward_iterator_tag, std::pair<K, T>>
+ {
+ friend class dict;
+
+ protected:
+ dict *ptr;
+ int index;
+ iterator(dict *ptr, int index) : ptr(ptr), index(index) {}
+
+ public:
+ iterator() {}
+ iterator operator++()
+ {
+ index--;
+ return *this;
+ }
+ iterator operator+=(int amt)
+ {
+ index -= amt;
+ return *this;
+ }
+ bool operator<(const iterator &other) const { return index > other.index; }
+ bool operator==(const iterator &other) const { return index == other.index; }
+ bool operator!=(const iterator &other) const { return index != other.index; }
+ std::pair<K, T> &operator*() { return ptr->entries[index].udata; }
+ std::pair<K, T> *operator->() { return &ptr->entries[index].udata; }
+ const std::pair<K, T> &operator*() const { return ptr->entries[index].udata; }
+ const std::pair<K, T> *operator->() const { return &ptr->entries[index].udata; }
+ operator const_iterator() const { return const_iterator(ptr, index); }
+ };
+
+ dict() {}
+
+ dict(const dict &other)
+ {
+ entries = other.entries;
+ do_rehash();
+ }
+
+ dict(dict &&other) { swap(other); }
+
+ dict &operator=(const dict &other)
+ {
+ entries = other.entries;
+ do_rehash();
+ return *this;
+ }
+
+ dict &operator=(dict &&other)
+ {
+ clear();
+ swap(other);
+ return *this;
+ }
+
+ dict(const std::initializer_list<std::pair<K, T>> &list)
+ {
+ for (auto &it : list)
+ insert(it);
+ }
+
+ template <class InputIterator> dict(InputIterator first, InputIterator last) { insert(first, last); }
+
+ template <class InputIterator> void insert(InputIterator first, InputIterator last)
+ {
+ for (; first != last; ++first)
+ insert(*first);
+ }
+
+ std::pair<iterator, bool> insert(const K &key)
+ {
+ int hash = do_hash(key);
+ int i = do_lookup(key, hash);
+ if (i >= 0)
+ return std::pair<iterator, bool>(iterator(this, i), false);
+ i = do_insert(key, hash);
+ return std::pair<iterator, bool>(iterator(this, i), true);
+ }
+
+ std::pair<iterator, bool> insert(const std::pair<K, T> &value)
+ {
+ int hash = do_hash(value.first);
+ int i = do_lookup(value.first, hash);
+ if (i >= 0)
+ return std::pair<iterator, bool>(iterator(this, i), false);
+ i = do_insert(value, hash);
+ return std::pair<iterator, bool>(iterator(this, i), true);
+ }
+
+ std::pair<iterator, bool> insert(std::pair<K, T> &&rvalue)
+ {
+ int hash = do_hash(rvalue.first);
+ int i = do_lookup(rvalue.first, hash);
+ if (i >= 0)
+ return std::pair<iterator, bool>(iterator(this, i), false);
+ i = do_insert(std::forward<std::pair<K, T>>(rvalue), hash);
+ return std::pair<iterator, bool>(iterator(this, i), true);
+ }
+
+ std::pair<iterator, bool> emplace(K const &key, T const &value)
+ {
+ int hash = do_hash(key);
+ int i = do_lookup(key, hash);
+ if (i >= 0)
+ return std::pair<iterator, bool>(iterator(this, i), false);
+ i = do_insert(std::make_pair(key, value), hash);
+ return std::pair<iterator, bool>(iterator(this, i), true);
+ }
+
+ std::pair<iterator, bool> emplace(K const &key, T &&rvalue)
+ {
+ int hash = do_hash(key);
+ int i = do_lookup(key, hash);
+ if (i >= 0)
+ return std::pair<iterator, bool>(iterator(this, i), false);
+ i = do_insert(std::make_pair(key, std::forward<T>(rvalue)), hash);
+ return std::pair<iterator, bool>(iterator(this, i), true);
+ }
+
+ std::pair<iterator, bool> emplace(K &&rkey, T const &value)
+ {
+ int hash = do_hash(rkey);
+ int i = do_lookup(rkey, hash);
+ if (i >= 0)
+ return std::pair<iterator, bool>(iterator(this, i), false);
+ i = do_insert(std::make_pair(std::forward<K>(rkey), value), hash);
+ return std::pair<iterator, bool>(iterator(this, i), true);
+ }
+
+ std::pair<iterator, bool> emplace(K &&rkey, T &&rvalue)
+ {
+ int hash = do_hash(rkey);
+ int i = do_lookup(rkey, hash);
+ if (i >= 0)
+ return std::pair<iterator, bool>(iterator(this, i), false);
+ i = do_insert(std::make_pair(std::forward<K>(rkey), std::forward<T>(rvalue)), hash);
+ return std::pair<iterator, bool>(iterator(this, i), true);
+ }
+
+ int erase(const K &key)
+ {
+ int hash = do_hash(key);
+ int index = do_lookup(key, hash);
+ return do_erase(index, hash);
+ }
+
+ iterator erase(iterator it)
+ {
+ int hash = do_hash(it->first);
+ do_erase(it.index, hash);
+ return ++it;
+ }
+
+ int count(const K &key) const
+ {
+ int hash = do_hash(key);
+ int i = do_lookup(key, hash);
+ return i < 0 ? 0 : 1;
+ }
+
+ int count(const K &key, const_iterator it) const
+ {
+ int hash = do_hash(key);
+ int i = do_lookup(key, hash);
+ return i < 0 || i > it.index ? 0 : 1;
+ }
+
+ iterator find(const K &key)
+ {
+ int hash = do_hash(key);
+ int i = do_lookup(key, hash);
+ if (i < 0)
+ return end();
+ return iterator(this, i);
+ }
+
+ const_iterator find(const K &key) const
+ {
+ int hash = do_hash(key);
+ int i = do_lookup(key, hash);
+ if (i < 0)
+ return end();
+ return const_iterator(this, i);
+ }
+
+ T &at(const K &key)
+ {
+ int hash = do_hash(key);
+ int i = do_lookup(key, hash);
+ if (i < 0)
+ throw std::out_of_range("dict::at()");
+ return entries[i].udata.second;
+ }
+
+ const T &at(const K &key) const
+ {
+ int hash = do_hash(key);
+ int i = do_lookup(key, hash);
+ if (i < 0)
+ throw std::out_of_range("dict::at()");
+ return entries[i].udata.second;
+ }
+
+ const T &at(const K &key, const T &defval) const
+ {
+ int hash = do_hash(key);
+ int i = do_lookup(key, hash);
+ if (i < 0)
+ return defval;
+ return entries[i].udata.second;
+ }
+
+ T &operator[](const K &key)
+ {
+ int hash = do_hash(key);
+ int i = do_lookup(key, hash);
+ if (i < 0)
+ i = do_insert(std::pair<K, T>(key, T()), hash);
+ return entries[i].udata.second;
+ }
+
+ template <typename Compare = std::less<K>> void sort(Compare comp = Compare())
+ {
+ std::sort(entries.begin(), entries.end(),
+ [comp](const entry_t &a, const entry_t &b) { return comp(b.udata.first, a.udata.first); });
+ do_rehash();
+ }
+
+ void swap(dict &other)
+ {
+ hashtable.swap(other.hashtable);
+ entries.swap(other.entries);
+ }
+
+ bool operator==(const dict &other) const
+ {
+ if (size() != other.size())
+ return false;
+ for (auto &it : entries) {
+ auto oit = other.find(it.udata.first);
+ if (oit == other.end() || !(oit->second == it.udata.second))
+ return false;
+ }
+ return true;
+ }
+
+ bool operator!=(const dict &other) const { return !operator==(other); }
+
+ unsigned int hash() const
+ {
+ unsigned int h = mkhash_init;
+ for (auto &entry : entries) {
+ h ^= hash_ops<K>::hash(entry.udata.first);
+ h ^= hash_ops<T>::hash(entry.udata.second);
+ }
+ return h;
+ }
+
+ void reserve(size_t n) { entries.reserve(n); }
+ size_t size() const { return entries.size(); }
+ bool empty() const { return entries.empty(); }
+ void clear()
+ {
+ hashtable.clear();
+ entries.clear();
+ }
+
+ iterator begin() { return iterator(this, int(entries.size()) - 1); }
+ iterator element(int n) { return iterator(this, int(entries.size()) - 1 - n); }
+ iterator end() { return iterator(nullptr, -1); }
+
+ const_iterator begin() const { return const_iterator(this, int(entries.size()) - 1); }
+ const_iterator element(int n) const { return const_iterator(this, int(entries.size()) - 1 - n); }
+ const_iterator end() const { return const_iterator(nullptr, -1); }
+};
+
+template <typename K, typename OPS> class pool
+{
+ template <typename, int, typename> friend class idict;
+
+ protected:
+ struct entry_t
+ {
+ K udata;
+ int next;
+
+ entry_t() {}
+ entry_t(const K &udata, int next) : udata(udata), next(next) {}
+ entry_t(K &&udata, int next) : udata(std::move(udata)), next(next) {}
+ };
+
+ std::vector<int> hashtable;
+ std::vector<entry_t> entries;
+ OPS ops;
+
+#ifdef NDEBUG
+ static inline void do_assert(bool) {}
+#else
+ static inline void do_assert(bool cond) { NPNR_ASSERT(cond); }
+#endif
+
+ int do_hash(const K &key) const
+ {
+ unsigned int hash = 0;
+ if (!hashtable.empty())
+ hash = ops.hash(key) % (unsigned int)(hashtable.size());
+ return hash;
+ }
+
+ void do_rehash()
+ {
+ hashtable.clear();
+ hashtable.resize(hashtable_size(entries.capacity() * hashtable_size_factor), -1);
+
+ for (int i = 0; i < int(entries.size()); i++) {
+ do_assert(-1 <= entries[i].next && entries[i].next < int(entries.size()));
+ int hash = do_hash(entries[i].udata);
+ entries[i].next = hashtable[hash];
+ hashtable[hash] = i;
+ }
+ }
+
+ int do_erase(int index, int hash)
+ {
+ do_assert(index < int(entries.size()));
+ if (hashtable.empty() || index < 0)
+ return 0;
+
+ int k = hashtable[hash];
+ if (k == index) {
+ hashtable[hash] = entries[index].next;
+ } else {
+ while (entries[k].next != index) {
+ k = entries[k].next;
+ do_assert(0 <= k && k < int(entries.size()));
+ }
+ entries[k].next = entries[index].next;
+ }
+
+ int back_idx = entries.size() - 1;
+
+ if (index != back_idx) {
+ int back_hash = do_hash(entries[back_idx].udata);
+
+ k = hashtable[back_hash];
+ if (k == back_idx) {
+ hashtable[back_hash] = index;
+ } else {
+ while (entries[k].next != back_idx) {
+ k = entries[k].next;
+ do_assert(0 <= k && k < int(entries.size()));
+ }
+ entries[k].next = index;
+ }
+
+ entries[index] = std::move(entries[back_idx]);
+ }
+
+ entries.pop_back();
+
+ if (entries.empty())
+ hashtable.clear();
+
+ return 1;
+ }
+
+ int do_lookup(const K &key, int &hash) const
+ {
+ if (hashtable.empty())
+ return -1;
+
+ if (entries.size() * hashtable_size_trigger > hashtable.size()) {
+ ((pool *)this)->do_rehash();
+ hash = do_hash(key);
+ }
+
+ int index = hashtable[hash];
+
+ while (index >= 0 && !ops.cmp(entries[index].udata, key)) {
+ index = entries[index].next;
+ do_assert(-1 <= index && index < int(entries.size()));
+ }
+
+ return index;
+ }
+
+ int do_insert(const K &value, int &hash)
+ {
+ if (hashtable.empty()) {
+ entries.emplace_back(value, -1);
+ do_rehash();
+ hash = do_hash(value);
+ } else {
+ entries.emplace_back(value, hashtable[hash]);
+ hashtable[hash] = entries.size() - 1;
+ }
+ return entries.size() - 1;
+ }
+
+ int do_insert(K &&rvalue, int &hash)
+ {
+ if (hashtable.empty()) {
+ entries.emplace_back(std::forward<K>(rvalue), -1);
+ do_rehash();
+ hash = do_hash(rvalue);
+ } else {
+ entries.emplace_back(std::forward<K>(rvalue), hashtable[hash]);
+ hashtable[hash] = entries.size() - 1;
+ }
+ return entries.size() - 1;
+ }
+
+ public:
+ class const_iterator : public std::iterator<std::forward_iterator_tag, K>
+ {
+ friend class pool;
+
+ protected:
+ const pool *ptr;
+ int index;
+ const_iterator(const pool *ptr, int index) : ptr(ptr), index(index) {}
+
+ public:
+ const_iterator() {}
+ const_iterator operator++()
+ {
+ index--;
+ return *this;
+ }
+ bool operator==(const const_iterator &other) const { return index == other.index; }
+ bool operator!=(const const_iterator &other) const { return index != other.index; }
+ const K &operator*() const { return ptr->entries[index].udata; }
+ const K *operator->() const { return &ptr->entries[index].udata; }
+ };
+
+ class iterator : public std::iterator<std::forward_iterator_tag, K>
+ {
+ friend class pool;
+
+ protected:
+ pool *ptr;
+ int index;
+ iterator(pool *ptr, int index) : ptr(ptr), index(index) {}
+
+ public:
+ iterator() {}
+ iterator operator++()
+ {
+ index--;
+ return *this;
+ }
+ bool operator==(const iterator &other) const { return index == other.index; }
+ bool operator!=(const iterator &other) const { return index != other.index; }
+ K &operator*() { return ptr->entries[index].udata; }
+ K *operator->() { return &ptr->entries[index].udata; }
+ const K &operator*() const { return ptr->entries[index].udata; }
+ const K *operator->() const { return &ptr->entries[index].udata; }
+ operator const_iterator() const { return const_iterator(ptr, index); }
+ };
+
+ pool() {}
+
+ pool(const pool &other)
+ {
+ entries = other.entries;
+ do_rehash();
+ }
+
+ pool(pool &&other) { swap(other); }
+
+ pool &operator=(const pool &other)
+ {
+ entries = other.entries;
+ do_rehash();
+ return *this;
+ }
+
+ pool &operator=(pool &&other)
+ {
+ clear();
+ swap(other);
+ return *this;
+ }
+
+ pool(const std::initializer_list<K> &list)
+ {
+ for (auto &it : list)
+ insert(it);
+ }
+
+ template <class InputIterator> pool(InputIterator first, InputIterator last) { insert(first, last); }
+
+ template <class InputIterator> void insert(InputIterator first, InputIterator last)
+ {
+ for (; first != last; ++first)
+ insert(*first);
+ }
+
+ std::pair<iterator, bool> insert(const K &value)
+ {
+ int hash = do_hash(value);
+ int i = do_lookup(value, hash);
+ if (i >= 0)
+ return std::pair<iterator, bool>(iterator(this, i), false);
+ i = do_insert(value, hash);
+ return std::pair<iterator, bool>(iterator(this, i), true);
+ }
+
+ std::pair<iterator, bool> insert(K &&rvalue)
+ {
+ int hash = do_hash(rvalue);
+ int i = do_lookup(rvalue, hash);
+ if (i >= 0)
+ return std::pair<iterator, bool>(iterator(this, i), false);
+ i = do_insert(std::forward<K>(rvalue), hash);
+ return std::pair<iterator, bool>(iterator(this, i), true);
+ }
+
+ template <typename... Args> std::pair<iterator, bool> emplace(Args &&...args)
+ {
+ return insert(K(std::forward<Args>(args)...));
+ }
+
+ int erase(const K &key)
+ {
+ int hash = do_hash(key);
+ int index = do_lookup(key, hash);
+ return do_erase(index, hash);
+ }
+
+ iterator erase(iterator it)
+ {
+ int hash = do_hash(*it);
+ do_erase(it.index, hash);
+ return ++it;
+ }
+
+ int count(const K &key) const
+ {
+ int hash = do_hash(key);
+ int i = do_lookup(key, hash);
+ return i < 0 ? 0 : 1;
+ }
+
+ int count(const K &key, const_iterator it) const
+ {
+ int hash = do_hash(key);
+ int i = do_lookup(key, hash);
+ return i < 0 || i > it.index ? 0 : 1;
+ }
+
+ iterator find(const K &key)
+ {
+ int hash = do_hash(key);
+ int i = do_lookup(key, hash);
+ if (i < 0)
+ return end();
+ return iterator(this, i);
+ }
+
+ const_iterator find(const K &key) const
+ {
+ int hash = do_hash(key);
+ int i = do_lookup(key, hash);
+ if (i < 0)
+ return end();
+ return const_iterator(this, i);
+ }
+
+ bool operator[](const K &key)
+ {
+ int hash = do_hash(key);
+ int i = do_lookup(key, hash);
+ return i >= 0;
+ }
+
+ template <typename Compare = std::less<K>> void sort(Compare comp = Compare())
+ {
+ std::sort(entries.begin(), entries.end(),
+ [comp](const entry_t &a, const entry_t &b) { return comp(b.udata, a.udata); });
+ do_rehash();
+ }
+
+ K pop()
+ {
+ iterator it = begin();
+ K ret = *it;
+ erase(it);
+ return ret;
+ }
+
+ void swap(pool &other)
+ {
+ hashtable.swap(other.hashtable);
+ entries.swap(other.entries);
+ }
+
+ bool operator==(const pool &other) const
+ {
+ if (size() != other.size())
+ return false;
+ for (auto &it : entries)
+ if (!other.count(it.udata))
+ return false;
+ return true;
+ }
+
+ bool operator!=(const pool &other) const { return !operator==(other); }
+
+ bool hash() const
+ {
+ unsigned int hashval = mkhash_init;
+ for (auto &it : entries)
+ hashval ^= ops.hash(it.udata);
+ return hashval;
+ }
+
+ void reserve(size_t n) { entries.reserve(n); }
+ size_t size() const { return entries.size(); }
+ bool empty() const { return entries.empty(); }
+ void clear()
+ {
+ hashtable.clear();
+ entries.clear();
+ }
+
+ iterator begin() { return iterator(this, int(entries.size()) - 1); }
+ iterator element(int n) { return iterator(this, int(entries.size()) - 1 - n); }
+ iterator end() { return iterator(nullptr, -1); }
+
+ const_iterator begin() const { return const_iterator(this, int(entries.size()) - 1); }
+ const_iterator element(int n) const { return const_iterator(this, int(entries.size()) - 1 - n); }
+ const_iterator end() const { return const_iterator(nullptr, -1); }
+};
+
+template <typename K, int offset, typename OPS> class idict
+{
+ pool<K, OPS> database;
+
+ public:
+ class const_iterator : public std::iterator<std::forward_iterator_tag, K>
+ {
+ friend class idict;
+
+ protected:
+ const idict &container;
+ int index;
+ const_iterator(const idict &container, int index) : container(container), index(index) {}
+
+ public:
+ const_iterator() {}
+ const_iterator operator++()
+ {
+ index++;
+ return *this;
+ }
+ bool operator==(const const_iterator &other) const { return index == other.index; }
+ bool operator!=(const const_iterator &other) const { return index != other.index; }
+ const K &operator*() const { return container[index]; }
+ const K *operator->() const { return &container[index]; }
+ };
+
+ int operator()(const K &key)
+ {
+ int hash = database.do_hash(key);
+ int i = database.do_lookup(key, hash);
+ if (i < 0)
+ i = database.do_insert(key, hash);
+ return i + offset;
+ }
+
+ int at(const K &key) const
+ {
+ int hash = database.do_hash(key);
+ int i = database.do_lookup(key, hash);
+ if (i < 0)
+ throw std::out_of_range("idict::at()");
+ return i + offset;
+ }
+
+ int at(const K &key, int defval) const
+ {
+ int hash = database.do_hash(key);
+ int i = database.do_lookup(key, hash);
+ if (i < 0)
+ return defval;
+ return i + offset;
+ }
+
+ int count(const K &key) const
+ {
+ int hash = database.do_hash(key);
+ int i = database.do_lookup(key, hash);
+ return i < 0 ? 0 : 1;
+ }
+
+ void expect(const K &key, int i)
+ {
+ int j = (*this)(key);
+ if (i != j)
+ throw std::out_of_range("idict::expect()");
+ }
+
+ const K &operator[](int index) const { return database.entries.at(index - offset).udata; }
+
+ void swap(idict &other) { database.swap(other.database); }
+
+ void reserve(size_t n) { database.reserve(n); }
+ size_t size() const { return database.size(); }
+ bool empty() const { return database.empty(); }
+ void clear() { database.clear(); }
+
+ const_iterator begin() const { return const_iterator(*this, offset); }
+ const_iterator element(int n) const { return const_iterator(*this, n); }
+ const_iterator end() const { return const_iterator(*this, offset + size()); }
+};
+
+template <typename K, typename OPS> class mfp
+{
+ mutable idict<K, 0, OPS> database;
+ mutable std::vector<int> parents;
+
+ public:
+ typedef typename idict<K, 0, OPS>::const_iterator const_iterator;
+
+ int operator()(const K &key) const
+ {
+ int i = database(key);
+ parents.resize(database.size(), -1);
+ return i;
+ }
+
+ const K &operator[](int index) const { return database[index]; }
+
+ int ifind(int i) const
+ {
+ int p = i, k = i;
+
+ while (parents[p] != -1)
+ p = parents[p];
+
+ while (k != p) {
+ int next_k = parents[k];
+ parents[k] = p;
+ k = next_k;
+ }
+
+ return p;
+ }
+
+ void imerge(int i, int j)
+ {
+ i = ifind(i);
+ j = ifind(j);
+
+ if (i != j)
+ parents[i] = j;
+ }
+
+ void ipromote(int i)
+ {
+ int k = i;
+
+ while (k != -1) {
+ int next_k = parents[k];
+ parents[k] = i;
+ k = next_k;
+ }
+
+ parents[i] = -1;
+ }
+
+ int lookup(const K &a) const { return ifind((*this)(a)); }
+
+ const K &find(const K &a) const
+ {
+ int i = database.at(a, -1);
+ if (i < 0)
+ return a;
+ return (*this)[ifind(i)];
+ }
+
+ void merge(const K &a, const K &b) { imerge((*this)(a), (*this)(b)); }
+
+ void promote(const K &a)
+ {
+ int i = database.at(a, -1);
+ if (i >= 0)
+ ipromote(i);
+ }
+
+ void swap(mfp &other)
+ {
+ database.swap(other.database);
+ parents.swap(other.parents);
+ }
+
+ void reserve(size_t n) { database.reserve(n); }
+ size_t size() const { return database.size(); }
+ bool empty() const { return database.empty(); }
+ void clear()
+ {
+ database.clear();
+ parents.clear();
+ }
+
+ const_iterator begin() const { return database.begin(); }
+ const_iterator element(int n) const { return database.element(n); }
+ const_iterator end() const { return database.end(); }
+};
+
+NEXTPNR_NAMESPACE_END
+
+#endif
diff --git a/common/idstring.h b/common/idstring.h
index c3ccbc6b..5a7719fa 100644
--- a/common/idstring.h
+++ b/common/idstring.h
@@ -56,18 +56,10 @@ struct IdString
bool operator!=(const IdString &other) const { return index != other.index; }
bool empty() const { return index == 0; }
+
+ unsigned int hash() const { return index; }
};
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 */
diff --git a/common/idstringlist.h b/common/idstringlist.h
index 24a46731..f101ecca 100644
--- a/common/idstringlist.h
+++ b/common/idstringlist.h
@@ -22,6 +22,7 @@
#define IDSTRING_LIST_H
#include <boost/functional/hash.hpp>
+#include "hashlib.h"
#include "idstring.h"
#include "nextpnr_namespaces.h"
#include "sso_array.h"
@@ -67,22 +68,16 @@ struct IdStringList
static IdStringList concat(IdStringList a, IdStringList b);
IdStringList slice(size_t s, size_t e) const;
-};
-
-NEXTPNR_NAMESPACE_END
-namespace std {
-template <> struct hash<NEXTPNR_NAMESPACE_PREFIX IdStringList>
-{
- std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX IdStringList &obj) const noexcept
+ unsigned int hash() const
{
- 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;
+ unsigned int h = mkhash_init;
+ for (const auto &val : ids)
+ h = mkhash(h, val.hash());
+ return h;
}
};
-} // namespace std
+
+NEXTPNR_NAMESPACE_END
#endif /* IDSTRING_LIST_H */
diff --git a/common/log.cc b/common/log.cc
index 01aec79a..a429d172 100644
--- a/common/log.cc
+++ b/common/log.cc
@@ -38,7 +38,7 @@ log_write_type log_write_function = nullptr;
std::string log_last_error;
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;
bool had_nonfatal_error = false;
diff --git a/common/log.h b/common/log.h
index 7dfdf165..e9237446 100644
--- a/common/log.h
+++ b/common/log.h
@@ -26,8 +26,8 @@
#include <stdarg.h>
#include <stdio.h>
#include <string>
-#include <unordered_map>
#include <vector>
+#include "hashlib.h"
#include "nextpnr_namespaces.h"
NEXTPNR_NAMESPACE_BEGIN
@@ -51,13 +51,19 @@ enum class LogLevel
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 log_write_type log_write_function;
extern std::string log_last_error;
extern void (*log_error_atexit)();
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 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
-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
diff --git a/common/nextpnr_base_types.h b/common/nextpnr_base_types.h
index 1a15bfcb..1707559b 100644
--- a/common/nextpnr_base_types.h
+++ b/common/nextpnr_base_types.h
@@ -30,6 +30,7 @@
#include <boost/functional/hash.hpp>
#include <string>
+#include "hashlib.h"
#include "idstring.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); }
+ unsigned int hash() const { return mkhash(x, mkhash(y, z)); }
};
struct ArcBounds
@@ -128,19 +130,4 @@ enum PlaceStrength
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 */
diff --git a/common/nextpnr_types.h b/common/nextpnr_types.h
index 67e60c50..4770f8ae 100644
--- a/common/nextpnr_types.h
+++ b/common/nextpnr_types.h
@@ -28,6 +28,7 @@
#include <unordered_set>
#include "archdefs.h"
+#include "hashlib.h"
#include "nextpnr_base_types.h"
#include "nextpnr_namespaces.h"
#include "property.h"
@@ -56,9 +57,9 @@ struct Region
bool constr_wires = false;
bool constr_pips = false;
- std::unordered_set<BelId> bels;
- std::unordered_set<WireId> wires;
- std::unordered_set<Loc> piplocs;
+ pool<BelId> bels;
+ pool<WireId> wires;
+ pool<Loc> piplocs;
};
struct PipMap
@@ -128,10 +129,10 @@ struct NetInfo : ArchNetInfo
PortRef driver;
std::vector<PortRef> users;
- std::unordered_map<IdString, Property> attrs;
+ dict<IdString, Property> attrs;
// 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
@@ -159,8 +160,8 @@ struct CellInfo : ArchCellInfo
IdString name, type, hierpath;
int32_t udata;
- std::unordered_map<IdString, PortInfo> ports;
- std::unordered_map<IdString, Property> attrs, params;
+ dict<IdString, PortInfo> ports;
+ dict<IdString, Property> attrs, params;
BelId bel;
PlaceStrength belStrength = STRENGTH_NONE;
@@ -232,13 +233,13 @@ struct HierarchicalCell
{
IdString name, type, parent, fullpath;
// 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
- 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
- std::unordered_map<IdString, HierarchicalPort> ports;
+ dict<IdString, HierarchicalPort> ports;
// Name inside cell instance -> global name
- std::unordered_map<IdString, IdString> hier_cells;
+ dict<IdString, IdString> hier_cells;
};
NEXTPNR_NAMESPACE_END
diff --git a/common/place_common.cc b/common/place_common.cc
index 7cbeca65..9a6c6158 100644
--- a/common/place_common.cc
+++ b/common/place_common.cc
@@ -178,8 +178,8 @@ class ConstraintLegaliseWorker
private:
Context *ctx;
std::set<IdString> rippedCells;
- std::unordered_map<IdString, Loc> oldLocations;
- std::unordered_map<ClusterId, std::vector<CellInfo *>> cluster2cells;
+ dict<IdString, Loc> oldLocations;
+ dict<ClusterId, std::vector<CellInfo *>> cluster2cells;
class IncreasingDiameterSearch
{
@@ -227,10 +227,10 @@ class ConstraintLegaliseWorker
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
- 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);
if (locBel == BelId())
@@ -324,7 +324,7 @@ class ConstraintLegaliseWorker
}
CellLocations solution;
- std::unordered_set<Loc> used;
+ pool<Loc> used;
if (valid_loc_for(cell, rootLoc, solution, used)) {
for (auto cp : solution) {
// First unbind all cells
@@ -377,9 +377,9 @@ class ConstraintLegaliseWorker
public:
ConstraintLegaliseWorker(Context *ctx) : ctx(ctx)
{
- for (auto cell : sorted(ctx->cells)) {
+ for (auto &cell : ctx->cells) {
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()
{
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);
}
- for (auto cell : sorted(ctx->cells)) {
- bool res = legalise_cell(cell.second);
+ for (auto &cell : ctx->cells) {
+ bool res = legalise_cell(cell.second.get());
if (!res) {
log_error("failed to place chain starting at cell '%s'\n", cell.first.c_str(ctx));
return -1;
@@ -434,8 +434,8 @@ class ConstraintLegaliseWorker
}
}
auto score = print_stats("replacing ripped up cells");
- for (auto cell : sorted(ctx->cells))
- if (get_constraints_distance(ctx, cell.second) != 0)
+ for (auto &cell : ctx->cells)
+ 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),
ctx->nameOfBel(cell.second->bel));
return score;
diff --git a/common/placer1.cc b/common/placer1.cc
index a3e7a696..a832e08f 100644
--- a/common/placer1.cc
+++ b/common/placer1.cc
@@ -46,19 +46,6 @@
#include "timing.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
class SAPlacer
@@ -87,8 +74,8 @@ class SAPlacer
}
diameter = std::max(max_x, max_y) + 1;
- std::unordered_set<IdString> cell_types_in_use;
- for (auto cell : sorted(ctx->cells)) {
+ pool<IdString> cell_types_in_use;
+ for (auto &cell : ctx->cells) {
IdString cell_type = cell.second->type;
cell_types_in_use.insert(cell_type);
}
@@ -108,8 +95,8 @@ class SAPlacer
net.second->udata = n++;
net_by_udata.push_back(net.second.get());
}
- for (auto &region : sorted(ctx->region)) {
- Region *r = region.second;
+ for (auto &region : ctx->region) {
+ Region *r = region.second.get();
BoundingBox bb;
if (r->constr_bels) {
bb.x0 = std::numeric_limits<int>::max();
@@ -360,12 +347,12 @@ class SAPlacer
// Only increase temperature if something was moved
autoplaced.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() &&
- ctx->getClusterRootCell(cell.second->cluster) == cell.second)
- chain_basis.push_back(cell.second);
+ ctx->getClusterRootCell(cell.second->cluster) == cell.second.get())
+ chain_basis.push_back(cell.second.get());
else if (cell.second->belStrength < STRENGTH_STRONG)
- autoplaced.push_back(cell.second);
+ autoplaced.push_back(cell.second.get());
}
// temp = post_legalise_temp;
// diameter = std::min<int>(M, diameter * post_legalise_dia_scale);
@@ -421,8 +408,8 @@ class SAPlacer
}
}
}
- for (auto cell : sorted(ctx->cells))
- if (get_constraints_distance(ctx, cell.second) != 0)
+ for (auto &cell : ctx->cells)
+ 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),
ctx->nameOfBel(cell.second->bel));
timing_analysis(ctx);
@@ -629,7 +616,7 @@ class SAPlacer
bool try_swap_chain(CellInfo *cell, BelId newBase)
{
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>> dest_bels;
double delta = 0;
@@ -831,8 +818,8 @@ class SAPlacer
// Set up the cost maps
void setup_costs()
{
- for (auto net : sorted(ctx->nets)) {
- NetInfo *ni = net.second;
+ for (auto &net : ctx->nets) {
+ NetInfo *ni = net.second.get();
if (ignore_net(ni))
continue;
net_bounds[ni->udata] = get_net_bounds(ni);
@@ -1065,7 +1052,7 @@ class SAPlacer
mc.already_changed_arcs[pn->udata][i] = true;
}
} 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]) {
mc.changed_arcs.emplace_back(std::make_pair(pn->udata, usr));
mc.already_changed_arcs[pn->udata][usr] = true;
@@ -1118,11 +1105,11 @@ class SAPlacer
// Build the cell port -> user index
void build_port_index()
{
- for (auto net : sorted(ctx->nets)) {
- NetInfo *ni = net.second;
+ for (auto &net : ctx->nets) {
+ NetInfo *ni = net.second.get();
for (size_t i = 0; i < ni->users.size(); 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
const int large_cell_thresh = 50;
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()
{
total_net_share = 0;
- nets_by_tile.resize(max_x + 1, std::vector<std::unordered_map<IdString, int>>(max_y + 1));
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ nets_by_tile.resize(max_x + 1, std::vector<dict<IdString, int>>(max_y + 1));
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (int(ci->ports.size()) > large_cell_thresh)
continue;
Loc loc = ctx->getBelLocation(ci->bel);
@@ -1194,7 +1181,7 @@ class SAPlacer
std::vector<std::vector<double>> net_arc_tcost;
// 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
wirelen_t last_wirelen_cost, curr_wirelen_cost;
@@ -1207,10 +1194,10 @@ class SAPlacer
bool improved = false;
int n_move, n_accept;
int diameter = 35, max_x = 1, max_y = 1;
- std::unordered_map<IdString, std::tuple<int, int>> bel_types;
- std::unordered_map<IdString, BoundingBox> region_bounds;
+ dict<IdString, std::tuple<int, int>> bel_types;
+ dict<IdString, BoundingBox> region_bounds;
FastBels fast_bels;
- std::unordered_set<BelId> locked_bels;
+ pool<BelId> locked_bels;
std::vector<NetInfo *> net_by_udata;
std::vector<decltype(NetInfo::udata)> old_udata;
bool require_legal = true;
diff --git a/common/placer_heap.cc b/common/placer_heap.cc
index 2f7c7ccb..f1419bdb 100644
--- a/common/placer_heap.cc
+++ b/common/placer_heap.cc
@@ -43,7 +43,6 @@
#include <numeric>
#include <queue>
#include <tuple>
-#include <unordered_map>
#include "fast_bels.h"
#include "log.h"
#include "nextpnr.h"
@@ -146,9 +145,9 @@ class HeAPPlacer
tmg.setup_only = true;
tmg.setup();
- for (auto cell : sorted(ctx->cells))
+ for (auto &cell : ctx->cells)
if (cell.second->cluster != ClusterId())
- cluster2cells[cell.second->cluster].push_back(cell.second);
+ cluster2cells[cell.second->cluster].push_back(cell.second.get());
}
bool place()
@@ -188,14 +187,14 @@ class HeAPPlacer
std::vector<std::tuple<CellInfo *, BelId, PlaceStrength>> solution;
- std::vector<std::unordered_set<BelBucketId>> heap_runs;
- std::unordered_set<BelBucketId> all_buckets;
- std::unordered_map<BelBucketId, int> bucket_count;
+ std::vector<pool<BelBucketId>> heap_runs;
+ pool<BelBucketId> all_buckets;
+ dict<BelBucketId, int> bucket_count;
for (auto cell : place_cells) {
BelBucketId bucket = ctx->getBelBucketForCellType(cell->type);
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);
}
bucket_count[bucket]++;
@@ -253,9 +252,9 @@ class HeAPPlacer
for (const auto &group : cfg.cellGroups)
CutSpreader(this, group).run();
- for (auto type : sorted(run))
+ for (auto type : run)
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();
// Run strict legalisation to find a valid bel for all cells
@@ -283,8 +282,8 @@ class HeAPPlacer
stalled = 0;
// Save solution
solution.clear();
- for (auto cell : sorted(ctx->cells)) {
- solution.emplace_back(cell.second, cell.second->bel, cell.second->belStrength);
+ for (auto &cell : ctx->cells) {
+ solution.emplace_back(cell.second.get(), cell.second->bel, cell.second->belStrength);
}
} else {
++stalled;
@@ -311,10 +310,10 @@ class HeAPPlacer
ctx->bindBel(bel, cell, strength);
}
- for (auto cell : sorted(ctx->cells)) {
+ for (auto &cell : ctx->cells) {
if (cell.second->bel == BelId())
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));
if (ctx->debug)
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;
FastBels fast_bels;
- std::unordered_map<IdString, std::tuple<int, int>> bel_types;
+ dict<IdString, std::tuple<int, int>> bel_types;
TimingAnalyser tmg;
@@ -370,7 +369,7 @@ class HeAPPlacer
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
// structure instead
@@ -381,7 +380,7 @@ class HeAPPlacer
double rawx, rawy;
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
// (only the root of each macro is placed.)
std::vector<CellInfo *> place_cells;
@@ -390,8 +389,8 @@ class HeAPPlacer
// cells of a certain type)
std::vector<CellInfo *> solve_cells;
- std::unordered_map<ClusterId, std::vector<CellInfo *>> cluster2cells;
- std::unordered_map<ClusterId, int> chain_size;
+ dict<ClusterId, std::vector<CellInfo *>> cluster2cells;
+ dict<ClusterId, int> chain_size;
// Performance counting
double solve_time = 0, cl_time = 0, sl_time = 0;
@@ -448,9 +447,9 @@ class HeAPPlacer
max_y = std::max(max_y, loc.y);
}
- std::unordered_set<IdString> cell_types_in_use;
- std::unordered_set<BelBucketId> buckets_in_use;
- for (auto cell : sorted(ctx->cells)) {
+ pool<IdString> cell_types_in_use;
+ pool<BelBucketId> buckets_in_use;
+ for (auto &cell : ctx->cells) {
IdString cell_type = cell.second->type;
cell_types_in_use.insert(cell_type);
BelBucketId bucket = ctx->getBelBucketForCellType(cell_type);
@@ -465,8 +464,8 @@ class HeAPPlacer
}
// Determine bounding boxes of region constraints
- for (auto &region : sorted(ctx->region)) {
- Region *r = region.second;
+ for (auto &region : ctx->region) {
+ Region *r = region.second.get();
BoundingBox bb;
if (r->constr_bels) {
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?)
void seed_placement()
{
- std::unordered_set<IdString> cell_types;
+ pool<IdString> cell_types;
for (const auto &cell : ctx->cells) {
cell_types.insert(cell.second->type);
}
- std::unordered_set<BelId> bels_used;
- std::unordered_map<IdString, std::deque<BelId>> available_bels;
+ pool<BelId> bels_used;
+ dict<IdString, std::deque<BelId>> available_bels;
for (auto bel : ctx->getBels()) {
if (!ctx->checkBelAvail(bel)) {
@@ -539,8 +538,8 @@ class HeAPPlacer
ctx->shuffle(t.second.begin(), t.second.end());
}
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->bel != BelId()) {
Loc loc = ctx->getBelLocation(ci->bel);
cell_locs[cell.first].x = loc.x;
@@ -591,7 +590,7 @@ class HeAPPlacer
cell_locs[cell.first].global = ctx->getBelGlobalBuf(bel);
// 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);
place_cells.push_back(ci);
placed = true;
@@ -612,12 +611,12 @@ class HeAPPlacer
}
// 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;
solve_cells.clear();
// First clear the udata of all cells
- for (auto cell : sorted(ctx->cells))
+ for (auto &cell : ctx->cells)
cell.second->udata = dont_solve;
// Then update cells to be placed, which excludes cell children
for (auto cell : place_cells) {
@@ -671,8 +670,8 @@ class HeAPPlacer
es.reset();
- for (auto net : sorted(ctx->nets)) {
- NetInfo *ni = net.second;
+ for (auto &net : ctx->nets) {
+ NetInfo *ni = net.second.get();
if (ni->driver.cell == nullptr)
continue;
if (ni->users.empty())
@@ -783,8 +782,8 @@ class HeAPPlacer
wirelen_t total_hpwl()
{
wirelen_t hpwl = 0;
- for (auto net : sorted(ctx->nets)) {
- NetInfo *ni = net.second;
+ for (auto &net : ctx->nets) {
+ NetInfo *ni = net.second.get();
if (ni->driver.cell == nullptr)
continue;
CellLocation &drvloc = cell_locs.at(ni->driver.cell->name);
@@ -809,8 +808,8 @@ class HeAPPlacer
auto startt = std::chrono::high_resolution_clock::now();
// Unbind all cells placed in this solution
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->bel != BelId() &&
(ci->udata != dont_solve ||
(ci->cluster != ClusterId() && ctx->getClusterRootCell(ci->cluster)->udata != dont_solve)))
@@ -1106,11 +1105,11 @@ class HeAPPlacer
class CutSpreader
{
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.
size_t idx = 0;
- for (BelBucketId bucket : sorted(buckets)) {
+ for (BelBucketId bucket : buckets) {
type_index[bucket] = idx;
FastBels::FastBelsData *fast_bels;
p->fast_bels.getBelsForBelBucket(bucket, &fast_bels);
@@ -1198,8 +1197,8 @@ class HeAPPlacer
private:
HeAPPlacer *p;
Context *ctx;
- std::unordered_set<BelBucketId> buckets;
- std::unordered_map<BelBucketId, size_t> type_index;
+ pool<BelBucketId> buckets;
+ dict<BelBucketId, size_t> type_index;
std::vector<std::vector<std::vector<int>>> occupancy;
std::vector<std::vector<int>> groups;
std::vector<std::vector<ChainExtent>> chaines;
@@ -1208,7 +1207,7 @@ class HeAPPlacer
std::vector<std::vector<std::vector<std::vector<BelId>>> *> fb;
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
std::vector<std::vector<std::vector<CellInfo *>>> cells_at_location;
@@ -1490,7 +1489,7 @@ class HeAPPlacer
}
}
if (!changed) {
- for (auto bucket : sorted(buckets)) {
+ for (auto bucket : buckets) {
if (reg.cells > reg.bels) {
IdString bucket_name = ctx->getBelBucketName(bucket);
log_error("Failed to expand region (%d, %d) |_> (%d, %d) of %d %ss\n", reg.x0, reg.y0,
diff --git a/common/placer_heap.h b/common/placer_heap.h
index 00913062..9b3c3ed0 100644
--- a/common/placer_heap.h
+++ b/common/placer_heap.h
@@ -46,10 +46,10 @@ struct PlacerHeapCfg
int spread_scale_x, spread_scale_y;
// 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
// 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);
diff --git a/common/pybindings.cc b/common/pybindings.cc
index 504074e1..00ebe66e 100644
--- a/common/pybindings.cc
+++ b/common/pybindings.cc
@@ -164,10 +164,10 @@ PYBIND11_EMBEDDED_MODULE(MODULE_NAME, m)
.def("maxFallDelay", &DelayQuad::maxFallDelay)
.def("delayPair", &DelayQuad::delayPair);
- typedef std::unordered_map<IdString, Property> AttrMap;
- typedef std::unordered_map<IdString, PortInfo> PortMap;
- typedef std::unordered_map<IdString, IdString> IdIdMap;
- typedef std::unordered_map<IdString, std::unique_ptr<Region>> RegionMap;
+ typedef dict<IdString, Property> AttrMap;
+ typedef dict<IdString, PortInfo> PortMap;
+ typedef dict<IdString, IdString> IdIdMap;
+ typedef dict<IdString, std::unique_ptr<Region>> RegionMap;
py::class_<BaseCtx>(m, "BaseCtx");
@@ -218,9 +218,9 @@ PYBIND11_EMBEDDED_MODULE(MODULE_NAME, m)
pass_through<PortType>>::def_wrap(pi_cls, "type");
typedef std::vector<PortRef> PortRefVector;
- typedef std::unordered_map<WireId, PipMap> WireMap;
- typedef std::unordered_set<BelId> BelSet;
- typedef std::unordered_set<WireId> WireSet;
+ typedef dict<WireId, PipMap> WireMap;
+ typedef pool<BelId> BelSet;
+ typedef pool<WireId> WireSet;
auto ni_cls = py::class_<ContextualWrapper<NetInfo &>>(m, "NetInfo");
readwrite_wrapper<NetInfo &, decltype(&NetInfo::name), &NetInfo::name, conv_to_str<IdString>,
diff --git a/common/router1.cc b/common/router1.cc
index 11107a40..374f7455 100644
--- a/common/router1.cc
+++ b/common/router1.cc
@@ -49,16 +49,13 @@ struct arc_key
: 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 *>()(arg.net_info);
- seed ^= std::hash<int>()(arg.user_idx) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
- seed ^= std::hash<int>()(arg.phys_idx) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
- return seed;
- }
- };
+ std::size_t seed = std::hash<NetInfo *>()(net_info);
+ seed ^= std::hash<int>()(user_idx) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
+ seed ^= std::hash<int>()(phys_idx) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
+ return seed;
+ }
};
struct arc_entry
@@ -107,15 +104,15 @@ struct Router1
const Router1Cfg &cfg;
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;
- std::unordered_map<arc_key, std::unordered_set<WireId>, arc_key::Hash> arc_to_wires;
- std::unordered_set<arc_key, arc_key::Hash> queued_arcs;
+ dict<WireId, pool<arc_key>> wire_to_arcs;
+ dict<arc_key, pool<WireId>> arc_to_wires;
+ 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::unordered_map<WireId, int> wireScores;
- std::unordered_map<NetInfo *, int> netScores;
+ dict<WireId, int> wireScores;
+ dict<NetInfo *, int, hash_ptr_ops> netScores;
int arcs_with_ripup = 0;
int arcs_without_ripup = 0;
@@ -295,11 +292,11 @@ struct Router1
void check()
{
- std::unordered_set<arc_key, arc_key::Hash> valid_arcs;
+ pool<arc_key> valid_arcs;
for (auto &net_it : ctx->nets) {
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))
continue;
@@ -357,8 +354,8 @@ struct Router1
void setup()
{
- std::unordered_map<WireId, NetInfo *> src_to_net;
- std::unordered_map<WireId, arc_key> dst_to_arc;
+ dict<WireId, NetInfo *> src_to_net;
+ dict<WireId, arc_key> dst_to_arc;
std::vector<IdString> net_names;
for (auto &net_it : ctx->nets)
@@ -472,7 +469,7 @@ struct Router1
// 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]);
for (WireId wire : old_arc_wires) {
@@ -720,7 +717,7 @@ struct Router1
// 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;
delay_t accumulated_path_delay = 0;
@@ -919,10 +916,10 @@ bool Context::checkRoutedDesign() const
struct ExtraWireInfo
{
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) {
WireId w = it.first;
@@ -930,7 +927,7 @@ bool Context::checkRoutedDesign() const
if (p != PipId()) {
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;
}
- 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 (auto dst_wire : ctx->getNetinfoSinkWires(net_info, net_info->users[user_idx])) {
log_assert(dst_wire != WireId());
@@ -963,10 +960,10 @@ bool Context::checkRoutedDesign() const
}
std::function<void(WireId, int)> setOrderNum;
- std::unordered_set<WireId> logged_wires;
+ pool<WireId> logged_wires;
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) {
found_loop = true;
log(" %*s=> loop\n", 2 * num, "");
@@ -998,10 +995,10 @@ bool Context::checkRoutedDesign() const
}
setOrderNum(src_wire, 1);
- std::unordered_set<WireId> dangling_wires;
+ pool<WireId> dangling_wires;
for (auto &it : db) {
- auto &db_entry = it.second;
+ auto &db_entry = *it.second;
if (db_entry.order_num == 0)
dangling_wires.insert(it.first);
}
@@ -1010,10 +1007,10 @@ bool Context::checkRoutedDesign() const
if (dangling_wires.empty()) {
log(" no dangling wires.\n");
} else {
- std::unordered_set<WireId> root_wires = dangling_wires;
+ pool<WireId> root_wires = dangling_wires;
for (WireId w : dangling_wires) {
- for (WireId c : db[w].children)
+ for (WireId c : db[w]->children)
root_wires.erase(c);
}
@@ -1064,8 +1061,8 @@ bool Context::checkRoutedDesign() const
return true;
}
-bool Context::getActualRouteDelay(WireId src_wire, WireId dst_wire, delay_t *delay,
- std::unordered_map<WireId, PipId> *route, bool useEstimate)
+bool Context::getActualRouteDelay(WireId src_wire, WireId dst_wire, delay_t *delay, dict<WireId, PipId> *route,
+ bool useEstimate)
{
// FIXME
return false;
diff --git a/common/router2.cc b/common/router2.cc
index 2156ce28..e1d3e75b 100644
--- a/common/router2.cc
+++ b/common/router2.cc
@@ -35,7 +35,6 @@
#include <fstream>
#include <queue>
-#include "hash_table.h"
#include "log.h"
#include "nextpnr.h"
#include "router1.h"
@@ -131,8 +130,8 @@ struct Router2
nets.resize(ctx->nets.size());
nets_by_udata.resize(ctx->nets.size());
size_t i = 0;
- for (auto net : sorted(ctx->nets)) {
- NetInfo *ni = net.second;
+ for (auto &net : ctx->nets) {
+ NetInfo *ni = net.second.get();
ni->udata = i;
nets_by_udata.at(i) = ni;
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;
PerWireData &wire_data(WireId w) { return flat_wires[wire_to_idx.at(w)]; }
@@ -231,8 +230,8 @@ struct Router2
flat_wires.push_back(pwd);
}
- for (auto net_pair : sorted(ctx->nets)) {
- auto *net = net_pair.second;
+ for (auto &net_pair : ctx->nets) {
+ auto *net = net_pair.second.get();
auto &nd = nets.at(net->udata);
for (size_t usr = 0; usr < net->users.size(); usr++) {
auto &ad = nd.arcs.at(usr);
@@ -284,7 +283,7 @@ struct Router2
std::priority_queue<QueuedWire, std::vector<QueuedWire>, QueuedWire::Greater> queue;
// 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
std::queue<int> backwards_queue;
@@ -465,7 +464,7 @@ struct Router2
bool did_something = false;
WireId src = ctx->getNetinfoSourceWire(net);
for (auto sink : ctx->getNetinfoSinkWires(net, net->users.at(i))) {
- std::unordered_set<WireId> rsv;
+ pool<WireId> rsv;
WireId cursor = sink;
bool done = false;
if (ctx->debug)
@@ -1083,7 +1082,7 @@ struct Router2
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;
// Build histogram
for (auto &wd : flat_wires) {
@@ -1099,7 +1098,7 @@ struct Router2
for (size_t i = 0; i <= max_cong; i++)
out << "bound=" << i << ",";
out << std::endl;
- for (auto &ty : sorted_ref(cong_by_type)) {
+ for (auto &ty : cong_by_type) {
out << ctx->nameOf(ty.first) << ",";
for (int count : ty.second)
out << count << ",";
diff --git a/common/sdf.cc b/common/sdf.cc
index 5c3d0a5a..814bf09a 100644
--- a/common/sdf.cc
+++ b/common/sdf.cc
@@ -254,9 +254,9 @@ void Context::writeSDF(std::ostream &out, bool cvc_mode) const
return rf;
};
- for (auto cell : sorted(cells)) {
+ for (const auto &cell : cells) {
Cell sc;
- const CellInfo *ci = cell.second;
+ const CellInfo *ci = cell.second.get();
sc.instance = ci->name.str(this);
sc.celltype = ci->type.str(this);
for (auto port : ci->ports) {
@@ -313,8 +313,8 @@ void Context::writeSDF(std::ostream &out, bool cvc_mode) const
wr.cells.push_back(sc);
}
- for (auto net : sorted(nets)) {
- NetInfo *ni = net.second;
+ for (auto &net : nets) {
+ NetInfo *ni = net.second.get();
if (ni->driver.cell == nullptr)
continue;
for (auto &usr : ni->users) {
diff --git a/common/timing.cc b/common/timing.cc
index ef5977de..1670bc7d 100644
--- a/common/timing.cc
+++ b/common/timing.cc
@@ -23,7 +23,6 @@
#include <boost/range/adaptor/reversed.hpp>
#include <deque>
#include <map>
-#include <unordered_map>
#include <utility>
#include "log.h"
#include "util.h"
@@ -52,17 +51,17 @@ void TimingAnalyser::run()
void TimingAnalyser::init_ports()
{
// Per cell port structures
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
- for (auto port : sorted_ref(ci->ports)) {
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
+ for (auto &port : ci->ports) {
auto &data = ports[CellPortKey(ci->name, port.first)];
data.type = port.second.type;
data.cell_port = CellPortKey(ci->name, port.first);
}
}
// Cell port to net port mapping
- for (auto net : sorted(ctx->nets)) {
- NetInfo *ni = net.second;
+ for (auto &net : ctx->nets) {
+ NetInfo *ni = net.second.get();
if (ni->driver.cell != nullptr)
ports[CellPortKey(ni->driver)].net_port = NetPortKey(ni->name);
for (size_t i = 0; i < ni->users.size(); i++)
@@ -138,8 +137,8 @@ void TimingAnalyser::get_cell_delays()
void TimingAnalyser::get_route_delays()
{
- for (auto net : sorted(ctx->nets)) {
- NetInfo *ni = net.second;
+ for (auto &net : ctx->nets) {
+ NetInfo *ni = net.second.get();
if (ni->driver.cell == nullptr || ni->driver.cell->bel == BelId())
continue;
for (auto &usr : ni->users) {
@@ -272,7 +271,7 @@ void TimingAnalyser::setup_port_domains()
void TimingAnalyser::reset_times()
{
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) {
t.second.value = init_delay;
t.second.path_length = 0;
@@ -426,7 +425,7 @@ void TimingAnalyser::walk_backward()
void TimingAnalyser::print_fmax()
{
// Temporary testing code for comparison only
- std::unordered_map<int, double> domain_fmax;
+ dict<int, double> domain_fmax;
for (auto p : topological_order) {
auto &pd = ports.at(p);
for (auto &req : pd.required) {
@@ -591,6 +590,7 @@ struct ClockEvent
ClockEdge 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
@@ -598,37 +598,10 @@ struct ClockPair
ClockEvent start, 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
-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::map<int, unsigned> DelayFrequency;
@@ -639,7 +612,7 @@ struct CriticalPath
delay_t path_period;
};
-typedef std::unordered_map<ClockPair, CriticalPath> CriticalPathMap;
+typedef dict<ClockPair, CriticalPath> CriticalPathMap;
struct Timing
{
@@ -660,7 +633,7 @@ struct Timing
delay_t min_remaining_budget;
bool false_startpoint = false;
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,
@@ -677,14 +650,14 @@ struct Timing
// 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
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
- std::unordered_map<const PortInfo *, unsigned> port_fanin;
+ dict<const PortInfo *, unsigned, hash_ptr_ops> port_fanin;
std::vector<IdString> input_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
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
// between all nets on the path
diff --git a/common/timing.h b/common/timing.h
index 133bd4eb..974bb26b 100644
--- a/common/timing.h
+++ b/common/timing.h
@@ -35,15 +35,7 @@ struct CellPortKey
port = pr.port;
}
IdString cell, port;
- struct 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;
- }
- };
+ unsigned int hash() const { return mkhash(cell.hash(), port.hash()); }
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
@@ -69,15 +61,8 @@ struct NetPortKey
return idx;
}
- struct Hash
- {
- 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;
- }
- };
+ unsigned int hash() const { return mkhash(net.hash(), 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
inline bool is_async() const { return clock == IdString(); }
- struct Hash
- {
- 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;
- }
- };
+ unsigned int hash() const { return mkhash(clock.hash(), int(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);
}
- struct Hash
- {
- 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;
- }
- };
+ unsigned int hash() const { return mkhash(launch, capture); }
};
struct TimingAnalyser
@@ -223,16 +193,17 @@ struct TimingAnalyser
NetPortKey net_port;
PortType type;
// per domain timings
- std::unordered_map<domain_id_t, ArrivReqTime> arrival;
- std::unordered_map<domain_id_t, ArrivReqTime> required;
- std::unordered_map<domain_id_t, PortDomainPairData> domain_pairs;
+ dict<domain_id_t, ArrivReqTime> arrival;
+ dict<domain_id_t, ArrivReqTime> required;
+ dict<domain_id_t, PortDomainPairData> domain_pairs;
// cell timing arcs to (outputs)/from (inputs) from this port
std::vector<CellArc> cell_arcs;
// routing delay into this port (input ports only)
- DelayPair route_delay;
+ DelayPair route_delay{0};
// worst criticality and slack across domain pairs
- float worst_crit;
- delay_t worst_setup_slack, worst_hold_slack;
+ float worst_crit = 0;
+ delay_t worst_setup_slack = std::numeric_limits<delay_t>::max(),
+ worst_hold_slack = std::numeric_limits<delay_t>::max();
};
struct PerDomain
@@ -260,9 +231,9 @@ struct TimingAnalyser
void copy_domains(const CellPortKey &from, const CellPortKey &to, bool backwards);
- std::unordered_map<CellPortKey, PerPort, CellPortKey::Hash> ports;
- std::unordered_map<ClockDomainKey, domain_id_t, ClockDomainKey::Hash> domain_to_id;
- std::unordered_map<ClockDomainPairKey, domain_id_t, ClockDomainPairKey::Hash> pair_to_id;
+ dict<CellPortKey, PerPort> ports;
+ dict<ClockDomainKey, domain_id_t> domain_to_id;
+ dict<ClockDomainPairKey, domain_id_t> pair_to_id;
std::vector<PerDomain> domains;
std::vector<PerDomainPair> domain_pairs;
diff --git a/common/timing_opt.cc b/common/timing_opt.cc
index 854cbc5b..da4907b6 100644
--- a/common/timing_opt.cc
+++ b/common/timing_opt.cc
@@ -35,8 +35,6 @@
#include "timing.h"
#include "util.h"
-#include "hash_table.h"
-
NEXTPNR_NAMESPACE_BEGIN
class TimingOptimiser
@@ -68,8 +66,8 @@ class TimingOptimiser
void setup_delay_limits()
{
max_net_delay.clear();
- for (auto net : sorted(ctx->nets)) {
- NetInfo *ni = net.second;
+ for (auto &net : ctx->nets) {
+ NetInfo *ni = net.second.get();
if (ni->driver.cell == nullptr)
continue;
for (auto usr : ni->users) {
@@ -167,7 +165,7 @@ class TimingOptimiser
BelId curr = cell->bel;
Loc curr_loc = ctx->getBelLocation(curr);
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 dx = -d; dx <= d; dx++) {
// Go through all the Bels at this location
@@ -239,7 +237,7 @@ class TimingOptimiser
std::vector<std::pair<NetInfo *, int>> crit_nets;
std::vector<IdString> 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);
for (auto net : netnames) {
if (crit_nets.size() >= max_count)
@@ -267,7 +265,7 @@ class TimingOptimiser
}
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) {
@@ -439,10 +437,10 @@ class TimingOptimiser
}
// Actual BFS path optimisation algorithm
- std::unordered_map<IdString, std::unordered_map<BelId, delay_t>> cumul_costs;
- std::unordered_map<std::pair<IdString, BelId>, std::pair<IdString, BelId>, PairHash> backtrace;
+ dict<IdString, dict<BelId, delay_t>> cumul_costs;
+ dict<std::pair<IdString, BelId>, std::pair<IdString, BelId>> backtrace;
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()]) {
// Swap for legality check
@@ -568,10 +566,10 @@ class TimingOptimiser
// Current candidate Bels for cells (linked in both direction>
std::vector<IdString> path_cells;
- std::unordered_map<IdString, std::unordered_set<BelId>> cell_neighbour_bels;
- std::unordered_map<BelId, std::unordered_set<IdString>> bel_candidate_cells;
+ dict<IdString, pool<BelId>> cell_neighbour_bels;
+ dict<BelId, pool<IdString>> bel_candidate_cells;
// 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;
TimingOptCfg cfg;
TimingAnalyser tmg;
diff --git a/common/timing_opt.h b/common/timing_opt.h
index 775d9596..46bf3500 100644
--- a/common/timing_opt.h
+++ b/common/timing_opt.h
@@ -29,7 +29,7 @@ struct TimingOptCfg
// 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
// for other cell types
- std::unordered_set<IdString> cellTypes;
+ pool<IdString> cellTypes;
};
extern bool timing_opt(Context *ctx, TimingOptCfg cfg);
diff --git a/common/util.h b/common/util.h
index 540646c7..542bd395 100644
--- a/common/util.h
+++ b/common/util.h
@@ -55,7 +55,7 @@ std::string str_or_default(const Container &ct, const KeyType &key, std::string
};
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);
if (found == ct.end())
@@ -78,8 +78,7 @@ template <typename Container, typename KeyType> int int_or_default(const Contain
return std::stoi(found->second);
};
-template <typename KeyType>
-int int_or_default(const std::unordered_map<KeyType, Property> &ct, const KeyType &key, int def = 0)
+template <typename KeyType> int int_or_default(const dict<KeyType, Property> &ct, const KeyType &key, int def = 0)
{
auto found = ct.find(key);
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)));
};
-// 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
inline const NetInfo *get_net_or_empty(const CellInfo *cell, const IdString port)
{
diff --git a/docs/archapi.md b/docs/archapi.md
index 6d17f01a..f2571f08 100644
--- a/docs/archapi.md
+++ b/docs/archapi.md
@@ -45,31 +45,31 @@ A scalar type that is used to represent delays. May be an integer or float type
### 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
-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
-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
-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
-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
-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
-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
@@ -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.
-*BaseArch default: returns `std::hash` of `BelId` cast to `uint32_t`*
+*BaseArch default: returns `bel.hash()`*
### 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.
-*BaseArch default: returns `std::hash` of `WireId` cast to `uint32_t`*
+*BaseArch default: returns `wire.hash()`*
### 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.
-*BaseArch default: returns `std::hash` of `WireId` cast to `uint32_t`*
+*BaseArch default: returns `pip.hash()`*
### void bindPip(PipId pip, NetInfo \*net, PlaceStrength strength)
diff --git a/ecp5/arch.h b/ecp5/arch.h
index 063a3df6..be1a44d8 100644
--- a/ecp5/arch.h
+++ b/ecp5/arch.h
@@ -419,23 +419,9 @@ struct DelayKey
{
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
{
using ArchArgsT = ArchArgs;
@@ -458,15 +444,15 @@ struct Arch : BaseArch<ArchRanges>
const PackageInfoPOD *package_info;
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::unordered_map<WireId, int> wire_fanout;
+ dict<WireId, int> wire_fanout;
// fast access to X and Y IdStrings for building object names
std::vector<IdString> x_ids, y_ids;
// 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;
Arch(ArchArgs args);
@@ -914,10 +900,10 @@ struct Arch : BaseArch<ArchRanges>
// Improves directivity of routing to DSP inputs, avoids issues
// with different routes to the same physical reset wire causing
// 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();
- 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::vector<std::string> availablePlacers;
diff --git a/ecp5/arch_place.cc b/ecp5/arch_place.cc
index 57c3b181..a98d96ec 100644
--- a/ecp5/arch_place.cc
+++ b/ecp5/arch_place.cc
@@ -98,15 +98,6 @@ void Arch::permute_luts()
TimingAnalyser tmg(getCtx());
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) {
std::vector<IdString> port_names;
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);
};
- for (auto cell : sorted(cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type == id_TRELLIS_SLICE && str_or_default(ci->params, id("MODE"), "LOGIC") == "LOGIC") {
proc_lut(ci, 0);
proc_lut(ci, 1);
@@ -169,8 +160,8 @@ void Arch::permute_luts()
void Arch::setup_wire_locations()
{
wire_loc_overrides.clear();
- for (auto cell : sorted(cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : cells) {
+ CellInfo *ci = cell.second.get();
if (ci->bel == BelId())
continue;
if (ci->type == id_MULT18X18D || ci->type == id_DCUA || ci->type == id_DDRDLL || ci->type == id_DQSBUFM ||
diff --git a/ecp5/arch_pybindings.cc b/ecp5/arch_pybindings.cc
index 5218ce36..35660afd 100644
--- a/ecp5/arch_pybindings.cc
+++ b/ecp5/arch_pybindings.cc
@@ -44,10 +44,10 @@ void arch_wrap_python(py::module &m)
.def("place", &Context::place)
.def("route", &Context::route);
- typedef std::unordered_map<IdString, std::unique_ptr<CellInfo>> CellMap;
- typedef std::unordered_map<IdString, std::unique_ptr<NetInfo>> NetMap;
- typedef std::unordered_map<IdString, IdString> AliasMap;
- typedef std::unordered_map<IdString, HierarchicalCell> HierarchyMap;
+ typedef dict<IdString, std::unique_ptr<CellInfo>> CellMap;
+ typedef dict<IdString, std::unique_ptr<NetInfo>> NetMap;
+ typedef dict<IdString, IdString> AliasMap;
+ typedef dict<IdString, HierarchicalCell> HierarchyMap;
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");
diff --git a/ecp5/archdefs.h b/ecp5/archdefs.h
index 2b4590e5..6243a9df 100644
--- a/ecp5/archdefs.h
+++ b/ecp5/archdefs.h
@@ -21,9 +21,8 @@
#ifndef ECP5_ARCHDEFS_H
#define ECP5_ARCHDEFS_H
-#include <boost/functional/hash.hpp>
-
#include "base_clusterinfo.h"
+#include "hashlib.h"
#include "idstring.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 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); }
@@ -78,6 +78,7 @@ struct BelId
{
return location == other.location ? index < other.index : location < other.location;
}
+ unsigned int hash() const { return mkhash(location.hash(), index); }
};
struct WireId
@@ -91,6 +92,7 @@ struct WireId
{
return location == other.location ? index < other.index : location < other.location;
}
+ unsigned int hash() const { return mkhash(location.hash(), index); }
};
struct PipId
@@ -104,6 +106,7 @@ struct PipId
{
return location == other.location ? index < other.index : location < other.location;
}
+ unsigned int hash() const { return mkhash(location.hash(), index); }
};
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); }
+ unsigned int hash() const { return mkhash(location.hash(), int(type)); }
};
struct DecalId
@@ -142,6 +146,7 @@ struct DecalId
{
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
@@ -180,72 +185,4 @@ struct ArchCellInfo : BaseClusterInfo
};
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 */
diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc
index f8d11d39..ac9d4a4d 100644
--- a/ecp5/bitstream.cc
+++ b/ecp5/bitstream.cc
@@ -569,8 +569,7 @@ static std::vector<bool> parse_config_str(const Property &p, int length)
return word;
}
-std::string intstr_or_default(const std::unordered_map<IdString, Property> &ct, const IdString &key,
- std::string def = "0")
+std::string intstr_or_default(const dict<IdString, Property> &ct, const IdString &key, std::string def = "0")
{
auto found = ct.find(key);
if (found == ct.end())
@@ -670,8 +669,8 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
}
}
// Find bank voltages
- std::unordered_map<int, IOVoltage> bankVcc;
- std::unordered_map<int, bool> bankLvds, bankVref, bankDiff;
+ dict<int, IOVoltage> bankVcc;
+ dict<int, bool> bankLvds, bankVref, bankDiff;
for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second.get();
diff --git a/ecp5/cells.cc b/ecp5/cells.cc
index 7f9f1579..edc80329 100644
--- a/ecp5/cells.cc
+++ b/ecp5/cells.cc
@@ -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,
- std::unordered_set<IdString> &todelete_cells)
+ pool<IdString> &todelete_cells)
{
if (nxio->type == ctx->id("$nextpnr_ibuf")) {
trio->params[ctx->id("DIR")] = std::string("INPUT");
diff --git a/ecp5/cells.h b/ecp5/cells.h
index e66f8f21..20ba97b4 100644
--- a/ecp5/cells.h
+++ b/ecp5/cells.h
@@ -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
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
diff --git a/ecp5/globals.cc b/ecp5/globals.cc
index 36bec64c..b840ac91 100644
--- a/ecp5/globals.cc
+++ b/ecp5/globals.cc
@@ -72,7 +72,7 @@ class Ecp5GlobalRouter
std::vector<NetInfo *> get_clocks()
{
- std::unordered_map<IdString, int> clockCount;
+ dict<IdString, int> clockCount;
for (auto &net : ctx->nets) {
NetInfo *ni = net.second.get();
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
std::vector<NetInfo *> clocks;
- for (auto &cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type == id_DCCA) {
NetInfo *glb = ci->ports.at(id_CLKO).net;
if (glb != nullptr) {
@@ -147,7 +147,7 @@ class Ecp5GlobalRouter
WireId globalWire;
IdString global_name = ctx->id(fmt_str("G_HPBX" << std::setw(2) << std::setfill('0') << global_index << "00"));
std::queue<WireId> upstream;
- std::unordered_map<WireId, PipId> backtrace;
+ dict<WireId, PipId> backtrace;
upstream.push(userWire);
bool already_routed = false;
WireId next;
@@ -230,7 +230,7 @@ class Ecp5GlobalRouter
bool simple_router(NetInfo *net, WireId src, WireId dst, bool allow_fail = false)
{
std::queue<WireId> visit;
- std::unordered_map<WireId, PipId> backtrace;
+ dict<WireId, PipId> backtrace;
visit.push(src);
WireId cursor;
while (true) {
@@ -340,7 +340,7 @@ class Ecp5GlobalRouter
bool has_short_route(WireId src, WireId dst, int thresh = 7)
{
std::queue<WireId> visit;
- std::unordered_map<WireId, PipId> backtrace;
+ dict<WireId, PipId> backtrace;
visit.push(src);
WireId cursor;
while (true) {
@@ -376,7 +376,7 @@ class Ecp5GlobalRouter
return length < thresh;
}
- std::unordered_set<WireId> used_pclkcib;
+ pool<WireId> used_pclkcib;
std::set<WireId> get_candidate_pclkcibs(BelId dcc)
{
@@ -535,9 +535,9 @@ class Ecp5GlobalRouter
fab_globals.insert(i);
}
std::vector<std::pair<PortRef *, int>> toroute;
- std::unordered_map<int, NetInfo *> clocks;
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ dict<int, NetInfo *> clocks;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type == id_DCCA) {
NetInfo *clock = ci->ports.at(id_CLKO).net;
NPNR_ASSERT(clock != nullptr);
@@ -577,8 +577,8 @@ class Ecp5GlobalRouter
void route_eclk_sources()
{
// Try and use dedicated paths if possible
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type == id_ECLKSYNCB || ci->type == id_TRELLIS_ECLKBUF || ci->type == id_ECLKBRIDGECS) {
std::vector<IdString> pins;
if (ci->type == id_ECLKSYNCB || ci->type == id_TRELLIS_ECLKBUF) {
@@ -595,7 +595,7 @@ class Ecp5GlobalRouter
WireId src = ctx->getNetinfoSourceWire(ni);
WireId dst = ctx->getBelPinWire(ci->bel, pin);
std::queue<WireId> visit;
- std::unordered_map<WireId, PipId> backtrace;
+ dict<WireId, PipId> backtrace;
visit.push(dst);
int iter = 0;
WireId cursor;
diff --git a/ecp5/lpf.cc b/ecp5/lpf.cc
index 6d134e8d..39576fcb 100644
--- a/ecp5/lpf.cc
+++ b/ecp5/lpf.cc
@@ -19,7 +19,6 @@
#include <boost/algorithm/string.hpp>
#include <sstream>
-#include <unordered_set>
#include "arch.h"
#include "log.h"
@@ -27,7 +26,7 @@
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",
"BACKGROUND_RECONFIG", "DONE_EX", "DONE_OD",
"DONE_PULL", "MCCLK_FREQ", "TRANSFR",
@@ -35,7 +34,7 @@ static const std::unordered_set<std::string> sysconfig_keys = {
"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",
"CLAMP", "OPENDRAIN", "DIFFRESISTOR", "DIFFDRIVE", "HYSTERESIS", "TERMINATION",
};
diff --git a/ecp5/main.cc b/ecp5/main.cc
index 5d9fc965..711c4944 100644
--- a/ecp5/main.cc
+++ b/ecp5/main.cc
@@ -34,7 +34,7 @@ class ECP5CommandHandler : public CommandHandler
public:
ECP5CommandHandler(int argc, char **argv);
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 customAfterLoad(Context *ctx) override;
void validate() override;
@@ -132,7 +132,7 @@ static std::string speedString(ArchArgs::SpeedGrade speed)
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;
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());
}
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type == ctx->id("$nextpnr_ibuf") || ci->type == ctx->id("$nextpnr_obuf") ||
ci->type == ctx->id("$nextpnr_iobuf")) {
if (!ci->attrs.count(ctx->id("LOC"))) {
diff --git a/ecp5/pack.cc b/ecp5/pack.cc
index bdf84bcf..19eda9e2 100644
--- a/ecp5/pack.cc
+++ b/ecp5/pack.cc
@@ -21,7 +21,6 @@
#include <boost/optional.hpp>
#include <iterator>
#include <queue>
-#include <unordered_set>
#include "cells.h"
#include "chain_utils.h"
#include "design_utils.h"
@@ -106,8 +105,8 @@ class Ecp5Packer
void find_lutff_pairs()
{
log_info("Finding LUTFF pairs...\n");
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (is_lut(ctx, ci) || is_pfumx(ctx, ci) || is_l6mux(ctx, ci)) {
NetInfo *znet = ci->ports.at(ctx->id("Z")).net;
if (znet != nullptr) {
@@ -261,9 +260,9 @@ class Ecp5Packer
void pair_luts()
{
log_info("Finding LUT-LUT pairs...\n");
- std::unordered_set<IdString> procdLuts;
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ pool<IdString> procdLuts;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (is_lut(ctx, ci) && procdLuts.find(cell.first) == procdLuts.end()) {
NetInfo *znet = ci->ports.at(ctx->id("Z")).net;
std::vector<NetInfo *> inpnets;
@@ -392,8 +391,8 @@ class Ecp5Packer
}
if (ctx->debug) {
log_info("Singleton LUTs (packer QoR debug): \n");
- for (auto cell : sorted(ctx->cells))
- if (is_lut(ctx, cell.second) && !procdLuts.count(cell.first))
+ for (auto &cell : ctx->cells)
+ if (is_lut(ctx, cell.second.get()) && !procdLuts.count(cell.first))
log_info(" %s\n", cell.first.c_str(ctx));
}
}
@@ -443,8 +442,8 @@ class Ecp5Packer
{
log_info("Packing IOs..\n");
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (is_nextpnr_iob(ctx, ci)) {
CellInfo *trio = nullptr;
NetInfo *ionet = nullptr;
@@ -536,8 +535,8 @@ class Ecp5Packer
void pack_lut5xs()
{
log_info("Packing LUT5-7s...\n");
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (is_pfumx(ctx, ci)) {
std::unique_ptr<CellInfo> packed =
create_ecp5_cell(ctx, ctx->id("TRELLIS_SLICE"), ci->name.str(ctx) + "_SLICE");
@@ -593,8 +592,8 @@ class Ecp5Packer
}
flush_cells();
// Pack LUT6s
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (is_l6mux(ctx, ci)) {
NetInfo *ofx0_0 = ci->ports.at(ctx->id("D0")).net;
if (ofx0_0 == nullptr)
@@ -651,8 +650,8 @@ class Ecp5Packer
}
flush_cells();
// Pack LUT7s
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (is_l6mux(ctx, ci)) {
NetInfo *ofx1_0 = ci->ports.at(ctx->id("D0")).net;
if (ofx1_0 == nullptr)
@@ -975,8 +974,8 @@ class Ecp5Packer
// Pack distributed RAM
void pack_dram()
{
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (is_dpram(ctx, ci)) {
// Create RAMW slice
@@ -1108,8 +1107,8 @@ class Ecp5Packer
void pack_remaining_luts()
{
log_info("Packing unpaired LUTs into a SLICE...\n");
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (is_lut(ctx, ci)) {
std::unique_ptr<CellInfo> 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
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;
visited_cells.insert(origin);
to_visit.push(origin);
@@ -1181,8 +1180,8 @@ class Ecp5Packer
++used_slices;
log_info("Packing unpaired FFs into a SLICE...\n");
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (is_ff(ctx, ci)) {
bool pack_dense = used_slices > (dense_pack_mode_thresh * available_slices);
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;
- for (auto net : sorted(ctx->nets)) {
- NetInfo *ni = net.second;
+ for (auto &net : ctx->nets) {
+ NetInfo *ni = net.second.get();
if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("GND")) {
IdString drv_cell = ni->driver.cell->name;
set_net_constant(ctx, ni, gnd_net.get(), false);
@@ -1461,8 +1460,8 @@ class Ecp5Packer
c->params[n] = c->params[o];
c->params.erase(o);
};
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
// Convert 36-bit PDP RAMs to regular 18-bit DP ones that match the Bel
if (ci->type == ctx->id("PDPW16KD")) {
ci->params[ctx->id("DATA_WIDTH_A")] = 36; // force PDP mode
@@ -1503,8 +1502,8 @@ class Ecp5Packer
ci->type = id_DP16KD;
}
}
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type == id_DP16KD) {
// Add ports, even if disconnected, to ensure correct tie-offs
for (int i = 0; i < 14; i++) {
@@ -1544,8 +1543,8 @@ class Ecp5Packer
// Pack DSPs
void pack_dsps()
{
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type == id_MULT18X18D) {
// Add ports, even if disconnected, to ensure correct tie-offs
for (auto sig : {"CLK", "CE", "RST"})
@@ -1708,8 +1707,8 @@ class Ecp5Packer
// "Pack" DCUs
void pack_dcus()
{
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type == id_DCUA) {
if (ci->attrs.count(ctx->id("LOC"))) {
std::string loc = ci->attrs.at(ctx->id("LOC")).as_string();
@@ -1759,8 +1758,8 @@ class Ecp5Packer
}
}
}
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type == id_EXTREFB) {
const NetInfo *refo = net_or_nullptr(ci, id_REFCLKO);
CellInfo *dcu = nullptr;
@@ -1800,8 +1799,8 @@ class Ecp5Packer
// Miscellaneous packer tasks
void pack_misc()
{
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type == id_USRMCLK) {
rename_port(ctx, ci, ctx->id("USRMCLKI"), id_PADDO);
rename_port(ctx, ci, ctx->id("USRMCLKTS"), id_PADDT);
@@ -1829,14 +1828,14 @@ class Ecp5Packer
if (ctx->getBelType(bel) == id_EHXPLLL && ctx->checkBelAvail(bel))
available_plls.insert(bel);
}
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type == id_EHXPLLL && ci->attrs.count(ctx->id("BEL")))
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
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type == id_EHXPLLL && !ci->attrs.count(ctx->id("BEL"))) {
const NetInfo *drivernet = net_or_nullptr(ci, id_CLKI);
if (drivernet == nullptr || drivernet->driver.cell == nullptr)
@@ -1863,8 +1862,8 @@ class Ecp5Packer
}
}
// Place PLLs driven by logic, etc, randomly
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type == id_EHXPLLL && !ci->attrs.count(ctx->id("BEL"))) {
if (available_plls.empty())
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));
std::queue<WireId> upstream;
- std::unordered_map<WireId, PipId> backtrace;
+ dict<WireId, PipId> backtrace;
upstream.push(userWire);
WireId next;
while (true) {
@@ -2026,12 +2025,12 @@ class Ecp5Packer
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
void pack_dqsbuf()
{
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type == id_DQSBUFM) {
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)
@@ -2119,7 +2118,7 @@ class Ecp5Packer
// 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) {
NetInfo *sclk = nullptr;
@@ -2265,8 +2264,8 @@ class Ecp5Packer
}
};
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
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 *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)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type == ctx->id("IDDRX1F")) {
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)
@@ -2692,8 +2691,8 @@ class Ecp5Packer
}
flush_cells();
// Constrain ECLK-related cells
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type == id_ECLKBRIDGECS) {
Loc loc;
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
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type == id_IOLOGIC || ci->type == id_DQSBUFM) {
if (!ci->ports.count(id_ECLK) || ci->ports.at(id_ECLK).net == nullptr)
continue;
@@ -2779,9 +2778,9 @@ class Ecp5Packer
}
}
flush_cells();
- std::unordered_set<BelId> used_eclksyncb;
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ pool<BelId> used_eclksyncb;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type == id_CLKDIVF) {
const NetInfo *clki = net_or_nullptr(ci, id_CLKI);
for (auto &eclk : eclks) {
@@ -2896,8 +2895,8 @@ class Ecp5Packer
}
}
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type == id_ECLKSYNCB) {
// **All** ECLKSYNCBs must be constrained
// 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)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type == id_CLKDIVF) {
if (ci->attrs.count(ctx->id("BEL")))
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; };
- std::unordered_set<IdString> user_constrained, changed_nets;
+ pool<IdString> user_constrained, changed_nets;
for (auto &net : ctx->nets) {
if (net.second->clkconstr != nullptr)
user_constrained.insert(net.first);
@@ -3041,7 +3040,7 @@ class Ecp5Packer
const int itermax = 5000;
while (!changed_nets.empty() && iter < itermax) {
++iter;
- std::unordered_set<IdString> changed_cells;
+ pool<IdString> changed_cells;
for (auto net : changed_nets) {
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)
@@ -3051,7 +3050,7 @@ class Ecp5Packer
changed_cells.insert(drv.cell->name);
}
changed_nets.clear();
- for (auto cell : sorted(changed_cells)) {
+ for (auto cell : changed_cells) {
CellInfo *ci = ctx->cells.at(cell).get();
if (ci->type == id_CLKDIVF) {
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
// later
- for (auto cell : sorted(ctx->cells)) {
- if (is_ff(ctx, cell.second) && cell.second->params.count(ctx->id("CEMUX")) &&
+ for (auto &cell : ctx->cells) {
+ if (is_ff(ctx, cell.second.get()) && cell.second->params.count(ctx->id("CEMUX")) &&
!cell.second->params[ctx->id("CEMUX")].is_string)
log_error("Found netlist using legacy-style JSON parameter values, please update your Yosys.\n");
}
@@ -3152,7 +3151,7 @@ class Ecp5Packer
private:
Context *ctx;
- std::unordered_set<IdString> packed_cells;
+ pool<IdString> packed_cells;
std::vector<std::unique_ptr<CellInfo>> new_cells;
struct SliceUsage
@@ -3163,10 +3162,10 @@ class Ecp5Packer
bool mux5_used = false, muxx_used = false;
};
- std::unordered_map<IdString, SliceUsage> sliceUsage;
- std::unordered_map<IdString, IdString> lutffPairs;
- std::unordered_map<IdString, IdString> fflutPairs;
- std::unordered_map<IdString, IdString> lutPairs;
+ dict<IdString, SliceUsage> sliceUsage;
+ dict<IdString, IdString> lutffPairs;
+ dict<IdString, IdString> fflutPairs;
+ dict<IdString, IdString> lutPairs;
};
// Main pack function
bool Arch::pack()
@@ -3188,8 +3187,8 @@ bool Arch::pack()
void Arch::assignArchInfo()
{
- for (auto cell : sorted(cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type == id_TRELLIS_SLICE) {
ci->sliceInfo.using_dff = false;
@@ -3301,7 +3300,7 @@ void Arch::assignArchInfo()
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"));
}
}
diff --git a/fpga_interchange/arch.cc b/fpga_interchange/arch.cc
index 71c68e66..8e7fe2a3 100644
--- a/fpga_interchange/arch.cc
+++ b/fpga_interchange/arch.cc
@@ -63,21 +63,8 @@ struct SiteBelPair
SiteBelPair(std::string site, IdString bel) : site(site), bel(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)
{
@@ -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) {
IdString site(package_pin.site);
IdString bel(package_pin.bel);
@@ -1951,7 +1938,7 @@ void Arch::unmask_bel_pins()
void Arch::remove_site_routing()
{
- HashTables::HashSet<WireId> wires_to_unbind;
+ pool<WireId> wires_to_unbind;
for (auto &net_pair : nets) {
for (auto &wire_pair : net_pair.second->wires) {
WireId wire = wire_pair.first;
@@ -2047,8 +2034,8 @@ void Arch::pack_default_conns()
std::vector<IdString> dead_nets;
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
const DefaultCellConnsPOD *conns = get_default_conns(ci->type);
if (conns == nullptr)
continue;
diff --git a/fpga_interchange/arch.h b/fpga_interchange/arch.h
index 5c7bbc52..c8a61430 100644
--- a/fpga_interchange/arch.h
+++ b/fpga_interchange/arch.h
@@ -103,14 +103,14 @@ struct Arch : ArchAPI<ArchRanges>
// Guard initialization of "by_name" maps if accessed from multiple
// threads on a "const Context *".
mutable std::mutex by_name_mutex;
- mutable std::unordered_map<IdString, int> tile_by_name;
- mutable std::unordered_map<IdString, std::pair<int, int>> site_by_name;
+ mutable dict<IdString, int> tile_by_name;
+ mutable dict<IdString, std::pair<int, int>> site_by_name;
- std::unordered_map<WireId, NetInfo *> wire_to_net;
- std::unordered_map<PipId, NetInfo *> pip_to_net;
+ dict<WireId, NetInfo *> wire_to_net;
+ dict<PipId, NetInfo *> pip_to_net;
DedicatedInterconnect dedicated_interconnect;
- HashTables::HashMap<int32_t, TileStatus> tileStatus;
+ dict<int32_t, TileStatus> tileStatus;
PseudoPipData pseudo_pip_data;
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,
- std::unordered_set<CellInfo *> *placed_cells);
+ void place_iobufs(WireId pad_wire, NetInfo *net, const pool<CellInfo *, hash_ptr_ops> &tightly_attached_bels,
+ pool<CellInfo *, hash_ptr_ops> *placed_cells);
void pack_ports();
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); }
- std::unordered_map<WireId, Loc> sink_locs, source_locs;
+ dict<WireId, Loc> sink_locs, source_locs;
// -------------------------------------------------
void assignArchInfo() final {}
@@ -875,8 +875,8 @@ struct Arch : ArchAPI<ArchRanges>
void write_physical_netlist(const std::string &filename) const;
void parse_xdc(const std::string &filename);
- std::unordered_set<IdString> io_port_types;
- std::unordered_set<BelId> pads;
+ pool<IdString> io_port_types;
+ pool<BelId> pads;
bool is_site_port(PipId pip) const
{
@@ -1083,7 +1083,7 @@ struct Arch : ArchAPI<ArchRanges>
IdString gnd_cell_pin;
IdString vcc_cell_pin;
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?
// Note: May be null in arch's without wire LUT types. Assumption is
diff --git a/fpga_interchange/arch_pack_io.cc b/fpga_interchange/arch_pack_io.cc
index 9322d028..fdbb1130 100644
--- a/fpga_interchange/arch_pack_io.cc
+++ b/fpga_interchange/arch_pack_io.cc
@@ -24,8 +24,8 @@
NEXTPNR_NAMESPACE_BEGIN
-void Arch::place_iobufs(WireId pad_wire, NetInfo *net, const std::unordered_set<CellInfo *> &tightly_attached_bels,
- std::unordered_set<CellInfo *> *placed_cells)
+void Arch::place_iobufs(WireId pad_wire, NetInfo *net, const pool<CellInfo *, hash_ptr_ops> &tightly_attached_bels,
+ pool<CellInfo *, hash_ptr_ops> *placed_cells)
{
for (BelPin bel_pin : getWireBelPins(pad_wire)) {
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()
{
- 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) {
const auto &tile = chip_info->tiles[i];
const auto &tile_type = chip_info->tile_types[tile.type];
@@ -66,9 +66,9 @@ void Arch::pack_ports()
}
// set(site_types) for package pins
- std::unordered_set<IdString> package_sites;
+ pool<IdString> package_sites;
// 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) {
IdString pin(package_pin.package_pin);
IdString bel(package_pin.bel);
@@ -78,7 +78,7 @@ void Arch::pack_ports()
for (size_t i = 0; i < chip_info->tiles.size(); ++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) {
auto &site_data = chip_info->sites[tile.sites[j]];
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.
- std::unordered_set<IdString> package_pin_site_types;
- std::unordered_map<IdString, std::unordered_set<IdString>> possible_package_site_types;
+ pool<IdString> package_pin_site_types;
+ dict<IdString, pool<IdString>> possible_package_site_types;
for (const TileInstInfoPOD &tile : chip_info->tiles) {
for (size_t site_index : tile.sites) {
const SiteInstInfoPOD &site = chip_info->sites[site_index];
@@ -121,7 +121,7 @@ void Arch::pack_ports()
for (auto port_pair : port_cells) {
IdString port_name = port_pair.first;
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) {
const PortInfo &port_info = port_pair.second;
@@ -145,7 +145,7 @@ void Arch::pack_ports()
}
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) {
NPNR_ASSERT(port_cells.find(cell->name) == port_cells.end());
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
// port.
- std::unordered_set<IdString> possible_site_types;
+ pool<IdString> possible_site_types;
for (const TileTypeInfoPOD &tile_type : chip_info->tile_types) {
IdString tile_type_name(tile_type.name);
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());
auto pin_iter = package_pin_bels.find(package_pin_id);
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));
}
- std::unordered_set<CellInfo *> placed_cells;
+ pool<CellInfo *, hash_ptr_ops> placed_cells;
bindBel(package_bel, port_cell, STRENGTH_FIXED);
placed_cells.emplace(port_cell);
diff --git a/fpga_interchange/arch_pybindings.cc b/fpga_interchange/arch_pybindings.cc
index 68619866..03b20841 100644
--- a/fpga_interchange/arch_pybindings.cc
+++ b/fpga_interchange/arch_pybindings.cc
@@ -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,
conv_from_str<BelId>>::def_wrap(ctx_cls, "explain_bel_status");
- typedef std::unordered_map<IdString, std::unique_ptr<CellInfo>> CellMap;
- typedef std::unordered_map<IdString, std::unique_ptr<NetInfo>> NetMap;
- typedef std::unordered_map<IdString, IdString> AliasMap;
- typedef std::unordered_map<IdString, HierarchicalCell> HierarchyMap;
+ typedef dict<IdString, std::unique_ptr<CellInfo>> CellMap;
+ typedef dict<IdString, std::unique_ptr<NetInfo>> NetMap;
+ typedef dict<IdString, IdString> AliasMap;
+ typedef dict<IdString, HierarchicalCell> HierarchyMap;
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");
diff --git a/fpga_interchange/archdefs.h b/fpga_interchange/archdefs.h
index c145b893..a50df43a 100644
--- a/fpga_interchange/archdefs.h
+++ b/fpga_interchange/archdefs.h
@@ -21,10 +21,9 @@
#ifndef FPGA_INTERCHANGE_ARCHDEFS_H
#define FPGA_INTERCHANGE_ARCHDEFS_H
-#include <boost/functional/hash.hpp>
#include <cstdint>
-#include "hash_table.h"
+#include "hashlib.h"
#include "luts.h"
#include "nextpnr_namespaces.h"
@@ -48,6 +47,7 @@ struct BelId
{
return tile < other.tile || (tile == other.tile && index < other.index);
}
+ unsigned int hash() const { return mkhash(tile, index); }
};
struct WireId
@@ -62,6 +62,7 @@ struct WireId
{
return tile < other.tile || (tile == other.tile && index < other.index);
}
+ unsigned int hash() const { return mkhash(tile, index); }
};
struct PipId
@@ -75,18 +76,21 @@ struct PipId
{
return tile < other.tile || (tile == other.tile && index < other.index);
}
+ unsigned int hash() const { return mkhash(tile, index); }
};
struct GroupId
{
bool operator==(const GroupId &other) const { return true; }
bool operator!=(const GroupId &other) const { return false; }
+ unsigned int hash() const { return 0; }
};
struct DecalId
{
bool operator==(const DecalId &other) const { return true; }
bool operator!=(const DecalId &other) const { return false; }
+ unsigned int hash() const { return 0; }
};
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; }
+ unsigned int hash() const { return name.hash(); }
};
typedef IdString ClusterId;
@@ -112,76 +117,12 @@ struct ArchNetInfo
struct ArchCellInfo
{
int32_t cell_mapping = -1;
- HashTables::HashMap<IdString, std::vector<IdString>> cell_bel_pins;
- HashTables::HashMap<IdString, std::vector<IdString>> masked_cell_bel_pins;
- HashTables::HashSet<IdString> const_ports;
+ dict<IdString, std::vector<IdString>> cell_bel_pins;
+ dict<IdString, std::vector<IdString>> masked_cell_bel_pins;
+ pool<IdString> const_ports;
LutCell lut_cell;
};
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 */
diff --git a/fpga_interchange/cell_parameters.h b/fpga_interchange/cell_parameters.h
index de82e76b..d6d4ccec 100644
--- a/fpga_interchange/cell_parameters.h
+++ b/fpga_interchange/cell_parameters.h
@@ -25,7 +25,6 @@
#include "chipdb.h"
#include "dynamic_bitarray.h"
-#include "hash_table.h"
#include "nextpnr_namespaces.h"
#include "property.h"
@@ -42,7 +41,7 @@ struct CellParameters
bool compare_property(const Context *ctx, IdString cell_type, IdString parameter, const Property &property,
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_hex_re;
diff --git a/fpga_interchange/cost_map.cc b/fpga_interchange/cost_map.cc
index 868fdca0..c20ba11b 100644
--- a/fpga_interchange/cost_map.cc
+++ b/fpga_interchange/cost_map.cc
@@ -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,
- 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;
diff --git a/fpga_interchange/cost_map.h b/fpga_interchange/cost_map.h
index 810d0198..88fb97e4 100644
--- a/fpga_interchange/cost_map.h
+++ b/fpga_interchange/cost_map.h
@@ -24,7 +24,6 @@
#include <boost/multi_array.hpp>
#include <mutex>
-#include "hash_table.h"
#include "lookahead.capnp.h"
#include "nextpnr_namespaces.h"
#include "nextpnr_types.h"
@@ -39,7 +38,7 @@ class CostMap
public:
delay_t get_delay(const Context *ctx, WireId src, WireId dst) const;
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 to_builder(lookahead_storage::CostMap::Builder builder) const;
@@ -53,7 +52,7 @@ class CostMap
};
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,
delay_t delay_penality);
diff --git a/fpga_interchange/dedicated_interconnect.cc b/fpga_interchange/dedicated_interconnect.cc
index 9f7e83ab..2f6fbcd3 100644
--- a/fpga_interchange/dedicated_interconnect.cc
+++ b/fpga_interchange/dedicated_interconnect.cc
@@ -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 src : sink_pair.second) {
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);
Loc sink_loc = ctx->getBelLocation(sink_bel);
- std::unordered_set<DeltaTileTypeBelPin> srcs;
+ pool<DeltaTileTypeBelPin> srcs;
while (!nodes_to_expand.empty()) {
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);
Loc src_loc = ctx->getBelLocation(src_bel);
- std::unordered_set<DeltaTileTypeBelPin> dsts;
+ pool<DeltaTileTypeBelPin> dsts;
while (!nodes_to_expand.empty()) {
WireNode node_to_expand = nodes_to_expand.back();
diff --git a/fpga_interchange/dedicated_interconnect.h b/fpga_interchange/dedicated_interconnect.h
index 9ddb05fd..085ced26 100644
--- a/fpga_interchange/dedicated_interconnect.h
+++ b/fpga_interchange/dedicated_interconnect.h
@@ -23,9 +23,9 @@
#include <boost/functional/hash.hpp>
#include <cstdint>
-#include <unordered_map>
#include "archdefs.h"
+#include "hashlib.h"
#include "idstring.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;
}
+ unsigned int hash() const { return mkhash(mkhash(tile_type, bel_index), bel_pin.hash()); }
};
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;
}
+ 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;
// This class models dedicated interconnect present in the given fabric.
@@ -123,8 +97,8 @@ struct DedicatedInterconnect
{
const Context *ctx;
- std::unordered_map<TileTypeBelPin, std::unordered_set<DeltaTileTypeBelPin>> sinks;
- std::unordered_map<TileTypeBelPin, std::unordered_set<DeltaTileTypeBelPin>> sources;
+ dict<TileTypeBelPin, pool<DeltaTileTypeBelPin>> sinks;
+ dict<TileTypeBelPin, pool<DeltaTileTypeBelPin>> sources;
void init(const Context *ctx);
diff --git a/fpga_interchange/fpga_interchange.cpp b/fpga_interchange/fpga_interchange.cpp
index cf89ef1c..1d08b128 100644
--- a/fpga_interchange/fpga_interchange.cpp
+++ b/fpga_interchange/fpga_interchange.cpp
@@ -43,7 +43,7 @@ static void write_message(::capnp::MallocMessageBuilder & message, const std::st
struct StringEnumerator {
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) {
auto result = string_to_index.emplace(s, strings.size());
@@ -59,7 +59,7 @@ struct StringEnumerator {
static PhysicalNetlist::PhysNetlist::RouteBranch::Builder emit_branch(
const Context * ctx,
StringEnumerator * strings,
- const std::unordered_map<PipId, PlaceStrength> &pip_place_strength,
+ const dict<PipId, PlaceStrength> &pip_place_strength,
PipId pip,
PhysicalNetlist::PhysNetlist::RouteBranch::Builder branch) {
if(ctx->is_pip_synthetic(pip)) {
@@ -264,10 +264,10 @@ static void init_bel_pin(
static void emit_net(
const Context * ctx,
StringEnumerator * strings,
- const std::unordered_map<WireId, std::vector<PipId>> &pip_downhill,
- const std::unordered_map<WireId, std::vector<BelPin>> &sinks,
- std::unordered_set<PipId> *pips,
- const std::unordered_map<PipId, PlaceStrength> &pip_place_strength,
+ const dict<WireId, std::vector<PipId>> &pip_downhill,
+ const dict<WireId, std::vector<BelPin>> &sinks,
+ pool<PipId> *pips,
+ const dict<PipId, PlaceStrength> &pip_place_strength,
WireId wire, PhysicalNetlist::PhysNetlist::RouteBranch::Builder branch) {
size_t number_branches = 0;
@@ -349,7 +349,7 @@ static PhysicalNetlist::PhysNetlist::RouteBranch::Builder init_local_source(
StringEnumerator * strings,
PhysicalNetlist::PhysNetlist::RouteBranch::Builder source_branch,
PipId root,
- const std::unordered_map<PipId, PlaceStrength> &pip_place_strength,
+ const dict<PipId, PlaceStrength> &pip_place_strength,
WireId *root_wire) {
WireId source_wire = ctx->getPipSrcWire(root);
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,
- 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<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());
- std::unordered_set<IdString> placed_cells;
+ pool<IdString> placed_cells;
for(const auto & cell_pair : ctx->cells) {
const CellInfo & cell = *cell_pair.second;
if(cell.bel == BelId()) {
@@ -444,7 +444,7 @@ void FpgaInterchange::write_physical_netlist(const Context * ctx, const std::str
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 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)));
}
- std::unordered_map<WireId, BelPin> root_wires;
- std::unordered_map<WireId, std::vector<PipId>> pip_downhill;
- std::unordered_set<PipId> pips;
+ dict<WireId, BelPin> root_wires;
+ dict<WireId, std::vector<PipId>> pip_downhill;
+ pool<PipId> pips;
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)) {
@@ -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) {
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);
@@ -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) {
WireId downhill_wire = wire_pair.first;
@@ -723,23 +723,11 @@ struct PortKey {
bool operator == (const PortKey &other) const {
return inst_idx == other.inst_idx && port_idx == other.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;
+ unsigned int hash() const {
+ return mkhash(inst_idx, port_idx);
}
};
-NEXTPNR_NAMESPACE_BEGIN
-
struct ModuleReader {
const LogicalNetlistImpl *root;
@@ -748,9 +736,9 @@ struct ModuleReader {
LogicalNetlist::Netlist::Cell::Reader cell;
LogicalNetlist::Netlist::CellDeclaration::Reader cell_decl;
- std::unordered_map<int32_t, LogicalNetlist::Netlist::Net::Reader> net_indicies;
- std::unordered_map<int32_t, std::string> disconnected_nets;
- std::unordered_map<PortKey, std::vector<int32_t>> connections;
+ dict<int32_t, LogicalNetlist::Netlist::Net::Reader> net_indicies;
+ dict<int32_t, std::string> disconnected_nets;
+ dict<PortKey, std::vector<int32_t>> connections;
ModuleReader(const LogicalNetlistImpl *root,
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
{
- // std::unordered_map<int32_t, LogicalNetlist::Netlist::Net::Reader> net_indicies;
for(auto net_pair : mod.net_indicies) {
NetReader net_reader(&mod, net_pair.first);
auto net = net_pair.second;
@@ -842,7 +829,6 @@ struct LogicalNetlistImpl
Func(strings.at(net.getName()), net_reader);
}
- // std::unordered_map<int32_t, IdString> disconnected_nets;
for(auto net_pair : mod.disconnected_nets) {
NetReader net_reader(&mod, net_pair.first);
Func(net_pair.second, net_reader);
diff --git a/fpga_interchange/globals.cc b/fpga_interchange/globals.cc
index 66d04f75..ed9f73a6 100644
--- a/fpga_interchange/globals.cc
+++ b/fpga_interchange/globals.cc
@@ -67,7 +67,7 @@ static int route_global_arc(Context *ctx, NetInfo *net, size_t usr_idx, size_t p
WireId startpoint;
GlobalVist best_visit;
std::queue<WireId> visit_queue;
- std::unordered_map<WireId, GlobalVist> visits;
+ dict<WireId, GlobalVist> visits;
visit_queue.push(dest);
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
// before the GBs it drives
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
const GlobalCellPOD *glb_cell = global_cell_info(ci->type);
if (glb_cell == nullptr)
continue;
@@ -239,8 +239,8 @@ void Arch::route_globals()
IdString gnd_net_name(chip_info->constants->gnd_net_name);
IdString vcc_net_name(chip_info->constants->vcc_net_name);
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
const GlobalCellPOD *glb_cell = global_cell_info(ci->type);
if (glb_cell == nullptr)
continue;
diff --git a/fpga_interchange/lookahead.cc b/fpga_interchange/lookahead.cc
index 6dc8c43a..f1cb13e1 100644
--- a/fpga_interchange/lookahead.cc
+++ b/fpga_interchange/lookahead.cc
@@ -64,9 +64,9 @@ struct PipAndCost
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;
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,
- const HashTables::HashMap<WireId, PipAndCost> &best_path,
- HashTables::HashMap<TypeWirePair, delay_t> *site_to_site_cost)
+static void update_site_to_site_costs(const Context *ctx, WireId first_wire, const dict<WireId, PipAndCost> &best_path,
+ dict<TypeWirePair, delay_t> *site_to_site_cost)
{
for (auto &best_pair : best_path) {
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,
- 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;
RoutingNode initial;
@@ -172,7 +171,7 @@ static void expand_output(const Context *ctx, WireId output_wire, Lookahead::Out
to_expand.push(initial);
- HashTables::HashMap<WireId, PipAndCost> best_path;
+ dict<WireId, PipAndCost> best_path;
while (!to_expand.empty()) {
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,
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) {
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
{
- 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;
};
@@ -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
// the delay storage.
WireId cursor = sink_wire;
- HashTables::HashSet<WireId> seen;
+ pool<WireId> seen;
while (cursor != src_wire) {
// No loops allowed in routing!
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,
DelayStorage *storage)
{
- HashTables::HashSet<WireId> seen;
+ pool<WireId> seen;
std::priority_queue<RoutingNode> to_expand;
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,
- TypeWireId wire_type, HashTables::HashSet<TypeWireSet> *types_explored,
- DelayStorage *storage, HashTables::HashSet<TypeWireId> *types_deferred,
- FlatWireMap<PipAndCost> *best_path)
+ TypeWireId wire_type, pool<TypeWireSet> *types_explored, DelayStorage *storage,
+ pool<TypeWireId> *types_deferred, 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) {
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,
- TypeWireId wire_type, HashTables::HashSet<TypeWireSet> *types_explored,
+ TypeWireId wire_type, pool<TypeWireSet> *types_explored,
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) {
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,
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) {
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;
FlatWireMap<PipAndCost> *best_path;
DelayStorage *storage;
- HashTables::HashSet<TypeWireSet> *explored;
- HashTables::HashSet<TypeWireId> *deferred;
+ pool<TypeWireSet> *explored;
+ pool<TypeWireId> *deferred;
virtual void lock() {}
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,
const std::vector<Sampler> &tiles_of_type, DeterministicRNG *rng,
FlatWireMap<PipAndCost> *best_path, DelayStorage *storage,
- HashTables::HashSet<TypeWireSet> *explored,
- HashTables::HashSet<TypeWireId> *deferred, HashTables::HashSet<int32_t> *tiles_left)
+ pool<TypeWireSet> *explored, pool<TypeWireId> *deferred, pool<int32_t> *tiles_left)
{
for (int32_t tile_type : tile_types) {
@@ -725,9 +722,9 @@ struct TbbExpandLocals : public ExpandLocals
std::mutex *all_costs_mutex;
DelayStorage *all_tiles_storage;
- HashTables::HashSet<TypeWireSet> *types_explored;
- HashTables::HashSet<TypeWireId> *types_deferred;
- HashTables::HashSet<int32_t> *tiles_left;
+ pool<TypeWireSet> *types_explored;
+ pool<TypeWireId> *types_deferred;
+ pool<int32_t> *tiles_left;
void lock() override { all_costs_mutex->lock(); }
@@ -785,16 +782,15 @@ struct TbbExpandLocals : public ExpandLocals
// 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,
DeterministicRNG *rng, std::mutex *all_costs_mutex,
- DelayStorage *all_tiles_storage, HashTables::HashSet<TypeWireSet> *types_explored,
- HashTables::HashSet<TypeWireId> *types_deferred,
- HashTables::HashSet<int32_t> *tiles_left)
+ DelayStorage *all_tiles_storage, pool<TypeWireSet> *types_explored,
+ pool<TypeWireId> *types_deferred, pool<int32_t> *tiles_left)
{
TbbExpandLocals locals;
DeterministicRNG rng_copy = *rng;
FlatWireMap<PipAndCost> best_path(ctx);
- HashTables::HashSet<TypeWireSet> explored;
- HashTables::HashSet<TypeWireId> deferred;
+ pool<TypeWireSet> explored;
+ pool<TypeWireId> deferred;
DelayStorage storage;
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");
}
- HashTables::HashSet<TypeWireId> input_site_ports;
+ pool<TypeWireId> input_site_ports;
for (BelId bel : ctx->getBels()) {
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;
// 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
// copies of another wire type. These can be cheaply computed after the
// graph has been explored.
- HashTables::HashSet<TypeWireId> types_deferred;
+ pool<TypeWireId> types_deferred;
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());
for (int32_t tile_type = 0; tile_type < ctx->chip_info->tile_types.ssize(); ++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
- tbb::parallel_for_each(
- all_tiles_storage.storage,
- [&](const std::pair<TypeWirePair, HashTables::HashMap<std::pair<int32_t, int32_t>, delay_t, PairHash>>
- &type_pair) {
+ tbb::parallel_for_each(all_tiles_storage.storage,
+ [&](const std::pair<TypeWirePair, dict<std::pair<int32_t, int32_t>, delay_t>> &type_pair) {
#else
for (const auto &type_pair : all_tiles_storage.storage) {
#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
- });
+ });
#else
}
#endif
diff --git a/fpga_interchange/lookahead.h b/fpga_interchange/lookahead.h
index b9d352d5..9655e13e 100644
--- a/fpga_interchange/lookahead.h
+++ b/fpga_interchange/lookahead.h
@@ -26,7 +26,6 @@
#include "cost_map.h"
#include "deterministic_rng.h"
-#include "hash_table.h"
#include "lookahead.capnp.h"
#include "nextpnr_namespaces.h"
#include "type_wire.h"
@@ -88,9 +87,9 @@ struct Lookahead
delay_t cost;
};
- HashTables::HashMap<TypeWireId, std::vector<InputSiteWireCost>> input_site_wires;
- HashTables::HashMap<TypeWireId, OutputSiteWireCost> output_site_wires;
- HashTables::HashMap<TypeWirePair, delay_t> site_to_site_cost;
+ dict<TypeWireId, std::vector<InputSiteWireCost>> input_site_wires;
+ dict<TypeWireId, OutputSiteWireCost> output_site_wires;
+ dict<TypeWirePair, delay_t> site_to_site_cost;
CostMap cost_map;
};
diff --git a/fpga_interchange/luts.cc b/fpga_interchange/luts.cc
index 882cc474..0156d379 100644
--- a/fpga_interchange/luts.cc
+++ b/fpga_interchange/luts.cc
@@ -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);
}
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,
- HashTables::HashSet<const LutBel *> *blocked_luts) const
+ pool<const LutBel *, hash_ptr_ops> *blocked_luts) const
{
std::vector<const LutBel *> unused_luts;
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;
}
-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;
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];
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) {
size_t bel_pin_idx = cell_to_bel_pin_remaps[cell_idx][pin_idx];
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;
}
-void check_equation(const LutCell &lut_cell, const std::unordered_map<IdString, IdString> &cell_to_bel_map,
- const LutBel &lut_bel, const std::vector<LogicLevel> &equation, uint32_t used_pins)
+void check_equation(const LutCell &lut_cell, const dict<IdString, IdString> &cell_to_bel_map, const LutBel &lut_bel,
+ const std::vector<LogicLevel> &equation, uint32_t used_pins)
{
std::vector<int8_t> pin_map;
pin_map.resize(lut_bel.pins.size(), -1);
diff --git a/fpga_interchange/luts.h b/fpga_interchange/luts.h
index df0ac124..cbb817c9 100644
--- a/fpga_interchange/luts.h
+++ b/fpga_interchange/luts.h
@@ -20,14 +20,11 @@
#ifndef LUTS_H
#define LUTS_H
-#include <unordered_map>
-#include <unordered_set>
-
#include "idstring.h"
#include "nextpnr_namespaces.h"
#include "dynamic_bitarray.h"
-#include "hash_table.h"
+#include "hashlib.h"
NEXTPNR_NAMESPACE_BEGIN
@@ -45,8 +42,8 @@ struct LutCell
{
// LUT cell pins for equation, LSB first.
std::vector<IdString> pins;
- std::unordered_set<IdString> lut_pins;
- std::unordered_set<IdString> vcc_pins;
+ pool<IdString> lut_pins;
+ pool<IdString> vcc_pins;
DynamicBitarray<> equation;
};
@@ -56,7 +53,7 @@ struct LutBel
// LUT BEL pins to LUT array index.
std::vector<IdString> pins;
- std::unordered_map<IdString, size_t> pin_to_index;
+ dict<IdString, size_t> pin_to_index;
IdString output_pin;
@@ -71,18 +68,18 @@ struct LutBel
// Work forward from cell definition and cell -> bel pin map and check that
// equation is valid.
-void check_equation(const LutCell &lut_cell, const std::unordered_map<IdString, IdString> &cell_to_bel_map,
- const LutBel &lut_bel, const std::vector<LogicLevel> &equation, uint32_t used_pins);
+void check_equation(const LutCell &lut_cell, const dict<IdString, IdString> &cell_to_bel_map, const LutBel &lut_bel,
+ const std::vector<LogicLevel> &equation, uint32_t used_pins);
struct LutElement
{
size_t width;
- std::unordered_map<IdString, LutBel> lut_bels;
+ dict<IdString, LutBel> lut_bels;
void compute_pin_order();
std::vector<IdString> pins;
- std::unordered_map<IdString, size_t> pin_to_index;
+ dict<IdString, size_t> pin_to_index;
};
struct LutMapper
@@ -92,7 +89,7 @@ struct LutMapper
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
// default constant.
@@ -101,7 +98,7 @@ struct LutMapper
// the pin is free to be a signal.
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,
- 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
// mapping in cells variable.
diff --git a/fpga_interchange/macros.cc b/fpga_interchange/macros.cc
index eee35d9f..8339829f 100644
--- a/fpga_interchange/macros.cc
+++ b/fpga_interchange/macros.cc
@@ -53,8 +53,8 @@ void Arch::expand_macros()
// Make up a list of cells, so we don't have modify-while-iterating issues
Context *ctx = getCtx();
std::vector<CellInfo *> cells;
- for (auto cell : sorted(ctx->cells))
- cells.push_back(cell.second);
+ for (auto &cell : ctx->cells)
+ cells.push_back(cell.second.get());
std::vector<CellInfo *> next_cells;
diff --git a/fpga_interchange/main.cc b/fpga_interchange/main.cc
index 4d331a32..1e1ac71f 100644
--- a/fpga_interchange/main.cc
+++ b/fpga_interchange/main.cc
@@ -36,7 +36,7 @@ class FpgaInterchangeCommandHandler : public CommandHandler
public:
FpgaInterchangeCommandHandler(int argc, char **argv);
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 customBitstream(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();
diff --git a/fpga_interchange/pseudo_pip_model.cc b/fpga_interchange/pseudo_pip_model.cc
index 64da4548..2441c8a9 100644
--- a/fpga_interchange/pseudo_pip_model.cc
+++ b/fpga_interchange/pseudo_pip_model.cc
@@ -44,7 +44,7 @@ void PseudoPipData::init_tile_type(const Context *ctx, int32_t tile_type)
max_pseudo_pip_index = pip_idx;
}
- HashTables::HashSet<size_t> sites;
+ pool<size_t> sites;
std::vector<PseudoPipBel> pseudo_pip_bels;
for (int32_t wire_index : pip_data.pseudo_cell_wires) {
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()) {
- 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());
// 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
// active.
- HashTables::HashSet<size_t> active_sites;
+ pool<size_t> active_sites;
for (size_t site = 0; site < sites.size(); ++site) {
if (!sites[site].cells_in_site.empty()) {
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.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) {
if (!active_pseudo_pips.count(pseudo_pip)) {
unused_pseudo_pips.push_back(pseudo_pip);
diff --git a/fpga_interchange/pseudo_pip_model.h b/fpga_interchange/pseudo_pip_model.h
index 1e79071d..b0e28059 100644
--- a/fpga_interchange/pseudo_pip_model.h
+++ b/fpga_interchange/pseudo_pip_model.h
@@ -24,7 +24,6 @@
#include <tuple>
#include "dynamic_bitarray.h"
-#include "hash_table.h"
#include "nextpnr_namespaces.h"
#include "nextpnr_types.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(); }
-};
-
-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;
- }
+ unsigned int hash() const { return mkhash(mkhash(tile_type, pip_index), site); }
};
-}; // namespace std
-
-NEXTPNR_NAMESPACE_BEGIN
-
// Storage for tile type generic pseudo pip data and lookup.
struct PseudoPipData
{
@@ -97,9 +78,9 @@ struct PseudoPipData
// 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;
- HashTables::HashMap<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;
- HashTables::HashMap<LogicBelKey, std::vector<PseudoPipBel>> logic_bels_for_pip;
+ dict<int32_t, size_t> max_pseudo_pip_for_tile_type;
+ dict<std::pair<int32_t, int32_t>, std::vector<size_t>> possibles_sites_for_pip;
+ dict<LogicBelKey, std::vector<PseudoPipBel>> logic_bels_for_pip;
};
// Tile instance fast pseudo pip lookup.
@@ -107,9 +88,9 @@ struct PseudoPipModel
{
int32_t tile;
DynamicBitarray<> allowed_pseudo_pips;
- HashTables::HashMap<int32_t, size_t> pseudo_pip_sites;
- HashTables::HashMap<size_t, std::vector<int32_t>> site_to_pseudo_pips;
- HashTables::HashSet<int32_t> active_pseudo_pips;
+ dict<int32_t, size_t> pseudo_pip_sites;
+ dict<size_t, std::vector<int32_t>> site_to_pseudo_pips;
+ pool<int32_t> active_pseudo_pips;
std::vector<int32_t> scratch;
// Call when a tile is initialized.
diff --git a/fpga_interchange/site_arch.cc b/fpga_interchange/site_arch.cc
index ed2f6c8d..6398d858 100644
--- a/fpga_interchange/site_arch.cc
+++ b/fpga_interchange/site_arch.cc
@@ -24,7 +24,7 @@
NEXTPNR_NAMESPACE_BEGIN
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)
{
}
diff --git a/fpga_interchange/site_arch.h b/fpga_interchange/site_arch.h
index a7da5c68..54b91a4a 100644
--- a/fpga_interchange/site_arch.h
+++ b/fpga_interchange/site_arch.h
@@ -22,13 +22,12 @@
#define SITE_ARCH_H
#include <cstdint>
-#include <unordered_set>
#include <vector>
#include "PhysicalNetlist.capnp.h"
#include "arch_iterators.h"
#include "chipdb.h"
-#include "hash_table.h"
+#include "hashlib.h"
#include "log.h"
#include "nextpnr_namespaces.h"
#include "nextpnr_types.h"
@@ -44,10 +43,10 @@ struct SiteInformation
const int32_t tile;
const int32_t tile_type;
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,
- 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;
@@ -143,6 +142,7 @@ struct SiteWire
WireId wire;
PipId pip;
NetInfo *net = nullptr;
+ unsigned int hash() const { return mkhash(mkhash(int(type), wire.hash()), mkhash(pip.hash(), uintptr_t(net))); }
};
struct SitePip
@@ -214,36 +214,8 @@ struct SitePip
{
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 SitePipUphillRange;
@@ -266,9 +238,9 @@ struct SiteNetInfo
{
NetInfo *net;
SiteWire driver;
- HashTables::HashSet<SiteWire> users;
+ pool<SiteWire> users;
- HashTables::HashMap<SiteWire, SitePipMap> wires;
+ dict<SiteWire, SitePipMap> wires;
};
struct SiteArch
@@ -276,8 +248,8 @@ struct SiteArch
const Context *const ctx;
const SiteInformation *const site_info;
- HashTables::HashMap<NetInfo *, SiteNetInfo> nets;
- HashTables::HashMap<SiteWire, SiteNetMap> wire_to_nets;
+ dict<NetInfo *, SiteNetInfo, hash_ptr_ops> nets;
+ dict<SiteWire, SiteNetMap> wire_to_nets;
NetInfo blocking_net;
SiteNetInfo blocking_site_net;
diff --git a/fpga_interchange/site_router.cc b/fpga_interchange/site_router.cc
index 69bd366f..090b9342 100644
--- a/fpga_interchange/site_router.cc
+++ b/fpga_interchange/site_router.cc
@@ -21,7 +21,6 @@
#include "design_utils.h"
#include "dynamic_bitarray.h"
-#include "hash_table.h"
#include "log.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
// conflicts.
- HashTables::HashMap<WireId, NetInfo *> wires;
+ dict<WireId, NetInfo *> wires;
for (CellInfo *cell : site_info->cells_in_site) {
BelId bel = cell->bel;
@@ -132,7 +131,7 @@ struct SiteExpansionLoop
bool expand_result;
SiteWire net_driver;
- HashTables::HashSet<SiteWire> net_users;
+ pool<SiteWire> net_users;
SiteRoutingSolution solution;
@@ -206,7 +205,7 @@ struct SiteExpansionLoop
auto node = new_node(net->driver, SitePip(), /*parent=*/nullptr);
- HashTables::HashSet<SiteWire> targets;
+ pool<SiteWire> targets;
targets.insert(net->users.begin(), net->users.end());
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.
std::vector<SiteWire> sinks;
- HashTables::HashMap<SiteWire, size_t> sink_map;
+ dict<SiteWire, size_t> sink_map;
size_t number_solutions = 0;
for (const auto *expansion : expansions) {
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,
- HashTables::HashSet<std::pair<IdString, int32_t>, PairHash> &lut_thrus)
+static void apply_routing(Context *ctx, const SiteArch &site_arch, pool<std::pair<IdString, int32_t>> &lut_thrus)
{
IdString gnd_net_name(ctx->chip_info->constants->gnd_net_name);
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,
- HashTables::HashSet<std::pair<IdString, IdString>, PairHash> *blocked_wires)
+static bool map_luts_in_site(const SiteInformation &site_info, pool<std::pair<IdString, IdString>> *blocked_wires)
{
const Context *ctx = site_info.ctx;
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;
}
- HashTables::HashSet<const LutBel *> blocked_luts;
+ pool<const LutBel *, hash_ptr_ops> blocked_luts;
if (!lut_mapper.remap_luts(ctx, &blocked_luts)) {
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.
-static void block_lut_outputs(SiteArch *site_arch,
- const HashTables::HashSet<std::pair<IdString, IdString>, PairHash> &blocked_wires)
+static void block_lut_outputs(SiteArch *site_arch, const pool<std::pair<IdString, IdString>> &blocked_wires)
{
const Context *ctx = site_arch->site_info->ctx;
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);
- 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)) {
site_ok = false;
return site_ok;
@@ -1263,7 +1259,7 @@ void SiteRouter::bindSiteRouting(Context *ctx)
}
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));
SiteArch site_arch(&site_info);
diff --git a/fpga_interchange/site_router.h b/fpga_interchange/site_router.h
index 0328b6b2..ad1cbf66 100644
--- a/fpga_interchange/site_router.h
+++ b/fpga_interchange/site_router.h
@@ -23,6 +23,7 @@
#include <cstdint>
+#include "hashlib.h"
#include "nextpnr_namespaces.h"
#include "nextpnr_types.h"
#include "site_arch.h"
@@ -37,9 +38,9 @@ struct SiteRouter
{
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;
- HashTables::HashSet<std::pair<IdString, int32_t>, PairHash> lut_thrus;
+ pool<std::pair<IdString, int32_t>> lut_thrus;
const int16_t site;
mutable bool dirty;
diff --git a/fpga_interchange/site_routing_cache.cc b/fpga_interchange/site_routing_cache.cc
index e6f4dc70..512ca2ac 100644
--- a/fpga_interchange/site_routing_cache.cc
+++ b/fpga_interchange/site_routing_cache.cc
@@ -70,7 +70,7 @@ void SiteRoutingSolution::store_solution(const SiteArch *ctx, const RouteNodeSto
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) {
SiteWire cursor = solution_sink(i);
NPNR_ASSERT(net.users.count(cursor) == 1);
diff --git a/fpga_interchange/site_routing_cache.h b/fpga_interchange/site_routing_cache.h
index 6ad218c7..b4baf65a 100644
--- a/fpga_interchange/site_routing_cache.h
+++ b/fpga_interchange/site_routing_cache.h
@@ -22,7 +22,6 @@
#define SITE_ROUTING_CACHE_H
#include "PhysicalNetlist.capnp.h"
-#include "hash_table.h"
#include "nextpnr_namespaces.h"
#include "site_arch.h"
#include "site_routing_storage.h"
@@ -97,35 +96,25 @@ struct SiteRoutingKey
}
static SiteRoutingKey make(const SiteArch *ctx, const SiteNetInfo &site_net);
-};
-
-NEXTPNR_NAMESPACE_END
-template <> struct std::hash<NEXTPNR_NAMESPACE_PREFIX SiteRoutingKey>
-{
- std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX SiteRoutingKey &key) const noexcept
+ unsigned int hash() const
{
- std::size_t seed = 0;
- boost::hash_combine(seed, std::hash<int32_t>()(key.tile_type));
- boost::hash_combine(seed, std::hash<int32_t>()(key.site));
- boost::hash_combine(seed, std::hash<PhysicalNetlist::PhysNetlist::NetType>()(key.net_type));
- boost::hash_combine(seed, std::hash<NEXTPNR_NAMESPACE_PREFIX SiteWire::Type>()(key.driver_type));
- boost::hash_combine(seed, std::hash<int32_t>()(key.driver_index));
- boost::hash_combine(seed, std::hash<std::size_t>()(key.user_types.size()));
- for (NEXTPNR_NAMESPACE_PREFIX SiteWire::Type user_type : key.user_types) {
- boost::hash_combine(seed, std::hash<NEXTPNR_NAMESPACE_PREFIX SiteWire::Type>()(user_type));
- }
-
- boost::hash_combine(seed, std::hash<std::size_t>()(key.user_indicies.size()));
- for (int32_t index : key.user_indicies) {
- boost::hash_combine(seed, std::hash<int32_t>()(index));
- }
+ unsigned int seed = 0;
+ seed = mkhash(seed, tile_type);
+ seed = mkhash(seed, site);
+ seed = mkhash(seed, int(net_type));
+ seed = mkhash(seed, int(driver_type));
+ seed = mkhash(seed, driver_index);
+ seed = mkhash(seed, user_types.size());
+ for (auto t : user_types)
+ seed = mkhash(seed, int(t));
+ seed = mkhash(seed, user_indicies.size());
+ for (auto i : user_indicies)
+ seed = mkhash(seed, i);
return seed;
}
};
-NEXTPNR_NAMESPACE_BEGIN
-
// Provides an LRU cache for site routing solutions.
class SiteRoutingCache
{
@@ -134,7 +123,7 @@ class SiteRoutingCache
void add_solutions(const SiteArch *ctx, const SiteNetInfo &net, const SiteRoutingSolution &solution);
private:
- HashTables::HashMap<SiteRoutingKey, SiteRoutingSolution> cache_;
+ dict<SiteRoutingKey, SiteRoutingSolution> cache_;
};
NEXTPNR_NAMESPACE_END
diff --git a/fpga_interchange/type_wire.cc b/fpga_interchange/type_wire.cc
index a08e024b..d1bdaed0 100644
--- a/fpga_interchange/type_wire.cc
+++ b/fpga_interchange/type_wire.cc
@@ -54,10 +54,9 @@ TypeWireSet::TypeWireSet(const Context *ctx, WireId wire)
std::sort(wire_types_.begin(), wire_types_.end());
- hash_ = 0;
- boost::hash_combine(hash_, std::hash<size_t>()(wire_types_.size()));
+ hash_ = wire_types_.size();
for (const auto &wire : wire_types_) {
- boost::hash_combine(hash_, std::hash<NEXTPNR_NAMESPACE_PREFIX TypeWireId>()(wire));
+ hash_ = mkhash(hash_, wire.hash());
}
}
diff --git a/fpga_interchange/type_wire.h b/fpga_interchange/type_wire.h
index f2a675ef..a472bccc 100644
--- a/fpga_interchange/type_wire.h
+++ b/fpga_interchange/type_wire.h
@@ -24,6 +24,7 @@
#include <algorithm>
#include <vector>
+#include "hashlib.h"
#include "nextpnr_namespaces.h"
#include "nextpnr_types.h"
@@ -48,6 +49,8 @@ struct TypeWireId
return type < other.type || (type == other.type && index < other.index);
}
+ unsigned int hash() const { return mkhash(type, index); }
+
int32_t type;
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; }
+
+ unsigned int hash() const { return mkhash(src.hash(), dst.hash()); }
};
struct TypeWireSet
{
public:
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_; }
private:
- std::size_t hash_;
+ unsigned int hash_;
std::vector<TypeWireId> wire_types_;
};
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 */
diff --git a/frontend/frontend_base.h b/frontend/frontend_base.h
index d39a8304..bc85fabb 100644
--- a/frontend/frontend_base.h
+++ b/frontend/frontend_base.h
@@ -118,7 +118,7 @@ struct ModuleInfo
{
bool is_top = false, is_blackbox = false, is_whitebox = false;
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
@@ -134,7 +134,7 @@ template <typename FrontendType> struct GenericFrontend
m.path = top;
ctx->top_module = top;
// 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;
}
@@ -148,8 +148,8 @@ template <typename FrontendType> struct GenericFrontend
using netname_dat_t = typename FrontendType::NetnameDataType;
using bitvector_t = typename FrontendType::BitVectorDataType;
- std::unordered_map<IdString, ModuleInfo> mods;
- std::unordered_map<IdString, const mod_dat_t> mod_refs;
+ dict<IdString, ModuleInfo> mods;
+ std::unordered_map<std::string, const mod_dat_t> mod_refs;
IdString top;
// 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) {
IdString mod_id = ctx->id(name);
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) {
if (name == "top")
mi.is_top = (value.intval != 0);
@@ -196,7 +196,7 @@ template <typename FrontendType> struct GenericFrontend
}
// 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)
- std::unordered_set<IdString> candidate_top;
+ pool<IdString> candidate_top;
for (auto &mod : mods)
if (!mod.second.is_box())
candidate_top.insert(mod.first);
@@ -207,7 +207,7 @@ template <typename FrontendType> struct GenericFrontend
if (candidate_top.size() == 0)
log_info("No candidate top level modules.\n");
else
- for (auto ctp : sorted(candidate_top))
+ for (auto ctp : candidate_top)
log_info("Candidate top module: '%s'\n", ctx->nameOf(ctp));
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);
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
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)));
ci->hierpath = m.path;
// 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; });
// Import port connectivity
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;
// Do the submodule import
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
diff --git a/generic/arch.cc b/generic/arch.cc
index a683e34e..eb43aa6f 100644
--- a/generic/arch.cc
+++ b/generic/arch.cc
@@ -553,8 +553,8 @@ bool Arch::place()
std::string placer = str_or_default(settings, id("placer"), defaultPlacer);
if (placer == "heap") {
bool have_iobuf_or_constr = false;
- for (auto cell : sorted(cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type == id("GENERIC_IOB") || ci->bel != BelId() || ci->attrs.count(id("BEL"))) {
have_iobuf_or_constr = true;
break;
diff --git a/generic/arch.h b/generic/arch.h
index 50d2731c..9b16d873 100644
--- a/generic/arch.h
+++ b/generic/arch.h
@@ -80,7 +80,7 @@ struct BelInfo
IdString type;
std::map<IdString, std::string> attrs;
CellInfo *bound_cell;
- std::unordered_map<IdString, PinInfo> pins;
+ dict<IdString, PinInfo> pins;
DecalXY decalxy;
int x, y, z;
bool gb;
@@ -101,27 +101,14 @@ struct CellDelayKey
{
IdString from, 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
{
- std::unordered_map<IdString, TimingPortClass> portClasses;
- std::unordered_map<CellDelayKey, DelayQuad> combDelays;
- std::unordered_map<IdString, std::vector<TimingClockingInfo>> clockingInfo;
+ dict<IdString, TimingPortClass> portClasses;
+ dict<CellDelayKey, DelayQuad> combDelays;
+ dict<IdString, std::vector<TimingClockingInfo>> clockingInfo;
};
struct ArchRanges
@@ -160,10 +147,10 @@ struct Arch : ArchAPI<ArchRanges>
{
std::string chipName;
- std::unordered_map<IdStringList, WireInfo> wires;
- std::unordered_map<IdStringList, PipInfo> pips;
- std::unordered_map<IdStringList, BelInfo> bels;
- std::unordered_map<GroupId, GroupInfo> groups;
+ dict<IdStringList, WireInfo> wires;
+ dict<IdStringList, PipInfo> pips;
+ dict<IdStringList, BelInfo> bels;
+ dict<GroupId, GroupInfo> groups;
// These functions include useful errors if not found
WireInfo &wire_info(IdStringList wire);
@@ -172,16 +159,16 @@ struct Arch : ArchAPI<ArchRanges>
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::unordered_map<DecalId, std::vector<GraphicElement>> decal_graphics;
+ dict<DecalId, std::vector<GraphicElement>> decal_graphics;
int gridDimX, gridDimY;
std::vector<std::vector<int>> tileBelDimZ;
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 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::unordered_set<IdString> cell_types;
+ pool<IdString> cell_types;
for (auto bel : bels) {
cell_types.insert(bel.second.type);
}
diff --git a/generic/arch_pybindings.cc b/generic/arch_pybindings.cc
index 50544dc1..735c7e41 100644
--- a/generic/arch_pybindings.cc
+++ b/generic/arch_pybindings.cc
@@ -138,9 +138,9 @@ void arch_wrap_python(py::module &m)
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");
- typedef std::unordered_map<IdString, std::unique_ptr<CellInfo>> CellMap;
- typedef std::unordered_map<IdString, std::unique_ptr<NetInfo>> NetMap;
- typedef std::unordered_map<IdString, HierarchicalCell> HierarchyMap;
+ typedef dict<IdString, std::unique_ptr<CellInfo>> CellMap;
+ typedef dict<IdString, std::unique_ptr<NetInfo>> NetMap;
+ typedef dict<IdString, HierarchicalCell> HierarchyMap;
readonly_wrapper<Context, decltype(&Context::cells), &Context::cells, wrap_context<CellMap &>>::def_wrap(ctx_cls,
"cells");
diff --git a/generic/archdefs.h b/generic/archdefs.h
index 0489ab04..06680cc1 100644
--- a/generic/archdefs.h
+++ b/generic/archdefs.h
@@ -20,8 +20,7 @@
#ifndef GENERIC_ARCHDEFS_H
#define GENERIC_ARCHDEFS_H
-#include <unordered_map>
-
+#include "hashlib.h"
#include "idstringlist.h"
NEXTPNR_NAMESPACE_BEGIN
@@ -52,7 +51,7 @@ struct ArchCellInfo
// Only packing rule for slice type primitives is a single clock per tile
const NetInfo *slice_clk;
// Cell to bel pin mapping
- std::unordered_map<IdString, std::vector<IdString>> bel_pins;
+ dict<IdString, std::vector<IdString>> bel_pins;
};
NEXTPNR_NAMESPACE_END
diff --git a/generic/cells.cc b/generic/cells.cc
index c4421f90..e1892353 100644
--- a/generic/cells.cc
+++ b/generic/cells.cc
@@ -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"));
}
-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")) {
iob->params[ctx->id("INPUT_USED")] = 1;
diff --git a/generic/cells.h b/generic/cells.h
index 646d738d..7a8443c5 100644
--- a/generic/cells.h
+++ b/generic/cells.h
@@ -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);
// 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
diff --git a/generic/main.cc b/generic/main.cc
index 784178c6..2352b246 100644
--- a/generic/main.cc
+++ b/generic/main.cc
@@ -32,7 +32,7 @@ class GenericCommandHandler : public CommandHandler
public:
GenericCommandHandler(int argc, char **argv);
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 customBitstream(Context *ctx) override;
@@ -52,7 +52,7 @@ po::options_description GenericCommandHandler::getArchOptions()
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;
if (values.find("arch.name") != values.end()) {
diff --git a/generic/pack.cc b/generic/pack.cc
index 6b984fef..dba86cce 100644
--- a/generic/pack.cc
+++ b/generic/pack.cc
@@ -19,7 +19,6 @@
#include <algorithm>
#include <iterator>
-#include <unordered_set>
#include "cells.h"
#include "design_utils.h"
#include "log.h"
@@ -32,16 +31,17 @@ static void pack_lut_lutffs(Context *ctx)
{
log_info("Packing LUT-FFs..\n");
- std::unordered_set<IdString> packed_cells;
+ pool<IdString> packed_cells;
std::vector<std::unique_ptr<CellInfo>> new_cells;
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ctx->verbose)
log_info("cell '%s' is of type '%s'\n", ci->name.c_str(ctx), ci->type.c_str(ctx));
if (is_lut(ctx, ci)) {
std::unique_ptr<CellInfo> packed =
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);
if (ctx->verbose)
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");
- std::unordered_set<IdString> packed_cells;
+ pool<IdString> packed_cells;
std::vector<std::unique_ptr<CellInfo>> new_cells;
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (is_ff(ctx, ci)) {
std::unique_ptr<CellInfo> packed =
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)
log_info("packed cell %s into %s\n", ci->name.c_str(ctx), packed->name.c_str(ctx));
packed_cells.insert(ci->name);
@@ -158,8 +159,8 @@ static void pack_constants(Context *ctx)
bool gnd_used = false, vcc_used = false;
- for (auto net : sorted(ctx->nets)) {
- NetInfo *ni = net.second;
+ for (auto &net : ctx->nets) {
+ NetInfo *ni = net.second.get();
if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("GND")) {
IdString drv_cell = ni->driver.cell->name;
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
static void pack_io(Context *ctx)
{
- std::unordered_set<IdString> packed_cells;
- std::unordered_set<IdString> delete_nets;
+ pool<IdString> packed_cells;
+ pool<IdString> delete_nets;
std::vector<std::unique_ptr<CellInfo>> new_cells;
log_info("Packing IOs..\n");
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (is_nextpnr_iob(ctx, ci)) {
CellInfo *iob = nullptr;
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);
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) {
diff --git a/gowin/arch.cc b/gowin/arch.cc
index 5e1811ea..85ff4829 100644
--- a/gowin/arch.cc
+++ b/gowin/arch.cc
@@ -1009,8 +1009,8 @@ bool Arch::place()
std::string placer = str_or_default(settings, id("placer"), defaultPlacer);
if (placer == "heap") {
bool have_iobuf_or_constr = false;
- for (auto cell : sorted(cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type == id("IOB") || ci->bel != BelId() || ci->attrs.count(id("BEL"))) {
have_iobuf_or_constr = true;
break;
diff --git a/gowin/arch.h b/gowin/arch.h
index 0f975f77..82fcb8c1 100644
--- a/gowin/arch.h
+++ b/gowin/arch.h
@@ -209,7 +209,7 @@ struct BelInfo
IdString name, type;
std::map<IdString, std::string> attrs;
CellInfo *bound_cell;
- std::unordered_map<IdString, PinInfo> pins;
+ dict<IdString, PinInfo> pins;
DecalXY decalxy;
int x, y, z;
bool gb;
@@ -229,27 +229,14 @@ struct CellDelayKey
{
IdString from, 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
{
- std::unordered_map<IdString, TimingPortClass> portClasses;
- std::unordered_map<CellDelayKey, DelayQuad> combDelays;
- std::unordered_map<IdString, std::vector<TimingClockingInfo>> clockingInfo;
+ dict<IdString, TimingPortClass> portClasses;
+ dict<CellDelayKey, DelayQuad> combDelays;
+ dict<IdString, std::vector<TimingClockingInfo>> clockingInfo;
};
struct ArchRanges : BaseArchRanges
@@ -287,10 +274,10 @@ struct Arch : BaseArch<ArchRanges>
const PackagePOD *package;
const TimingGroupsPOD *speed;
- std::unordered_map<IdString, WireInfo> wires;
- std::unordered_map<IdString, PipInfo> pips;
- std::unordered_map<IdString, BelInfo> bels;
- std::unordered_map<GroupId, GroupInfo> groups;
+ dict<IdString, WireInfo> wires;
+ dict<IdString, PipInfo> pips;
+ dict<IdString, BelInfo> bels;
+ dict<GroupId, GroupInfo> groups;
// These functions include useful errors if not found
WireInfo &wire_info(IdString wire);
@@ -299,16 +286,16 @@ struct Arch : BaseArch<ArchRanges>
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::unordered_map<DecalId, std::vector<GraphicElement>> decal_graphics;
+ dict<DecalId, std::vector<GraphicElement>> decal_graphics;
int gridDimX, gridDimY;
std::vector<std::vector<int>> tileBelDimZ;
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 addPip(IdString name, IdString type, IdString srcWire, IdString dstWire, DelayQuad delay, Loc loc);
diff --git a/gowin/arch_pybindings.cc b/gowin/arch_pybindings.cc
index 24a55ac7..58dcbae7 100644
--- a/gowin/arch_pybindings.cc
+++ b/gowin/arch_pybindings.cc
@@ -137,9 +137,9 @@ void arch_wrap_python(py::module &m)
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");
- typedef std::unordered_map<IdString, std::unique_ptr<CellInfo>> CellMap;
- typedef std::unordered_map<IdString, std::unique_ptr<NetInfo>> NetMap;
- typedef std::unordered_map<IdString, HierarchicalCell> HierarchyMap;
+ typedef dict<IdString, std::unique_ptr<CellInfo>> CellMap;
+ typedef dict<IdString, std::unique_ptr<NetInfo>> NetMap;
+ typedef dict<IdString, HierarchicalCell> HierarchyMap;
readonly_wrapper<Context, decltype(&Context::cells), &Context::cells, wrap_context<CellMap &>>::def_wrap(ctx_cls,
"cells");
diff --git a/gowin/cells.cc b/gowin/cells.cc
index e45cd482..93f1246f 100644
--- a/gowin/cells.cc
+++ b/gowin/cells.cc
@@ -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);
}
-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) {
iob->params[id_INPUT_USED] = 1;
diff --git a/gowin/cells.h b/gowin/cells.h
index 30b29f5b..7bf1befd 100644
--- a/gowin/cells.h
+++ b/gowin/cells.h
@@ -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);
// 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
diff --git a/gowin/main.cc b/gowin/main.cc
index 674eac03..0f3a61cb 100644
--- a/gowin/main.cc
+++ b/gowin/main.cc
@@ -34,7 +34,7 @@ class GowinCommandHandler : public CommandHandler
public:
GowinCommandHandler(int argc, char **argv);
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 customAfterLoad(Context *ctx) override;
@@ -52,7 +52,7 @@ po::options_description GowinCommandHandler::getArchOptions()
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::smatch match;
diff --git a/gowin/pack.cc b/gowin/pack.cc
index 204f1c22..d3a749ea 100644
--- a/gowin/pack.cc
+++ b/gowin/pack.cc
@@ -21,7 +21,6 @@
#include <algorithm>
#include <iostream>
#include <iterator>
-#include <unordered_set>
#include "cells.h"
#include "design_utils.h"
#include "log.h"
@@ -34,15 +33,16 @@ static void pack_lut_lutffs(Context *ctx)
{
log_info("Packing LUT-FFs..\n");
- std::unordered_set<IdString> packed_cells;
+ pool<IdString> packed_cells;
std::vector<std::unique_ptr<CellInfo>> new_cells;
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ctx->verbose)
log_info("cell '%s' is of type '%s'\n", ctx->nameOf(ci), ci->type.c_str(ctx));
if (is_lut(ctx, ci)) {
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);
if (ctx->verbose)
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");
- std::unordered_set<IdString> packed_cells;
+ pool<IdString> packed_cells;
std::vector<std::unique_ptr<CellInfo>> new_cells;
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (is_ff(ctx, ci)) {
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)
log_info("packed cell %s into %s\n", ctx->nameOf(ci), ctx->nameOf(packed.get()));
packed_cells.insert(ci->name);
@@ -158,8 +159,8 @@ static void pack_constants(Context *ctx)
bool gnd_used = false;
- for (auto net : sorted(ctx->nets)) {
- NetInfo *ni = net.second;
+ for (auto &net : ctx->nets) {
+ NetInfo *ni = net.second.get();
if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("GND")) {
IdString drv_cell = ni->driver.cell->name;
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
static void pack_io(Context *ctx)
{
- std::unordered_set<IdString> packed_cells;
- std::unordered_set<IdString> delete_nets;
+ pool<IdString> packed_cells;
+ pool<IdString> delete_nets;
std::vector<std::unique_ptr<CellInfo>> new_cells;
log_info("Packing IOs..\n");
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (is_gowin_iob(ctx, ci)) {
CellInfo *iob = nullptr;
switch (ci->type.index) {
@@ -251,7 +252,8 @@ static void pack_io(Context *ctx)
packed_cells.insert(ci->name);
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) {
diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt
index 21d0c1e0..1deffcfb 100644
--- a/gui/CMakeLists.txt
+++ b/gui/CMakeLists.txt
@@ -40,10 +40,6 @@ endif()
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)
foreach(lib_dep ${EXTRA_LIB_DEPS})
diff --git a/gui/treemodel.cc b/gui/treemodel.cc
index cc563202..b0dc51db 100644
--- a/gui/treemodel.cc
+++ b/gui/treemodel.cc
@@ -58,7 +58,7 @@ void IdList::updateElements(Context *ctx, std::vector<IdStringList> elements)
bool changed = false;
// 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) {
element_set.insert(elem);
auto existing = managed_.find(elem);
diff --git a/gui/treemodel.h b/gui/treemodel.h
index e9c42a0f..e2692f3e 100644
--- a/gui/treemodel.h
+++ b/gui/treemodel.h
@@ -140,7 +140,7 @@ class IdList : public Item
private:
// Children that we manage the memory for, stored for quick lookup from
// 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.
ElementType child_type_;
@@ -184,7 +184,7 @@ template <typename ElementT> class ElementList : public Item
ElementGetter getter_;
// Children that we manage the memory for, stored for quick lookup from
// 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.
ElementType child_type_;
diff --git a/ice40/arch.h b/ice40/arch.h
index 29396f49..9c9a118f 100644
--- a/ice40/arch.h
+++ b/ice40/arch.h
@@ -400,10 +400,10 @@ struct Arch : BaseArch<ArchRanges>
const ChipInfoPOD *chip_info;
const PackageInfoPOD *package_info;
- mutable std::unordered_map<IdStringList, int> bel_by_name;
- mutable std::unordered_map<IdStringList, int> wire_by_name;
- mutable std::unordered_map<IdStringList, int> pip_by_name;
- mutable std::unordered_map<Loc, int> bel_by_loc;
+ mutable dict<IdStringList, int> bel_by_name;
+ mutable dict<IdStringList, int> wire_by_name;
+ mutable dict<IdStringList, int> pip_by_name;
+ mutable dict<Loc, int> bel_by_loc;
std::vector<bool> bel_carry;
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
std::vector<IdString> x_ids, y_ids;
// 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;
Arch(ArchArgs args);
diff --git a/ice40/arch_pybindings.cc b/ice40/arch_pybindings.cc
index 6922887d..41c97b1b 100644
--- a/ice40/arch_pybindings.cc
+++ b/ice40/arch_pybindings.cc
@@ -60,10 +60,10 @@ void arch_wrap_python(py::module &m)
.def("place", &Context::place)
.def("route", &Context::route);
- typedef std::unordered_map<IdString, std::unique_ptr<CellInfo>> CellMap;
- typedef std::unordered_map<IdString, std::unique_ptr<NetInfo>> NetMap;
- typedef std::unordered_map<IdString, IdString> AliasMap;
- typedef std::unordered_map<IdString, HierarchicalCell> HierarchyMap;
+ typedef dict<IdString, std::unique_ptr<CellInfo>> CellMap;
+ typedef dict<IdString, std::unique_ptr<NetInfo>> NetMap;
+ typedef dict<IdString, IdString> AliasMap;
+ typedef dict<IdString, HierarchicalCell> HierarchyMap;
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");
diff --git a/ice40/archdefs.h b/ice40/archdefs.h
index c2b7019c..6ef5432f 100644
--- a/ice40/archdefs.h
+++ b/ice40/archdefs.h
@@ -20,9 +20,8 @@
#ifndef ICE40_ARCHDEFS_H
#define ICE40_ARCHDEFS_H
-#include <boost/functional/hash.hpp>
-
#include "base_clusterinfo.h"
+#include "hashlib.h"
#include "idstring.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; }
+ unsigned int hash() const { return index; }
};
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; }
+ unsigned int hash() const { return index; }
};
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; }
+ unsigned int hash() const { return index; }
};
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); }
+ unsigned int hash() const { return mkhash(mkhash(x, y), int(type)); }
};
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); }
+ unsigned int hash() const { return mkhash(index, int(type)); }
};
struct ArchNetInfo
@@ -159,48 +163,4 @@ typedef IdString ClusterId;
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 */
diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc
index 6b625b6a..56b5561c 100644
--- a/ice40/bitstream.cc
+++ b/ice40/bitstream.cc
@@ -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)
-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;
@@ -387,8 +387,8 @@ void write_asc(const Context *ctx, std::ostream &out)
}
// Scan for PLL and collects the affected SB_IOs
- std::unordered_set<Loc> sb_io_used_by_pll_out;
- std::unordered_set<Loc> sb_io_used_by_pll_pad;
+ pool<Loc> sb_io_used_by_pll_out;
+ pool<Loc> sb_io_used_by_pll_pad;
for (auto &cell : ctx->cells) {
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);
// Discover permutation
- std::unordered_map<int, int> input_perm;
+ dict<int, int> input_perm;
std::set<int> unused;
for (int i = 0; i < 4; i++)
unused.insert(i);
diff --git a/ice40/cells.cc b/ice40/cells.cc
index d23b6c49..9517c590 100644
--- a/ice40/cells.cc
+++ b/ice40/cells.cc
@@ -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"));
}
-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")) {
sbio->params[ctx->id("PIN_TYPE")] = 1;
diff --git a/ice40/cells.h b/ice40/cells.h
index 777ca3e2..d4c0edf4 100644
--- a/ice40/cells.h
+++ b/ice40/cells.h
@@ -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);
// 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
bool is_clock_port(const BaseCtx *ctx, const PortRef &port);
diff --git a/ice40/chains.cc b/ice40/chains.cc
index 2607959a..cfc8b4a1 100644
--- a/ice40/chains.cc
+++ b/ice40/chains.cc
@@ -253,15 +253,15 @@ class ChainConstrainer
return i3_next;
return (CellInfo *)nullptr;
});
- std::unordered_set<IdString> chained;
+ pool<IdString> chained;
for (auto &base_chain : carry_chains) {
for (auto c : base_chain.cells)
chained.insert(c->name);
}
// Any cells not in chains, but with carry enabled, must also be put in a single-carry chain
// for correct processing
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (chained.find(cell.first) == chained.end() && is_lc(ctx, ci) &&
bool_or_default(ci->params, ctx->id("CARRY_ENABLE"))) {
CellChain sChain;
diff --git a/ice40/delay.cc b/ice40/delay.cc
index a3469876..0bcab160 100644
--- a/ice40/delay.cc
+++ b/ice40/delay.cc
@@ -62,7 +62,7 @@ void ice40DelayFuzzerMain(Context *ctx)
WireId src = srcWires[index];
WireId dst = dstWires[index++];
- std::unordered_map<WireId, PipId> route;
+ dict<WireId, PipId> route;
#if NUM_FUZZ_ROUTES <= 1000
if (!ctx->getActualRouteDelay(src, dst, nullptr, &route, false))
diff --git a/ice40/main.cc b/ice40/main.cc
index e537c2f4..28e6de9a 100644
--- a/ice40/main.cc
+++ b/ice40/main.cc
@@ -35,7 +35,7 @@ class Ice40CommandHandler : public CommandHandler
public:
Ice40CommandHandler(int argc, char **argv);
virtual ~Ice40CommandHandler(){};
- 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 validate() override;
void customAfterLoad(Context *ctx) override;
@@ -129,7 +129,7 @@ void Ice40CommandHandler::setupArchContext(Context *ctx)
}
}
-std::unique_ptr<Context> Ice40CommandHandler::createContext(std::unordered_map<std::string, Property> &values)
+std::unique_ptr<Context> Ice40CommandHandler::createContext(dict<std::string, Property> &values)
{
ArchArgs chipArgs;
chipArgs.type = ArchArgs::NONE;
diff --git a/ice40/pack.cc b/ice40/pack.cc
index 51138a22..62b08534 100644
--- a/ice40/pack.cc
+++ b/ice40/pack.cc
@@ -21,7 +21,6 @@
#include <algorithm>
#include <iterator>
-#include <unordered_set>
#include "cells.h"
#include "chains.h"
#include "design_utils.h"
@@ -35,15 +34,16 @@ static void pack_lut_lutffs(Context *ctx)
{
log_info("Packing LUT-FFs..\n");
int lut_only = 0, lut_and_ff = 0;
- std::unordered_set<IdString> packed_cells;
+ pool<IdString> packed_cells;
std::vector<std::unique_ptr<CellInfo>> new_cells;
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ctx->verbose)
log_info("cell '%s' is of type '%s'\n", ci->name.c_str(ctx), ci->type.c_str(ctx));
if (is_lut(ctx, ci)) {
std::unique_ptr<CellInfo> packed = create_ice_cell(ctx, ctx->id("ICESTORM_LC"), 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);
if (ctx->verbose)
log_info("packed cell %s into %s\n", ci->name.c_str(ctx), packed->name.c_str(ctx));
@@ -99,16 +99,17 @@ static void pack_nonlut_ffs(Context *ctx)
{
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;
int ff_only = 0;
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (is_ff(ctx, ci)) {
std::unique_ptr<CellInfo> packed =
create_ice_cell(ctx, ctx->id("ICESTORM_LC"), 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)
log_info("packed cell %s into %s\n", ci->name.c_str(ctx), packed->name.c_str(ctx));
packed_cells.insert(ci->name);
@@ -142,13 +143,13 @@ static bool net_is_constant(const Context *ctx, NetInfo *net, bool &value)
static void pack_carries(Context *ctx)
{
log_info("Packing carries..\n");
- std::unordered_set<IdString> exhausted_cells;
- std::unordered_set<IdString> packed_cells;
+ pool<IdString> exhausted_cells;
+ pool<IdString> packed_cells;
std::vector<std::unique_ptr<CellInfo>> new_cells;
int carry_only = 0;
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (is_carry(ctx, ci)) {
packed_cells.insert(cell.first);
@@ -272,11 +273,11 @@ static void pack_ram(Context *ctx)
{
log_info("Packing RAMs..\n");
- std::unordered_set<IdString> packed_cells;
+ pool<IdString> packed_cells;
std::vector<std::unique_ptr<CellInfo>> new_cells;
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (is_ram(ctx, ci)) {
std::unique_ptr<CellInfo> packed =
create_ice_cell(ctx, ctx->id("ICESTORM_RAM"), ci->name.str(ctx) + "_RAM");
@@ -379,8 +380,8 @@ static void pack_constants(Context *ctx)
bool gnd_used = false;
- for (auto net : sorted(ctx->nets)) {
- NetInfo *ni = net.second;
+ for (auto &net : ctx->nets) {
+ NetInfo *ni = net.second.get();
if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("GND")) {
IdString drv_cell = ni->driver.cell->name;
set_net_constant(ctx, ni, gnd_net_info, false);
@@ -464,13 +465,13 @@ static bool is_ice_iob(const Context *ctx, const CellInfo *cell)
// Pack IO buffers
static void pack_io(Context *ctx)
{
- std::unordered_set<IdString> packed_cells;
- std::unordered_set<IdString> delete_nets;
+ pool<IdString> packed_cells;
+ pool<IdString> delete_nets;
std::vector<std::unique_ptr<CellInfo>> new_cells;
log_info("Packing IOs..\n");
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (is_nextpnr_iob(ctx, ci)) {
CellInfo *sb = nullptr, *rgb = nullptr;
if (ci->type == ctx->id("$nextpnr_ibuf") || ci->type == ctx->id("$nextpnr_iobuf")) {
@@ -531,7 +532,8 @@ static void pack_io(Context *ctx)
for (auto port : ci->ports)
disconnect_port(ctx, ci, port.first);
packed_cells.insert(ci->name);
- std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(sb->attrs, sb->attrs.begin()));
+ for (auto &attr : ci->attrs)
+ sb->attrs[attr.first] = attr.second;
} else if (is_sb_io(ctx, ci) || is_sb_gb_io(ctx, ci)) {
NetInfo *net = ci->ports.at(ctx->id("PACKAGE_PIN")).net;
if ((net != nullptr) && ((net->users.size() > 2) ||
@@ -541,8 +543,8 @@ static void pack_io(Context *ctx)
ci->name.c_str(ctx));
}
}
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (is_sb_gb_io(ctx, ci)) {
// If something is connecto the GLOBAL OUTPUT, create the fake 'matching' SB_GB
std::unique_ptr<CellInfo> gb =
@@ -637,8 +639,8 @@ static void promote_globals(Context *ctx)
const int enable_fanout_thresh = 15;
const int reset_fanout_thresh = 15;
std::map<IdString, int> clock_count, reset_count, cen_count, logic_count;
- for (auto net : sorted(ctx->nets)) {
- NetInfo *ni = net.second;
+ for (auto &net : ctx->nets) {
+ NetInfo *ni = net.second.get();
if (ni->driver.cell != nullptr && !ctx->is_global_net(ni)) {
clock_count[net.first] = 0;
reset_count[net.first] = 0;
@@ -778,8 +780,8 @@ static void place_plls(Context *ctx)
}
// Find all the PLLs cells we need to place and do pre-checks
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (!is_sb_pll40(ctx, ci))
continue;
@@ -861,8 +863,8 @@ static void place_plls(Context *ctx)
}
// Scan all SB_IOs to check for conflict with PLL BELs
- for (auto io_cell : sorted(ctx->cells)) {
- CellInfo *io_ci = io_cell.second;
+ for (auto &io_cell : ctx->cells) {
+ CellInfo *io_ci = io_cell.second.get();
if (!is_sb_io(ctx, io_ci))
continue;
@@ -899,8 +901,8 @@ static void place_plls(Context *ctx)
}
// Scan all SB_GBs to check for conflicts with PLL BELs
- for (auto gb_cell : sorted(ctx->cells)) {
- CellInfo *gb_ci = gb_cell.second;
+ for (auto &gb_cell : ctx->cells) {
+ CellInfo *gb_ci = gb_cell.second.get();
if (!is_gbuf(ctx, gb_ci))
continue;
@@ -1116,12 +1118,12 @@ static void pack_special(Context *ctx)
{
log_info("Packing special functions..\n");
- std::unordered_set<IdString> packed_cells;
+ pool<IdString> packed_cells;
std::vector<std::unique_ptr<CellInfo>> new_cells;
// Handle LED_DRV_CUR first to set the ledCurConnected flag before RGB_DRV is handled below.
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (is_sb_led_drv_cur(ctx, ci)) {
/* Force placement (no choices anyway) */
cell_place_unique(ctx, ci);
@@ -1139,8 +1141,8 @@ static void pack_special(Context *ctx)
ctx->nets.erase(ledpu_net->name);
}
}
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (is_sb_lfosc(ctx, ci)) {
std::unique_ptr<CellInfo> packed =
create_ice_cell(ctx, ctx->id("ICESTORM_LFOSC"), ci->name.str(ctx) + "_OSC");
@@ -1296,10 +1298,10 @@ void pack_plls(Context *ctx)
{
log_info("Packing PLLs..\n");
- std::unordered_set<IdString> packed_cells;
+ pool<IdString> packed_cells;
std::vector<std::unique_ptr<CellInfo>> new_cells;
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (is_sb_pll40(ctx, ci)) {
bool is_pad = is_sb_pll40_pad(ctx, ci);
bool is_core = !is_pad;
diff --git a/ice40/pcf.cc b/ice40/pcf.cc
index 56a4a336..c6289892 100644
--- a/ice40/pcf.cc
+++ b/ice40/pcf.cc
@@ -108,8 +108,8 @@ bool apply_pcf(Context *ctx, std::string filename, std::istream &in)
log_error("unsupported PCF command '%s' (on line %d)\n", cmd.c_str(), lineno);
}
}
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type == ctx->id("$nextpnr_ibuf") || ci->type == ctx->id("$nextpnr_obuf") ||
ci->type == ctx->id("$nextpnr_iobuf")) {
if (!ci->attrs.count(ctx->id("BEL"))) {
diff --git a/json/jsonwrite.cc b/json/jsonwrite.cc
index f92b7038..88d66519 100644
--- a/json/jsonwrite.cc
+++ b/json/jsonwrite.cc
@@ -45,7 +45,7 @@ std::string get_string(std::string str)
std::string get_name(IdString name, Context *ctx) { return get_string(name.c_str(ctx)); }
-void write_parameters(std::ostream &f, Context *ctx, const std::unordered_map<IdString, Property> &parameters,
+void write_parameters(std::ostream &f, Context *ctx, const dict<IdString, Property> &parameters,
bool for_module = false)
{
bool first = true;
@@ -64,11 +64,10 @@ struct PortGroup
PortType dir;
};
-std::vector<PortGroup> group_ports(Context *ctx, const std::unordered_map<IdString, PortInfo> &ports,
- bool is_cell = false)
+std::vector<PortGroup> group_ports(Context *ctx, const dict<IdString, PortInfo> &ports, bool is_cell = false)
{
std::vector<PortGroup> groups;
- std::unordered_map<std::string, size_t> base_to_group;
+ dict<std::string, size_t> base_to_group;
for (auto &pair : ports) {
std::string name = pair.second.name.str(ctx);
if ((name.back() != ']') || (name.find('[') == std::string::npos)) {
diff --git a/machxo2/arch.h b/machxo2/arch.h
index 15535fe1..219e87f2 100644
--- a/machxo2/arch.h
+++ b/machxo2/arch.h
@@ -403,12 +403,12 @@ struct Arch : BaseArch<ArchRanges>
const ChipInfoPOD *chip_info;
const PackageInfoPOD *package_info;
- mutable std::unordered_map<IdStringList, PipId> pip_by_name;
+ mutable dict<IdStringList, PipId> pip_by_name;
// fast access to X and Y IdStrings for building object names
std::vector<IdString> x_ids, y_ids;
// inverse of the above for name->object mapping
- std::unordered_map<IdString, int> id_to_x, id_to_y;
+ dict<IdString, int> id_to_x, id_to_y;
// Helpers
template <typename Id> const TileTypePOD *tile_info(Id &id) const
diff --git a/machxo2/arch_pybindings.cc b/machxo2/arch_pybindings.cc
index 07e25437..aaca813a 100644
--- a/machxo2/arch_pybindings.cc
+++ b/machxo2/arch_pybindings.cc
@@ -45,10 +45,10 @@ void arch_wrap_python(py::module &m)
.def("place", &Context::place)
.def("route", &Context::route);
- typedef std::unordered_map<IdString, std::unique_ptr<CellInfo>> CellMap;
- typedef std::unordered_map<IdString, std::unique_ptr<NetInfo>> NetMap;
- typedef std::unordered_map<IdString, IdString> AliasMap;
- typedef std::unordered_map<IdString, HierarchicalCell> HierarchyMap;
+ typedef dict<IdString, std::unique_ptr<CellInfo>> CellMap;
+ typedef dict<IdString, std::unique_ptr<NetInfo>> NetMap;
+ typedef dict<IdString, IdString> AliasMap;
+ typedef dict<IdString, HierarchicalCell> HierarchyMap;
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");
diff --git a/machxo2/archdefs.h b/machxo2/archdefs.h
index 2d50dddb..de633673 100644
--- a/machxo2/archdefs.h
+++ b/machxo2/archdefs.h
@@ -22,6 +22,7 @@
#define MACHXO2_ARCHDEFS_H
#include "base_clusterinfo.h"
+#include "hashlib.h"
#include "idstring.h"
#include "nextpnr_namespaces.h"
@@ -59,6 +60,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 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); }
@@ -74,6 +76,7 @@ struct BelId
{
return location == other.location ? index < other.index : location < other.location;
}
+ unsigned int hash() const { return mkhash(location.hash(), index); }
};
struct WireId
@@ -87,6 +90,7 @@ struct WireId
{
return location == other.location ? index < other.index : location < other.location;
}
+ unsigned int hash() const { return mkhash(location.hash(), index); }
};
struct PipId
@@ -100,6 +104,7 @@ struct PipId
{
return location == other.location ? index < other.index : location < other.location;
}
+ unsigned int hash() const { return mkhash(location.hash(), index); }
};
typedef IdString GroupId;
@@ -119,47 +124,4 @@ struct ArchCellInfo : BaseClusterInfo
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;
- }
-};
-
-} // namespace std
-
#endif /* MACHXO2_ARCHDEFS_H */
diff --git a/machxo2/bitstream.cc b/machxo2/bitstream.cc
index d695b094..8c538bae 100644
--- a/machxo2/bitstream.cc
+++ b/machxo2/bitstream.cc
@@ -114,8 +114,7 @@ static std::vector<bool> int_to_bitvector(int val, int size)
return bv;
}
-std::string intstr_or_default(const std::unordered_map<IdString, Property> &ct, const IdString &key,
- std::string def = "0")
+std::string intstr_or_default(const dict<IdString, Property> &ct, const IdString &key, std::string def = "0")
{
auto found = ct.find(key);
if (found == ct.end())
diff --git a/machxo2/cells.cc b/machxo2/cells.cc
index 03ba0a41..c71247f2 100644
--- a/machxo2/cells.cc
+++ b/machxo2/cells.cc
@@ -175,6 +175,6 @@ void dff_to_lc(Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut)
}
}
-void nxio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *iob, std::unordered_set<IdString> &todelete_cells) {}
+void nxio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *iob, pool<IdString> &todelete_cells) {}
NEXTPNR_NAMESPACE_END
diff --git a/machxo2/cells.h b/machxo2/cells.h
index a6de219e..afb08138 100644
--- a/machxo2/cells.h
+++ b/machxo2/cells.h
@@ -49,7 +49,7 @@ void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff = tr
void dff_to_lc(Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut = false);
// 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
diff --git a/machxo2/main.cc b/machxo2/main.cc
index 961fe9ae..1dfee16a 100644
--- a/machxo2/main.cc
+++ b/machxo2/main.cc
@@ -34,7 +34,7 @@ class MachXO2CommandHandler : public CommandHandler
public:
MachXO2CommandHandler(int argc, char **argv);
virtual ~MachXO2CommandHandler(){};
- 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 customBitstream(Context *ctx) override;
@@ -82,7 +82,7 @@ void MachXO2CommandHandler::customBitstream(Context *ctx)
write_bitstream(ctx, textcfg);
}
-std::unique_ptr<Context> MachXO2CommandHandler::createContext(std::unordered_map<std::string, Property> &values)
+std::unique_ptr<Context> MachXO2CommandHandler::createContext(dict<std::string, Property> &values)
{
ArchArgs chipArgs;
chipArgs.type = ArchArgs::NONE;
diff --git a/machxo2/pack.cc b/machxo2/pack.cc
index 5a6cd97b..6f2ee8e4 100644
--- a/machxo2/pack.cc
+++ b/machxo2/pack.cc
@@ -20,7 +20,6 @@
#include <algorithm>
#include <iterator>
-#include <unordered_set>
#include "cells.h"
#include "design_utils.h"
#include "log.h"
@@ -33,15 +32,16 @@ static void pack_lut_lutffs(Context *ctx)
{
log_info("Packing LUT-FFs..\n");
- std::unordered_set<IdString> packed_cells;
+ pool<IdString> packed_cells;
std::vector<std::unique_ptr<CellInfo>> new_cells;
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ctx->verbose)
log_info("cell '%s' is of type '%s'\n", ci->name.c_str(ctx), ci->type.c_str(ctx));
if (is_lut(ctx, ci)) {
std::unique_ptr<CellInfo> packed = create_machxo2_cell(ctx, id_FACADE_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);
if (ctx->verbose)
@@ -90,18 +90,19 @@ static void pack_remaining_ffs(Context *ctx)
{
log_info("Packing remaining FFs..\n");
- std::unordered_set<IdString> packed_cells;
+ pool<IdString> packed_cells;
std::vector<std::unique_ptr<CellInfo>> new_cells;
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (is_ff(ctx, ci)) {
if (ctx->verbose)
log_info("cell '%s' of type '%s remains unpacked'\n", ci->name.c_str(ctx), ci->type.c_str(ctx));
std::unique_ptr<CellInfo> packed = create_machxo2_cell(ctx, id_FACADE_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;
auto dff_bel = ci->attrs.find(ctx->id("BEL"));
dff_to_lc(ctx, ci, packed.get(), false);
@@ -128,7 +129,7 @@ static void set_net_constant(Context *ctx, NetInfo *orig, NetInfo *constnet, boo
{
(void)constval;
- std::unordered_set<IdString> packed_cells;
+ pool<IdString> packed_cells;
std::vector<std::unique_ptr<CellInfo>> new_cells;
orig->driver.cell = nullptr;
@@ -142,7 +143,8 @@ static void set_net_constant(Context *ctx, NetInfo *orig, NetInfo *constnet, boo
log_info("FACADE_FF %s is driven by a constant\n", uc->name.c_str(ctx));
std::unique_ptr<CellInfo> lc = create_machxo2_cell(ctx, id_FACADE_SLICE, uc->name.str(ctx) + "_CONST");
- std::copy(uc->attrs.begin(), uc->attrs.end(), std::inserter(lc->attrs, lc->attrs.begin()));
+ for (auto &attr : uc->attrs)
+ lc->attrs[attr.first] = attr.second;
dff_to_lc(ctx, uc, lc.get(), true);
packed_cells.insert(uc->name);
@@ -193,8 +195,8 @@ static void pack_constants(Context *ctx)
std::vector<IdString> dead_nets;
- for (auto net : sorted(ctx->nets)) {
- NetInfo *ni = net.second;
+ for (auto &net : ctx->nets) {
+ NetInfo *ni = net.second.get();
if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("GND")) {
IdString drv_cell = ni->driver.cell->name;
set_net_constant(ctx, ni, gnd_net.get(), false);
@@ -230,12 +232,12 @@ static bool is_facade_iob(const Context *ctx, const CellInfo *cell) { return cel
// attributes.
static void pack_io(Context *ctx)
{
- std::unordered_set<IdString> packed_cells;
+ pool<IdString> packed_cells;
log_info("Packing IOs..\n");
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (is_nextpnr_iob(ctx, ci)) {
for (auto &p : ci->ports)
disconnect_port(ctx, ci, p.first);
diff --git a/mistral/arch.cc b/mistral/arch.cc
index cfa3e8b3..70e8f806 100644
--- a/mistral/arch.cc
+++ b/mistral/arch.cc
@@ -375,8 +375,8 @@ void Arch::assign_default_pinmap(CellInfo *cell)
void Arch::assignArchInfo()
{
- for (auto cell : sorted(cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : cells) {
+ CellInfo *ci = cell.second.get();
if (is_comb_cell(ci->type))
assign_comb_info(ci);
else if (ci->type == id_MISTRAL_FF)
diff --git a/mistral/arch.h b/mistral/arch.h
index ee2c84a3..1a42530a 100644
--- a/mistral/arch.h
+++ b/mistral/arch.h
@@ -85,7 +85,7 @@ struct BelInfo
// For cases where we need to determine an original block index, due to multiple bels at the same tile this
// might not be the same as the nextpnr z-coordinate
int block_index;
- std::unordered_map<IdString, PinInfo> pins;
+ dict<IdString, PinInfo> pins;
// Info for different kinds of bels
union
{
@@ -153,7 +153,7 @@ struct UpDownhillPipRange
UpDownhillPipIterator b, e;
UpDownhillPipRange(const std::vector<WireId> &v, WireId other_wire, bool is_uphill)
- : b(v.cbegin(), other_wire, is_uphill), e(v.cend(), other_wire, is_uphill){};
+ : b(v.begin(), other_wire, is_uphill), e(v.end(), other_wire, is_uphill){};
UpDownhillPipIterator begin() const { return b; }
UpDownhillPipIterator end() const { return e; }
@@ -161,7 +161,7 @@ struct UpDownhillPipRange
// This iterates over the list of wires, and for each wire yields its uphill pips, as an efficient way of going over
// all the pips in the device
-using WireMapIterator = std::unordered_map<WireId, WireInfo>::const_iterator;
+using WireMapIterator = dict<WireId, WireInfo>::const_iterator;
struct AllPipIterator
{
WireMapIterator base, end;
@@ -196,8 +196,7 @@ struct AllPipRange
{
AllPipIterator b, e;
- AllPipRange(const std::unordered_map<WireId, WireInfo> &wires)
- : b(wires.cbegin(), wires.cend(), -1), e(wires.cend(), wires.cend(), 0)
+ AllPipRange(const dict<WireId, WireInfo> &wires) : b(wires.begin(), wires.end(), -1), e(wires.end(), wires.end(), 0)
{
// Starting the begin iterator at index -1 and incrementing it ensures we skip over the first wire if it has no
// uphill pips
@@ -211,7 +210,7 @@ struct AllPipRange
// This transforms a map to a range of keys, used as the wire iterator
template <typename T> struct key_range
{
- key_range(const T &t) : b(t.cbegin()), e(t.cend()){};
+ key_range(const T &t) : b(t.begin()), e(t.end()){};
typename T::const_iterator b, e;
struct xformed_iterator : public T::const_iterator
@@ -224,7 +223,7 @@ template <typename T> struct key_range
xformed_iterator end() const { return xformed_iterator(e); }
};
-using AllWireRange = key_range<std::unordered_map<WireId, WireInfo>>;
+using AllWireRange = key_range<dict<WireId, WireInfo>>;
struct ArchRanges : BaseArchRanges
{
@@ -489,7 +488,7 @@ struct Arch : BaseArch<ArchRanges>
static const std::string defaultRouter;
static const std::vector<std::string> availableRouters;
- std::unordered_map<WireId, WireInfo> wires;
+ dict<WireId, WireInfo> wires;
// List of LABs
std::vector<LABInfo> labs;
@@ -499,13 +498,13 @@ struct Arch : BaseArch<ArchRanges>
// Conversion between numbers and rnode types and IdString, for fast wire name implementation
std::vector<IdString> int2id;
- std::unordered_map<IdString, int> id2int;
+ dict<IdString, int> id2int;
std::vector<IdString> rn_t2id;
- std::unordered_map<IdString, CycloneV::rnode_type_t> id2rn_t;
+ dict<IdString, CycloneV::rnode_type_t> id2rn_t;
// This structure is only used for nextpnr-created wires
- std::unordered_map<IdStringList, WireId> npnr_wirebyname;
+ dict<IdStringList, WireId> npnr_wirebyname;
std::vector<std::vector<BelInfo>> bels_by_tile;
std::vector<BelId> all_bels;
@@ -525,18 +524,18 @@ struct Arch : BaseArch<ArchRanges>
// -------------------------------------------------
void assign_default_pinmap(CellInfo *cell);
- static const std::unordered_map<IdString, IdString> comb_pinmap;
+ static const dict<IdString, IdString> comb_pinmap;
// -------------------------------------------------
- typedef std::unordered_map<IdString, CellPinStyle> CellPinsData; // pins.cc
- static const std::unordered_map<IdString, CellPinsData> cell_pins_db; // pins.cc
+ typedef dict<IdString, CellPinStyle> CellPinsData; // pins.cc
+ static const dict<IdString, CellPinsData> cell_pins_db; // pins.cc
CellPinStyle get_cell_pin_style(const CellInfo *cell, IdString port) const; // pins.cc
// -------------------------------------------------
// List of IO constraints, used by QSF parser
- std::unordered_map<IdString, std::unordered_map<IdString, Property>> io_attr;
+ dict<IdString, dict<IdString, Property>> io_attr;
void read_qsf(std::istream &in); // qsf.cc
// -------------------------------------------------
diff --git a/mistral/arch_pybindings.cc b/mistral/arch_pybindings.cc
index 23716c93..c44a1fab 100644
--- a/mistral/arch_pybindings.cc
+++ b/mistral/arch_pybindings.cc
@@ -50,10 +50,10 @@ void arch_wrap_python(py::module &m)
fn_wrapper_2a<Context, decltype(&Context::compute_lut_mask), &Context::compute_lut_mask, pass_through<uint64_t>,
pass_through<uint32_t>, pass_through<uint8_t>>::def_wrap(ctx_cls, "compute_lut_mask");
- typedef std::unordered_map<IdString, std::unique_ptr<CellInfo>> CellMap;
- typedef std::unordered_map<IdString, std::unique_ptr<NetInfo>> NetMap;
- typedef std::unordered_map<IdString, IdString> AliasMap;
- typedef std::unordered_map<IdString, HierarchicalCell> HierarchyMap;
+ typedef dict<IdString, std::unique_ptr<CellInfo>> CellMap;
+ typedef dict<IdString, std::unique_ptr<NetInfo>> NetMap;
+ typedef dict<IdString, IdString> AliasMap;
+ typedef dict<IdString, HierarchicalCell> HierarchyMap;
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");
diff --git a/mistral/archdefs.h b/mistral/archdefs.h
index 60bdcfeb..8b4256ab 100644
--- a/mistral/archdefs.h
+++ b/mistral/archdefs.h
@@ -20,15 +20,16 @@
#ifndef MISTRAL_ARCHDEFS_H
#define MISTRAL_ARCHDEFS_H
-#include <boost/functional/hash.hpp>
-
#include "base_clusterinfo.h"
#include "cyclonev.h"
+#include "hashlib.h"
#include "idstring.h"
#include "nextpnr_assertions.h"
#include "nextpnr_namespaces.h"
+#include <limits>
+
NEXTPNR_NAMESPACE_BEGIN
using mistral::CycloneV;
@@ -84,6 +85,7 @@ struct BelId
bool operator==(const BelId &other) const { return pos == other.pos && z == other.z; }
bool operator!=(const BelId &other) const { return pos != other.pos || z != other.z; }
bool operator<(const BelId &other) const { return pos < other.pos || (pos == other.pos && z < other.z); }
+ unsigned int hash() const { return mkhash(pos, z); }
};
static constexpr auto invalid_rnode = std::numeric_limits<CycloneV::rnode_t>::max();
@@ -104,6 +106,7 @@ struct WireId
bool operator==(const WireId &other) const { return node == other.node; }
bool operator!=(const WireId &other) const { return node != other.node; }
bool operator<(const WireId &other) const { return node < other.node; }
+ unsigned int hash() const { return unsigned(node); }
};
struct PipId
@@ -115,6 +118,7 @@ struct PipId
bool operator==(const PipId &other) const { return src == other.src && dst == other.dst; }
bool operator!=(const PipId &other) const { return src != other.src || dst != other.dst; }
bool operator<(const PipId &other) const { return dst < other.dst || (dst == other.dst && src < other.src); }
+ unsigned int hash() const { return mkhash(src, dst); }
};
typedef IdString DecalId;
@@ -199,38 +203,11 @@ struct ArchCellInfo : BaseClusterInfo
} ffInfo;
};
- std::unordered_map<IdString, ArchPinInfo> pin_data;
+ dict<IdString, ArchPinInfo> pin_data;
CellPinState get_pin_state(IdString pin) const;
};
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<uint32_t>()((static_cast<uint32_t>(bel.pos) << 16) | bel.z);
- }
-};
-
-template <> struct hash<NEXTPNR_NAMESPACE_PREFIX WireId>
-{
- std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX WireId &wire) const noexcept
- {
- return hash<uint32_t>()(wire.node);
- }
-};
-
-template <> struct hash<NEXTPNR_NAMESPACE_PREFIX PipId>
-{
- std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX PipId &pip) const noexcept
- {
- return hash<uint64_t>()((uint64_t(pip.dst) << 32) | pip.src);
- }
-};
-
-} // namespace std
-
#endif
diff --git a/mistral/bitstream.cc b/mistral/bitstream.cc
index 340ba6b9..0e8b9c85 100644
--- a/mistral/bitstream.cc
+++ b/mistral/bitstream.cc
@@ -156,9 +156,9 @@ struct MistralBitgen
void write_routing()
{
- for (auto net : sorted(ctx->nets)) {
- NetInfo *ni = net.second;
- for (auto wire : sorted_ref(ni->wires)) {
+ for (auto &net : ctx->nets) {
+ NetInfo *ni = net.second.get();
+ for (auto &wire : ni->wires) {
PipId pip = wire.second.pip;
if (pip == PipId())
continue;
@@ -200,8 +200,8 @@ struct MistralBitgen
void write_cells()
{
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
Loc loc = ctx->getBelLocation(ci->bel);
int bi = ctx->bel_data(ci->bel).block_index;
if (ctx->is_io_cell(ci->type))
diff --git a/mistral/lab.cc b/mistral/lab.cc
index abd0fec3..56bc604a 100644
--- a/mistral/lab.cc
+++ b/mistral/lab.cc
@@ -718,7 +718,7 @@ void Arch::reassign_alm_inputs(uint32_t lab, uint8_t alm)
// - C, E0, and F0 are exclusive to the top LUT5 secion
// - D, E1, and F1 are exclusive to the bottom LUT5 section
// First find up to two shared inputs
- std::unordered_map<IdString, int> shared_nets;
+ dict<IdString, int> shared_nets;
if (luts[0] && luts[1]) {
for (int i = 0; i < luts[0]->combInfo.lut_input_count; i++) {
for (int j = 0; j < luts[1]->combInfo.lut_input_count; j++) {
@@ -826,7 +826,7 @@ void Arch::reassign_alm_inputs(uint32_t lab, uint8_t alm)
// This default cell-bel pin mapping is used to provide estimates during placement only. It will have errors and
// overlaps and a correct mapping will be resolved twixt placement and routing
-const std::unordered_map<IdString, IdString> Arch::comb_pinmap = {
+const dict<IdString, IdString> Arch::comb_pinmap = {
{id_A, id_F0}, // fastest input first
{id_B, id_E0}, {id_C, id_D}, {id_D, id_C}, {id_D0, id_C}, {id_D1, id_B},
{id_E, id_B}, {id_F, id_A}, {id_Q, id_COMBOUT}, {id_SO, id_COMBOUT},
diff --git a/mistral/main.cc b/mistral/main.cc
index 7b4f9594..0afba3d8 100644
--- a/mistral/main.cc
+++ b/mistral/main.cc
@@ -33,7 +33,7 @@ class MistralCommandHandler : public CommandHandler
public:
MistralCommandHandler(int argc, char **argv);
virtual ~MistralCommandHandler(){};
- 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 customBitstream(Context *ctx) override;
void customAfterLoad(Context *ctx) override;
@@ -71,7 +71,7 @@ void MistralCommandHandler::customBitstream(Context *ctx)
}
}
-std::unique_ptr<Context> MistralCommandHandler::createContext(std::unordered_map<std::string, Property> &values)
+std::unique_ptr<Context> MistralCommandHandler::createContext(dict<std::string, Property> &values)
{
ArchArgs chipArgs;
if (!vm.count("mistral")) {
diff --git a/mistral/pack.cc b/mistral/pack.cc
index 90fbfd78..98ab22bf 100644
--- a/mistral/pack.cc
+++ b/mistral/pack.cc
@@ -133,8 +133,8 @@ struct MistralPacker
// Remove unused inverters and high/low drivers
std::vector<IdString> trim_cells;
std::vector<IdString> trim_nets;
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type != id_MISTRAL_NOT && ci->type != id_GND && ci->type != id_VCC)
continue;
IdString port = (ci->type == id_MISTRAL_NOT) ? id_Q : id_Y;
@@ -161,15 +161,15 @@ struct MistralPacker
void pack_constants()
{
// Iterate through cells
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
// Skip certain cells at this point
if (ci->type != id_MISTRAL_NOT && ci->type != id_GND && ci->type != id_VCC)
- process_inv_constants(cell.second);
+ process_inv_constants(ci);
}
// Special case - SDATA can only be trimmed if SLOAD is low
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type != id_MISTRAL_FF)
continue;
if (ci->get_pin_state(id_SLOAD) != PIN_0)
@@ -185,7 +185,7 @@ struct MistralPacker
// Find the actual IO buffer corresponding to a port; and copy attributes across to it
// Note that this relies on Yosys to do IO buffer inference, to avoid tristate issues once we get to synthesised
// JSON. In all cases the nextpnr-inserted IO buffers are removed as redundant.
- for (auto &port : sorted_ref(ctx->ports)) {
+ for (auto &port : ctx->ports) {
if (!ctx->cells.count(port.first))
log_error("Port '%s' doesn't seem to have a corresponding top level IO\n", ctx->nameOf(port.first));
CellInfo *ci = ctx->cells.at(port.first).get();
@@ -256,8 +256,8 @@ struct MistralPacker
// Step 0: deal with top level inserted IO buffers
prepare_io();
// Stage 1: apply constraints
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
// Iterate through all IO buffer primitives
if (!ctx->is_io_cell(ci->type))
continue;
@@ -286,8 +286,8 @@ struct MistralPacker
void constrain_carries()
{
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type != id_MISTRAL_ALUT_ARITH)
continue;
const NetInfo *cin = get_net_or_empty(ci, id_CI);
@@ -332,8 +332,8 @@ struct MistralPacker
}
}
// Check we reached all the cells in the above pass
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type != id_MISTRAL_ALUT_ARITH)
continue;
if (ci->cluster == ClusterId())
diff --git a/mistral/pins.cc b/mistral/pins.cc
index c3637115..51cb83c4 100644
--- a/mistral/pins.cc
+++ b/mistral/pins.cc
@@ -23,7 +23,7 @@
NEXTPNR_NAMESPACE_BEGIN
-const std::unordered_map<IdString, Arch::CellPinsData> Arch::cell_pins_db = {
+const dict<IdString, Arch::CellPinsData> Arch::cell_pins_db = {
// For combinational cells, inversion and tieing can be implemented by manipulating the LUT function
{id_MISTRAL_ALUT2, {{{}, PINSTYLE_COMB}}},
{id_MISTRAL_ALUT3, {{{}, PINSTYLE_COMB}}},
diff --git a/mistral/qsf.cc b/mistral/qsf.cc
index 9a128595..88f51b1b 100644
--- a/mistral/qsf.cc
+++ b/mistral/qsf.cc
@@ -34,7 +34,7 @@ struct QsfOption
bool required; // error out if this option isn't passed
};
-typedef std::unordered_map<std::string, std::vector<std::string>> option_map_t;
+typedef dict<std::string, std::vector<std::string>> option_map_t;
struct QsfCommand
{
diff --git a/nexus/arch.cc b/nexus/arch.cc
index d5bb9deb..d90236a8 100644
--- a/nexus/arch.cc
+++ b/nexus/arch.cc
@@ -667,19 +667,19 @@ bool Arch::place()
void Arch::pre_routing()
{
- for (auto cell : sorted(cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type == id_MULT9_CORE || ci->type == id_PREADD9_CORE || ci->type == id_MULT18_CORE ||
ci->type == id_MULT18X36_CORE || ci->type == id_MULT36_CORE || ci->type == id_REG18_CORE ||
ci->type == id_ACC54_CORE) {
- for (auto port : sorted_ref(ci->ports)) {
+ for (auto &port : ci->ports) {
WireId wire = getBelPinWire(ci->bel, port.first);
if (wire != WireId())
dsp_wires.insert(wire);
}
}
if (ci->type == id_LRAM_CORE) {
- for (auto port : sorted_ref(ci->ports)) {
+ for (auto &port : ci->ports) {
WireId wire = getBelPinWire(ci->bel, port.first);
if (wire != WireId())
lram_wires.insert(wire);
diff --git a/nexus/arch.h b/nexus/arch.h
index b3558413..a669be0d 100644
--- a/nexus/arch.h
+++ b/nexus/arch.h
@@ -916,7 +916,7 @@ struct Arch : BaseArch<ArchRanges>
// fast access to X and Y IdStrings for building object names
std::vector<IdString> x_ids, y_ids;
// inverse of the above for name->object mapping
- std::unordered_map<IdString, int> id_to_x, id_to_y;
+ dict<IdString, int> id_to_x, id_to_y;
// -------------------------------------------------
@@ -1181,7 +1181,7 @@ struct Arch : BaseArch<ArchRanges>
// for better DSP bounding boxes
void pre_routing();
- std::unordered_set<WireId> dsp_wires, lram_wires;
+ pool<WireId> dsp_wires, lram_wires;
// -------------------------------------------------
@@ -1271,9 +1271,9 @@ struct Arch : BaseArch<ArchRanges>
// -------------------------------------------------
- typedef std::unordered_map<IdString, CellPinStyle> CellPinsData;
+ typedef dict<IdString, CellPinStyle> CellPinsData;
- std::unordered_map<IdString, CellPinsData> cell_pins_db;
+ dict<IdString, CellPinsData> cell_pins_db;
CellPinStyle get_cell_pin_style(const CellInfo *cell, IdString port) const;
void init_cell_pin_data();
@@ -1361,7 +1361,7 @@ struct Arch : BaseArch<ArchRanges>
// -------------------------------------------------
// Data about different IO standard, mostly used by bitgen
- static const std::unordered_map<std::string, IOTypeData> io_types;
+ static const dict<std::string, IOTypeData> io_types;
int get_io_type_vcc(const std::string &io_type) const;
bool is_io_type_diff(const std::string &io_type) const;
bool is_io_type_ref(const std::string &io_type) const;
@@ -1388,7 +1388,7 @@ struct Arch : BaseArch<ArchRanges>
// -------------------------------------------------
// List of IO constraints, used by PDC parser
- std::unordered_map<IdString, std::unordered_map<IdString, Property>> io_attr;
+ dict<IdString, dict<IdString, Property>> io_attr;
void read_pdc(std::istream &in);
diff --git a/nexus/arch_pybindings.cc b/nexus/arch_pybindings.cc
index a8b04ba7..d6bc7329 100644
--- a/nexus/arch_pybindings.cc
+++ b/nexus/arch_pybindings.cc
@@ -46,10 +46,10 @@ void arch_wrap_python(py::module &m)
.def("place", &Context::place)
.def("route", &Context::route);
- typedef std::unordered_map<IdString, std::unique_ptr<CellInfo>> CellMap;
- typedef std::unordered_map<IdString, std::unique_ptr<NetInfo>> NetMap;
- typedef std::unordered_map<IdString, HierarchicalCell> HierarchyMap;
- typedef std::unordered_map<IdString, IdString> AliasMap;
+ typedef dict<IdString, std::unique_ptr<CellInfo>> CellMap;
+ typedef dict<IdString, std::unique_ptr<NetInfo>> NetMap;
+ typedef dict<IdString, HierarchicalCell> HierarchyMap;
+ typedef dict<IdString, IdString> AliasMap;
typedef UpDownhillPipRange UphillPipRange;
typedef UpDownhillPipRange DownhillPipRange;
diff --git a/nexus/archdefs.h b/nexus/archdefs.h
index 660f166c..f2b5a45d 100644
--- a/nexus/archdefs.h
+++ b/nexus/archdefs.h
@@ -20,10 +20,8 @@
#ifndef NEXUS_ARCHDEFS_H
#define NEXUS_ARCHDEFS_H
-#include <boost/functional/hash.hpp>
-#include <unordered_map>
-
#include "base_clusterinfo.h"
+#include "hashlib.h"
#include "idstring.h"
#include "nextpnr_namespaces.h"
@@ -62,6 +60,7 @@ struct BelId
{
return tile < other.tile || (tile == other.tile && index < other.index);
}
+ unsigned int hash() const { return mkhash(tile, index); }
};
struct WireId
@@ -80,6 +79,7 @@ struct WireId
{
return tile < other.tile || (tile == other.tile && index < other.index);
}
+ unsigned int hash() const { return mkhash(tile, index); }
};
struct PipId
@@ -97,6 +97,7 @@ struct PipId
{
return tile < other.tile || (tile == other.tile && index < other.index);
}
+ unsigned int hash() const { return mkhash(tile, index); }
};
typedef IdString BelBucketId;
@@ -111,6 +112,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); }
+ unsigned int hash() const { return mkhash(mkhash(x, y), int(type)); }
};
struct DecalId
@@ -134,6 +136,7 @@ struct DecalId
{
return (type != other.type) || (index != other.index) || (active != other.active);
}
+ unsigned int hash() const { return mkhash(index, int(type)); }
};
struct ArchNetInfo
@@ -178,68 +181,9 @@ struct ArchCellInfo : BaseClusterInfo
int tmg_index = -1;
// Map from cell/bel ports to logical timing ports
- std::unordered_map<IdString, IdString> tmg_portmap;
+ dict<IdString, IdString> tmg_portmap;
};
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;
- 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 /* NEXUS_ARCHDEFS_H */
diff --git a/nexus/fasm.cc b/nexus/fasm.cc
index 0afefa4b..48483bfe 100644
--- a/nexus/fasm.cc
+++ b/nexus/fasm.cc
@@ -248,7 +248,7 @@ struct NexusFasmWriter
// Write out the mux config for a cell
void write_cell_muxes(const CellInfo *cell)
{
- for (auto port : sorted_cref(cell->ports)) {
+ for (auto &port : cell->ports) {
// Only relevant to inputs
if (port.second.type != PORT_IN)
continue;
@@ -336,7 +336,7 @@ struct NexusFasmWriter
pop(2);
}
- std::unordered_set<BelId> used_io;
+ pool<BelId> used_io;
struct BankConfig
{
@@ -539,7 +539,7 @@ struct NexusFasmWriter
push_bel(bel);
if (cell->type != id_MULT18_CORE && cell->type != id_MULT18X36_CORE && cell->type != id_MULT36_CORE)
write_bit(stringf("MODE.%s", ctx->nameOf(cell->type)));
- for (auto param : sorted_cref(cell->params)) {
+ for (auto &param : cell->params) {
const std::string &param_name = param.first.str(ctx);
if (is_mux_param(param_name))
continue;
@@ -556,7 +556,7 @@ struct NexusFasmWriter
// Which PLL params are 'word' values
/* clang-format off */
- const std::unordered_map<std::string, int> pll_word_params = {
+ const dict<std::string, int> pll_word_params = {
{"DIVA", 7}, {"DELA", 7}, {"PHIA", 3}, {"DIVB", 7},
{"DELB", 7}, {"PHIB", 3}, {"DIVC", 7}, {"DELC", 7},
{"PHIC", 3}, {"DIVD", 7}, {"DELD", 7}, {"PHID", 3},
@@ -582,7 +582,7 @@ struct NexusFasmWriter
};
// Which MIPI params are 'word' values
- const std::unordered_map<std::string, int> dphy_word_params = {
+ const dict<std::string, int> dphy_word_params = {
{"CM", 8}, {"CN", 5}, {"CO", 3}, {"RSEL", 2}, {"RXCDRP", 2},
{"RXDATAWIDTHHS", 2}, {"RXLPRP", 3}, {"TEST_ENBL", 6},
{"TEST_PATTERN", 32}, {"TST", 4}, {"TXDATAWIDTHHS", 2},
@@ -601,7 +601,7 @@ struct NexusFasmWriter
write_cell_muxes(cell);
pop();
push(stringf("IP_%s", ctx->nameOf(IdString(ctx->bel_data(bel).name))));
- for (auto param : sorted_cref(cell->params)) {
+ for (auto &param : cell->params) {
const std::string &name = param.first.str(ctx);
if (is_mux_param(name) || name == "CLKMUX_FB" || name == "SEL_FBK")
continue;
@@ -622,7 +622,7 @@ struct NexusFasmWriter
{
BelId bel = cell->bel;
push(stringf("IP_%s", ctx->nameOf(IdString(ctx->bel_data(bel).name))));
- for (auto param : sorted_cref(cell->params)) {
+ for (auto &param : cell->params) {
const std::string &name = param.first.str(ctx);
if (is_mux_param(name) || name == "GSR")
continue;
@@ -683,7 +683,7 @@ struct NexusFasmWriter
write_comment("# Unused bels");
// DSP primitives are configured to a default mode; even if unused
- static const std::unordered_map<IdString, std::vector<std::string>> dsp_defconf = {
+ static const dict<IdString, std::vector<std::string>> dsp_defconf = {
{id_MULT9_CORE,
{
"GSR.ENABLED",
@@ -733,7 +733,7 @@ struct NexusFasmWriter
}
}
}
- std::unordered_map<int, int> bank_vcco;
+ dict<int, int> bank_vcco;
// bank VccO in mV
int get_bank_vcco(const std::string &iostd)
{
@@ -753,8 +753,8 @@ struct NexusFasmWriter
// Write out placeholder bankref config
void write_bankcfg()
{
- for (auto c : sorted(ctx->cells)) {
- const CellInfo *ci = c.second;
+ for (auto &c : ctx->cells) {
+ const CellInfo *ci = c.second.get();
if (ci->type != id_SEIO33_CORE)
continue;
if (!ci->attrs.count(id_IO_TYPE))
@@ -809,12 +809,12 @@ struct NexusFasmWriter
write_attribute("oxide.device_variant", ctx->variant);
blank();
// Write routing
- for (auto n : sorted(ctx->nets)) {
- write_net(n.second);
+ for (auto &n : ctx->nets) {
+ write_net(n.second.get());
}
// Write cell config
- for (auto c : sorted(ctx->cells)) {
- const CellInfo *ci = c.second;
+ for (auto &c : ctx->cells) {
+ const CellInfo *ci = c.second.get();
write_comment(stringf("# Cell %s", ctx->nameOf(ci)));
if (ci->type == id_OXIDE_COMB)
write_comb(ci);
diff --git a/nexus/global.cc b/nexus/global.cc
index 53306e21..9a0d095b 100644
--- a/nexus/global.cc
+++ b/nexus/global.cc
@@ -49,7 +49,7 @@ struct NexusGlobalRouter
// Queue of wires to visit
std::queue<WireId> visit;
// Wire -> upstream pip
- std::unordered_map<WireId, PipId> backtrace;
+ dict<WireId, PipId> backtrace;
// Lookup source and destination wires
WireId src = ctx->getNetinfoSourceWire(net);
@@ -155,8 +155,8 @@ struct NexusGlobalRouter
void operator()()
{
log_info("Routing globals...\n");
- for (auto net : sorted(ctx->nets)) {
- NetInfo *ni = net.second;
+ for (auto &net : ctx->nets) {
+ NetInfo *ni = net.second.get();
CellInfo *drv = ni->driver.cell;
if (drv == nullptr)
continue;
diff --git a/nexus/io.cc b/nexus/io.cc
index fd5e584f..314d80b6 100644
--- a/nexus/io.cc
+++ b/nexus/io.cc
@@ -23,7 +23,7 @@
NEXTPNR_NAMESPACE_BEGIN
-const std::unordered_map<std::string, IOTypeData> Arch::io_types = {
+const dict<std::string, IOTypeData> Arch::io_types = {
{"LVCMOS33", {IOSTYLE_SE_WR, 330}}, {"LVCMOS25", {IOSTYLE_SE_WR, 250}},
{"LVCMOS18", {IOSTYLE_SE_WR, 180}}, {"LVCMOS15", {IOSTYLE_SE_WR, 150}},
{"LVCMOS12", {IOSTYLE_SE_WR, 120}}, {"LVCMOS10", {IOSTYLE_SE_WR, 120}},
diff --git a/nexus/main.cc b/nexus/main.cc
index cced1b95..66b1a61e 100644
--- a/nexus/main.cc
+++ b/nexus/main.cc
@@ -33,7 +33,7 @@ class NexusCommandHandler : public CommandHandler
public:
NexusCommandHandler(int argc, char **argv);
virtual ~NexusCommandHandler(){};
- 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 customBitstream(Context *ctx) override;
void customAfterLoad(Context *ctx) override;
@@ -66,7 +66,7 @@ void NexusCommandHandler::customBitstream(Context *ctx)
}
}
-std::unique_ptr<Context> NexusCommandHandler::createContext(std::unordered_map<std::string, Property> &values)
+std::unique_ptr<Context> NexusCommandHandler::createContext(dict<std::string, Property> &values)
{
ArchArgs chipArgs;
if (!vm.count("device")) {
diff --git a/nexus/pack.cc b/nexus/pack.cc
index 66ab4b09..1d977f2c 100644
--- a/nexus/pack.cc
+++ b/nexus/pack.cc
@@ -106,16 +106,16 @@ struct NexusPacker
struct XFormRule
{
IdString new_type;
- std::unordered_map<IdString, IdString> port_xform;
- std::unordered_map<IdString, std::vector<IdString>> port_multixform;
- std::unordered_map<IdString, IdString> param_xform;
+ dict<IdString, IdString> port_xform;
+ dict<IdString, std::vector<IdString>> port_multixform;
+ dict<IdString, IdString> param_xform;
std::vector<std::pair<IdString, std::string>> set_attrs;
std::vector<std::pair<IdString, Property>> set_params;
std::vector<std::pair<IdString, Property>> default_params;
std::vector<std::tuple<IdString, IdString, int, int64_t>> parse_params;
};
- void xform_cell(const std::unordered_map<IdString, XFormRule> &rules, CellInfo *ci)
+ void xform_cell(const dict<IdString, XFormRule> &rules, CellInfo *ci)
{
auto &rule = rules.at(ci->type);
ci->type = rule.new_type;
@@ -178,12 +178,12 @@ struct NexusPacker
ci->params[param.first] = param.second;
}
- void generic_xform(const std::unordered_map<IdString, XFormRule> &rules, bool print_summary = false)
+ void generic_xform(const dict<IdString, XFormRule> &rules, bool print_summary = false)
{
std::map<std::string, int> cell_count;
std::map<std::string, int> new_types;
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (rules.count(ci->type)) {
cell_count[ci->type.str(ctx)]++;
xform_cell(rules, ci);
@@ -205,7 +205,7 @@ struct NexusPacker
void pack_luts()
{
log_info("Packing LUTs...\n");
- std::unordered_map<IdString, XFormRule> lut_rules;
+ dict<IdString, XFormRule> lut_rules;
lut_rules[id_LUT4].new_type = id_OXIDE_COMB;
lut_rules[id_LUT4].port_xform[id_Z] = id_F;
lut_rules[id_LUT4].parse_params.emplace_back(id_INIT, id_INIT, 16, 0);
@@ -229,7 +229,7 @@ struct NexusPacker
void pack_ffs()
{
log_info("Packing FFs...\n");
- std::unordered_map<IdString, XFormRule> ff_rules;
+ dict<IdString, XFormRule> ff_rules;
for (auto type : {id_FD1P3BX, id_FD1P3DX, id_FD1P3IX, id_FD1P3JX}) {
ff_rules[type].new_type = id_OXIDE_FF;
ff_rules[type].port_xform[id_CK] = id_CLK;
@@ -262,7 +262,7 @@ struct NexusPacker
generic_xform(ff_rules, true);
}
- std::unordered_map<IdString, BelId> reference_bels;
+ dict<IdString, BelId> reference_bels;
void autocreate_ports(CellInfo *cell)
{
@@ -303,8 +303,8 @@ struct NexusPacker
{
// Gets a constant net, given the driver type (VHI or VLO)
// If one doesn't exist already; then create it
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type != type)
continue;
NetInfo *z = get_net_or_empty(ci, id_Z);
@@ -369,8 +369,8 @@ struct NexusPacker
// Remove unused inverters and high/low drivers
std::vector<IdString> trim_cells;
std::vector<IdString> trim_nets;
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type != id_INV && ci->type != id_VLO && ci->type != id_VHI && ci->type != id_VCC_DRV)
continue;
NetInfo *z = get_net_or_empty(ci, id_Z);
@@ -474,7 +474,7 @@ struct NexusPacker
// Find the actual IO buffer corresponding to a port; and copy attributes across to it
// Note that this relies on Yosys to do IO buffer inference, to match vendor tooling behaviour
// In all cases the nextpnr-inserted IO buffers are removed as redundant.
- for (auto &port : sorted_ref(ctx->ports)) {
+ for (auto &port : ctx->ports) {
if (!ctx->cells.count(port.first))
log_error("Port '%s' doesn't seem to have a corresponding top level IO\n", ctx->nameOf(port.first));
CellInfo *ci = ctx->cells.at(port.first).get();
@@ -549,11 +549,10 @@ struct NexusPacker
void pack_io()
{
- std::unordered_set<IdString> iob_types = {id_IB, id_OB, id_OBZ, id_BB,
- id_BB_I3C_A, id_SEIO33, id_SEIO18, id_DIFFIO18,
- id_SEIO33_CORE, id_SEIO18_CORE, id_DIFFIO18_CORE};
+ pool<IdString> iob_types = {id_IB, id_OB, id_OBZ, id_BB, id_BB_I3C_A, id_SEIO33,
+ id_SEIO18, id_DIFFIO18, id_SEIO33_CORE, id_SEIO18_CORE, id_DIFFIO18_CORE};
- std::unordered_map<IdString, XFormRule> io_rules;
+ dict<IdString, XFormRule> io_rules;
// For the low level primitives, make sure we always preserve their type
io_rules[id_SEIO33_CORE].new_type = id_SEIO33_CORE;
@@ -567,20 +566,20 @@ struct NexusPacker
io_rules[id_SEIO33].port_xform[id_PADDT] = id_T;
io_rules[id_SEIO33].port_xform[id_IOPAD] = id_B;
- io_rules[id_BB_I3C_A] = io_rules[id_SEIO33];
+ io_rules[id_BB_I3C_A] = XFormRule(io_rules[id_SEIO33]);
- io_rules[id_SEIO18] = io_rules[id_SEIO33];
+ io_rules[id_SEIO18] = XFormRule(io_rules[id_SEIO33]);
io_rules[id_SEIO18].new_type = id_SEIO18_CORE;
- io_rules[id_DIFFIO18] = io_rules[id_SEIO33];
+ io_rules[id_DIFFIO18] = XFormRule(io_rules[id_SEIO33]);
io_rules[id_DIFFIO18].new_type = id_DIFFIO18_CORE;
// Stage 0: deal with top level inserted IO buffers
prepare_io();
// Stage 1: setup constraints
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
// Iterate through all IO buffer primitives
if (!iob_types.count(ci->type))
continue;
@@ -625,8 +624,8 @@ struct NexusPacker
// Stage 2: apply rules for primitives that need them
generic_xform(io_rules, false);
// Stage 3: all other IO primitives become their bel type
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
// Iterate through all IO buffer primitives
if (!iob_types.count(ci->type))
continue;
@@ -660,12 +659,12 @@ struct NexusPacker
gnd_net = get_const_net(id_VLO);
dedi_vcc_net = get_const_net(id_VCC_DRV);
// Iterate through cells
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
// Skip certain cells at this point
if (ci->type != id_LUT4 && ci->type != id_INV && ci->type != id_VHI && ci->type != id_VLO &&
ci->type != id_VCC_DRV)
- process_inv_constants(cell.second);
+ process_inv_constants(ci);
}
// Remove superfluous inverters and constant drivers
trim_design();
@@ -677,8 +676,8 @@ struct NexusPacker
{
int iter = 0;
std::queue<WireId> visit;
- std::unordered_set<WireId> seen_wires;
- std::unordered_set<BelId> seen_bels;
+ pool<WireId> seen_wires;
+ pool<BelId> seen_bels;
BelId bel = get_bel_attr(cell);
if (bel == BelId())
@@ -751,7 +750,7 @@ struct NexusPacker
return best_bel;
}
- std::unordered_set<BelId> used_bels;
+ pool<BelId> used_bels;
// Pre-place a primitive based on routeability first and distance second
bool preplace_prim(CellInfo *cell, IdString pin, bool strict_routing)
@@ -854,8 +853,8 @@ struct NexusPacker
{
std::vector<std::pair<int, IdString>> clk_fanout;
int available_globals = 16;
- for (auto net : sorted(ctx->nets)) {
- NetInfo *ni = net.second;
+ for (auto &net : ctx->nets) {
+ NetInfo *ni = net.second.get();
// Skip undriven nets; and nets that are already global
if (ni->driver.cell == nullptr)
continue;
@@ -894,8 +893,8 @@ struct NexusPacker
bool did_something = true;
while (did_something) {
did_something = false;
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type == id_OSC_CORE)
did_something |= preplace_singleton(ci);
else if (ci->type == id_DCC)
@@ -916,8 +915,8 @@ struct NexusPacker
{
// Do this so we don't have an iterate-and-modfiy situation
std::vector<CellInfo *> lutrams;
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type != id_DPR16X4)
continue;
lutrams.push_back(ci);
@@ -1024,15 +1023,15 @@ struct NexusPacker
void convert_prims()
{
// Convert primitives from their non-CORE variant to their CORE variant
- static const std::unordered_map<IdString, IdString> prim_map = {
+ static const dict<IdString, IdString> prim_map = {
{id_OSCA, id_OSC_CORE}, {id_DP16K, id_DP16K_MODE}, {id_PDP16K, id_PDP16K_MODE},
{id_PDPSC16K, id_PDPSC16K_MODE}, {id_SP16K, id_SP16K_MODE}, {id_FIFO16K, id_FIFO16K_MODE},
{id_SP512K, id_SP512K_MODE}, {id_DPSC512K, id_DPSC512K_MODE}, {id_PDPSC512K, id_PDPSC512K_MODE},
{id_PLL, id_PLL_CORE}, {id_DPHY, id_DPHY_CORE},
};
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (!prim_map.count(ci->type))
continue;
prim_to_core(ci, prim_map.at(ci->type));
@@ -1048,7 +1047,7 @@ struct NexusPacker
void pack_bram()
{
- std::unordered_map<IdString, XFormRule> bram_rules;
+ dict<IdString, XFormRule> bram_rules;
bram_rules[id_DP16K_MODE].new_type = id_OXIDE_EBR;
bram_rules[id_DP16K_MODE].set_params.emplace_back(id_MODE, std::string("DP16K"));
bram_rules[id_DP16K_MODE].parse_params.emplace_back(id_CSDECODE_A, id_CSDECODE_A, 3, 7);
@@ -1074,7 +1073,7 @@ struct NexusPacker
add_bus_xform(bram_rules[id_PDP16K_MODE], "DO", "DOA", 18, 18, 0);
// Pseudo dual port; single clock
- bram_rules[id_PDPSC16K_MODE] = bram_rules[id_PDP16K_MODE];
+ bram_rules[id_PDPSC16K_MODE] = XFormRule(bram_rules[id_PDP16K_MODE]);
bram_rules[id_PDPSC16K_MODE].set_params.clear();
bram_rules[id_PDPSC16K_MODE].set_params.emplace_back(id_MODE, std::string("PDPSC16K"));
bram_rules[id_PDPSC16K_MODE].set_params.emplace_back(id_WEAMUX, std::string("1"));
@@ -1084,8 +1083,8 @@ struct NexusPacker
generic_xform(bram_rules, true);
int wid = 2;
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type != id_OXIDE_EBR)
continue;
if (ci->params.count(id_WID))
@@ -1096,7 +1095,7 @@ struct NexusPacker
void pack_lram()
{
- std::unordered_map<IdString, XFormRule> lram_rules;
+ dict<IdString, XFormRule> lram_rules;
lram_rules[id_SP512K_MODE].new_type = id_LRAM_CORE;
lram_rules[id_SP512K_MODE].set_params.emplace_back(id_EBR_SP_EN, std::string("ENABLE"));
lram_rules[id_SP512K_MODE].port_xform[id_CE] = id_CEA;
@@ -1129,8 +1128,8 @@ struct NexusPacker
log_info("Packing LRAM...\n");
generic_xform(lram_rules, true);
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type != id_LRAM_CORE)
continue;
if (str_or_default(ci->params, ctx->id("ECC_BYTE_SEL"), "BYTE_EN") == "BYTE_EN")
@@ -1151,8 +1150,8 @@ struct NexusPacker
void pack_widefn()
{
std::vector<CellInfo *> widefns;
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type != id_WIDEFN9)
continue;
widefns.push_back(ci);
@@ -1200,8 +1199,8 @@ struct NexusPacker
// Find root carry cells
log_info("Packing carries...\n");
std::vector<CellInfo *> roots;
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type != id_CCU2)
continue;
if (get_net_or_empty(ci, id_CIN) != nullptr)
@@ -1296,7 +1295,7 @@ struct NexusPacker
// Automatically generate cascade connections downstream of a cell
// using the temporary placement that we use solely to access the routing graph
- void auto_cascade_cell(CellInfo *cell, BelId bel, const std::unordered_map<BelId, CellInfo *> &bel2cell)
+ void auto_cascade_cell(CellInfo *cell, BelId bel, const dict<BelId, CellInfo *> &bel2cell)
{
// Create outputs based on the actual bel
for (auto bp : ctx->getBelPins(bel)) {
@@ -1306,7 +1305,7 @@ struct NexusPacker
continue;
cell->addOutput(bp);
}
- for (auto port : sorted_ref(cell->ports)) {
+ for (auto &port : cell->ports) {
// Skip if not an output, or being used already for something else
if (port.second.type != PORT_OUT || port.second.net != nullptr)
continue;
@@ -1322,7 +1321,7 @@ struct NexusPacker
// Standard BFS-type exploration
std::queue<WireId> visit;
- std::unordered_set<WireId> in_queue;
+ pool<WireId> in_queue;
visit.push(start_wire);
in_queue.insert(start_wire);
int iter = 0;
@@ -1403,8 +1402,8 @@ struct NexusPacker
// We first create a temporary placement so we can access the routing graph
bool found = false;
- std::unordered_map<BelId, CellInfo *> bel2cell;
- std::unordered_map<IdString, BelId> cell2bel;
+ dict<BelId, CellInfo *> bel2cell;
+ dict<IdString, BelId> cell2bel;
for (BelId root_bel : ctx->getBels()) {
if (ctx->getBelType(root_bel) != root->type)
@@ -1592,7 +1591,7 @@ struct NexusPacker
int wide; // DSP is a "wide" (dot-product) variant
};
- const std::unordered_map<IdString, DSPMacroType> dsp_types = {
+ const dict<IdString, DSPMacroType> dsp_types = {
{id_MULT9X9, {9, 9, 0, 18, 1, 0, 0, false, false, -1}},
{id_MULT18X18, {18, 18, 0, 36, 2, 1, 0, false, false, -1}},
{id_MULT18X36, {18, 36, 0, 54, 4, 2, 1, false, false, -1}},
@@ -1609,8 +1608,8 @@ struct NexusPacker
log_info("Packing DSPs...\n");
std::vector<CellInfo *> to_remove;
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (!dsp_types.count(ci->type))
continue;
auto &mt = dsp_types.at(ci->type);
@@ -1792,7 +1791,7 @@ struct NexusPacker
}
for (auto cell : to_remove) {
- for (auto port : sorted_ref(cell->ports))
+ for (auto &port : cell->ports)
disconnect_port(ctx, cell, port.first);
ctx->cells.erase(cell->name);
}
@@ -1805,7 +1804,7 @@ struct NexusPacker
auto equals_epsilon = [](delay_t a, delay_t b) { return (std::abs(a - b) / std::max(double(b), 1.0)) < 1e-3; };
- std::unordered_set<IdString> user_constrained, changed_nets;
+ pool<IdString> user_constrained, changed_nets;
for (auto &net : ctx->nets) {
if (net.second->clkconstr != nullptr)
user_constrained.insert(net.first);
@@ -1883,7 +1882,7 @@ struct NexusPacker
const int itermax = 5000;
while (!changed_nets.empty() && iter < itermax) {
++iter;
- std::unordered_set<IdString> changed_cells;
+ pool<IdString> changed_cells;
for (auto net : changed_nets) {
for (auto &user : ctx->nets.at(net)->users)
if (user.port == id_CLKI || user.port == id_REFCK)
@@ -1893,7 +1892,7 @@ struct NexusPacker
changed_cells.insert(drv.cell->name);
}
changed_nets.clear();
- for (auto cell : sorted(changed_cells)) {
+ for (auto cell : changed_cells) {
CellInfo *ci = ctx->cells.at(cell).get();
if (ci->type == id_DCC) {
copy_constraint(ci, id_CLKI, id_CLKO, 1);
@@ -1945,12 +1944,12 @@ struct NexusPacker
void pack_plls()
{
- const std::unordered_map<IdString, std::string> pll_defaults = {
+ const dict<IdString, std::string> pll_defaults = {
{id_FLOCK_CTRL, "2X"}, {id_FLOCK_EN, "ENABLED"}, {id_FLOCK_SRC_SEL, "REFCLK"},
{id_DIV_DEL, "0b0000001"}, {id_FBK_PI_RC, "0b1100"}, {id_FBK_PR_IC, "0b1000"},
};
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type == id_PLL_CORE) {
// Extra log to phys rules
rename_port(ctx, ci, id_PLLPOWERDOWN_N, id_PLLPDN);
@@ -1966,7 +1965,7 @@ struct NexusPacker
// Map LOC attribute on DPHY_CORE to a bel
// TDPHY_CORE2 is Radiant 2.0 style, DPHY0 is Radiant 2.2
// TODO: LIFCL-17 (perhaps remove the hardcoded map)
- const std::unordered_map<std::string, std::string> dphy_loc_map = {
+ const dict<std::string, std::string> dphy_loc_map = {
{"TDPHY_CORE2", "X4/Y0/TDPHY_CORE2"},
{"DPHY0", "X4/Y0/TDPHY_CORE2"},
{"TDPHY_CORE26", "X28/Y0/TDPHY_CORE26"},
@@ -1975,8 +1974,8 @@ struct NexusPacker
void pack_ip()
{
- for (auto cell : sorted(ctx->cells)) {
- CellInfo *ci = cell.second;
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
if (ci->type == id_DPHY_CORE) {
auto loc_attr = ci->attrs.find(id_LOC);
if (loc_attr == ci->attrs.end())
@@ -2026,8 +2025,8 @@ bool Arch::pack()
void Arch::assignArchInfo()
{
- for (auto cell : sorted(cells)) {
- assignCellInfo(cell.second);
+ for (auto &cell : cells) {
+ assignCellInfo(cell.second.get());
}
}
diff --git a/nexus/pdc.cc b/nexus/pdc.cc
index 1ffe0a64..f81bb74e 100644
--- a/nexus/pdc.cc
+++ b/nexus/pdc.cc
@@ -406,7 +406,7 @@ struct PDCParser
TCLValue cmd_ldc_set_port(const std::vector<TCLValue> &arguments)
{
- std::unordered_map<IdString, Property> args;
+ dict<IdString, Property> args;
for (int i = 1; i < int(arguments.size()); i++) {
auto &arg = arguments.at(i);
if (arg.is_string) {
diff --git a/nexus/pins.cc b/nexus/pins.cc
index a283953b..e9841f4b 100644
--- a/nexus/pins.cc
+++ b/nexus/pins.cc
@@ -24,7 +24,7 @@ NEXTPNR_NAMESPACE_BEGIN
namespace {
-static const std::unordered_map<IdString, Arch::CellPinsData> base_cell_pin_data = {
+static const dict<IdString, Arch::CellPinsData> base_cell_pin_data = {
{id_OXIDE_COMB,
{
{id_WCK, PINSTYLE_DEDI},
diff --git a/nexus/post_place.cc b/nexus/post_place.cc
index b6817b57..068c013e 100644
--- a/nexus/post_place.cc
+++ b/nexus/post_place.cc
@@ -88,9 +88,9 @@ struct NexusPostPlaceOpt
void opt_lutffs()
{
int moves_made = 0;
- for (auto cell : sorted(ctx->cells)) {
+ for (auto &cell : ctx->cells) {
// Search for FF cells
- CellInfo *ff = cell.second;
+ CellInfo *ff = cell.second.get();
if (ff->type != id_OXIDE_FF)
continue;
// Check M ('fabric') input net
diff --git a/tests b/tests
-Subproject caf7261be7b34b365ab6d8449455891c2ed28fa
+Subproject 1cc7ee785957c14f83b89d6bf18f14d072e6312