14#include "llvm/ADT/STLExtras.h"
15#include "llvm/ADT/StringExtras.h"
16#include "llvm/Support/MathExtras.h"
29 llvm::StringLiteral name;
30 uint32_t (PortType::*
get)() const;
37 {
"addr_width", &PortType::getAddrWidth},
38 {
"data_width", &PortType::getDataWidth},
39 {
"user_width", &PortType::getUserWidth},
40 {
"write_id_width", &PortType::getWriteIdWidth},
41 {
"read_id_width", &PortType::getReadIdWidth}};
47 PortType port,
const Twine &portDesc,
49 const Twine &referenceDesc) {
50 for (
const WidthField &field : fields) {
51 uint32_t width = (port.*field.get)();
52 uint32_t expected = (reference.*field.get)();
53 if (width != expected)
54 return op.emitOpError()
55 << portDesc <<
"'s '" << field.name <<
"' (" << width
56 <<
") must match " << referenceDesc <<
"'s (" << expected <<
")";
65 for (
auto [i, value] : llvm::enumerate(downstream))
66 for (WindowAttr window :
67 cast<PortType>(value.getType()).getWindows().getWindows())
68 if (window.getBase() <= address && address <= window.getLast())
79static std::pair<uint64_t, uint64_t>
81 uint64_t writes = 0, reads = 0;
82 for (Value value : upstream) {
83 auto manager = cast<PortType>(value.getType());
84 if (!manager.getWindows().overlaps(downstream.getWindows()))
86 writes += manager.getOutstandingWrites();
87 reads += manager.getOutstandingReads();
89 return {writes, reads};
95 std::pair<uint64_t, uint64_t> reaching,
96 const Twine &sourceDesc) {
97 auto [writes, reads] = reaching;
98 if (port.getOutstandingWrites() != writes)
99 return op->emitOpError() << portDesc <<
"'s 'outstanding_writes' ("
100 << port.getOutstandingWrites() <<
") must be the "
101 << writes <<
" writes " << sourceDesc;
102 if (port.getOutstandingReads() != reads)
103 return op->emitOpError() << portDesc <<
"'s 'outstanding_reads' ("
104 << port.getOutstandingReads() <<
") must be the "
105 << reads <<
" reads " << sourceDesc;
109LogicalResult XbarOp::verify() {
110 ValueRange upstream = getUpstream();
111 ValueRange downstream = getDownstream();
112 if (upstream.empty())
113 return emitOpError(
"must have at least one upstream port");
114 if (downstream.empty())
115 return emitOpError(
"must have at least one downstream port");
118 auto upstreamTy = cast<PortType>(upstream.front().getType());
119 for (
auto [i, value] :
llvm::enumerate(upstream.drop_front()))
121 *this,
kWidths, cast<PortType>(value.getType()),
122 "upstream port #" + Twine(i + 1), upstreamTy,
"upstream port #0")))
126 uint32_t idBits = llvm::Log2_64_Ceil(upstream.size());
129 for (
auto [i, value] :
llvm::enumerate(downstream)) {
130 auto downstreamTy = cast<PortType>(value.getType());
133 "downstream port #" + Twine(i), upstreamTy,
"upstream port #0")))
138 for (
const WidthField &field :
140 uint32_t least = (upstreamTy.*field.get)() + idBits;
141 if ((downstreamTy.*field.get)() < least)
143 <<
"downstream port #" << i <<
"'s '" << field.name
144 <<
"' must be at least " << least <<
" to tag transactions from "
145 << upstream.size() <<
" managers, got "
146 << (downstreamTy.*field.get)();
151 for (
auto [i, value] :
llvm::enumerate(downstream)) {
152 auto windows = cast<PortType>(value.getType()).getWindows();
153 for (
auto [j, other] :
llvm::enumerate(downstream.take_front(i)))
154 if (windows.overlaps(cast<PortType>(other.getType()).getWindows()))
155 return emitOpError() <<
"downstream ports #" << j <<
" and #" << i
156 <<
" have overlapping windows";
163 for (
auto [i, value] :
llvm::enumerate(upstream)) {
164 auto managerTy = cast<PortType>(value.getType());
165 for (WindowAttr window : managerTy.getWindows().getWindows()) {
168 for (uint64_t address = window.getBase();;) {
173 <<
"address 0x" << llvm::utohexstr(address,
true)
174 <<
", in upstream port #" << i
175 <<
"'s windows, is not covered by any downstream port";
176 if (!covering.getBurstSpecs().covers(window.getBurstSpecs()))
178 <<
"downstream port #" << j
179 <<
" does not support all the bursts upstream port #" << i
180 <<
" issues at address 0x"
181 << llvm::utohexstr(address,
true)
182 <<
"; upstream requires " << window.getBurstSpecs()
183 <<
", downstream supports " << covering.getBurstSpecs();
186 if (covering.getLast() >= window.getLast())
191 address = covering.getLast() + 1;
198 for (
auto [i, value] :
llvm::enumerate(downstream)) {
199 auto downstreamTy = cast<PortType>(value.getType());
201 *
this,
"downstream port #" + Twine(i), downstreamTy,
203 "the managers reaching it can issue")))
215#define GET_OP_CLASSES
216#include "circt/Dialect/AXI4/AXI4.cpp.inc"
static LogicalResult verifyOutstanding(Operation *op, const Twine &portDesc, PortType port, std::pair< uint64_t, uint64_t > reaching, const Twine &sourceDesc)
Verify that port holds exactly the outstanding requests reaching it.
static std::pair< size_t, WindowAttr > findDownstreamWindow(ValueRange downstream, uint64_t address)
The downstream port and window covering address, or a null window if no downstream port covers it.
static std::pair< uint64_t, uint64_t > routingOutstandingBelow(ValueRange upstream, PortType downstream)
The outstanding writes and reads a routing op sends down downstream, from the upstream ports whose wi...
static LogicalResult verifyWidthsMatch(XbarOp op, ArrayRef< WidthField > fields, PortType port, const Twine &portDesc, PortType reference, const Twine &referenceDesc)
Verify that port agrees with reference on each of the widths in fields.
static constexpr WidthField kWidths[]
static constexpr size_t kNumSharedWidths
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.