CIRCT 24.0.0git
Loading...
Searching...
No Matches
AXI4Attributes.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
11#include "mlir/IR/Builders.h"
12#include "mlir/IR/DialectImplementation.h"
13#include "llvm/ADT/STLExtras.h"
14#include "llvm/ADT/SmallVector.h"
15#include "llvm/ADT/StringExtras.h"
16#include "llvm/ADT/TypeSwitch.h"
17#include "llvm/Support/MathExtras.h"
18
19using namespace circt;
20using namespace axi4;
21using namespace mlir;
22
23#include "circt/Dialect/AXI4/AXI4Enums.cpp.inc"
24
25#define GET_ATTRDEF_CLASSES
26#include "circt/Dialect/AXI4/AXI4Attributes.cpp.inc"
27
28LogicalResult
29BurstSpecAttr::verify(function_ref<InFlightDiagnostic()> emitError,
30 BurstKind kind, uint32_t len) {
31 // AXI4 permits 1-16 beats for 'fixed', 1-256 for 'incr', and only 2, 4, 8,
32 // or 16 for 'wrap'.
33 switch (kind) {
34 case BurstKind::Fixed:
35 if (len == 0 || len > 16)
36 return emitError() << "'fixed' burst 'len' must be between 1 and 16, got "
37 << len;
38 break;
39 case BurstKind::Incr:
40 if (len == 0 || len > 256)
41 return emitError() << "'incr' burst 'len' must be between 1 and 256, got "
42 << len;
43 break;
44 case BurstKind::Wrap:
45 if (len < 2 || len > 16 || !llvm::isPowerOf2_32(len))
46 return emitError() << "'wrap' burst 'len' must be 2, 4, 8, or 16, got "
47 << len;
48 break;
49 }
50 return success();
51}
52
53/// Ordering for burst_set construction
54bool BurstSpecAttr::compareCanonical(BurstSpecAttr lhs, BurstSpecAttr rhs) {
55 if (lhs.getKind() != rhs.getKind())
56 return lhs.getKind() < rhs.getKind();
57 return lhs.getLen() < rhs.getLen();
58}
59
60LogicalResult BurstSetAttr::verify(function_ref<InFlightDiagnostic()> emitError,
61 ArrayRef<BurstSpecAttr> burstSpecs) {
62 if (burstSpecs.empty())
63 return emitError() << "'burst_set' must be non-empty";
64 return success();
65}
66
67bool BurstSetAttr::covers(BurstSetAttr other) {
68 // A `len` is a maximum, so a spec covers every shorter one of its kind
69 return llvm::all_of(other.getBurstSpecs(), [&](BurstSpecAttr required) {
70 return llvm::any_of(getBurstSpecs(), [&](BurstSpecAttr spec) {
71 return spec.getKind() == required.getKind() &&
72 spec.getLen() >= required.getLen();
73 });
74 });
75}
76
77LogicalResult WindowAttr::verify(function_ref<InFlightDiagnostic()> emitError,
78 uint64_t base, uint64_t last,
79 BurstSetAttr burstSpecs) {
80 if (last < base)
81 return emitError() << "window 'last' address 0x"
82 << llvm::utohexstr(last, /*LowerCase=*/true)
83 << " must not be less than 'base' address 0x"
84 << llvm::utohexstr(base, /*LowerCase=*/true);
85 return success();
86}
87
88bool WindowAttr::overlaps(WindowAttr other) {
89 return getBase() <= other.getLast() && other.getBase() <= getLast();
90}
91
92SmallVector<WindowAttr> WindowSetAttr::normalize(MLIRContext *ctx,
93 ArrayRef<WindowAttr> windows) {
94 // Split the address space at every point where the specs could change (i.e.
95 // the start and end points of the windows).
96 // Then, for each of those segments, accumulate all the specs that cover it,
97 // and create a window accordingly.
98
99 SmallVector<uint64_t> cuts;
100 for (WindowAttr window : windows) {
101 cuts.push_back(window.getBase());
102 if (window.getLast() != UINT64_MAX)
103 cuts.push_back(window.getLast() + 1);
104 }
105 llvm::sort(cuts);
106 cuts.erase(llvm::unique(cuts), cuts.end());
107
108 SmallVector<WindowAttr> normalized;
109 SmallVector<BurstSpecAttr> specs;
110 for (size_t i = 0; i < cuts.size(); ++i) {
111 uint64_t lo = cuts[i];
112 uint64_t hi = i + 1 < cuts.size() ? cuts[i + 1] - 1 : UINT64_MAX;
113
114 // Collect the set of specs that cover this segment
115 specs.clear();
116 for (WindowAttr window : windows)
117 if (window.getBase() <= lo && lo <= window.getLast())
118 llvm::append_range(specs, window.getBurstSpecs().getBurstSpecs());
119
120 // Nothing covers the segment - a gap between windows.
121 if (specs.empty())
122 continue;
123
124 // BurstSetAttr::get sorts the union and merges each kind for us.
125 auto burstSpecs = BurstSetAttr::get(ctx, specs);
126
127 // Merge into the previous window where they are contiguous and share
128 // capabilities.
129 if (!normalized.empty() && normalized.back().getLast() + 1 == lo &&
130 normalized.back().getBurstSpecs() == burstSpecs)
131 lo = normalized.pop_back_val().getBase();
132 normalized.push_back(WindowAttr::get(ctx, lo, hi, burstSpecs));
133 }
134 return normalized;
135}
136
137LogicalResult
138WindowSetAttr::verify(function_ref<InFlightDiagnostic()> emitError,
139 ArrayRef<WindowAttr> windows) {
140 if (windows.empty())
141 return emitError() << "'window_set' must be non-empty";
142 return success();
143}
144
145bool WindowSetAttr::overlaps(WindowSetAttr other) {
146 // Both sets contain sorted windows, so we know a window that doesn't overlap
147 // the current one and ends first can't overlap anything later either
148 ArrayRef<WindowAttr> windows = getWindows();
149 ArrayRef<WindowAttr> otherWindows = other.getWindows();
150 for (size_t i = 0, j = 0; i < windows.size() && j < otherWindows.size();) {
151 WindowAttr window = windows[i], otherWindow = otherWindows[j];
152 if (window.overlaps(otherWindow))
153 return true;
154 if (window.getLast() < otherWindow.getLast())
155 ++i;
156 else
157 ++j;
158 }
159 return false;
160}
161
162void AXI4Dialect::registerAttributes() {
163 addAttributes<
164#define GET_ATTRDEF_LIST
165#include "circt/Dialect/AXI4/AXI4Attributes.cpp.inc"
166 >();
167}
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.