162 lines
4.6 KiB
C++
162 lines
4.6 KiB
C++
/*
|
|
* 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 <limits>
|
|
|
|
#include "nextpnr_namespaces.h"
|
|
#include "site_arch.h"
|
|
|
|
NEXTPNR_NAMESPACE_BEGIN
|
|
|
|
struct RouteNode
|
|
{
|
|
void clear()
|
|
{
|
|
parent = std::numeric_limits<size_t>::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<RouteNode> nodes;
|
|
std::vector<size_t> 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<RouteNodeStorage *>(this), idx);
|
|
}
|
|
|
|
// Return all node from the current owner to the free list.
|
|
void free_nodes(std::vector<size_t> &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 */
|