nextpnr/himbaechel/himbaechel_api.h
Miodrag Milanović d810aac867
Add GroupId related calls to Himbaechel API (#1399)
* Add GroupId related calls to Himbaechel API

* Example uarch using new API features

* Update drawGroup to propagate only GroupId
2024-12-05 13:59:33 +01:00

155 lines
6.8 KiB
C++

/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2021-23 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 HIMBAECHEL_API_H
#define HIMBAECHEL_API_H
#include "nextpnr_namespaces.h"
#include "nextpnr_types.h"
NEXTPNR_NAMESPACE_BEGIN
/*
Himbaechel -- a series of bigger arches
Himbaechel extends on the existing Viaduct API in nextpnr-generic for smaller, lower-impact architectures by a
deduplicated BBA chipdb format as well as API hooks more suited to such size and complexity devices.
It allows an arch to programmatically build a set of bels (placement locations) and a routing graph at compile time into
a space-efficient (both disk and runtime RAM) deduplicated database with fast lookups; and then hook into nextpnr's flow
and validity checking rules at runtime with custom C++ code.
To create a Himbaechel 'uarch', the following are required:
- an implementation of HimbaechelAPI. This should define things like rules for how LUTs and FFs can be placed together
in a SLICE.
- "ahead-of-time" Python scripts to programmatically build a routing graph for the device as well as list of placement
locations, in a way that will become space-efficient
- an instance of a struct deriving from HimbaechelArch - this is how the uarch is discovered. Override create(args) to
create an instance of your HimabaechelAPI implementation.
- these should be within C++ files in a new subfolder of 'himbaechel/uarches/'. Add the name of this subfolder to the
list of HIMBAECHEL_UARCHES in family.cmake if building in-tree.
For an example of how these pieces fit together; see 'himbaechel/uarches/example' which implements a small synthetic
architecture using this framework.
*/
struct Arch;
struct Context;
struct PlacerHeapCfg;
struct HimbaechelAPI
{
// Architecture specific context initialization
virtual void init(Context *ctx);
// Called after context is initialized, but before any commands are executed
virtual void setupArchContext() {}
// If constids are being used, this is used to set them up early
// then it is responsible for loading the db blob with arch->load_chipdb()
virtual void init_database(Arch *arch) = 0;
Context *ctx;
bool with_gui = false;
// --- Bel functions ---
// Called when a bel is placed/unplaced (with cell=nullptr for a unbind)
virtual void notifyBelChange(BelId bel, CellInfo *cell) {}
// This only needs to return false if a bel is disabled for a microarch-specific reason and not just because it's
// bound (which the base generic will deal with)
virtual bool checkBelAvail(BelId bel) const { return true; }
// Mirror the ArchAPI functions - see archapi.md
virtual std::vector<IdString> getCellTypes() const;
virtual BelBucketId getBelBucketForBel(BelId bel) const;
virtual BelBucketId getBelBucketForCellType(IdString cell_type) const;
virtual bool isValidBelForCellType(IdString cell_type, BelId bel) const;
virtual bool isBelLocationValid(BelId bel, bool explain_invalid = false) const { return true; }
// --- Wire and pip functions ---
// Called when a wire/pip is placed/unplaced (with net=nullptr for a unbind)
virtual void notifyWireChange(WireId wire, NetInfo *net) {}
virtual void notifyPipChange(PipId pip, NetInfo *net) {}
// These only need to return false if a wire/pip is disabled for a microarch-specific reason and not just because
// it's bound (which the base arch will deal with)
virtual bool checkWireAvail(WireId wire) const { return true; }
virtual bool checkPipAvail(PipId pip) const { return true; }
virtual bool checkPipAvailForNet(PipId pip, const NetInfo *net) const { return checkPipAvail(pip); };
// --- Route lookahead ---
virtual delay_t estimateDelay(WireId src, WireId dst) const;
virtual delay_t predictDelay(BelId src_bel, IdString src_pin, BelId dst_bel, IdString dst_pin) const;
virtual BoundingBox getRouteBoundingBox(WireId src, WireId dst) const;
// Cell->bel pin mapping
virtual bool map_cell_bel_pins(CellInfo *cell) const { return false; }
// Cluster
virtual CellInfo *getClusterRootCell(ClusterId cluster) const;
virtual BoundingBox getClusterBounds(ClusterId cluster) const;
virtual Loc getClusterOffset(const CellInfo *cell) const;
virtual bool isClusterStrict(const CellInfo *cell) const;
virtual bool getClusterPlacement(ClusterId cluster, BelId root_bel,
std::vector<std::pair<CellInfo *, BelId>> &placement) const;
// Graphics
virtual void drawBel(std::vector<GraphicElement> &g, GraphicElement::style_t style, IdString bel_type, Loc loc) {};
virtual void drawWire(std::vector<GraphicElement> &g, GraphicElement::style_t style, Loc loc, IdString wire_type,
int32_t tilewire, IdString tile_type) {};
virtual void drawPip(std::vector<GraphicElement> &g, GraphicElement::style_t style, Loc loc, WireId src,
IdString src_type, int32_t src_id, WireId dst, IdString dst_type, int32_t dst_id) {};
virtual void drawGroup(std::vector<GraphicElement> &g, GroupId group, Loc loc) {};
// Routing methods
virtual void expandBoundingBox(BoundingBox &bb) const;
// --- Flow hooks ---
virtual void pack() {}; // replaces the pack function
// Called before and after main placement and routing
virtual void prePlace() {};
virtual void postPlace() {};
virtual void preRoute() {};
virtual void postRoute() {};
// For custom placer configuration
virtual void configurePlacerHeap(PlacerHeapCfg &cfg) {};
virtual ~HimbaechelAPI() {};
};
struct HimbaechelArch
{
static HimbaechelArch *list_head;
HimbaechelArch *list_next = nullptr;
std::string name;
HimbaechelArch(const std::string &name);
~HimbaechelArch() {};
virtual bool match_device(const std::string &device) = 0;
virtual std::unique_ptr<HimbaechelAPI> create(const std::string &device,
const dict<std::string, std::string> &args) = 0;
static std::string list();
static HimbaechelArch *find_match(const std::string &device);
};
NEXTPNR_NAMESPACE_END
#endif