nextpnr/fpga_interchange/site_routing_storage.h

162 lines
4.6 KiB
C
Raw Normal View History

/*
* 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 */