diff options
author | gatecat <gatecat@ds0.me> | 2022-02-26 15:11:33 +0000 |
---|---|---|
committer | gatecat <gatecat@ds0.me> | 2022-02-26 15:11:33 +0000 |
commit | 434a9737bb459189b463c8768454ea6c0e151406 (patch) | |
tree | 9930d7e5787d0eb757f29db66f2efc2575456eca /common | |
parent | 0b4f1e2b51990a512edd2129145b3ff463dcdd21 (diff) | |
download | nextpnr-434a9737bb459189b463c8768454ea6c0e151406.tar.gz nextpnr-434a9737bb459189b463c8768454ea6c0e151406.tar.bz2 nextpnr-434a9737bb459189b463c8768454ea6c0e151406.zip |
Add indexed_store container type
Signed-off-by: gatecat <gatecat@ds0.me>
Diffstat (limited to 'common')
-rw-r--r-- | common/indexed_store.h | 266 | ||||
-rw-r--r-- | common/nextpnr_types.h | 1 |
2 files changed, 267 insertions, 0 deletions
diff --git a/common/indexed_store.h b/common/indexed_store.h new file mode 100644 index 00000000..5579b039 --- /dev/null +++ b/common/indexed_store.h @@ -0,0 +1,266 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2021-22 gatecat <gatecat@ds0.me> + * + * 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 INDEXED_STORE_H +#define INDEXED_STORE_H + +#include <algorithm> +#include <limits> +#include <vector> + +#include "nextpnr_assertions.h" +#include "nextpnr_namespaces.h" + +NEXTPNR_NAMESPACE_BEGIN + +template <typename T> struct store_index +{ + int32_t m_index = -1; + store_index() = default; + explicit store_index(int32_t index) : m_index(index){}; + int32_t idx() const { return m_index; } + void set(int32_t index) { m_index = index; } + bool empty() const { return m_index == -1; } + bool operator==(const store_index<T> &other) const { return m_index == other.m_index; } + bool operator!=(const store_index<T> &other) const { return m_index != other.m_index; } + bool operator<(const store_index<T> &other) const { return m_index < other.m_index; } + unsigned int hash() const { return m_index; } + + operator bool() const { return !empty(); } + bool operator!() const { return empty(); } +}; + +// "Slotted" indexed object store +template <typename T> class indexed_store +{ + private: + // This should move to using std::optional at some point + class slot + { + private: + alignas(T) unsigned char storage[sizeof(T)]; + int32_t next_free; + bool active; + inline T &obj() { return reinterpret_cast<T &>(storage); } + inline const T &obj() const { return reinterpret_cast<const T &>(storage); } + friend class indexed_store<T>; + + public: + slot() : active(false), next_free(std::numeric_limits<int32_t>::max()){}; + slot(slot &&other) : active(other.active), next_free(other.next_free) + { + if (active) + ::new (static_cast<void *>(&storage)) T(std::move(other.obj())); + }; + + template <class... Args> void create(Args &&...args) + { + NPNR_ASSERT(!active); + active = true; + ::new (static_cast<void *>(&storage)) T(std::forward<Args &&>(args)...); + } + bool empty() const { return !active; } + T &get() + { + NPNR_ASSERT(active); + return reinterpret_cast<T &>(storage); + } + const T &get() const + { + NPNR_ASSERT(active); + return reinterpret_cast<const T &>(storage); + } + void free(int32_t first_free) + { + NPNR_ASSERT(active); + obj().~T(); + active = false; + next_free = first_free; + } + ~slot() + { + if (active) + obj().~T(); + } + }; + + std::vector<slot> slots; + int32_t first_free = 0; + int32_t active_count = 0; + + public: + // Create a new entry and return its index + template <class... Args> store_index<T> add(Args &&...args) + { + ++active_count; + if (first_free == int32_t(slots.size())) { + slots.emplace_back(); + slots.back().create(std::forward<Args &&>(args)...); + ++first_free; + return store_index<T>(int32_t(slots.size()) - 1); + } else { + int32_t idx = first_free; + auto &slot = slots.at(idx); + first_free = slot.next_free; + slot.create(std::forward<Args &&>(args)...); + return store_index<T>(idx); + } + } + + // Remove an entry at an index + void remove(store_index<T> idx) + { + --active_count; + slots.at(idx.m_index).free(first_free); + first_free = idx.m_index; + } + + // Number of live entries + int32_t entries() const { return active_count; } + + // Reserve a certain amount of space + void reserve(int32_t size) { slots.reser module \$__XILINX_RAMB36_SDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
parameter CLKPOL2 = 1;
parameter CLKPOL3 = 1;
parameter [36863:0] INIT = 36864'bx;
input CLK2;
input CLK3;
input [8:0] A1ADDR;
output [71:0] A1DATA;
input A1EN;
input [8:0] B1ADDR;
input [71:0] B1DATA;
input [7:0] B1EN;
wire [15:0] A1ADDR_16 = {A1ADDR, 6'b0};
wire [15:0] B1ADDR_16 = {B1ADDR, 6'b0};
div> |