/* * 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 SITE_ROUTING_STORAGE #define SITE_ROUTING_STORAGE #include #include "nextpnr_namespaces.h" #include "site_arch.h" NEXTPNR_NAMESPACE_BEGIN struct RouteNode { void clear() { parent = std::numeric_limits::max(); pip = SitePip(); wire = SiteWire(); flags = 0; depth = 0; } enum Flags { // Has this path left the site? LEFT_SITE = 0, // Has this path entered the site? ENTERED_SITE = 1, // Has this path left the site after entering it? // This node should be discarded as being part of an illegal path // which allows entering and exiting a site, situation that needs // to be handled with a tile PIP. LEFT_SITE_AFTER_ENTERING = 2, }; bool has_left_site() const { return (flags & (1 << LEFT_SITE)) != 0; } bool has_left_site_after_entering() const { return (flags & (1 << LEFT_SITE_AFTER_ENTERING)) != 0; } bool can_leave_site() const { return !has_left_site(); } bool is_valid_node() const { return !has_left_site_after_entering(); } void mark_left_site() { flags |= (1 << LEFT_SITE); } void mark_left_site_after_entering() { flags |= (has_entered_site() << LEFT_SITE_AFTER_ENTERING); } bool has_entered_site() const { return (flags & (1 << ENTERED_SITE)) != 0; } bool can_enter_site() const { return !has_entered_site(); } void mark_entered_site() { flags |= (1 << ENTERED_SITE); } size_t parent; SitePip pip; // What pip was taken to reach this node. SiteWire wire; // What wire is this routing node located at? int32_t flags; int32_t depth; }; struct RouteNodeStorage; class Node { public: Node(RouteNodeStorage *storage, size_t idx) : storage_(storage), idx_(idx) {} size_t get_index() const { return idx_; } RouteNode &operator*(); const RouteNode &operator*() const; RouteNode *operator->(); const RouteNode *operator->() const; bool has_parent() const; Node parent(); private: RouteNodeStorage *storage_; size_t idx_; }; struct RouteNodeStorage { // Free list of nodes. std::vector nodes; std::vector free_list; // Either allocate a new node if no nodes are on the free list, or return // an element from the free list. Node alloc_node() { if (free_list.empty()) { nodes.emplace_back(); nodes.back().clear(); return Node(this, nodes.size() - 1); } size_t idx = free_list.back(); free_list.pop_back(); nodes[idx].clear(); return Node(this, idx); } Node get_node(size_t idx) { NPNR_ASSERT(idx < nodes.size()); return Node(this, idx); } const Node get_node(size_t idx) const { NPNR_ASSERT(idx < nodes.size()); return Node(const_cast(this), idx); } // Return all node from the current owner to the free list. void free_nodes(std::vector &other_free_list) { free_list.insert(free_list.end(), other_free_list.begin(), other_free_list.end()); } }; inline RouteNode &Node::operator*() { return storage_->nodes[idx_]; } inline const RouteNode &Node::operator*() const { return storage_->nodes[idx_]; } inline RouteNode *Node::operator->() { return &storage_->nodes[idx_]; } inline const RouteNode *Node::operator->() const { return &storage_->nodes[idx_]; } inline bool Node::has_parent() const { return storage_->nodes[idx_].parent < storage_->nodes.size(); } inline Node Node::parent() { size_t parent_idx = storage_->nodes[idx_].parent; NPNR_ASSERT(parent_idx < storage_->nodes.size()); return Node(storage_, parent_idx); } NEXTPNR_NAMESPACE_END #endif /* SITE_ROUTING_STORAGE */