nextpnr/common/kernel/basectx.h
2024-10-01 15:24:40 +02:00

254 lines
7.5 KiB
C++

/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 Claire Xenia Wolf <claire@yosyshq.com>
* Copyright (C) 2018 Serge Bazanski <q3k@q3k.org>
*
* 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 BASECTX_H
#define BASECTX_H
#include <mutex>
#include <unordered_map>
#include <vector>
#ifndef NPNR_DISABLE_THREADS
#include <boost/thread.hpp>
#endif
#include "hashlib.h"
#include "idstring.h"
#include "nextpnr_namespaces.h"
#include "nextpnr_types.h"
#include "property.h"
#include "str_ring_buffer.h"
NEXTPNR_NAMESPACE_BEGIN
struct Context;
struct BaseCtx
{
#ifndef NPNR_DISABLE_THREADS
// Lock to perform mutating actions on the Context.
std::mutex mutex;
boost::thread::id mutex_owner;
// Lock to be taken by UI when wanting to access context - the yield()
// method will lock/unlock it when its' released the main mutex to make
// sure the UI is not starved.
std::mutex ui_mutex;
#endif
// ID String database.
mutable std::unordered_map<std::string, int> *idstring_str_to_idx;
mutable std::vector<const std::string *> *idstring_idx_to_str;
// Temporary string backing store for logging
mutable StrRingBuffer log_strs;
// Project settings and config switches
dict<IdString, Property> settings;
// Placed nets and cells.
dict<IdString, std::unique_ptr<NetInfo>> nets;
dict<IdString, std::unique_ptr<CellInfo>> cells;
// Hierarchical (non-leaf) cells by full path
dict<IdString, HierarchicalCell> 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
dict<IdString, IdString> net_aliases;
// Top-level ports
dict<IdString, PortInfo> ports;
dict<IdString, CellInfo *> port_cells;
// Floorplanning regions
dict<IdString, std::unique_ptr<Region>> region;
// Context meta data
dict<IdString, Property> attrs;
// Fmax data post timing analysis
TimingResult timing_result;
Context *as_ctx = nullptr;
// Has the frontend loaded a design?
bool design_loaded;
BaseCtx()
{
idstring_str_to_idx = new std::unordered_map<std::string, int>;
idstring_idx_to_str = new std::vector<const std::string *>;
IdString::initialize_add(this, "", 0);
IdString::initialize_arch(this);
design_loaded = false;
}
virtual ~BaseCtx()
{
delete idstring_str_to_idx;
delete idstring_idx_to_str;
}
// Must be called before performing any mutating changes on the Ctx/Arch.
void lock(void)
{
#ifndef NPNR_DISABLE_THREADS
mutex.lock();
mutex_owner = boost::this_thread::get_id();
#endif
}
void unlock(void)
{
#ifndef NPNR_DISABLE_THREADS
NPNR_ASSERT(boost::this_thread::get_id() == mutex_owner);
mutex.unlock();
#endif
}
// Must be called by the UI before rendering data. This lock will be
// prioritized when processing code calls yield().
void lock_ui(void)
{
#ifndef NPNR_DISABLE_THREADS
ui_mutex.lock();
mutex.lock();
#endif
}
void unlock_ui(void)
{
#ifndef NPNR_DISABLE_THREADS
mutex.unlock();
ui_mutex.unlock();
#endif
}
// Yield to UI by unlocking the main mutex, flashing the UI mutex and
// relocking the main mutex. Call this when you're performing a
// long-standing action while holding a lock to let the UI show
// visualization updates.
// Must be called with the main lock taken.
void yield(void)
{
#ifndef NPNR_DISABLE_THREADS
unlock();
ui_mutex.lock();
ui_mutex.unlock();
lock();
#endif
}
IdString id(const std::string &s) const { return IdString(this, s); }
IdString id(const char *s) const { return IdString(this, s); }
IdString idf(const char *fmt, ...) const; // create IdString using printf formatting
Context *getCtx() { return as_ctx; }
const Context *getCtx() const { return as_ctx; }
const char *nameOf(IdString name) const { return name.c_str(this); }
template <typename T> const char *nameOf(const T *obj) const
{
if (obj == nullptr)
return "";
return obj->name.c_str(this);
}
const char *nameOfBel(BelId bel) const;
const char *nameOfWire(WireId wire) const;
const char *nameOfPip(PipId pip) const;
const char *nameOfGroup(GroupId group) const;
// Wrappers of arch functions that take a string and handle IdStringList parsing
BelId getBelByNameStr(const std::string &str);
WireId getWireByNameStr(const std::string &str);
PipId getPipByNameStr(const std::string &str);
GroupId getGroupByNameStr(const std::string &str);
// --------------------------------------------------------------
bool allUiReload = true;
bool frameUiReload = false;
pool<BelId> belUiReload;
pool<WireId> wireUiReload;
pool<PipId> pipUiReload;
pool<GroupId> groupUiReload;
void refreshUi() { allUiReload = true; }
void refreshUiFrame() { frameUiReload = true; }
void refreshUiBel(BelId bel) { belUiReload.insert(bel); }
void refreshUiWire(WireId wire) { wireUiReload.insert(wire); }
void refreshUiPip(PipId pip) { pipUiReload.insert(pip); }
void refreshUiGroup(GroupId group) { groupUiReload.insert(group); }
// --------------------------------------------------------------
NetInfo *getNetByAlias(IdString alias) const
{
if (nets.count(alias) > 0)
return nets.at(alias).get();
if (net_aliases.count(alias) == 0)
return nullptr;
return nets.at(net_aliases.at(alias)).get();
}
// Intended to simplify Python API
void addClock(IdString net, float freq);
void createRectangularRegion(IdString name, int x0, int y0, int x1, int y1);
void addBelToRegion(IdString name, BelId bel);
void constrainCellToRegion(IdString cell, IdString region_name);
// Helper functions for the partial reconfiguration plug API using PseudoCells
void createRegionPlug(IdString name, IdString type, Loc approx_loc);
void addPlugPin(IdString plug, IdString pin, PortType dir, WireId wire);
// Helper functions for Python bindings
NetInfo *createNet(IdString name);
void connectPort(IdString net, IdString cell, IdString port);
void disconnectPort(IdString cell, IdString port);
void ripupNet(IdString name);
void lockNetRouting(IdString name);
void renameNet(IdString old_name, IdString new_name);
CellInfo *createCell(IdString name, IdString type);
void copyBelPorts(IdString cell, BelId bel);
// Workaround for lack of wrappable constructors
DecalXY constructDecalXY(DecalId decal, float x, float y);
void archInfoToAttributes();
void attributesToArchInfo();
};
NEXTPNR_NAMESPACE_END
#endif /* BASECTX_H */