1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2021 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 VIADUCT_API_H
#define VIADUCT_API_H
#include "nextpnr_namespaces.h"
#include "nextpnr_types.h"
NEXTPNR_NAMESPACE_BEGIN
/*
Viaduct -- a series of small arches
Viaduct is a framework that provides an 'inbetween' step between nextpnr-generic
using Python bindings and a full-custom arch.
It allows an arch to programmatically build a set of bels (placement locations)
and a routing graph in-memory at startup; and then hook into nextpnr's flow
and validity checking rules at runtime with custom C++ code.
To create a Viaduct 'uarch', the following are required:
- an implementation of ViaductAPI. At a minimum; you will need to use ctx->addBel, ctx->addWire and ctx->addPip to
create the graph of placement and routing resources in-memory. Also implement any placement validity checking required -
like rules for how LUTs and FFs can be placed together in a SLICE.
- an instance of a struct deriving from ViaductArch - this is how the uarch is discovered. Override create(args) to
create an instance of your ViaductAPI implementation.
- these should be within C++ files in a new subfolder of 'viaduct'. Add the name of this subfolder to the list of
VIADUCT_UARCHES in family.cmake if building in-tree.
For an example of how these pieces fit together; see 'viaduct/example' which implements a small synthetic architecture
using this framework.
*/
struct Context;
struct ViaductAPI
{
virtual void init(Context *ctx);
Context *ctx;
// --- 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) 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, 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 ArcBounds getRouteBoundingBox(WireId src, WireId dst) 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(){};
virtual ~ViaductAPI(){};
};
struct ViaductArch
{
static ViaductArch *list_head;
ViaductArch *list_next = nullptr;
std::string name;
ViaductArch(const std::string &name);
~ViaductArch(){};
virtual std::unique_ptr<ViaductAPI> create(const dict<std::string, std::string> &args) = 0;
static std::string list();
static std::unique_ptr<ViaductAPI> create(const std::string &name, const dict<std::string, std::string> &args);
};
NEXTPNR_NAMESPACE_END
#endif
|