From 76ef7688643ae777f670b2bb2fbab2ddbeed9196 Mon Sep 17 00:00:00 2001 From: gatecat Date: Tue, 1 Jun 2021 15:46:16 +0100 Subject: [PATCH 01/11] common: Import hashlib from Yosys Signed-off-by: gatecat --- common/hashlib.h | 1183 +++++++++++++++++++++++++++++++++++ common/nextpnr_base_types.h | 1 + 2 files changed, 1184 insertions(+) create mode 100644 common/hashlib.h diff --git a/common/hashlib.h b/common/hashlib.h new file mode 100644 index 00000000..48db024f --- /dev/null +++ b/common/hashlib.h @@ -0,0 +1,1183 @@ +// 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 in 2014 +// ------------------------------------------------------- + +#ifndef HASHLIB_H +#define HASHLIB_H + +#include +#include +#include +#include + +#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 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 static inline bool cmp(T a, T b) { return a == b; } +}; + +template <> struct hash_ops : hash_int_ops +{ + static inline unsigned int hash(bool a) { return a ? 1 : 0; } +}; +template <> struct hash_ops : hash_int_ops +{ + static inline unsigned int hash(int32_t a) { return a; } +}; +template <> struct hash_ops : hash_int_ops +{ + static inline unsigned int hash(int64_t a) { return mkhash((unsigned int)(a), (unsigned int)(a >> 32)); } +}; + +template <> struct hash_ops +{ + 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 struct hash_ops> +{ + static inline bool cmp(std::pair a, std::pair b) { return a == b; } + static inline unsigned int hash(std::pair a) + { + return mkhash(hash_ops

::hash(a.first), hash_ops::hash(a.second)); + } +}; + +template struct hash_ops> +{ + static inline bool cmp(std::tuple a, std::tuple b) { return a == b; } + template + static inline typename std::enable_if::type hash(std::tuple) + { + return mkhash_init; + } + template + static inline typename std::enable_if::type hash(std::tuple a) + { + typedef hash_ops>::type> element_ops_t; + return mkhash(hash(a), element_ops_t::hash(std::get(a))); + } +}; + +template struct hash_ops> +{ + static inline bool cmp(std::vector a, std::vector b) { return a == b; } + static inline unsigned int hash(std::vector a) + { + unsigned int h = mkhash_init; + for (auto k : a) + h = mkhash(h, hash_ops::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 static inline unsigned int hash(const T *a) { return a ? a->hash() : 0; } +}; + +template inline unsigned int mkhash(const T &v) { return hash_ops().hash(v); } + +inline int hashtable_size(int min_size) +{ + static std::vector 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 > class dict; +template > class idict; +template > class pool; +template > class mfp; + +template class dict +{ + struct entry_t + { + std::pair udata; + int next; + + entry_t() {} + entry_t(const std::pair &udata, int next) : udata(udata), next(next) {} + entry_t(std::pair &&udata, int next) : udata(std::move(udata)), next(next) {} + bool operator<(const entry_t &other) const { return udata.first < other.udata.first; } + }; + + std::vector hashtable; + std::vector 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(key, T()), -1); + do_rehash(); + hash = do_hash(key); + } else { + entries.emplace_back(std::pair(key, T()), hashtable[hash]); + hashtable[hash] = entries.size() - 1; + } + return entries.size() - 1; + } + + int do_insert(const std::pair &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 &&rvalue, int &hash) + { + if (hashtable.empty()) { + auto key = rvalue.first; + entries.emplace_back(std::forward>(rvalue), -1); + do_rehash(); + hash = do_hash(key); + } else { + entries.emplace_back(std::forward>(rvalue), hashtable[hash]); + hashtable[hash] = entries.size() - 1; + } + return entries.size() - 1; + } + + public: + class const_iterator : public std::iterator> + { + 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 &operator*() const { return ptr->entries[index].udata; } + const std::pair *operator->() const { return &ptr->entries[index].udata; } + }; + + class iterator : public std::iterator> + { + 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 &operator*() { return ptr->entries[index].udata; } + std::pair *operator->() { return &ptr->entries[index].udata; } + const std::pair &operator*() const { return ptr->entries[index].udata; } + const std::pair *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> &list) + { + for (auto &it : list) + insert(it); + } + + template dict(InputIterator first, InputIterator last) { insert(first, last); } + + template void insert(InputIterator first, InputIterator last) + { + for (; first != last; ++first) + insert(*first); + } + + std::pair insert(const K &key) + { + int hash = do_hash(key); + int i = do_lookup(key, hash); + if (i >= 0) + return std::pair(iterator(this, i), false); + i = do_insert(key, hash); + return std::pair(iterator(this, i), true); + } + + std::pair insert(const std::pair &value) + { + int hash = do_hash(value.first); + int i = do_lookup(value.first, hash); + if (i >= 0) + return std::pair(iterator(this, i), false); + i = do_insert(value, hash); + return std::pair(iterator(this, i), true); + } + + std::pair insert(std::pair &&rvalue) + { + int hash = do_hash(rvalue.first); + int i = do_lookup(rvalue.first, hash); + if (i >= 0) + return std::pair(iterator(this, i), false); + i = do_insert(std::forward>(rvalue), hash); + return std::pair(iterator(this, i), true); + } + + std::pair 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(this, i), false); + i = do_insert(std::make_pair(key, value), hash); + return std::pair(iterator(this, i), true); + } + + std::pair emplace(K const &key, T &&rvalue) + { + int hash = do_hash(key); + int i = do_lookup(key, hash); + if (i >= 0) + return std::pair(iterator(this, i), false); + i = do_insert(std::make_pair(key, std::forward(rvalue)), hash); + return std::pair(iterator(this, i), true); + } + + std::pair emplace(K &&rkey, T const &value) + { + int hash = do_hash(rkey); + int i = do_lookup(rkey, hash); + if (i >= 0) + return std::pair(iterator(this, i), false); + i = do_insert(std::make_pair(std::forward(rkey), value), hash); + return std::pair(iterator(this, i), true); + } + + std::pair emplace(K &&rkey, T &&rvalue) + { + int hash = do_hash(rkey); + int i = do_lookup(rkey, hash); + if (i >= 0) + return std::pair(iterator(this, i), false); + i = do_insert(std::make_pair(std::forward(rkey), std::forward(rvalue)), hash); + return std::pair(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(key, T()), hash); + return entries[i].udata.second; + } + + template > 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::hash(entry.udata.first); + h ^= hash_ops::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 class pool +{ + template 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 hashtable; + std::vector 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(rvalue), -1); + do_rehash(); + hash = do_hash(rvalue); + } else { + entries.emplace_back(std::forward(rvalue), hashtable[hash]); + hashtable[hash] = entries.size() - 1; + } + return entries.size() - 1; + } + + public: + class const_iterator : public std::iterator + { + 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 + { + 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 &list) + { + for (auto &it : list) + insert(it); + } + + template pool(InputIterator first, InputIterator last) { insert(first, last); } + + template void insert(InputIterator first, InputIterator last) + { + for (; first != last; ++first) + insert(*first); + } + + std::pair insert(const K &value) + { + int hash = do_hash(value); + int i = do_lookup(value, hash); + if (i >= 0) + return std::pair(iterator(this, i), false); + i = do_insert(value, hash); + return std::pair(iterator(this, i), true); + } + + std::pair insert(K &&rvalue) + { + int hash = do_hash(rvalue); + int i = do_lookup(rvalue, hash); + if (i >= 0) + return std::pair(iterator(this, i), false); + i = do_insert(std::forward(rvalue), hash); + return std::pair(iterator(this, i), true); + } + + template std::pair emplace(Args &&...args) + { + return insert(K(std::forward(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 > 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 class idict +{ + pool database; + + public: + class const_iterator : public std::iterator + { + 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 class mfp +{ + mutable idict database; + mutable std::vector parents; + + public: + typedef typename idict::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/nextpnr_base_types.h b/common/nextpnr_base_types.h index 1a15bfcb..19786d6e 100644 --- a/common/nextpnr_base_types.h +++ b/common/nextpnr_base_types.h @@ -30,6 +30,7 @@ #include #include +#include "hashlib.h" #include "idstring.h" #include "nextpnr_namespaces.h" From ff72454f8391ab4785fa8314f3efbbea96c30422 Mon Sep 17 00:00:00 2001 From: gatecat Date: Tue, 1 Jun 2021 16:12:57 +0100 Subject: [PATCH 02/11] Add hash() member functions Signed-off-by: gatecat --- common/idstring.h | 2 ++ common/idstringlist.h | 9 +++++++++ docs/archapi.md | 14 +++++++------- ecp5/archdefs.h | 7 +++++++ fpga_interchange/archdefs.h | 5 +++++ ice40/archdefs.h | 6 ++++++ machxo2/archdefs.h | 5 +++++ mistral/archdefs.h | 4 ++++ nexus/archdefs.h | 6 ++++++ 9 files changed, 51 insertions(+), 7 deletions(-) diff --git a/common/idstring.h b/common/idstring.h index c3ccbc6b..aba40ae6 100644 --- a/common/idstring.h +++ b/common/idstring.h @@ -56,6 +56,8 @@ 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 diff --git a/common/idstringlist.h b/common/idstringlist.h index 24a46731..753b408c 100644 --- a/common/idstringlist.h +++ b/common/idstringlist.h @@ -22,6 +22,7 @@ #define IDSTRING_LIST_H #include +#include "hashlib.h" #include "idstring.h" #include "nextpnr_namespaces.h" #include "sso_array.h" @@ -67,6 +68,14 @@ struct IdStringList static IdStringList concat(IdStringList a, IdStringList b); IdStringList slice(size_t s, size_t e) const; + + unsigned int hash() const + { + unsigned int h = mkhash_init; + for (const auto &val : ids) + h = mkhash(h, val.hash()); + return h; + } }; NEXTPNR_NAMESPACE_END diff --git a/docs/archapi.md b/docs/archapi.md index 6d17f01a..80aa1d96 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`. +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`. +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`. +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`. +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`. +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`. +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`. +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 diff --git a/ecp5/archdefs.h b/ecp5/archdefs.h index 2b4590e5..57168af3 100644 --- a/ecp5/archdefs.h +++ b/ecp5/archdefs.h @@ -24,6 +24,7 @@ #include #include "base_clusterinfo.h" +#include "hashlib.h" #include "idstring.h" #include "nextpnr_namespaces.h" @@ -63,6 +64,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 +80,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 +94,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 +108,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 +124,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 +148,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 diff --git a/fpga_interchange/archdefs.h b/fpga_interchange/archdefs.h index c145b893..aa3f1e6e 100644 --- a/fpga_interchange/archdefs.h +++ b/fpga_interchange/archdefs.h @@ -25,6 +25,7 @@ #include #include "hash_table.h" +#include "hashlib.h" #include "luts.h" #include "nextpnr_namespaces.h" @@ -48,6 +49,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 +64,7 @@ struct WireId { return tile < other.tile || (tile == other.tile && index < other.index); } + unsigned int hash() const { return mkhash(tile, index); } }; struct PipId @@ -75,6 +78,7 @@ struct PipId { return tile < other.tile || (tile == other.tile && index < other.index); } + unsigned int hash() const { return mkhash(tile, index); } }; struct GroupId @@ -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; diff --git a/ice40/archdefs.h b/ice40/archdefs.h index c2b7019c..2d962851 100644 --- a/ice40/archdefs.h +++ b/ice40/archdefs.h @@ -23,6 +23,7 @@ #include #include "base_clusterinfo.h" +#include "hashlib.h" #include "idstring.h" #include "nextpnr_namespaces.h" @@ -55,6 +56,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 +66,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 +76,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 +100,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 +118,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 diff --git a/machxo2/archdefs.h b/machxo2/archdefs.h index 2d50dddb..afcc72aa 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; diff --git a/mistral/archdefs.h b/mistral/archdefs.h index 60bdcfeb..9d953223 100644 --- a/mistral/archdefs.h +++ b/mistral/archdefs.h @@ -25,6 +25,7 @@ #include "base_clusterinfo.h" #include "cyclonev.h" +#include "hashlib.h" #include "idstring.h" #include "nextpnr_assertions.h" #include "nextpnr_namespaces.h" @@ -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::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; diff --git a/nexus/archdefs.h b/nexus/archdefs.h index 660f166c..db8a3af4 100644 --- a/nexus/archdefs.h +++ b/nexus/archdefs.h @@ -24,6 +24,7 @@ #include #include "base_clusterinfo.h" +#include "hashlib.h" #include "idstring.h" #include "nextpnr_namespaces.h" @@ -62,6 +63,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 +82,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 +100,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 +115,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 +139,7 @@ struct DecalId { return (type != other.type) || (index != other.index) || (active != other.active); } + unsigned int hash() const { return mkhash(index, int(type)); } }; struct ArchNetInfo From 579b98c5963c2b86d191d481a2147a663a8196dd Mon Sep 17 00:00:00 2001 From: gatecat Date: Tue, 1 Jun 2021 16:51:18 +0100 Subject: [PATCH 03/11] Use hashlib for core netlist structures Signed-off-by: gatecat --- common/basectx.h | 26 +++--- common/chain_utils.h | 4 +- common/context.cc | 4 +- common/hashlib.h | 4 + common/nextpnr_types.h | 23 +++--- common/place_common.cc | 14 ++-- common/placer1.cc | 30 +++---- common/placer_heap.cc | 38 ++++----- common/pybindings.cc | 14 ++-- common/router2.cc | 8 +- common/sdf.cc | 8 +- common/timing.cc | 14 ++-- common/timing_opt.cc | 6 +- common/util.h | 5 +- ecp5/arch_place.cc | 12 +-- ecp5/arch_pybindings.cc | 8 +- ecp5/bitstream.cc | 3 +- ecp5/globals.cc | 12 +-- ecp5/main.cc | 4 +- ecp5/pack.cc | 122 ++++++++++++++-------------- fpga_interchange/arch.cc | 4 +- fpga_interchange/arch_pybindings.cc | 8 +- fpga_interchange/archdefs.h | 2 + fpga_interchange/globals.cc | 8 +- fpga_interchange/macros.cc | 4 +- generic/arch.cc | 4 +- generic/arch_pybindings.cc | 6 +- generic/pack.cc | 25 +++--- gowin/arch.cc | 4 +- gowin/arch_pybindings.cc | 6 +- gowin/pack.cc | 25 +++--- ice40/arch_pybindings.cc | 8 +- ice40/chains.cc | 4 +- ice40/pack.cc | 65 ++++++++------- ice40/pcf.cc | 4 +- json/jsonwrite.cc | 5 +- machxo2/arch_pybindings.cc | 8 +- machxo2/bitstream.cc | 3 +- machxo2/pack.cc | 25 +++--- mistral/arch.cc | 4 +- mistral/arch_pybindings.cc | 8 +- mistral/bitstream.cc | 10 +-- mistral/pack.cc | 28 +++---- nexus/arch.cc | 8 +- nexus/arch_pybindings.cc | 8 +- nexus/fasm.cc | 20 ++--- nexus/global.cc | 4 +- nexus/pack.cc | 80 +++++++++--------- nexus/post_place.cc | 4 +- 49 files changed, 383 insertions(+), 368 deletions(-) diff --git a/common/basectx.h b/common/basectx.h index fccd12af..dd48c33c 100644 --- a/common/basectx.h +++ b/common/basectx.h @@ -59,29 +59,29 @@ struct BaseCtx mutable StrRingBuffer log_strs; // Project settings and config switches - std::unordered_map settings; + dict settings; // Placed nets and cells. - std::unordered_map> nets; - std::unordered_map> cells; + dict> nets; + dict> cells; // Hierarchical (non-leaf) cells by full path - std::unordered_map hierarchy; + dict 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 net_aliases; + dict net_aliases; // Top-level ports - std::unordered_map ports; - std::unordered_map port_cells; + dict ports; + dict port_cells; // Floorplanning regions - std::unordered_map> region; + dict> region; // Context meta data - std::unordered_map attrs; + dict attrs; Context *as_ctx = nullptr; @@ -186,10 +186,10 @@ struct BaseCtx bool allUiReload = true; bool frameUiReload = false; - std::unordered_set belUiReload; - std::unordered_set wireUiReload; - std::unordered_set pipUiReload; - std::unordered_set groupUiReload; + pool belUiReload; + pool wireUiReload; + pool pipUiReload; + pool 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 find_chains(const Context *ctx, F1 cell_type_predicate, F { std::set chained; std::vector 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/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/hashlib.h b/common/hashlib.h index 48db024f..30fefc65 100644 --- a/common/hashlib.h +++ b/common/hashlib.h @@ -339,6 +339,10 @@ template class dict } public: + using key_type = K; + using mapped_type = T; + using value_type = std::pair; + class const_iterator : public std::iterator> { friend class dict; 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 #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 bels; - std::unordered_set wires; - std::unordered_set piplocs; + pool bels; + pool wires; + pool piplocs; }; struct PipMap @@ -128,10 +129,10 @@ struct NetInfo : ArchNetInfo PortRef driver; std::vector users; - std::unordered_map attrs; + dict attrs; // wire -> uphill_pip - std::unordered_map wires; + dict wires; std::vector 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 ports; - std::unordered_map attrs, params; + dict ports; + dict 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 leaf_cells, nets; + dict leaf_cells, nets; // Global name -> name inside cell instance - std::unordered_map leaf_cells_by_gname, nets_by_gname; + dict leaf_cells_by_gname, nets_by_gname; // Cell port to net - std::unordered_map ports; + dict ports; // Name inside cell instance -> global name - std::unordered_map hier_cells; + dict hier_cells; }; NEXTPNR_NAMESPACE_END diff --git a/common/place_common.cc b/common/place_common.cc index 7cbeca65..ece47b5a 100644 --- a/common/place_common.cc +++ b/common/place_common.cc @@ -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..f9cef92f 100644 --- a/common/placer1.cc +++ b/common/placer1.cc @@ -88,7 +88,7 @@ class SAPlacer diameter = std::max(max_x, max_y) + 1; std::unordered_set cell_types_in_use; - for (auto cell : sorted(ctx->cells)) { + for (auto &cell : ctx->cells) { IdString cell_type = cell.second->type; cell_types_in_use.insert(cell_type); } @@ -108,8 +108,8 @@ class SAPlacer net.second->udata = n++; net_by_udata.push_back(net.second.get()); } - for (auto ®ion : sorted(ctx->region)) { - Region *r = region.second; + for (auto ®ion : ctx->region) { + Region *r = region.second.get(); BoundingBox bb; if (r->constr_bels) { bb.x0 = std::numeric_limits::max(); @@ -360,12 +360,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(M, diameter * post_legalise_dia_scale); @@ -421,8 +421,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); @@ -831,8 +831,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); @@ -1118,8 +1118,8 @@ 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; @@ -1135,8 +1135,8 @@ class SAPlacer { total_net_share = 0; nets_by_tile.resize(max_x + 1, std::vector>(max_y + 1)); - for (auto cell : sorted(ctx->cells)) { - CellInfo *ci = cell.second; + 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); diff --git a/common/placer_heap.cc b/common/placer_heap.cc index 2f7c7ccb..c26e1556 100644 --- a/common/placer_heap.cc +++ b/common/placer_heap.cc @@ -146,9 +146,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() @@ -283,8 +283,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 +311,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)); @@ -450,7 +450,7 @@ class HeAPPlacer std::unordered_set cell_types_in_use; std::unordered_set buckets_in_use; - for (auto cell : sorted(ctx->cells)) { + 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 +465,8 @@ class HeAPPlacer } // Determine bounding boxes of region constraints - for (auto ®ion : sorted(ctx->region)) { - Region *r = region.second; + for (auto ®ion : ctx->region) { + Region *r = region.second.get(); BoundingBox bb; if (r->constr_bels) { bb.x0 = std::numeric_limits::max(); @@ -539,8 +539,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 +591,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; @@ -617,7 +617,7 @@ class HeAPPlacer 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 +671,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 +783,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 +809,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))) 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 AttrMap; - typedef std::unordered_map PortMap; - typedef std::unordered_map IdIdMap; - typedef std::unordered_map> RegionMap; + typedef dict AttrMap; + typedef dict PortMap; + typedef dict IdIdMap; + typedef dict> RegionMap; py::class_(m, "BaseCtx"); @@ -218,9 +218,9 @@ PYBIND11_EMBEDDED_MODULE(MODULE_NAME, m) pass_through>::def_wrap(pi_cls, "type"); typedef std::vector PortRefVector; - typedef std::unordered_map WireMap; - typedef std::unordered_set BelSet; - typedef std::unordered_set WireSet; + typedef dict WireMap; + typedef pool BelSet; + typedef pool WireSet; auto ni_cls = py::class_>(m, "NetInfo"); readwrite_wrapper, diff --git a/common/router2.cc b/common/router2.cc index 2156ce28..b0f53ce1 100644 --- a/common/router2.cc +++ b/common/router2.cc @@ -131,8 +131,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()); @@ -231,8 +231,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); 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..b68ca35c 100644 --- a/common/timing.cc +++ b/common/timing.cc @@ -52,17 +52,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 +138,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) { diff --git a/common/timing_opt.cc b/common/timing_opt.cc index 854cbc5b..2659f04e 100644 --- a/common/timing_opt.cc +++ b/common/timing_opt.cc @@ -68,8 +68,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) { @@ -239,7 +239,7 @@ class TimingOptimiser std::vector> crit_nets; std::vector netnames; std::transform(ctx->nets.begin(), ctx->nets.end(), std::back_inserter(netnames), - [](const std::pair> &kv) { return kv.first; }); + [](const std::pair> &kv) { return kv.first; }); ctx->sorted_shuffle(netnames); for (auto net : netnames) { if (crit_nets.size() >= max_count) diff --git a/common/util.h b/common/util.h index 540646c7..b3e8cbf0 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 -std::string str_or_default(const std::unordered_map &ct, const KeyType &key, std::string def = "") +std::string str_or_default(const dict &ct, const KeyType &key, std::string def = "") { auto found = ct.find(key); if (found == ct.end()) @@ -78,8 +78,7 @@ template int int_or_default(const Contain return std::stoi(found->second); }; -template -int int_or_default(const std::unordered_map &ct, const KeyType &key, int def = 0) +template int int_or_default(const dict &ct, const KeyType &key, int def = 0) { auto found = ct.find(key); if (found == ct.end()) diff --git a/ecp5/arch_place.cc b/ecp5/arch_place.cc index 57c3b181..0da20151 100644 --- a/ecp5/arch_place.cc +++ b/ecp5/arch_place.cc @@ -99,8 +99,8 @@ void Arch::permute_luts() tmg.setup(); std::unordered_map port_to_user; - for (auto net : sorted(nets)) { - NetInfo *ni = net.second; + for (auto &net : nets) { + NetInfo *ni = net.second.get(); 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; @@ -157,8 +157,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 +169,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> CellMap; - typedef std::unordered_map> NetMap; - typedef std::unordered_map AliasMap; - typedef std::unordered_map HierarchyMap; + typedef dict> CellMap; + typedef dict> NetMap; + typedef dict AliasMap; + typedef dict HierarchyMap; auto belpin_cls = py::class_>(m, "BelPin"); readonly_wrapper>::def_wrap(belpin_cls, "bel"); diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc index f8d11d39..c8349f88 100644 --- a/ecp5/bitstream.cc +++ b/ecp5/bitstream.cc @@ -569,8 +569,7 @@ static std::vector parse_config_str(const Property &p, int length) return word; } -std::string intstr_or_default(const std::unordered_map &ct, const IdString &key, - std::string def = "0") +std::string intstr_or_default(const dict &ct, const IdString &key, std::string def = "0") { auto found = ct.find(key); if (found == ct.end()) diff --git a/ecp5/globals.cc b/ecp5/globals.cc index 36bec64c..1e86fe6b 100644 --- a/ecp5/globals.cc +++ b/ecp5/globals.cc @@ -91,8 +91,8 @@ class Ecp5GlobalRouter } // DCCAs must always drive globals std::vector 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) { @@ -536,8 +536,8 @@ class Ecp5GlobalRouter } std::vector> toroute; std::unordered_map 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 *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 pins; if (ci->type == id_ECLKSYNCB || ci->type == id_TRELLIS_ECLKBUF) { diff --git a/ecp5/main.cc b/ecp5/main.cc index 5d9fc965..f6d734e1 100644 --- a/ecp5/main.cc +++ b/ecp5/main.cc @@ -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..db5d22a1 100644 --- a/ecp5/pack.cc +++ b/ecp5/pack.cc @@ -106,8 +106,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) { @@ -262,8 +262,8 @@ class Ecp5Packer { log_info("Finding LUT-LUT pairs...\n"); std::unordered_set procdLuts; - 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) && procdLuts.find(cell.first) == procdLuts.end()) { NetInfo *znet = ci->ports.at(ctx->id("Z")).net; std::vector inpnets; @@ -392,8 +392,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 +443,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 +536,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 packed = create_ecp5_cell(ctx, ctx->id("TRELLIS_SLICE"), ci->name.str(ctx) + "_SLICE"); @@ -593,8 +593,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 +651,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 +975,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 +1108,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 slice = create_ecp5_cell(ctx, ctx->id("TRELLIS_SLICE"), ci->name.str(ctx) + "_SLICE"); @@ -1181,8 +1181,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 +1403,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 +1461,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 +1503,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 +1544,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 +1708,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 +1759,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 +1800,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 +1829,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 +1863,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)); @@ -2030,8 +2030,8 @@ class Ecp5Packer // 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) @@ -2265,8 +2265,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 +2349,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 +2692,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 +2760,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; @@ -2780,8 +2780,8 @@ class Ecp5Packer } flush_cells(); std::unordered_set used_eclksyncb; - 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) { const NetInfo *clki = net_or_nullptr(ci, id_CLKI); for (auto &eclk : eclks) { @@ -2896,8 +2896,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 +2921,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; @@ -3114,8 +3114,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"); } @@ -3188,8 +3188,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 +3301,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..663587fd 100644 --- a/fpga_interchange/arch.cc +++ b/fpga_interchange/arch.cc @@ -2047,8 +2047,8 @@ void Arch::pack_default_conns() std::vector 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_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>::def_wrap(ctx_cls, "explain_bel_status"); - typedef std::unordered_map> CellMap; - typedef std::unordered_map> NetMap; - typedef std::unordered_map AliasMap; - typedef std::unordered_map HierarchyMap; + typedef dict> CellMap; + typedef dict> NetMap; + typedef dict AliasMap; + typedef dict HierarchyMap; auto belpin_cls = py::class_>(m, "BelPin"); readonly_wrapper>::def_wrap(belpin_cls, "bel"); diff --git a/fpga_interchange/archdefs.h b/fpga_interchange/archdefs.h index aa3f1e6e..ba4fe054 100644 --- a/fpga_interchange/archdefs.h +++ b/fpga_interchange/archdefs.h @@ -85,12 +85,14 @@ 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 diff --git a/fpga_interchange/globals.cc b/fpga_interchange/globals.cc index 66d04f75..918b916e 100644 --- a/fpga_interchange/globals.cc +++ b/fpga_interchange/globals.cc @@ -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/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 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 next_cells; 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_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, conv_from_str, pass_through, pass_through>::def_wrap(ctx_cls, "DecalXY"); - typedef std::unordered_map> CellMap; - typedef std::unordered_map> NetMap; - typedef std::unordered_map HierarchyMap; + typedef dict> CellMap; + typedef dict> NetMap; + typedef dict HierarchyMap; readonly_wrapper>::def_wrap(ctx_cls, "cells"); diff --git a/generic/pack.cc b/generic/pack.cc index 6b984fef..a1c325f8 100644 --- a/generic/pack.cc +++ b/generic/pack.cc @@ -34,14 +34,15 @@ static void pack_lut_lutffs(Context *ctx) std::unordered_set packed_cells; std::vector> 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 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)); @@ -91,12 +92,13 @@ static void pack_nonlut_ffs(Context *ctx) std::unordered_set packed_cells; std::vector> 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 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 +160,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); @@ -207,8 +209,8 @@ static void pack_io(Context *ctx) std::vector> 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 +256,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_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, conv_from_str, pass_through, pass_through>::def_wrap(ctx_cls, "DecalXY"); - typedef std::unordered_map> CellMap; - typedef std::unordered_map> NetMap; - typedef std::unordered_map HierarchyMap; + typedef dict> CellMap; + typedef dict> NetMap; + typedef dict HierarchyMap; readonly_wrapper>::def_wrap(ctx_cls, "cells"); diff --git a/gowin/pack.cc b/gowin/pack.cc index 204f1c22..a2998c63 100644 --- a/gowin/pack.cc +++ b/gowin/pack.cc @@ -36,13 +36,14 @@ static void pack_lut_lutffs(Context *ctx) std::unordered_set packed_cells; std::vector> 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 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())); @@ -92,11 +93,12 @@ static void pack_nonlut_ffs(Context *ctx) std::unordered_set packed_cells; std::vector> 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 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 +160,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); @@ -216,8 +218,8 @@ static void pack_io(Context *ctx) std::vector> 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 +253,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/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> CellMap; - typedef std::unordered_map> NetMap; - typedef std::unordered_map AliasMap; - typedef std::unordered_map HierarchyMap; + typedef dict> CellMap; + typedef dict> NetMap; + typedef dict AliasMap; + typedef dict HierarchyMap; auto belpin_cls = py::class_>(m, "BelPin"); readonly_wrapper>::def_wrap(belpin_cls, "bel"); diff --git a/ice40/chains.cc b/ice40/chains.cc index 2607959a..f75d329f 100644 --- a/ice40/chains.cc +++ b/ice40/chains.cc @@ -260,8 +260,8 @@ class ChainConstrainer } // 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/pack.cc b/ice40/pack.cc index 51138a22..1d05a8c2 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -37,13 +37,14 @@ static void pack_lut_lutffs(Context *ctx) int lut_only = 0, lut_and_ff = 0; std::unordered_set packed_cells; std::vector> 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 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)); @@ -103,12 +104,13 @@ static void pack_nonlut_ffs(Context *ctx) std::vector> 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 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); @@ -147,8 +149,8 @@ static void pack_carries(Context *ctx) std::vector> 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); @@ -275,8 +277,8 @@ static void pack_ram(Context *ctx) std::unordered_set packed_cells; std::vector> 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 packed = create_ice_cell(ctx, ctx->id("ICESTORM_RAM"), ci->name.str(ctx) + "_RAM"); @@ -379,8 +381,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); @@ -469,8 +471,8 @@ static void pack_io(Context *ctx) std::vector> 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 +533,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 +544,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 gb = @@ -637,8 +640,8 @@ static void promote_globals(Context *ctx) const int enable_fanout_thresh = 15; const int reset_fanout_thresh = 15; std::map 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 +781,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 +864,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 +902,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; @@ -1120,8 +1123,8 @@ static void pack_special(Context *ctx) std::vector> 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 +1142,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 packed = create_ice_cell(ctx, ctx->id("ICESTORM_LFOSC"), ci->name.str(ctx) + "_OSC"); @@ -1298,8 +1301,8 @@ void pack_plls(Context *ctx) std::unordered_set packed_cells; std::vector> 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..dbf43351 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 ¶meters, +void write_parameters(std::ostream &f, Context *ctx, const dict ¶meters, bool for_module = false) { bool first = true; @@ -64,8 +64,7 @@ struct PortGroup PortType dir; }; -std::vector group_ports(Context *ctx, const std::unordered_map &ports, - bool is_cell = false) +std::vector group_ports(Context *ctx, const dict &ports, bool is_cell = false) { std::vector groups; std::unordered_map base_to_group; 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> CellMap; - typedef std::unordered_map> NetMap; - typedef std::unordered_map AliasMap; - typedef std::unordered_map HierarchyMap; + typedef dict> CellMap; + typedef dict> NetMap; + typedef dict AliasMap; + typedef dict HierarchyMap; auto belpin_cls = py::class_>(m, "BelPin"); readonly_wrapper>::def_wrap(belpin_cls, "bel"); 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 int_to_bitvector(int val, int size) return bv; } -std::string intstr_or_default(const std::unordered_map &ct, const IdString &key, - std::string def = "0") +std::string intstr_or_default(const dict &ct, const IdString &key, std::string def = "0") { auto found = ct.find(key); if (found == ct.end()) diff --git a/machxo2/pack.cc b/machxo2/pack.cc index 5a6cd97b..26bda946 100644 --- a/machxo2/pack.cc +++ b/machxo2/pack.cc @@ -35,13 +35,14 @@ static void pack_lut_lutffs(Context *ctx) std::unordered_set packed_cells; std::vector> 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 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) @@ -93,15 +94,16 @@ static void pack_remaining_ffs(Context *ctx) std::unordered_set packed_cells; std::vector> 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 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); @@ -142,7 +144,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 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 +196,8 @@ static void pack_constants(Context *ctx) std::vector 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); @@ -234,8 +237,8 @@ static void pack_io(Context *ctx) 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_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, pass_through, pass_through>::def_wrap(ctx_cls, "compute_lut_mask"); - typedef std::unordered_map> CellMap; - typedef std::unordered_map> NetMap; - typedef std::unordered_map AliasMap; - typedef std::unordered_map HierarchyMap; + typedef dict> CellMap; + typedef dict> NetMap; + typedef dict AliasMap; + typedef dict HierarchyMap; auto belpin_cls = py::class_>(m, "BelPin"); readonly_wrapper>::def_wrap(belpin_cls, "bel"); 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/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 trim_cells; std::vector 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/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_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> CellMap; - typedef std::unordered_map> NetMap; - typedef std::unordered_map HierarchyMap; - typedef std::unordered_map AliasMap; + typedef dict> CellMap; + typedef dict> NetMap; + typedef dict HierarchyMap; + typedef dict AliasMap; typedef UpDownhillPipRange UphillPipRange; typedef UpDownhillPipRange DownhillPipRange; diff --git a/nexus/fasm.cc b/nexus/fasm.cc index 0afefa4b..13fe00c1 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; @@ -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 ¶m : cell->params) { const std::string ¶m_name = param.first.str(ctx); if (is_mux_param(param_name)) continue; @@ -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 ¶m : 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 ¶m : cell->params) { const std::string &name = param.first.str(ctx); if (is_mux_param(name) || name == "GSR") continue; @@ -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..fa6212e8 100644 --- a/nexus/global.cc +++ b/nexus/global.cc @@ -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/pack.cc b/nexus/pack.cc index 66ab4b09..812731cf 100644 --- a/nexus/pack.cc +++ b/nexus/pack.cc @@ -182,8 +182,8 @@ struct NexusPacker { std::map cell_count; std::map 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); @@ -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 trim_cells; std::vector 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(); @@ -579,8 +579,8 @@ struct NexusPacker 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 +625,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 +660,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(); @@ -854,8 +854,8 @@ struct NexusPacker { std::vector> 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 +894,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 +916,8 @@ struct NexusPacker { // Do this so we don't have an iterate-and-modfiy situation std::vector 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); @@ -1031,8 +1031,8 @@ struct NexusPacker {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)); @@ -1084,8 +1084,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)) @@ -1129,8 +1129,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 +1151,8 @@ struct NexusPacker void pack_widefn() { std::vector 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 +1200,8 @@ struct NexusPacker // Find root carry cells log_info("Packing carries...\n"); std::vector 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) @@ -1306,7 +1306,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; @@ -1609,8 +1609,8 @@ struct NexusPacker log_info("Packing DSPs...\n"); std::vector 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 +1792,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); } @@ -1949,8 +1949,8 @@ struct NexusPacker {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); @@ -1975,8 +1975,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 +2026,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/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 From 43b8dde923b8cf57a206526fd6e66ebf1c436010 Mon Sep 17 00:00:00 2001 From: gatecat Date: Tue, 1 Jun 2021 17:52:25 +0100 Subject: [PATCH 04/11] Use hashlib in placers Signed-off-by: gatecat --- common/fast_bels.h | 4 ++-- common/nextpnr_base_types.h | 1 + common/place_common.cc | 10 ++++---- common/placer1.cc | 20 ++++++++-------- common/placer_heap.cc | 47 ++++++++++++++++++------------------- common/placer_heap.h | 4 ++-- ecp5/arch_place.cc | 9 ------- 7 files changed, 43 insertions(+), 52 deletions(-) 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 cell_types; + dict cell_types; std::vector> fast_bels_by_cell_type; - std::unordered_map partition_types; + dict partition_types; std::vector> fast_bels_by_partition_type; }; diff --git a/common/nextpnr_base_types.h b/common/nextpnr_base_types.h index 19786d6e..ba1af68c 100644 --- a/common/nextpnr_base_types.h +++ b/common/nextpnr_base_types.h @@ -90,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 diff --git a/common/place_common.cc b/common/place_common.cc index ece47b5a..9a6c6158 100644 --- a/common/place_common.cc +++ b/common/place_common.cc @@ -178,8 +178,8 @@ class ConstraintLegaliseWorker private: Context *ctx; std::set rippedCells; - std::unordered_map oldLocations; - std::unordered_map> cluster2cells; + dict oldLocations; + dict> cluster2cells; class IncreasingDiameterSearch { @@ -227,10 +227,10 @@ class ConstraintLegaliseWorker int sign = 0; }; - typedef std::unordered_map CellLocations; + typedef dict 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 &usedLocations) + bool valid_loc_for(const CellInfo *cell, Loc loc, CellLocations &solution, pool &usedLocations) { BelId locBel = ctx->getBelByLocation(loc); if (locBel == BelId()) @@ -324,7 +324,7 @@ class ConstraintLegaliseWorker } CellLocations solution; - std::unordered_set used; + pool used; if (valid_loc_for(cell, rootLoc, solution, used)) { for (auto cp : solution) { // First unbind all cells diff --git a/common/placer1.cc b/common/placer1.cc index f9cef92f..e8c6aa64 100644 --- a/common/placer1.cc +++ b/common/placer1.cc @@ -87,7 +87,7 @@ class SAPlacer } diameter = std::max(max_x, max_y) + 1; - std::unordered_set cell_types_in_use; + pool cell_types_in_use; for (auto &cell : ctx->cells) { IdString cell_type = cell.second->type; cell_types_in_use.insert(cell_type); @@ -629,7 +629,7 @@ class SAPlacer bool try_swap_chain(CellInfo *cell, BelId newBase) { std::vector> cell_rel; - std::unordered_set cells; + pool cells; std::vector> moves_made; std::vector> dest_bels; double delta = 0; @@ -1065,7 +1065,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; @@ -1122,7 +1122,7 @@ class SAPlacer 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,11 +1130,11 @@ class SAPlacer // Simple routeability driven placement const int large_cell_thresh = 50; int total_net_share = 0; - std::vector>> nets_by_tile; + std::vector>> nets_by_tile; void setup_nets_by_tile() { total_net_share = 0; - nets_by_tile.resize(max_x + 1, std::vector>(max_y + 1)); + nets_by_tile.resize(max_x + 1, std::vector>(max_y + 1)); for (auto &cell : ctx->cells) { CellInfo *ci = cell.second.get(); if (int(ci->ports.size()) > large_cell_thresh) @@ -1194,7 +1194,7 @@ class SAPlacer std::vector> net_arc_tcost; // Fast lookup for cell port to net user index - std::unordered_map fast_port_to_user; + dict, 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 +1207,10 @@ class SAPlacer bool improved = false; int n_move, n_accept; int diameter = 35, max_x = 1, max_y = 1; - std::unordered_map> bel_types; - std::unordered_map region_bounds; + dict> bel_types; + dict region_bounds; FastBels fast_bels; - std::unordered_set locked_bels; + pool locked_bels; std::vector net_by_udata; std::vector old_udata; bool require_legal = true; diff --git a/common/placer_heap.cc b/common/placer_heap.cc index c26e1556..f1419bdb 100644 --- a/common/placer_heap.cc +++ b/common/placer_heap.cc @@ -43,7 +43,6 @@ #include #include #include -#include #include "fast_bels.h" #include "log.h" #include "nextpnr.h" @@ -188,14 +187,14 @@ class HeAPPlacer std::vector> solution; - std::vector> heap_runs; - std::unordered_set all_buckets; - std::unordered_map bucket_count; + std::vector> heap_runs; + pool all_buckets; + dict 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{bucket}); + heap_runs.push_back(pool{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 &grp) { return !grp.count(type); })) + [type](const pool &grp) { return !grp.count(type); })) CutSpreader(this, {type}).run(); // Run strict legalisation to find a valid bel for all cells @@ -360,7 +359,7 @@ class HeAPPlacer int max_x = 0, max_y = 0; FastBels fast_bels; - std::unordered_map> bel_types; + dict> bel_types; TimingAnalyser tmg; @@ -370,7 +369,7 @@ class HeAPPlacer int x0 = 0, x1 = 0, y0 = 0, y1 = 0; }; - std::unordered_map constraint_region_bounds; + dict 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 cell_locs; + dict 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 place_cells; @@ -390,8 +389,8 @@ class HeAPPlacer // cells of a certain type) std::vector solve_cells; - std::unordered_map> cluster2cells; - std::unordered_map chain_size; + dict> cluster2cells; + dict chain_size; // Performance counting double solve_time = 0, cl_time = 0, sl_time = 0; @@ -448,8 +447,8 @@ class HeAPPlacer max_y = std::max(max_y, loc.y); } - std::unordered_set cell_types_in_use; - std::unordered_set buckets_in_use; + pool cell_types_in_use; + pool buckets_in_use; for (auto &cell : ctx->cells) { IdString cell_type = cell.second->type; cell_types_in_use.insert(cell_type); @@ -515,13 +514,13 @@ class HeAPPlacer // FIXME: Are there better approaches to the initial placement (e.g. greedy?) void seed_placement() { - std::unordered_set cell_types; + pool cell_types; for (const auto &cell : ctx->cells) { cell_types.insert(cell.second->type); } - std::unordered_set bels_used; - std::unordered_map> available_bels; + pool bels_used; + dict> available_bels; for (auto bel : ctx->getBels()) { if (!ctx->checkBelAvail(bel)) { @@ -612,7 +611,7 @@ class HeAPPlacer } // Setup the cells to be solved, returns the number of rows - int setup_solve_cells(std::unordered_set *buckets = nullptr) + int setup_solve_cells(pool *buckets = nullptr) { int row = 0; solve_cells.clear(); @@ -1106,11 +1105,11 @@ class HeAPPlacer class CutSpreader { public: - CutSpreader(HeAPPlacer *p, const std::unordered_set &buckets) : p(p), ctx(p->ctx), buckets(buckets) + CutSpreader(HeAPPlacer *p, const pool &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 buckets; - std::unordered_map type_index; + pool buckets; + dict type_index; std::vector>> occupancy; std::vector> groups; std::vector> chaines; @@ -1208,7 +1207,7 @@ class HeAPPlacer std::vector>> *> fb; std::vector regions; - std::unordered_set merged_regions; + pool merged_regions; // Cells at a location, sorted by real (not integer) x and y std::vector>> 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 ioBufTypes; + pool ioBufTypes; // These cell types are part of the same unit (e.g. slices split into // components) so will always be spread together - std::vector> cellGroups; + std::vector> cellGroups; }; extern bool placer_heap(Context *ctx, PlacerHeapCfg cfg); diff --git a/ecp5/arch_place.cc b/ecp5/arch_place.cc index 0da20151..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 port_to_user; - for (auto &net : nets) { - NetInfo *ni = net.second.get(); - 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 port_names; for (int i = 0; i < 4; i++) From dfe0ce599a8d713eb1caabcd44626aa052390312 Mon Sep 17 00:00:00 2001 From: gatecat Date: Tue, 1 Jun 2021 21:12:17 +0100 Subject: [PATCH 05/11] Bump tests submodule Signed-off-by: gatecat --- tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests b/tests index caf7261b..1cc7ee78 160000 --- a/tests +++ b/tests @@ -1 +1 @@ -Subproject commit caf7261be7b34b365ab6d8449455891c2ed28faa +Subproject commit 1cc7ee785957c14f83b89d6bf18f14d072e6312e From f4fed62c05a9595e22a8ec54add5531225911741 Mon Sep 17 00:00:00 2001 From: gatecat Date: Wed, 2 Jun 2021 09:28:53 +0100 Subject: [PATCH 06/11] Use hashlib in routers Signed-off-by: gatecat --- common/context.h | 2 +- common/router1.cc | 63 ++++++++++++++++++++++------------------------- common/router2.cc | 11 ++++----- ice40/delay.cc | 2 +- 4 files changed, 37 insertions(+), 41 deletions(-) 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 *route = nullptr, bool useEstimate = true); + dict *route = nullptr, bool useEstimate = true); // -------------------------------------------------------------- // call after changing hierpath or adding/removing nets and cells 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()(arg.net_info); - seed ^= std::hash()(arg.user_idx) + 0x9e3779b9 + (seed << 6) + (seed >> 2); - seed ^= std::hash()(arg.phys_idx) + 0x9e3779b9 + (seed << 6) + (seed >> 2); - return seed; - } - }; + std::size_t seed = std::hash()(net_info); + seed ^= std::hash()(user_idx) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + seed ^= std::hash()(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::Less> arc_queue; - std::unordered_map> wire_to_arcs; - std::unordered_map, arc_key::Hash> arc_to_wires; - std::unordered_set queued_arcs; + dict> wire_to_arcs; + dict> arc_to_wires; + pool queued_arcs; - std::unordered_map visited; + dict visited; std::priority_queue, QueuedWire::Greater> queue; - std::unordered_map wireScores; - std::unordered_map netScores; + dict wireScores; + dict netScores; int arcs_with_ripup = 0; int arcs_without_ripup = 0; @@ -295,11 +292,11 @@ struct Router1 void check() { - std::unordered_set valid_arcs; + pool valid_arcs; for (auto &net_it : ctx->nets) { NetInfo *net_info = net_it.second.get(); - std::unordered_set valid_wires_for_net; + pool valid_wires_for_net; if (skip_net(net_info)) continue; @@ -357,8 +354,8 @@ struct Router1 void setup() { - std::unordered_map src_to_net; - std::unordered_map dst_to_arc; + dict src_to_net; + dict dst_to_arc; std::vector 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 old_arc_wires; + pool 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 unassign_wires = arc_to_wires[arc]; + pool 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 children; + pool children; }; - std::unordered_map db; + dict> 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()).first->second->children.insert(w); } } @@ -948,7 +945,7 @@ bool Context::checkRoutedDesign() const found_unrouted = true; } - std::unordered_map dest_wires; + dict 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 setOrderNum; - std::unordered_set logged_wires; + pool logged_wires; setOrderNum = [&](WireId w, int num) { - auto &db_entry = db[w]; + auto &db_entry = *db.emplace(w, std::make_unique()).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 dangling_wires; + pool 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 root_wires = dangling_wires; + pool 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 *route, bool useEstimate) +bool Context::getActualRouteDelay(WireId src_wire, WireId dst_wire, delay_t *delay, dict *route, + bool useEstimate) { // FIXME return false; diff --git a/common/router2.cc b/common/router2.cc index b0f53ce1..e1d3e75b 100644 --- a/common/router2.cc +++ b/common/router2.cc @@ -35,7 +35,6 @@ #include #include -#include "hash_table.h" #include "log.h" #include "nextpnr.h" #include "router1.h" @@ -198,7 +197,7 @@ struct Router2 } } - HashTables::HashMap wire_to_idx; + dict wire_to_idx; std::vector flat_wires; PerWireData &wire_data(WireId w) { return flat_wires[wire_to_idx.at(w)]; } @@ -284,7 +283,7 @@ struct Router2 std::priority_queue, QueuedWire::Greater> queue; // Special case where one net has multiple logical arcs to the same physical sink - std::unordered_set processed_sinks; + pool processed_sinks; // Backwards routing std::queue 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 rsv; + pool 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> cong_by_type; + dict> 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/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 route; + dict route; #if NUM_FUZZ_ROUTES <= 1000 if (!ctx->getActualRouteDelay(src, dst, nullptr, &route, false)) From ecc19c2c083f7e3ed7da95557731ded803d2cb1d Mon Sep 17 00:00:00 2001 From: gatecat Date: Wed, 2 Jun 2021 10:01:36 +0100 Subject: [PATCH 07/11] Using hashlib in arches Signed-off-by: gatecat --- common/base_arch.h | 12 ++-- common/hashlib.h | 9 +++ ecp5/arch.h | 26 ++------ ecp5/bitstream.cc | 4 +- ecp5/cells.cc | 2 +- ecp5/cells.h | 2 +- ecp5/globals.cc | 14 ++-- ecp5/lpf.cc | 5 +- ecp5/pack.cc | 29 ++++----- fpga_interchange/arch.cc | 19 +----- fpga_interchange/arch.h | 22 +++---- fpga_interchange/arch_pack_io.cc | 26 ++++---- fpga_interchange/archdefs.h | 7 +- fpga_interchange/cell_parameters.h | 3 +- fpga_interchange/cost_map.cc | 2 +- fpga_interchange/cost_map.h | 5 +- fpga_interchange/dedicated_interconnect.cc | 6 +- fpga_interchange/dedicated_interconnect.h | 36 ++-------- fpga_interchange/fpga_interchange.cpp | 54 ++++++--------- fpga_interchange/globals.cc | 2 +- fpga_interchange/lookahead.cc | 76 ++++++++++------------ fpga_interchange/lookahead.h | 7 +- fpga_interchange/luts.cc | 14 ++-- fpga_interchange/luts.h | 23 +++---- fpga_interchange/pseudo_pip_model.cc | 8 +-- fpga_interchange/pseudo_pip_model.h | 35 +++------- fpga_interchange/site_arch.cc | 2 +- fpga_interchange/site_arch.h | 46 +++---------- fpga_interchange/site_router.cc | 24 +++---- fpga_interchange/site_router.h | 5 +- fpga_interchange/site_routing_cache.cc | 2 +- fpga_interchange/site_routing_cache.h | 39 ++++------- fpga_interchange/type_wire.cc | 5 +- fpga_interchange/type_wire.h | 36 ++-------- generic/arch.h | 39 ++++------- generic/archdefs.h | 5 +- generic/cells.cc | 2 +- generic/cells.h | 2 +- generic/pack.cc | 9 ++- gowin/arch.h | 37 ++++------- gowin/cells.cc | 2 +- gowin/cells.h | 2 +- gowin/pack.cc | 9 ++- ice40/arch.h | 10 +-- ice40/bitstream.cc | 8 +-- ice40/cells.cc | 2 +- ice40/cells.h | 2 +- ice40/chains.cc | 2 +- ice40/pack.cc | 19 +++--- machxo2/arch.h | 4 +- machxo2/cells.cc | 2 +- machxo2/cells.h | 2 +- machxo2/pack.cc | 9 ++- mistral/arch.h | 29 ++++----- mistral/archdefs.h | 2 +- mistral/lab.cc | 4 +- mistral/pins.cc | 2 +- mistral/qsf.cc | 2 +- nexus/arch.h | 12 ++-- nexus/archdefs.h | 3 +- nexus/fasm.cc | 10 +-- nexus/global.cc | 2 +- nexus/io.cc | 2 +- nexus/pack.cc | 63 +++++++++--------- nexus/pdc.cc | 2 +- nexus/pins.cc | 2 +- 66 files changed, 359 insertions(+), 550 deletions(-) diff --git a/common/base_arch.h b/common/base_arch.h index fbafee99..c7d9f380 100644 --- a/common/base_arch.h +++ b/common/base_arch.h @@ -441,23 +441,23 @@ template struct BaseArch : ArchAPI // -------------------------------------------------------------- // 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 base_bel2cell; - std::unordered_map base_wire2net; - std::unordered_map base_pip2net; + dict base_bel2cell; + dict base_wire2net; + dict base_pip2net; // For the default cell/bel bucket implementations std::vector cell_types; std::vector bel_buckets; - std::unordered_map> bucket_bels; + dict> 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 bel_types; + pool 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/hashlib.h b/common/hashlib.h index 30fefc65..063df78f 100644 --- a/common/hashlib.h +++ b/common/hashlib.h @@ -74,6 +74,15 @@ template <> struct hash_ops : hash_int_ops static inline unsigned int hash(int64_t a) { return mkhash((unsigned int)(a), (unsigned int)(a >> 32)); } }; +template <> struct hash_ops : hash_int_ops +{ + static inline unsigned int hash(uint32_t a) { return a; } +}; +template <> struct hash_ops : hash_int_ops +{ + static inline unsigned int hash(uint64_t a) { return mkhash((unsigned int)(a), (unsigned int)(a >> 32)); } +}; + template <> struct hash_ops { static inline bool cmp(const std::string &a, const std::string &b) { return a == b; } 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 -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX DelayKey &dk) const noexcept - { - std::size_t seed = std::hash()(dk.celltype); - seed ^= std::hash()(dk.from) + 0x9e3779b9 + (seed << 6) + (seed >> 2); - seed ^= std::hash()(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 const PackageInfoPOD *package_info; const SpeedGradePOD *speed_grade; - mutable std::unordered_map pip_by_name; + mutable dict pip_by_name; std::vector bel_to_cell; - std::unordered_map wire_fanout; + dict wire_fanout; // fast access to X and Y IdStrings for building object names std::vector x_ids, y_ids; // inverse of the above for name->object mapping - std::unordered_map id_to_x, id_to_y; + dict id_to_x, id_to_y; ArchArgs args; Arch(ArchArgs args); @@ -914,10 +900,10 @@ struct Arch : BaseArch // 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> wire_loc_overrides; + dict> wire_loc_overrides; void setup_wire_locations(); - mutable std::unordered_map> celldelay_cache; + mutable dict> celldelay_cache; static const std::string defaultPlacer; static const std::vector availablePlacers; diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc index c8349f88..ac9d4a4d 100644 --- a/ecp5/bitstream.cc +++ b/ecp5/bitstream.cc @@ -669,8 +669,8 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex } } // Find bank voltages - std::unordered_map bankVcc; - std::unordered_map bankLvds, bankVref, bankDiff; + dict bankVcc; + dict 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> &created_cells, - std::unordered_set &todelete_cells) + pool &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> &created_cells, - std::unordered_set &todelete_cells); + pool &todelete_cells); NEXTPNR_NAMESPACE_END diff --git a/ecp5/globals.cc b/ecp5/globals.cc index 1e86fe6b..b840ac91 100644 --- a/ecp5/globals.cc +++ b/ecp5/globals.cc @@ -72,7 +72,7 @@ class Ecp5GlobalRouter std::vector get_clocks() { - std::unordered_map clockCount; + dict 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")) @@ -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 upstream; - std::unordered_map backtrace; + dict 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 visit; - std::unordered_map backtrace; + dict 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 visit; - std::unordered_map backtrace; + dict backtrace; visit.push(src); WireId cursor; while (true) { @@ -376,7 +376,7 @@ class Ecp5GlobalRouter return length < thresh; } - std::unordered_set used_pclkcib; + pool used_pclkcib; std::set get_candidate_pclkcibs(BelId dcc) { @@ -535,7 +535,7 @@ class Ecp5GlobalRouter fab_globals.insert(i); } std::vector> toroute; - std::unordered_map clocks; + dict clocks; for (auto &cell : ctx->cells) { CellInfo *ci = cell.second.get(); if (ci->type == id_DCCA) { @@ -595,7 +595,7 @@ class Ecp5GlobalRouter WireId src = ctx->getNetinfoSourceWire(ni); WireId dst = ctx->getBelPinWire(ci->bel, pin); std::queue visit; - std::unordered_map backtrace; + dict 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 #include -#include #include "arch.h" #include "log.h" @@ -27,7 +26,7 @@ NEXTPNR_NAMESPACE_BEGIN -static const std::unordered_set sysconfig_keys = { +static const pool 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 sysconfig_keys = { "COMPRESS_CONFIG", "CONFIG_MODE", "INBUF", }; -static const std::unordered_set iobuf_keys = { +static const pool iobuf_keys = { "IO_TYPE", "BANK", "BANK_VCC", "VREF", "PULLMODE", "DRIVE", "SLEWRATE", "CLAMP", "OPENDRAIN", "DIFFRESISTOR", "DIFFDRIVE", "HYSTERESIS", "TERMINATION", }; diff --git a/ecp5/pack.cc b/ecp5/pack.cc index db5d22a1..19eda9e2 100644 --- a/ecp5/pack.cc +++ b/ecp5/pack.cc @@ -21,7 +21,6 @@ #include #include #include -#include #include "cells.h" #include "chain_utils.h" #include "design_utils.h" @@ -261,7 +260,7 @@ class Ecp5Packer void pair_luts() { log_info("Finding LUT-LUT pairs...\n"); - std::unordered_set procdLuts; + pool procdLuts; for (auto &cell : ctx->cells) { CellInfo *ci = cell.second.get(); if (is_lut(ctx, ci) && procdLuts.find(cell.first) == procdLuts.end()) { @@ -1134,7 +1133,7 @@ class Ecp5Packer // Used for packing an FF into a nearby SLICE template CellInfo *find_nearby_cell(CellInfo *origin, TFunc Func) { - std::unordered_set visited_cells; + pool visited_cells; std::queue to_visit; visited_cells.insert(origin); to_visit.push(origin); @@ -1971,7 +1970,7 @@ class Ecp5Packer IdString global_name = ctx->id("G_BANK" + std::to_string(bank) + "ECLK" + std::to_string(found_eclk)); std::queue upstream; - std::unordered_map backtrace; + dict backtrace; upstream.push(userWire); WireId next; while (true) { @@ -2026,7 +2025,7 @@ class Ecp5Packer new_cells.push_back(std::move(zero_cell)); } - std::unordered_map> dqsbuf_dqsg; + dict> dqsbuf_dqsg; // Pack DQSBUFs void pack_dqsbuf() { @@ -2119,7 +2118,7 @@ class Ecp5Packer // Pack IOLOGIC void pack_iologic() { - std::unordered_map pio_iologic; + dict pio_iologic; auto set_iologic_sclk = [&](CellInfo *iol, CellInfo *prim, IdString port, bool input, bool disconnect = true) { NetInfo *sclk = nullptr; @@ -2779,7 +2778,7 @@ class Ecp5Packer } } flush_cells(); - std::unordered_set used_eclksyncb; + pool used_eclksyncb; for (auto &cell : ctx->cells) { CellInfo *ci = cell.second.get(); if (ci->type == id_CLKDIVF) { @@ -2967,7 +2966,7 @@ class Ecp5Packer auto equals_epsilon = [](delay_t a, delay_t b) { return (std::abs(a - b) / std::max(double(b), 1.0)) < 1e-3; }; - std::unordered_set user_constrained, changed_nets; + pool 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 changed_cells; + pool 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"); @@ -3152,7 +3151,7 @@ class Ecp5Packer private: Context *ctx; - std::unordered_set packed_cells; + pool packed_cells; std::vector> new_cells; struct SliceUsage @@ -3163,10 +3162,10 @@ class Ecp5Packer bool mux5_used = false, muxx_used = false; }; - std::unordered_map sliceUsage; - std::unordered_map lutffPairs; - std::unordered_map fflutPairs; - std::unordered_map lutPairs; + dict sliceUsage; + dict lutffPairs; + dict fflutPairs; + dict lutPairs; }; // Main pack function bool Arch::pack() diff --git a/fpga_interchange/arch.cc b/fpga_interchange/arch.cc index 663587fd..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()(site), bel.hash()); } }; -NEXTPNR_NAMESPACE_END - -template <> struct std::hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX SiteBelPair &site_bel) const noexcept - { - std::size_t seed = 0; - boost::hash_combine(seed, std::hash()(site_bel.site)); - boost::hash_combine(seed, std::hash()(site_bel.bel)); - return seed; - } -}; - -NEXTPNR_NAMESPACE_BEGIN static std::pair 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 site_bel_pads; + pool 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 wires_to_unbind; + pool wires_to_unbind; for (auto &net_pair : nets) { for (auto &wire_pair : net_pair.second->wires) { WireId wire = wire_pair.first; 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 // 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 tile_by_name; - mutable std::unordered_map> site_by_name; + mutable dict tile_by_name; + mutable dict> site_by_name; - std::unordered_map wire_to_net; - std::unordered_map pip_to_net; + dict wire_to_net; + dict pip_to_net; DedicatedInterconnect dedicated_interconnect; - HashTables::HashMap tileStatus; + dict tileStatus; PseudoPipData pseudo_pip_data; ArchArgs args; @@ -685,8 +685,8 @@ struct Arch : ArchAPI // ------------------------------------------------- - void place_iobufs(WireId pad_wire, NetInfo *net, const std::unordered_set &tightly_attached_bels, - std::unordered_set *placed_cells); + void place_iobufs(WireId pad_wire, NetInfo *net, const pool &tightly_attached_bels, + pool *placed_cells); void pack_ports(); void decode_lut_cells(); @@ -858,7 +858,7 @@ struct Arch : ArchAPI IdString get_bel_tiletype(BelId bel) const { return IdString(loc_info(chip_info, bel).name); } - std::unordered_map sink_locs, source_locs; + dict sink_locs, source_locs; // ------------------------------------------------- void assignArchInfo() final {} @@ -875,8 +875,8 @@ struct Arch : ArchAPI void write_physical_netlist(const std::string &filename) const; void parse_xdc(const std::string &filename); - std::unordered_set io_port_types; - std::unordered_set pads; + pool io_port_types; + pool pads; bool is_site_port(PipId pip) const { @@ -1083,7 +1083,7 @@ struct Arch : ArchAPI IdString gnd_cell_pin; IdString vcc_cell_pin; std::vector> lut_elements; - std::unordered_map lut_cells; + dict 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 &tightly_attached_bels, - std::unordered_set *placed_cells) +void Arch::place_iobufs(WireId pad_wire, NetInfo *net, const pool &tightly_attached_bels, + pool *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 tile_type_prototypes; + dict 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 package_sites; + pool package_sites; // Package pin -> (Site type -> BelId) - std::unordered_map>> package_pin_bels; + dict>> 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 package_pin_sites; + pool 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 package_pin_site_types; - std::unordered_map> possible_package_site_types; + pool package_pin_site_types; + dict> 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 tightly_attached_bels; + pool 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 cell_types_in_io_group; + pool 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 possible_site_types; + pool 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> package_pin_bels; + // dict> 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 placed_cells; + pool placed_cells; bindBel(package_bel, port_cell, STRENGTH_FIXED); placed_cells.emplace(port_cell); diff --git a/fpga_interchange/archdefs.h b/fpga_interchange/archdefs.h index ba4fe054..2d27cccf 100644 --- a/fpga_interchange/archdefs.h +++ b/fpga_interchange/archdefs.h @@ -24,7 +24,6 @@ #include #include -#include "hash_table.h" #include "hashlib.h" #include "luts.h" #include "nextpnr_namespaces.h" @@ -119,9 +118,9 @@ struct ArchNetInfo struct ArchCellInfo { int32_t cell_mapping = -1; - HashTables::HashMap> cell_bel_pins; - HashTables::HashMap> masked_cell_bel_pins; - HashTables::HashSet const_ports; + dict> cell_bel_pins; + dict> masked_cell_bel_pins; + pool const_ports; LutCell lut_cell; }; 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, const CellParameterPOD *, PairHash> parameters; + dict, 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, delay_t, PairHash> &delays) + const dict, 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 #include -#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, delay_t, PairHash> &delays); + const dict, 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 cost_map_; + dict cost_map_; void fill_holes(const Context *ctx, const TypeWirePair &wire_pair, boost::multi_array &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 seen_pins; + pool 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 srcs; + pool 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 dsts; + pool 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 #include -#include #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 -{ - 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()(type_bel_pin.tile_type)); - boost::hash_combine(seed, std::hash()(type_bel_pin.bel_index)); - boost::hash_combine(seed, std::hash()(type_bel_pin.bel_pin)); - return seed; - } -}; - -template <> struct std::hash -{ - 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()(delta_bel_pin.delta_x)); - boost::hash_combine(seed, std::hash()(delta_bel_pin.delta_y)); - boost::hash_combine(seed, std::hash()(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> sinks; - std::unordered_map> sources; + dict> sinks; + dict> 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 strings; - std::unordered_map string_to_index; + dict 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 &pip_place_strength, + const dict &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> &pip_downhill, - const std::unordered_map> &sinks, - std::unordered_set *pips, - const std::unordered_map &pip_place_strength, + const dict> &pip_downhill, + const dict> &sinks, + pool *pips, + const dict &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 &pip_place_strength, + const dict &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> &pip_downhill, + const dict> &pip_downhill, std::vector *root_pips) { std::vector 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 placed_cells; + pool 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 ports; - std::unordered_map sites; + dict 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 root_wires; - std::unordered_map> pip_downhill; - std::unordered_set pips; + dict root_wires; + dict> pip_downhill; + pool 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> sinks; + dict> 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 pip_place_strength; + dict 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 -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX PortKey &key) const noexcept - { - std::size_t seed = 0; - boost::hash_combine(seed, std::hash()(key.inst_idx)); - boost::hash_combine(seed, std::hash()(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 net_indicies; - std::unordered_map disconnected_nets; - std::unordered_map> connections; + dict net_indicies; + dict disconnected_nets; + dict> connections; ModuleReader(const LogicalNetlistImpl *root, LogicalNetlist::Netlist::CellInstance::Reader cell_inst, bool is_top); @@ -834,7 +822,6 @@ struct LogicalNetlistImpl template void foreach_netname(const ModuleReader &mod, TFunc Func) const { - // std::unordered_map 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 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 918b916e..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 visit_queue; - std::unordered_map visits; + dict visits; visit_queue.push(dest); visits[dest].downhill = PipId(); 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 *input_costs) +static void expand_input(const Context *ctx, WireId input_wire, dict *input_costs) { - HashTables::HashSet seen; + pool seen; std::priority_queue 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 &best_path, - HashTables::HashMap *site_to_site_cost) +static void update_site_to_site_costs(const Context *ctx, WireId first_wire, const dict &best_path, + dict *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 *site_to_site_cost) + dict *site_to_site_cost) { - HashTables::HashSet seen; + pool seen; std::priority_queue 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 best_path; + dict 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 *input_costs) { - HashTables::HashMap input_costs_map; + dict 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, delay_t, PairHash>> storage; + dict, delay_t>> storage; int32_t max_explore_depth; }; @@ -290,7 +289,7 @@ static void update_results(const Context *ctx, const FlatWireMap &be // Starting from end of result, walk backwards and record the path into // the delay storage. WireId cursor = sink_wire; - HashTables::HashSet seen; + pool 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 &be static void expand_routing_graph_from_wire(const Context *ctx, WireId first_wire, FlatWireMap *best_path, DelayStorage *storage) { - HashTables::HashSet seen; + pool seen; std::priority_queue 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 *types_explored, - DelayStorage *storage, HashTables::HashSet *types_deferred, - FlatWireMap *best_path) + TypeWireId wire_type, pool *types_explored, DelayStorage *storage, + pool *types_deferred, FlatWireMap *best_path) { - HashTables::HashSet new_types_explored; + pool 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 *types_explored, + TypeWireId wire_type, pool *types_explored, DelayStorage *storage, FlatWireMap *best_path) { - HashTables::HashSet new_types_explored; + pool 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 *site_to_site_cost) + dict *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 *best_path; DelayStorage *storage; - HashTables::HashSet *explored; - HashTables::HashSet *deferred; + pool *explored; + pool *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 &tile_types, const std::vector &tiles_of_type, DeterministicRNG *rng, FlatWireMap *best_path, DelayStorage *storage, - HashTables::HashSet *explored, - HashTables::HashSet *deferred, HashTables::HashSet *tiles_left) + pool *explored, pool *deferred, pool *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 *types_explored; - HashTables::HashSet *types_deferred; - HashTables::HashSet *tiles_left; + pool *types_explored; + pool *types_deferred; + pool *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 &tiles_of_type, DeterministicRNG *rng, std::mutex *all_costs_mutex, - DelayStorage *all_tiles_storage, HashTables::HashSet *types_explored, - HashTables::HashSet *types_deferred, - HashTables::HashSet *tiles_left) + DelayStorage *all_tiles_storage, pool *types_explored, + pool *types_deferred, pool *tiles_left) { TbbExpandLocals locals; DeterministicRNG rng_copy = *rng; FlatWireMap best_path(ctx); - HashTables::HashSet explored; - HashTables::HashSet deferred; + pool explored; + pool 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 input_site_ports; + pool 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 types_explored; + pool 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 types_deferred; + pool types_deferred; std::vector tile_types; - HashTables::HashSet tiles_left; + pool 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, delay_t, PairHash>> - &type_pair) { + tbb::parallel_for_each(all_tiles_storage.storage, + [&](const std::pair, 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> input_site_wires; - HashTables::HashMap output_site_wires; - HashTables::HashMap site_to_site_cost; + dict> input_site_wires; + dict output_site_wires; + dict 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 blocked_luts; + pool blocked_luts; return check_wires(bel_to_cell_pin_remaps, lut_bels, used_pins, &blocked_luts); } uint32_t LutMapper::check_wires(const std::vector> &bel_to_cell_pin_remaps, const std::vector &lut_bels, uint32_t used_pins, - HashTables::HashSet *blocked_luts) const + pool *blocked_luts) const { std::vector unused_luts; for (auto &lut_bel_pair : element.lut_bels) { @@ -253,9 +253,9 @@ uint32_t LutMapper::check_wires(const std::vector> &bel_to_ return vcc_mask; } -bool LutMapper::remap_luts(const Context *ctx, HashTables::HashSet *blocked_luts) +bool LutMapper::remap_luts(const Context *ctx, pool *blocked_luts) { - std::unordered_map lut_pin_map; + dict lut_pin_map; std::vector lut_bels; lut_bels.resize(cells.size()); @@ -366,7 +366,7 @@ bool LutMapper::remap_luts(const Context *ctx, HashTables::HashSet cell_to_bel_map; + dict 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 &cell_to_bel_map, - const LutBel &lut_bel, const std::vector &equation, uint32_t used_pins) +void check_equation(const LutCell &lut_cell, const dict &cell_to_bel_map, const LutBel &lut_bel, + const std::vector &equation, uint32_t used_pins) { std::vector 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 -#include - #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 pins; - std::unordered_set lut_pins; - std::unordered_set vcc_pins; + pool lut_pins; + pool vcc_pins; DynamicBitarray<> equation; }; @@ -56,7 +53,7 @@ struct LutBel // LUT BEL pins to LUT array index. std::vector pins; - std::unordered_map pin_to_index; + dict 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 &cell_to_bel_map, - const LutBel &lut_bel, const std::vector &equation, uint32_t used_pins); +void check_equation(const LutCell &lut_cell, const dict &cell_to_bel_map, const LutBel &lut_bel, + const std::vector &equation, uint32_t used_pins); struct LutElement { size_t width; - std::unordered_map lut_bels; + dict lut_bels; void compute_pin_order(); std::vector pins; - std::unordered_map pin_to_index; + dict pin_to_index; }; struct LutMapper @@ -92,7 +89,7 @@ struct LutMapper std::vector cells; - bool remap_luts(const Context *ctx, HashTables::HashSet *blocked_luts); + bool remap_luts(const Context *ctx, pool *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> &bel_to_cell_pin_remaps, const std::vector &lut_bels, uint32_t used_pins, - HashTables::HashSet *blocked_luts) const; + pool *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/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 sites; + pool sites; std::vector 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 pseudo_cell_wires; + pool 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 active_sites; + pool 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 used_bels; + dict 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 #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(); } + + unsigned int hash() const { return mkhash(mkhash(tile_type, pip_index), site); } }; -NEXTPNR_NAMESPACE_END - -namespace std { -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX LogicBelKey &key) const noexcept - { - std::size_t seed = 0; - boost::hash_combine(seed, hash()(key.tile_type)); - boost::hash_combine(seed, hash()(key.pip_index)); - boost::hash_combine(seed, hash()(key.site)); - - return seed; - } -}; - -}; // 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 &get_logic_bels_for_pip(const Context *ctx, int32_t site, PipId pip) const; - HashTables::HashMap max_pseudo_pip_for_tile_type; - HashTables::HashMap, std::vector, PairHash> possibles_sites_for_pip; - HashTables::HashMap> logic_bels_for_pip; + dict max_pseudo_pip_for_tile_type; + dict, std::vector> possibles_sites_for_pip; + dict> 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 pseudo_pip_sites; - HashTables::HashMap> site_to_pseudo_pips; - HashTables::HashSet active_pseudo_pips; + dict pseudo_pip_sites; + dict> site_to_pseudo_pips; + pool active_pseudo_pips; std::vector 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 &cells_in_site) + const pool &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 -#include #include #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 &cells_in_site; + const pool &cells_in_site; SiteInformation(const Context *ctx, int32_t tile, int32_t site, - const std::unordered_set &cells_in_site); + const pool &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 -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX SiteWire &site_wire) const noexcept - { - std::size_t seed = 0; - boost::hash_combine(seed, std::hash()(site_wire.type)); - boost::hash_combine(seed, std::hash()(site_wire.wire)); - boost::hash_combine(seed, std::hash()(site_wire.pip)); - boost::hash_combine(seed, std::hash()(site_wire.net)); - return seed; - } -}; - -template <> struct std::hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX SitePip &site_pip) const noexcept - { - std::size_t seed = 0; - boost::hash_combine(seed, std::hash()(site_pip.type)); - boost::hash_combine(seed, std::hash()(site_pip.pip)); - boost::hash_combine(seed, std::hash()(site_pip.wire)); - boost::hash_combine(seed, std::hash()(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 users; + pool users; - HashTables::HashMap wires; + dict wires; }; struct SiteArch @@ -276,8 +248,8 @@ struct SiteArch const Context *const ctx; const SiteInformation *const site_info; - HashTables::HashMap nets; - HashTables::HashMap wire_to_nets; + dict nets; + dict 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 wires; + dict 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 net_users; + pool net_users; SiteRoutingSolution solution; @@ -206,7 +205,7 @@ struct SiteExpansionLoop auto node = new_node(net->driver, SitePip(), /*parent=*/nullptr); - HashTables::HashSet targets; + pool 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 sinks; - HashTables::HashMap sink_map; + dict 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, PairHash> &lut_thrus) +static void apply_routing(Context *ctx, const SiteArch &site_arch, pool> &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, PairHash> *blocked_wires) +static bool map_luts_in_site(const SiteInformation &site_info, pool> *blocked_wires) { const Context *ctx = site_info.ctx; const std::vector &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 blocked_luts; + pool 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, PairHash> &blocked_wires) +static void block_lut_outputs(SiteArch *site_arch, const pool> &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, PairHash> blocked_wires; + pool> 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, PairHash> blocked_wires; + pool> 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 +#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 cells_in_site; + pool cells_in_site; std::vector valid_pips; - HashTables::HashSet, PairHash> lut_thrus; + pool> 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 seen_users; + pool 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 -{ - 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()(key.tile_type)); - boost::hash_combine(seed, std::hash()(key.site)); - boost::hash_combine(seed, std::hash()(key.net_type)); - boost::hash_combine(seed, std::hash()(key.driver_type)); - boost::hash_combine(seed, std::hash()(key.driver_index)); - boost::hash_combine(seed, std::hash()(key.user_types.size())); - for (NEXTPNR_NAMESPACE_PREFIX SiteWire::Type user_type : key.user_types) { - boost::hash_combine(seed, std::hash()(user_type)); - } - - boost::hash_combine(seed, std::hash()(key.user_indicies.size())); - for (int32_t index : key.user_indicies) { - boost::hash_combine(seed, std::hash()(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 cache_; + dict 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()(wire_types_.size())); + hash_ = wire_types_.size(); for (const auto &wire : wire_types_) { - boost::hash_combine(hash_, std::hash()(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 #include +#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 wire_types_; }; NEXTPNR_NAMESPACE_END -template <> struct std::hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX TypeWireId &wire) const noexcept - { - std::size_t seed = 0; - boost::hash_combine(seed, std::hash()(wire.type)); - boost::hash_combine(seed, std::hash()(wire.index)); - return seed; - } -}; - -template <> struct std::hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX TypeWirePair &pair) const noexcept - { - std::size_t seed = 0; - boost::hash_combine(seed, std::hash()(pair.src)); - boost::hash_combine(seed, std::hash()(pair.dst)); - return seed; - } -}; - -template <> struct std::hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX TypeWireSet &set) const noexcept { return set.hash(); } -}; - #endif /* TYPE_WIRE_H */ 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 attrs; CellInfo *bound_cell; - std::unordered_map pins; + dict 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 -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX CellDelayKey &dk) const noexcept - { - std::size_t seed = std::hash()(dk.from); - seed ^= std::hash()(dk.to) + 0x9e3779b9 + (seed << 6) + (seed >> 2); - return seed; - } -}; -} // namespace std -NEXTPNR_NAMESPACE_BEGIN - struct CellTiming { - std::unordered_map portClasses; - std::unordered_map combDelays; - std::unordered_map> clockingInfo; + dict portClasses; + dict combDelays; + dict> clockingInfo; }; struct ArchRanges @@ -160,10 +147,10 @@ struct Arch : ArchAPI { std::string chipName; - std::unordered_map wires; - std::unordered_map pips; - std::unordered_map bels; - std::unordered_map groups; + dict wires; + dict pips; + dict bels; + dict groups; // These functions include useful errors if not found WireInfo &wire_info(IdStringList wire); @@ -172,16 +159,16 @@ struct Arch : ArchAPI std::vector bel_ids, wire_ids, pip_ids; - std::unordered_map bel_by_loc; + dict bel_by_loc; std::vector>> bels_by_tile; - std::unordered_map> decal_graphics; + dict> decal_graphics; int gridDimX, gridDimY; std::vector> tileBelDimZ; std::vector> tilePipDimZ; - std::unordered_map cellTiming; + dict 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 std::vector getCellTypes() const override { - std::unordered_set cell_types; + pool cell_types; for (auto bel : bels) { cell_types.insert(bel.second.type); } 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 - +#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> bel_pins; + dict> 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 &todelete_cells) +void nxio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *iob, pool &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 &todelete_cells); +void nxio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *sbio, pool &todelete_cells); NEXTPNR_NAMESPACE_END diff --git a/generic/pack.cc b/generic/pack.cc index a1c325f8..dba86cce 100644 --- a/generic/pack.cc +++ b/generic/pack.cc @@ -19,7 +19,6 @@ #include #include -#include #include "cells.h" #include "design_utils.h" #include "log.h" @@ -32,7 +31,7 @@ static void pack_lut_lutffs(Context *ctx) { log_info("Packing LUT-FFs..\n"); - std::unordered_set packed_cells; + pool packed_cells; std::vector> new_cells; for (auto &cell : ctx->cells) { CellInfo *ci = cell.second.get(); @@ -89,7 +88,7 @@ static void pack_nonlut_ffs(Context *ctx) { log_info("Packing non-LUT FFs..\n"); - std::unordered_set packed_cells; + pool packed_cells; std::vector> new_cells; for (auto &cell : ctx->cells) { @@ -203,8 +202,8 @@ static bool is_generic_iob(const Context *ctx, const CellInfo *cell) { return ce // Pack IO buffers static void pack_io(Context *ctx) { - std::unordered_set packed_cells; - std::unordered_set delete_nets; + pool packed_cells; + pool delete_nets; std::vector> new_cells; log_info("Packing IOs..\n"); 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 attrs; CellInfo *bound_cell; - std::unordered_map pins; + dict 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 -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX CellDelayKey &dk) const noexcept - { - std::size_t seed = std::hash()(dk.from); - seed ^= std::hash()(dk.to) + 0x9e3779b9 + (seed << 6) + (seed >> 2); - return seed; - } -}; -} // namespace std -NEXTPNR_NAMESPACE_BEGIN - struct CellTiming { - std::unordered_map portClasses; - std::unordered_map combDelays; - std::unordered_map> clockingInfo; + dict portClasses; + dict combDelays; + dict> clockingInfo; }; struct ArchRanges : BaseArchRanges @@ -287,10 +274,10 @@ struct Arch : BaseArch const PackagePOD *package; const TimingGroupsPOD *speed; - std::unordered_map wires; - std::unordered_map pips; - std::unordered_map bels; - std::unordered_map groups; + dict wires; + dict pips; + dict bels; + dict groups; // These functions include useful errors if not found WireInfo &wire_info(IdString wire); @@ -299,16 +286,16 @@ struct Arch : BaseArch std::vector bel_ids, wire_ids, pip_ids; - std::unordered_map bel_by_loc; + dict bel_by_loc; std::vector>> bels_by_tile; - std::unordered_map> decal_graphics; + dict> decal_graphics; int gridDimX, gridDimY; std::vector> tileBelDimZ; std::vector> tilePipDimZ; - std::unordered_map cellTiming; + dict 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/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 &todelete_cells) +void gwio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *iob, pool &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 &todelete_cells); +void gwio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *sbio, pool &todelete_cells); NEXTPNR_NAMESPACE_END diff --git a/gowin/pack.cc b/gowin/pack.cc index a2998c63..d3a749ea 100644 --- a/gowin/pack.cc +++ b/gowin/pack.cc @@ -21,7 +21,6 @@ #include #include #include -#include #include "cells.h" #include "design_utils.h" #include "log.h" @@ -34,7 +33,7 @@ static void pack_lut_lutffs(Context *ctx) { log_info("Packing LUT-FFs..\n"); - std::unordered_set packed_cells; + pool packed_cells; std::vector> new_cells; for (auto &cell : ctx->cells) { CellInfo *ci = cell.second.get(); @@ -90,7 +89,7 @@ static void pack_nonlut_ffs(Context *ctx) { log_info("Packing non-LUT FFs..\n"); - std::unordered_set packed_cells; + pool packed_cells; std::vector> new_cells; for (auto &cell : ctx->cells) { @@ -212,8 +211,8 @@ static bool is_gowin_iob(const Context *ctx, const CellInfo *cell) // Pack IO buffers static void pack_io(Context *ctx) { - std::unordered_set packed_cells; - std::unordered_set delete_nets; + pool packed_cells; + pool delete_nets; std::vector> new_cells; log_info("Packing IOs..\n"); 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 const ChipInfoPOD *chip_info; const PackageInfoPOD *package_info; - mutable std::unordered_map bel_by_name; - mutable std::unordered_map wire_by_name; - mutable std::unordered_map pip_by_name; - mutable std::unordered_map bel_by_loc; + mutable dict bel_by_name; + mutable dict wire_by_name; + mutable dict pip_by_name; + mutable dict bel_by_loc; std::vector bel_carry; std::vector bel_to_cell; @@ -414,7 +414,7 @@ struct Arch : BaseArch // fast access to X and Y IdStrings for building object names std::vector x_ids, y_ids; // inverse of the above for name->object mapping - std::unordered_map id_to_x, id_to_y; + dict id_to_x, id_to_y; ArchArgs args; Arch(ArchArgs args); 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 &input_permute) +unsigned permute_lut(unsigned orig_init, const dict &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 sb_io_used_by_pll_out; - std::unordered_set sb_io_used_by_pll_pad; + pool sb_io_used_by_pll_out; + pool 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 lc(20, false); // Discover permutation - std::unordered_map input_perm; + dict input_perm; std::set 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 &todelete_cells) +void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio, pool &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 &todelete_cells); +void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio, pool &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 f75d329f..cfc8b4a1 100644 --- a/ice40/chains.cc +++ b/ice40/chains.cc @@ -253,7 +253,7 @@ class ChainConstrainer return i3_next; return (CellInfo *)nullptr; }); - std::unordered_set chained; + pool chained; for (auto &base_chain : carry_chains) { for (auto c : base_chain.cells) chained.insert(c->name); diff --git a/ice40/pack.cc b/ice40/pack.cc index 1d05a8c2..62b08534 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -21,7 +21,6 @@ #include #include -#include #include "cells.h" #include "chains.h" #include "design_utils.h" @@ -35,7 +34,7 @@ static void pack_lut_lutffs(Context *ctx) { log_info("Packing LUT-FFs..\n"); int lut_only = 0, lut_and_ff = 0; - std::unordered_set packed_cells; + pool packed_cells; std::vector> new_cells; for (auto &cell : ctx->cells) { CellInfo *ci = cell.second.get(); @@ -100,7 +99,7 @@ static void pack_nonlut_ffs(Context *ctx) { log_info("Packing non-LUT FFs..\n"); - std::unordered_set packed_cells; + pool packed_cells; std::vector> new_cells; int ff_only = 0; @@ -144,8 +143,8 @@ static bool net_is_constant(const Context *ctx, NetInfo *net, bool &value) static void pack_carries(Context *ctx) { log_info("Packing carries..\n"); - std::unordered_set exhausted_cells; - std::unordered_set packed_cells; + pool exhausted_cells; + pool packed_cells; std::vector> new_cells; int carry_only = 0; @@ -274,7 +273,7 @@ static void pack_ram(Context *ctx) { log_info("Packing RAMs..\n"); - std::unordered_set packed_cells; + pool packed_cells; std::vector> new_cells; for (auto &cell : ctx->cells) { @@ -466,8 +465,8 @@ static bool is_ice_iob(const Context *ctx, const CellInfo *cell) // Pack IO buffers static void pack_io(Context *ctx) { - std::unordered_set packed_cells; - std::unordered_set delete_nets; + pool packed_cells; + pool delete_nets; std::vector> new_cells; log_info("Packing IOs..\n"); @@ -1119,7 +1118,7 @@ static void pack_special(Context *ctx) { log_info("Packing special functions..\n"); - std::unordered_set packed_cells; + pool packed_cells; std::vector> new_cells; // Handle LED_DRV_CUR first to set the ledCurConnected flag before RGB_DRV is handled below. @@ -1299,7 +1298,7 @@ void pack_plls(Context *ctx) { log_info("Packing PLLs..\n"); - std::unordered_set packed_cells; + pool packed_cells; std::vector> new_cells; for (auto &cell : ctx->cells) { CellInfo *ci = cell.second.get(); 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 const ChipInfoPOD *chip_info; const PackageInfoPOD *package_info; - mutable std::unordered_map pip_by_name; + mutable dict pip_by_name; // fast access to X and Y IdStrings for building object names std::vector x_ids, y_ids; // inverse of the above for name->object mapping - std::unordered_map id_to_x, id_to_y; + dict id_to_x, id_to_y; // Helpers template const TileTypePOD *tile_info(Id &id) const 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 &todelete_cells) {} +void nxio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *iob, pool &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 &todelete_cells); +void nxio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *sbio, pool &todelete_cells); NEXTPNR_NAMESPACE_END diff --git a/machxo2/pack.cc b/machxo2/pack.cc index 26bda946..6f2ee8e4 100644 --- a/machxo2/pack.cc +++ b/machxo2/pack.cc @@ -20,7 +20,6 @@ #include #include -#include #include "cells.h" #include "design_utils.h" #include "log.h" @@ -33,7 +32,7 @@ static void pack_lut_lutffs(Context *ctx) { log_info("Packing LUT-FFs..\n"); - std::unordered_set packed_cells; + pool packed_cells; std::vector> new_cells; for (auto &cell : ctx->cells) { CellInfo *ci = cell.second.get(); @@ -91,7 +90,7 @@ static void pack_remaining_ffs(Context *ctx) { log_info("Packing remaining FFs..\n"); - std::unordered_set packed_cells; + pool packed_cells; std::vector> new_cells; for (auto &cell : ctx->cells) { @@ -130,7 +129,7 @@ static void set_net_constant(Context *ctx, NetInfo *orig, NetInfo *constnet, boo { (void)constval; - std::unordered_set packed_cells; + pool packed_cells; std::vector> new_cells; orig->driver.cell = nullptr; @@ -233,7 +232,7 @@ static bool is_facade_iob(const Context *ctx, const CellInfo *cell) { return cel // attributes. static void pack_io(Context *ctx) { - std::unordered_set packed_cells; + pool packed_cells; log_info("Packing IOs..\n"); 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 pins; + dict pins; // Info for different kinds of bels union { @@ -153,7 +153,7 @@ struct UpDownhillPipRange UpDownhillPipIterator b, e; UpDownhillPipRange(const std::vector &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::const_iterator; +using WireMapIterator = dict::const_iterator; struct AllPipIterator { WireMapIterator base, end; @@ -196,8 +196,7 @@ struct AllPipRange { AllPipIterator b, e; - AllPipRange(const std::unordered_map &wires) - : b(wires.cbegin(), wires.cend(), -1), e(wires.cend(), wires.cend(), 0) + AllPipRange(const dict &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 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 struct key_range xformed_iterator end() const { return xformed_iterator(e); } }; -using AllWireRange = key_range>; +using AllWireRange = key_range>; struct ArchRanges : BaseArchRanges { @@ -489,7 +488,7 @@ struct Arch : BaseArch static const std::string defaultRouter; static const std::vector availableRouters; - std::unordered_map wires; + dict wires; // List of LABs std::vector labs; @@ -499,13 +498,13 @@ struct Arch : BaseArch // Conversion between numbers and rnode types and IdString, for fast wire name implementation std::vector int2id; - std::unordered_map id2int; + dict id2int; std::vector rn_t2id; - std::unordered_map id2rn_t; + dict id2rn_t; // This structure is only used for nextpnr-created wires - std::unordered_map npnr_wirebyname; + dict npnr_wirebyname; std::vector> bels_by_tile; std::vector all_bels; @@ -525,18 +524,18 @@ struct Arch : BaseArch // ------------------------------------------------- void assign_default_pinmap(CellInfo *cell); - static const std::unordered_map comb_pinmap; + static const dict comb_pinmap; // ------------------------------------------------- - typedef std::unordered_map CellPinsData; // pins.cc - static const std::unordered_map cell_pins_db; // pins.cc + typedef dict CellPinsData; // pins.cc + static const dict 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> io_attr; + dict> io_attr; void read_qsf(std::istream &in); // qsf.cc // ------------------------------------------------- diff --git a/mistral/archdefs.h b/mistral/archdefs.h index 9d953223..71e14ec2 100644 --- a/mistral/archdefs.h +++ b/mistral/archdefs.h @@ -203,7 +203,7 @@ struct ArchCellInfo : BaseClusterInfo } ffInfo; }; - std::unordered_map pin_data; + dict pin_data; CellPinState get_pin_state(IdString pin) const; }; 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 shared_nets; + dict 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 Arch::comb_pinmap = { +const dict 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/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 Arch::cell_pins_db = { +const dict 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> option_map_t; +typedef dict> option_map_t; struct QsfCommand { 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 // fast access to X and Y IdStrings for building object names std::vector x_ids, y_ids; // inverse of the above for name->object mapping - std::unordered_map id_to_x, id_to_y; + dict id_to_x, id_to_y; // ------------------------------------------------- @@ -1181,7 +1181,7 @@ struct Arch : BaseArch // for better DSP bounding boxes void pre_routing(); - std::unordered_set dsp_wires, lram_wires; + pool dsp_wires, lram_wires; // ------------------------------------------------- @@ -1271,9 +1271,9 @@ struct Arch : BaseArch // ------------------------------------------------- - typedef std::unordered_map CellPinsData; + typedef dict CellPinsData; - std::unordered_map cell_pins_db; + dict 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 // ------------------------------------------------- // Data about different IO standard, mostly used by bitgen - static const std::unordered_map io_types; + static const dict 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 // ------------------------------------------------- // List of IO constraints, used by PDC parser - std::unordered_map> io_attr; + dict> io_attr; void read_pdc(std::istream &in); diff --git a/nexus/archdefs.h b/nexus/archdefs.h index db8a3af4..76ba605b 100644 --- a/nexus/archdefs.h +++ b/nexus/archdefs.h @@ -21,7 +21,6 @@ #define NEXUS_ARCHDEFS_H #include -#include #include "base_clusterinfo.h" #include "hashlib.h" @@ -184,7 +183,7 @@ struct ArchCellInfo : BaseClusterInfo int tmg_index = -1; // Map from cell/bel ports to logical timing ports - std::unordered_map tmg_portmap; + dict tmg_portmap; }; NEXTPNR_NAMESPACE_END diff --git a/nexus/fasm.cc b/nexus/fasm.cc index 13fe00c1..48483bfe 100644 --- a/nexus/fasm.cc +++ b/nexus/fasm.cc @@ -336,7 +336,7 @@ struct NexusFasmWriter pop(2); } - std::unordered_set used_io; + pool used_io; struct BankConfig { @@ -556,7 +556,7 @@ struct NexusFasmWriter // Which PLL params are 'word' values /* clang-format off */ - const std::unordered_map pll_word_params = { + const dict 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 dphy_word_params = { + const dict 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}, @@ -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> dsp_defconf = { + static const dict> dsp_defconf = { {id_MULT9_CORE, { "GSR.ENABLED", @@ -733,7 +733,7 @@ struct NexusFasmWriter } } } - std::unordered_map bank_vcco; + dict bank_vcco; // bank VccO in mV int get_bank_vcco(const std::string &iostd) { diff --git a/nexus/global.cc b/nexus/global.cc index fa6212e8..9a0d095b 100644 --- a/nexus/global.cc +++ b/nexus/global.cc @@ -49,7 +49,7 @@ struct NexusGlobalRouter // Queue of wires to visit std::queue visit; // Wire -> upstream pip - std::unordered_map backtrace; + dict backtrace; // Lookup source and destination wires WireId src = ctx->getNetinfoSourceWire(net); 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 Arch::io_types = { +const dict 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/pack.cc b/nexus/pack.cc index 812731cf..1d977f2c 100644 --- a/nexus/pack.cc +++ b/nexus/pack.cc @@ -106,16 +106,16 @@ struct NexusPacker struct XFormRule { IdString new_type; - std::unordered_map port_xform; - std::unordered_map> port_multixform; - std::unordered_map param_xform; + dict port_xform; + dict> port_multixform; + dict param_xform; std::vector> set_attrs; std::vector> set_params; std::vector> default_params; std::vector> parse_params; }; - void xform_cell(const std::unordered_map &rules, CellInfo *ci) + void xform_cell(const dict &rules, CellInfo *ci) { auto &rule = rules.at(ci->type); ci->type = rule.new_type; @@ -178,7 +178,7 @@ struct NexusPacker ci->params[param.first] = param.second; } - void generic_xform(const std::unordered_map &rules, bool print_summary = false) + void generic_xform(const dict &rules, bool print_summary = false) { std::map cell_count; std::map new_types; @@ -205,7 +205,7 @@ struct NexusPacker void pack_luts() { log_info("Packing LUTs...\n"); - std::unordered_map lut_rules; + dict 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 ff_rules; + dict 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 reference_bels; + dict reference_bels; void autocreate_ports(CellInfo *cell) { @@ -549,11 +549,10 @@ struct NexusPacker void pack_io() { - std::unordered_set 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 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 io_rules; + dict 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,12 +566,12 @@ 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 @@ -677,8 +676,8 @@ struct NexusPacker { int iter = 0; std::queue visit; - std::unordered_set seen_wires; - std::unordered_set seen_bels; + pool seen_wires; + pool seen_bels; BelId bel = get_bel_attr(cell); if (bel == BelId()) @@ -751,7 +750,7 @@ struct NexusPacker return best_bel; } - std::unordered_set used_bels; + pool used_bels; // Pre-place a primitive based on routeability first and distance second bool preplace_prim(CellInfo *cell, IdString pin, bool strict_routing) @@ -1024,7 +1023,7 @@ struct NexusPacker void convert_prims() { // Convert primitives from their non-CORE variant to their CORE variant - static const std::unordered_map prim_map = { + static const dict 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}, @@ -1048,7 +1047,7 @@ struct NexusPacker void pack_bram() { - std::unordered_map bram_rules; + dict 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")); @@ -1096,7 +1095,7 @@ struct NexusPacker void pack_lram() { - std::unordered_map lram_rules; + dict 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; @@ -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 &bel2cell) + void auto_cascade_cell(CellInfo *cell, BelId bel, const dict &bel2cell) { // Create outputs based on the actual bel for (auto bp : ctx->getBelPins(bel)) { @@ -1322,7 +1321,7 @@ struct NexusPacker // Standard BFS-type exploration std::queue visit; - std::unordered_set in_queue; + pool 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 bel2cell; - std::unordered_map cell2bel; + dict bel2cell; + dict 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 dsp_types = { + const dict 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}}, @@ -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 user_constrained, changed_nets; + pool 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 changed_cells; + pool 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,7 +1944,7 @@ struct NexusPacker void pack_plls() { - const std::unordered_map pll_defaults = { + const dict 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"}, }; @@ -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 dphy_loc_map = { + const dict dphy_loc_map = { {"TDPHY_CORE2", "X4/Y0/TDPHY_CORE2"}, {"DPHY0", "X4/Y0/TDPHY_CORE2"}, {"TDPHY_CORE26", "X28/Y0/TDPHY_CORE26"}, 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 &arguments) { - std::unordered_map args; + dict 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 base_cell_pin_data = { +static const dict base_cell_pin_data = { {id_OXIDE_COMB, { {id_WCK, PINSTYLE_DEDI}, From b8a68f5f35af49c36d6f4e86a3a1c5afa1b3215f Mon Sep 17 00:00:00 2001 From: gatecat Date: Wed, 2 Jun 2021 11:03:13 +0100 Subject: [PATCH 08/11] Using hashlib in timing Signed-off-by: gatecat --- common/timing.cc | 47 ++++++++----------------------------- common/timing.h | 61 +++++++++++++----------------------------------- 2 files changed, 26 insertions(+), 82 deletions(-) diff --git a/common/timing.cc b/common/timing.cc index b68ca35c..1670bc7d 100644 --- a/common/timing.cc +++ b/common/timing.cc @@ -23,7 +23,6 @@ #include #include #include -#include #include #include "log.h" #include "util.h" @@ -272,7 +271,7 @@ void TimingAnalyser::setup_port_domains() void TimingAnalyser::reset_times() { for (auto &port : ports) { - auto do_reset = [&](std::unordered_map ×) { + auto do_reset = [&](dict ×) { 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 domain_fmax; + dict 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 -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX ClockEvent &obj) const noexcept - { - std::size_t seed = 0; - boost::hash_combine(seed, hash()(obj.clock)); - boost::hash_combine(seed, hash()(int(obj.edge))); - return seed; - } -}; - -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX ClockPair &obj) const noexcept - { - std::size_t seed = 0; - boost::hash_combine(seed, hash()(obj.start)); - boost::hash_combine(seed, hash()(obj.start)); - return seed; - } -}; - -} // namespace std -NEXTPNR_NAMESPACE_BEGIN - typedef std::vector PortRefVector; typedef std::map DelayFrequency; @@ -639,7 +612,7 @@ struct CriticalPath delay_t path_period; }; -typedef std::unordered_map CriticalPathMap; +typedef dict CriticalPathMap; struct Timing { @@ -660,7 +633,7 @@ struct Timing delay_t min_remaining_budget; bool false_startpoint = false; std::vector min_required; - std::unordered_map arrival_time; + dict 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 topological_order; - std::unordered_map> net_data; + dict, 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 port_fanin; + dict port_fanin; std::vector input_ports; std::vector output_ports; - std::unordered_set ooc_port_nets; + pool 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> crit_nets; + dict> 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()(arg.cell); - seed ^= std::hash()(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()(arg.net); - seed ^= std::hash()(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()(arg.clock); - seed ^= std::hash()(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()(arg.launch); - seed ^= std::hash()(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 arrival; - std::unordered_map required; - std::unordered_map domain_pairs; + dict arrival; + dict required; + dict domain_pairs; // cell timing arcs to (outputs)/from (inputs) from this port std::vector 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::max(), + worst_hold_slack = std::numeric_limits::max(); }; struct PerDomain @@ -260,9 +231,9 @@ struct TimingAnalyser void copy_domains(const CellPortKey &from, const CellPortKey &to, bool backwards); - std::unordered_map ports; - std::unordered_map domain_to_id; - std::unordered_map pair_to_id; + dict ports; + dict domain_to_id; + dict pair_to_id; std::vector domains; std::vector domain_pairs; From eca1a4cee4f310c7e2c1216bd678143c1967edd4 Mon Sep 17 00:00:00 2001 From: gatecat Date: Wed, 2 Jun 2021 11:36:56 +0100 Subject: [PATCH 09/11] Use hashlib in most remaining code Signed-off-by: gatecat --- common/archcheck.cc | 18 +++++++++--------- common/basectx.h | 1 + common/command.cc | 4 ++-- common/command.h | 2 +- common/constraints.h | 4 ++-- common/log.cc | 2 +- common/log.h | 20 ++++++++------------ common/timing_opt.cc | 18 ++++++++---------- common/timing_opt.h | 2 +- ecp5/main.cc | 4 ++-- fpga_interchange/main.cc | 4 ++-- generic/main.cc | 4 ++-- gowin/main.cc | 4 ++-- gui/treemodel.cc | 2 +- gui/treemodel.h | 4 ++-- ice40/main.cc | 4 ++-- json/jsonwrite.cc | 2 +- machxo2/main.cc | 4 ++-- mistral/main.cc | 4 ++-- nexus/main.cc | 4 ++-- 20 files changed, 53 insertions(+), 58 deletions(-) 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 usedz; + pool 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 last_access_list; // Quick wire -> list element lookup. - std::unordered_map::iterator> last_access_map; + dict::iterator> last_access_map; - std::unordered_map pips_downhill; - std::unordered_map pips_uphill; + dict pips_downhill; + dict 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 pips_downhill; - std::unordered_map pips_uphill; + dict pips_downhill; + dict 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 cell_types_in_bucket; + pool 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 cell_types_unused; + pool cell_types_unused; - std::unordered_set bels_in_bucket; + pool bels_in_bucket; for (BelId bel : ctx->getBelsInBucket(bucket)) { BelBucketId bucket2 = ctx->getBelBucketForBel(bel); log_assert(bucket == bucket2); diff --git a/common/basectx.h b/common/basectx.h index dd48c33c..12f63f98 100644 --- a/common/basectx.h +++ b/common/basectx.h @@ -28,6 +28,7 @@ #include #endif +#include "hashlib.h" #include "idstring.h" #include "nextpnr_namespaces.h" #include "nextpnr_types.h" 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 values; + dict values; std::unique_ptr ctx = createContext(values); setupContext(ctx.get()); setupArchContext(ctx.get()); @@ -475,7 +475,7 @@ int CommandHandler::exec() std::unique_ptr CommandHandler::load_json(std::string filename) { - std::unordered_map values; + dict values; std::unique_ptr 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 createContext(std::unordered_map &values) = 0; + virtual std::unique_ptr createContext(dict &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 -#include #include #include "archdefs.h" #include "exclusive_state_groups.h" +#include "hashlib.h" #include "idstring.h" #include "nextpnr_namespaces.h" @@ -53,7 +53,7 @@ template TagState; - std::unordered_map> definitions; + dict> definitions; template void bindBel(TagState *tags, const ConstraintRange constraints); 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 message_count_by_level; +dict 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 #include #include -#include #include +#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> 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 message_count_by_level; +extern dict 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 -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX LogLevel &loglevel) const noexcept - { - return std::hash()((int)loglevel); - } -}; -} // namespace std - #endif diff --git a/common/timing_opt.cc b/common/timing_opt.cc index 2659f04e..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 @@ -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{}; + cell_neighbour_bels[cell->name] = pool{}; for (int dy = -d; dy <= d; dy++) { for (int dx = -d; dx <= d; dx++) { // Go through all the Bels at this location @@ -267,7 +265,7 @@ class TimingOptimiser } NPNR_ASSERT_FALSE("port user not found on net"); }; - std::unordered_set used_ports; + pool used_ports; for (auto crit_net : crit_nets) { @@ -439,10 +437,10 @@ class TimingOptimiser } // Actual BFS path optimisation algorithm - std::unordered_map> cumul_costs; - std::unordered_map, std::pair, PairHash> backtrace; + dict> cumul_costs; + dict, std::pair> backtrace; std::queue> visit; - std::unordered_set, PairHash> to_visit; + pool> 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 path_cells; - std::unordered_map> cell_neighbour_bels; - std::unordered_map> bel_candidate_cells; + dict> cell_neighbour_bels; + dict> bel_candidate_cells; // Map cell ports to net delay limit - std::unordered_map, delay_t, PairHash> max_net_delay; + dict, 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 cellTypes; + pool cellTypes; }; extern bool timing_opt(Context *ctx, TimingOptCfg cfg); diff --git a/ecp5/main.cc b/ecp5/main.cc index f6d734e1..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 createContext(std::unordered_map &values) override; + std::unique_ptr createContext(dict &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 ECP5CommandHandler::createContext(std::unordered_map &values) +std::unique_ptr ECP5CommandHandler::createContext(dict &values) { ArchArgs chipArgs; chipArgs.type = ArchArgs::NONE; 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 createContext(std::unordered_map &values) override; + std::unique_ptr createContext(dict &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 FpgaInterchangeCommandHandler::createContext(std::unordered_map &values) +std::unique_ptr FpgaInterchangeCommandHandler::createContext(dict &values) { auto start = std::chrono::high_resolution_clock::now(); 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 createContext(std::unordered_map &values) override; + std::unique_ptr createContext(dict &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 GenericCommandHandler::createContext(std::unordered_map &values) +std::unique_ptr GenericCommandHandler::createContext(dict &values) { ArchArgs chipArgs; if (values.find("arch.name") != values.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 createContext(std::unordered_map &values) override; + std::unique_ptr createContext(dict &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 GowinCommandHandler::createContext(std::unordered_map &values) +std::unique_ptr GowinCommandHandler::createContext(dict &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/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 elements) bool changed = false; // For any elements that are not yet in managed_, created them. - std::unordered_set element_set; + pool 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> managed_; + dict> managed_; // Type of children that the list creates. ElementType child_type_; @@ -184,7 +184,7 @@ template class ElementList : public Item ElementGetter getter_; // Children that we manage the memory for, stored for quick lookup from // IdString to child. - std::unordered_map> managed_; + dict> managed_; // Type of children that he list creates. ElementType child_type_; 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 createContext(std::unordered_map &values) override; + std::unique_ptr createContext(dict &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 Ice40CommandHandler::createContext(std::unordered_map &values) +std::unique_ptr Ice40CommandHandler::createContext(dict &values) { ArchArgs chipArgs; chipArgs.type = ArchArgs::NONE; diff --git a/json/jsonwrite.cc b/json/jsonwrite.cc index dbf43351..88d66519 100644 --- a/json/jsonwrite.cc +++ b/json/jsonwrite.cc @@ -67,7 +67,7 @@ struct PortGroup std::vector group_ports(Context *ctx, const dict &ports, bool is_cell = false) { std::vector groups; - std::unordered_map base_to_group; + dict 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/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 createContext(std::unordered_map &values) override; + std::unique_ptr createContext(dict &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 MachXO2CommandHandler::createContext(std::unordered_map &values) +std::unique_ptr MachXO2CommandHandler::createContext(dict &values) { ArchArgs chipArgs; chipArgs.type = ArchArgs::NONE; 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 createContext(std::unordered_map &values) override; + std::unique_ptr createContext(dict &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 MistralCommandHandler::createContext(std::unordered_map &values) +std::unique_ptr MistralCommandHandler::createContext(dict &values) { ArchArgs chipArgs; if (!vm.count("mistral")) { 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 createContext(std::unordered_map &values) override; + std::unique_ptr createContext(dict &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 NexusCommandHandler::createContext(std::unordered_map &values) +std::unique_ptr NexusCommandHandler::createContext(dict &values) { ArchArgs chipArgs; if (!vm.count("device")) { From 897e2c2fdc43bcf097aa8805c424c4443bcefad5 Mon Sep 17 00:00:00 2001 From: gatecat Date: Wed, 2 Jun 2021 11:44:57 +0100 Subject: [PATCH 10/11] Use hashlib in frontend, where possible Signed-off-by: gatecat --- frontend/frontend_base.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/frontend/frontend_base.h b/frontend/frontend_base.h index d39a8304..4fb71076 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 instantiated_celltypes; + pool instantiated_celltypes; }; template struct GenericFrontend @@ -148,7 +148,7 @@ template struct GenericFrontend using netname_dat_t = typename FrontendType::NetnameDataType; using bitvector_t = typename FrontendType::BitVectorDataType; - std::unordered_map mods; + dict mods; std::unordered_map mod_refs; IdString top; @@ -196,7 +196,7 @@ template 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 candidate_top; + pool candidate_top; for (auto &mod : mods) if (!mod.second.is_box()) candidate_top.insert(mod.first); @@ -207,7 +207,7 @@ template 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 struct GenericFrontend index_to_net_flatindex.resize(idx + 1, -1); return index_to_net_flatindex.at(idx); } - std::unordered_map> port_to_bus; + dict> port_to_bus; // All of the names given to a net std::vector> net_names; }; @@ -453,7 +453,7 @@ template 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 port_dirs; + dict 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) { From dcbb322447a7fb59cabe197ec1dd2307acfa3681 Mon Sep 17 00:00:00 2001 From: gatecat Date: Wed, 2 Jun 2021 12:09:40 +0100 Subject: [PATCH 11/11] Remove redundant code after hashlib move Signed-off-by: gatecat --- .github/ci/build_interchange.sh | 2 +- .gitmodules | 3 -- 3rdparty/abseil-cpp | 1 - CMakeLists.txt | 16 +------- common/base_arch.h | 6 +-- common/hash_table.h | 63 ----------------------------- common/idstring.h | 10 ----- common/idstringlist.h | 14 ------- common/nextpnr_base_types.h | 15 ------- common/placer1.cc | 13 ------ common/util.h | 36 ----------------- docs/archapi.md | 6 +-- ecp5/archdefs.h | 70 --------------------------------- fpga_interchange/archdefs.h | 65 ------------------------------ frontend/frontend_base.h | 8 ++-- gui/CMakeLists.txt | 4 -- ice40/archdefs.h | 46 ---------------------- machxo2/archdefs.h | 43 -------------------- mistral/archdefs.h | 31 +-------------- nexus/archdefs.h | 61 ---------------------------- 20 files changed, 14 insertions(+), 499 deletions(-) delete mode 160000 3rdparty/abseil-cpp delete mode 100644 common/hash_table.h 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 index a7669879..00000000 --- a/3rdparty/abseil-cpp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a76698790753d2ec71f655cdc84d61bcb27780d4 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/base_arch.h b/common/base_arch.h index c7d9f380..457e6582 100644 --- a/common/base_arch.h +++ b/common/base_arch.h @@ -148,7 +148,7 @@ template struct BaseArch : ArchAPI virtual char getNameDelimiter() const override { return ' '; } // Bel methods - virtual uint32_t getBelChecksum(BelId bel) const override { return uint32_t(std::hash()(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 struct BaseArch : ArchAPI { return empty_if_possible(); } - virtual uint32_t getWireChecksum(WireId wire) const override { return uint32_t(std::hash()(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 struct BaseArch : ArchAPI { return empty_if_possible(); } - virtual uint32_t getPipChecksum(PipId pip) const override { return uint32_t(std::hash()(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()); 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 -#include -#else -#include -#include -#endif - -#include - -#include "nextpnr_namespaces.h" - -NEXTPNR_NAMESPACE_BEGIN - -namespace HashTables { -#if defined(USE_ABSEIL) -template > -using HashMap = absl::flat_hash_map; -template > using HashSet = absl::flat_hash_set; -#else -template > -using HashMap = std::unordered_map; -template > using HashSet = std::unordered_set; -#endif - -}; // namespace HashTables - -struct PairHash -{ - template std::size_t operator()(const std::pair &idp) const noexcept - { - std::size_t seed = 0; - boost::hash_combine(seed, std::hash()(idp.first)); - boost::hash_combine(seed, std::hash()(idp.second)); - return seed; - } -}; - -NEXTPNR_NAMESPACE_END - -#endif /* HASH_TABLE_H */ diff --git a/common/idstring.h b/common/idstring.h index aba40ae6..5a7719fa 100644 --- a/common/idstring.h +++ b/common/idstring.h @@ -62,14 +62,4 @@ struct IdString NEXTPNR_NAMESPACE_END -namespace std { -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX IdString &obj) const noexcept - { - return std::hash()(obj.index); - } -}; -} // namespace std - #endif /* IDSTRING_H */ diff --git a/common/idstringlist.h b/common/idstringlist.h index 753b408c..f101ecca 100644 --- a/common/idstringlist.h +++ b/common/idstringlist.h @@ -80,18 +80,4 @@ struct IdStringList NEXTPNR_NAMESPACE_END -namespace std { -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX IdStringList &obj) const noexcept - { - std::size_t seed = 0; - boost::hash_combine(seed, hash()(obj.size())); - for (auto &id : obj) - boost::hash_combine(seed, hash()(id)); - return seed; - } -}; -} // namespace std - #endif /* IDSTRING_LIST_H */ diff --git a/common/nextpnr_base_types.h b/common/nextpnr_base_types.h index ba1af68c..1707559b 100644 --- a/common/nextpnr_base_types.h +++ b/common/nextpnr_base_types.h @@ -130,19 +130,4 @@ enum PlaceStrength NEXTPNR_NAMESPACE_END -namespace std { -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX Loc &obj) const noexcept - { - std::size_t seed = 0; - boost::hash_combine(seed, hash()(obj.x)); - boost::hash_combine(seed, hash()(obj.y)); - boost::hash_combine(seed, hash()(obj.z)); - return seed; - } -}; - -} // namespace std - #endif /* NEXTPNR_BASE_TYPES_H */ diff --git a/common/placer1.cc b/common/placer1.cc index e8c6aa64..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::size_t operator()(const std::pair &idp) const noexcept - { - std::size_t seed = 0; - boost::hash_combine(seed, hash()(idp.first)); - boost::hash_combine(seed, hash()(idp.second)); - return seed; - } -}; -} // namespace std - NEXTPNR_NAMESPACE_BEGIN class SAPlacer diff --git a/common/util.h b/common/util.h index b3e8cbf0..542bd395 100644 --- a/common/util.h +++ b/common/util.h @@ -102,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 std::map sorted(const std::unordered_map> &orig) -{ - std::map 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 std::map sorted_ref(std::unordered_map &orig) -{ - std::map 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 std::map sorted_cref(const std::unordered_map &orig) -{ - std::map 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 std::set sorted(const std::unordered_set &orig) -{ - std::set 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 80aa1d96..f2571f08 100644 --- a/docs/archapi.md +++ b/docs/archapi.md @@ -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/archdefs.h b/ecp5/archdefs.h index 57168af3..6243a9df 100644 --- a/ecp5/archdefs.h +++ b/ecp5/archdefs.h @@ -21,8 +21,6 @@ #ifndef ECP5_ARCHDEFS_H #define ECP5_ARCHDEFS_H -#include - #include "base_clusterinfo.h" #include "hashlib.h" #include "idstring.h" @@ -187,72 +185,4 @@ struct ArchCellInfo : BaseClusterInfo }; NEXTPNR_NAMESPACE_END - -namespace std { -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX Location &loc) const noexcept - { - std::size_t seed = std::hash()(loc.x); - seed ^= std::hash()(loc.y) + 0x9e3779b9 + (seed << 6) + (seed >> 2); - return seed; - } -}; - -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX BelId &bel) const noexcept - { - std::size_t seed = std::hash()(bel.location); - seed ^= std::hash()(bel.index) + 0x9e3779b9 + (seed << 6) + (seed >> 2); - return seed; - } -}; - -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX WireId &wire) const noexcept - { - std::size_t seed = std::hash()(wire.location); - seed ^= std::hash()(wire.index) + 0x9e3779b9 + (seed << 6) + (seed >> 2); - return seed; - } -}; - -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX PipId &pip) const noexcept - { - std::size_t seed = std::hash()(pip.location); - seed ^= std::hash()(pip.index) + 0x9e3779b9 + (seed << 6) + (seed >> 2); - return seed; - } -}; - -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX GroupId &group) const noexcept - { - std::size_t seed = 0; - boost::hash_combine(seed, hash()(group.type)); - boost::hash_combine(seed, hash()(group.location)); - return seed; - } -}; - -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX DecalId &decal) const noexcept - { - std::size_t seed = 0; - boost::hash_combine(seed, hash()(decal.type)); - boost::hash_combine(seed, hash()(decal.location)); - boost::hash_combine(seed, hash()(decal.z)); - boost::hash_combine(seed, hash()(decal.active)); - return seed; - } -}; - -} // namespace std - #endif /* ECP5_ARCHDEFS_H */ diff --git a/fpga_interchange/archdefs.h b/fpga_interchange/archdefs.h index 2d27cccf..a50df43a 100644 --- a/fpga_interchange/archdefs.h +++ b/fpga_interchange/archdefs.h @@ -21,7 +21,6 @@ #ifndef FPGA_INTERCHANGE_ARCHDEFS_H #define FPGA_INTERCHANGE_ARCHDEFS_H -#include #include #include "hashlib.h" @@ -126,68 +125,4 @@ struct ArchCellInfo NEXTPNR_NAMESPACE_END -namespace std { -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX BelId &bel) const noexcept - { - std::size_t seed = 0; - boost::hash_combine(seed, hash()(bel.tile)); - boost::hash_combine(seed, hash()(bel.index)); - return seed; - } -}; - -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX WireId &wire) const noexcept - { - std::size_t seed = 0; - boost::hash_combine(seed, hash()(wire.tile)); - boost::hash_combine(seed, hash()(wire.index)); - return seed; - } -}; - -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX PipId &pip) const noexcept - { - std::size_t seed = 0; - boost::hash_combine(seed, hash()(pip.tile)); - boost::hash_combine(seed, hash()(pip.index)); - return seed; - } -}; - -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX GroupId &group) const noexcept - { - std::size_t seed = 0; - return seed; - } -}; - -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX DecalId &decal) const noexcept - { - std::size_t seed = 0; - return seed; - } -}; - -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX BelBucketId &bucket) const noexcept - { - std::size_t seed = 0; - boost::hash_combine(seed, hash()(bucket.name)); - return seed; - } -}; - -} // namespace std - #endif /* FPGA_INTERCHANGE_ARCHDEFS_H */ diff --git a/frontend/frontend_base.h b/frontend/frontend_base.h index 4fb71076..bc85fabb 100644 --- a/frontend/frontend_base.h +++ b/frontend/frontend_base.h @@ -134,7 +134,7 @@ template 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; } @@ -149,7 +149,7 @@ template struct GenericFrontend using bitvector_t = typename FrontendType::BitVectorDataType; dict mods; - std::unordered_map mod_refs; + std::unordered_map mod_refs; IdString top; // Process the list of modules and determine @@ -159,7 +159,7 @@ template 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); @@ -531,7 +531,7 @@ template 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/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/ice40/archdefs.h b/ice40/archdefs.h index 2d962851..6ef5432f 100644 --- a/ice40/archdefs.h +++ b/ice40/archdefs.h @@ -20,8 +20,6 @@ #ifndef ICE40_ARCHDEFS_H #define ICE40_ARCHDEFS_H -#include - #include "base_clusterinfo.h" #include "hashlib.h" #include "idstring.h" @@ -165,48 +163,4 @@ typedef IdString ClusterId; NEXTPNR_NAMESPACE_END -namespace std { -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX BelId &bel) const noexcept { return hash()(bel.index); } -}; - -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX WireId &wire) const noexcept - { - return hash()(wire.index); - } -}; - -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX PipId &pip) const noexcept { return hash()(pip.index); } -}; - -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX GroupId &group) const noexcept - { - std::size_t seed = 0; - boost::hash_combine(seed, hash()(group.type)); - boost::hash_combine(seed, hash()(group.x)); - boost::hash_combine(seed, hash()(group.y)); - return seed; - } -}; - -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX DecalId &decal) const noexcept - { - std::size_t seed = 0; - boost::hash_combine(seed, hash()(decal.type)); - boost::hash_combine(seed, hash()(decal.index)); - return seed; - } -}; - -} // namespace std - #endif /* ICE40_ARCHDEFS_H */ diff --git a/machxo2/archdefs.h b/machxo2/archdefs.h index afcc72aa..de633673 100644 --- a/machxo2/archdefs.h +++ b/machxo2/archdefs.h @@ -124,47 +124,4 @@ struct ArchCellInfo : BaseClusterInfo NEXTPNR_NAMESPACE_END -namespace std { -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX Location &loc) const noexcept - { - std::size_t seed = std::hash()(loc.x); - seed ^= std::hash()(loc.y) + 0x9e3779b9 + (seed << 6) + (seed >> 2); - return seed; - } -}; - -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX BelId &bel) const noexcept - { - std::size_t seed = std::hash()(bel.location); - seed ^= std::hash()(bel.index) + 0x9e3779b9 + (seed << 6) + (seed >> 2); - return seed; - } -}; - -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX WireId &wire) const noexcept - { - std::size_t seed = std::hash()(wire.location); - seed ^= std::hash()(wire.index) + 0x9e3779b9 + (seed << 6) + (seed >> 2); - return seed; - } -}; - -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX PipId &pip) const noexcept - { - std::size_t seed = std::hash()(pip.location); - seed ^= std::hash()(pip.index) + 0x9e3779b9 + (seed << 6) + (seed >> 2); - return seed; - } -}; - -} // namespace std - #endif /* MACHXO2_ARCHDEFS_H */ diff --git a/mistral/archdefs.h b/mistral/archdefs.h index 71e14ec2..8b4256ab 100644 --- a/mistral/archdefs.h +++ b/mistral/archdefs.h @@ -20,8 +20,6 @@ #ifndef MISTRAL_ARCHDEFS_H #define MISTRAL_ARCHDEFS_H -#include - #include "base_clusterinfo.h" #include "cyclonev.h" @@ -30,6 +28,8 @@ #include "nextpnr_assertions.h" #include "nextpnr_namespaces.h" +#include + NEXTPNR_NAMESPACE_BEGIN using mistral::CycloneV; @@ -210,31 +210,4 @@ struct ArchCellInfo : BaseClusterInfo NEXTPNR_NAMESPACE_END -namespace std { -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX BelId &bel) const noexcept - { - return hash()((static_cast(bel.pos) << 16) | bel.z); - } -}; - -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX WireId &wire) const noexcept - { - return hash()(wire.node); - } -}; - -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX PipId &pip) const noexcept - { - return hash()((uint64_t(pip.dst) << 32) | pip.src); - } -}; - -} // namespace std - #endif diff --git a/nexus/archdefs.h b/nexus/archdefs.h index 76ba605b..f2b5a45d 100644 --- a/nexus/archdefs.h +++ b/nexus/archdefs.h @@ -20,8 +20,6 @@ #ifndef NEXUS_ARCHDEFS_H #define NEXUS_ARCHDEFS_H -#include - #include "base_clusterinfo.h" #include "hashlib.h" #include "idstring.h" @@ -188,63 +186,4 @@ struct ArchCellInfo : BaseClusterInfo NEXTPNR_NAMESPACE_END -namespace std { -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX BelId &bel) const noexcept - { - std::size_t seed = 0; - boost::hash_combine(seed, hash()(bel.tile)); - boost::hash_combine(seed, hash()(bel.index)); - return seed; - } -}; - -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX WireId &wire) const noexcept - { - std::size_t seed = 0; - boost::hash_combine(seed, hash()(wire.tile)); - boost::hash_combine(seed, hash()(wire.index)); - return seed; - } -}; - -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX PipId &pip) const noexcept - { - std::size_t seed = 0; - boost::hash_combine(seed, hash()(pip.tile)); - boost::hash_combine(seed, hash()(pip.index)); - return seed; - } -}; - -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX GroupId &group) const noexcept - { - std::size_t seed = 0; - boost::hash_combine(seed, hash()(group.type)); - boost::hash_combine(seed, hash()(group.x)); - boost::hash_combine(seed, hash()(group.y)); - return seed; - } -}; - -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX DecalId &decal) const noexcept - { - std::size_t seed = 0; - boost::hash_combine(seed, hash()(decal.type)); - boost::hash_combine(seed, hash()(decal.index)); - return seed; - } -}; - -} // namespace std - #endif /* NEXUS_ARCHDEFS_H */