MLIR-AIE 1.4.5.dev
AIERegisterDatabase.cpp
Go to the documentation of this file.
1//===- AIERegisterDatabase.cpp ----------------------------------*- C++ -*-===//
2//
3// Copyright (C) 2025 Advanced Micro Devices, Inc.
4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5//
6//===----------------------------------------------------------------------===//
7// Register and event database implementation
8//===----------------------------------------------------------------------===//
9
11#include "llvm/ADT/STLExtras.h"
12#include "llvm/Support/ErrorOr.h"
13#include "llvm/Support/FileSystem.h"
14#include "llvm/Support/MemoryBuffer.h"
15#include "llvm/Support/Path.h"
16#include "llvm/Support/Program.h"
17#include "llvm/Support/raw_ostream.h"
18#include <algorithm>
19#include <cstdlib>
20#include <limits>
21
22using namespace xilinx::AIE;
23using namespace llvm;
24
25const BitFieldInfo *RegisterInfo::getField(StringRef fieldName) const {
26 for (const auto &field : bit_fields) {
27 if (field.name == fieldName) {
28 return &field;
29 }
30 }
31 return nullptr;
32}
33
34namespace {
35std::optional<std::string> findRegDBFile(llvm::StringRef fileName) {
36 auto checkDirectory = [&](llvm::StringRef dir) -> std::optional<std::string> {
37 if (dir.empty())
38 return std::nullopt;
39 llvm::SmallString<256> candidate(dir);
40 llvm::sys::path::append(candidate, fileName);
41 if (llvm::sys::fs::exists(candidate))
42 return std::string(candidate.str());
43 return std::nullopt;
44 };
45
46 if (const char *installDir = std::getenv("MLIR_AIE_INSTALL_DIR")) {
47 llvm::SmallString<256> dir(installDir);
48 llvm::sys::path::append(dir, "lib", "regdb");
49 if (auto path = checkDirectory(dir))
50 return path;
51 }
52
53 std::string mainExecutable = llvm::sys::fs::getMainExecutable(
54 nullptr, reinterpret_cast<void *>(&findRegDBFile));
55 if (!mainExecutable.empty()) {
56 llvm::SmallString<256> dir(mainExecutable);
57 llvm::sys::path::remove_filename(dir);
58 llvm::sys::path::append(dir, "..", "lib", "regdb");
59 llvm::sys::path::remove_dots(dir, true);
60 if (auto path = checkDirectory(dir))
61 return path;
62 }
63
64 return std::nullopt;
65}
66} // namespace
67
68std::unique_ptr<RegisterDatabase> RegisterDatabase::loadAIE2() {
69 auto registerPath = findRegDBFile("aie_registers_aie2.json");
70 auto eventPath = findRegDBFile("events_database.json");
71
72 if (!registerPath || !eventPath) {
73 llvm::errs() << "Failed to locate AIE register database resources. "
74 << "Set MLIR_AIE_INSTALL_DIR to the "
75 << "MLIR-AIE installation path.\n";
76 return nullptr;
77 }
78
79 auto db = std::unique_ptr<RegisterDatabase>(new RegisterDatabase());
80 if (!db->loadFromJSON(*registerPath, *eventPath))
81 return nullptr;
82 db->buildOffsetIndex();
83
84 return db;
85}
86
87bool RegisterDatabase::loadFromJSON(StringRef registerPath,
88 StringRef eventPath) {
89 // Load register database
90 auto registerBuf = MemoryBuffer::getFile(registerPath);
91 if (!registerBuf) {
92 llvm::errs() << "Failed to load register database: " << registerPath
93 << "\n";
94 return false;
95 }
96
97 auto registerJSON = json::parse(registerBuf.get()->getBuffer());
98 if (!registerJSON) {
99 llvm::errs() << "Failed to parse register JSON\n";
100 return false;
101 }
102
103 // Parse register database
104 auto *root = registerJSON->getAsObject();
105 if (!root)
106 return false;
107
108 auto *modules = root->getObject("modules");
109 if (!modules)
110 return false;
111
112 // Iterate through modules (CORE_MODULE, MEMORY_MODULE, etc.)
113 for (const auto &modulePair : *modules) {
114 StringRef moduleName = modulePair.first;
115 auto *moduleObj = modulePair.second.getAsObject();
116 if (!moduleObj)
117 continue;
118
119 auto *registers = moduleObj->getArray("registers");
120 if (!registers)
121 continue;
122
123 // Parse each register
124 for (const auto &regVal : *registers) {
125 auto *regObj = regVal.getAsObject();
126 if (!regObj)
127 continue;
128
129 RegisterInfo regInfo;
130 regInfo.module = moduleName.str();
131 regInfo.offset = 0; // Initialize to 0
132
133 if (auto name = regObj->getString("name"))
134 regInfo.name = name->str();
135 if (auto offset = regObj->getString("offset")) {
136 // Parse hex offset (string like "0x00000340D0")
137 StringRef offsetStr = *offset;
138 // Remove "0x" prefix if present
139 if (offsetStr.starts_with("0x") || offsetStr.starts_with("0X"))
140 offsetStr = offsetStr.drop_front(2);
141
142 uint64_t offsetVal;
143 if (offsetStr.getAsInteger(16, offsetVal)) {
144 llvm::errs() << "Warning: Failed to parse offset '" << *offset
145 << "' for register " << regInfo.name << "\n";
146 } else {
147 regInfo.offset = static_cast<uint32_t>(offsetVal);
148 }
149 }
150 if (auto width = regObj->getInteger("width"))
151 regInfo.width = static_cast<uint32_t>(*width);
152 if (auto type = regObj->getString("type"))
153 regInfo.type = type->str();
154 if (auto reset = regObj->getString("reset"))
155 regInfo.reset = reset->str();
156 if (auto desc = regObj->getString("description"))
157 regInfo.description = desc->str();
158
159 // Parse bit fields
160 if (auto *fields = regObj->getArray("bit_fields")) {
161 for (const auto &fieldVal : *fields) {
162 auto *fieldObj = fieldVal.getAsObject();
163 if (!fieldObj)
164 continue;
165
166 BitFieldInfo fieldInfo;
167 if (auto name = fieldObj->getString("name"))
168 fieldInfo.name = name->str();
169 if (auto *bitRange = fieldObj->getArray("bit_range")) {
170 if (bitRange->size() == 2) {
171 if (auto start = (*bitRange)[0].getAsInteger())
172 fieldInfo.bit_start = static_cast<uint32_t>(*start);
173 if (auto end = (*bitRange)[1].getAsInteger())
174 fieldInfo.bit_end = static_cast<uint32_t>(*end);
175 }
176 }
177 if (auto type = fieldObj->getString("type"))
178 fieldInfo.type = type->str();
179 if (auto reset = fieldObj->getString("reset"))
180 fieldInfo.reset = reset->str();
181 if (auto desc = fieldObj->getString("description"))
182 fieldInfo.description = desc->str();
183
184 regInfo.bit_fields.push_back(fieldInfo);
185 }
186 }
187
188 // Store with module::name as key for uniqueness (lowercase for
189 // case-insensitive lookup)
190 std::string key = moduleName.lower() + "::" + regInfo.name;
191 llvm::transform(key, key.begin(), ::tolower);
192 registers_[key] = regInfo;
193 }
194 }
195
196 // Load event database
197 auto eventBuf = MemoryBuffer::getFile(eventPath);
198 if (!eventBuf) {
199 llvm::errs() << "Failed to load event database: " << eventPath << "\n";
200 return false;
201 }
202
203 auto eventJSON = json::parse(eventBuf.get()->getBuffer());
204 if (!eventJSON) {
205 llvm::errs() << "Failed to parse event JSON\n";
206 return false;
207 }
208
209 // Parse event database for aie2
210 auto *eventRoot = eventJSON->getAsObject();
211 if (!eventRoot)
212 return false;
213
214 auto *aie2 = eventRoot->getObject("aie2");
215 if (!aie2) {
216 llvm::errs() << "Failed to find 'aie2' architecture in event database\n";
217 return false;
218 }
219
220 auto *eventModules = aie2->getObject("modules");
221 if (!eventModules)
222 return false;
223
224 // Iterate through modules (core, memory, pl, mem_tile)
225 for (const auto &modulePair : *eventModules) {
226 StringRef moduleName = modulePair.first;
227 auto *events = modulePair.second.getAsArray();
228 if (!events)
229 continue;
230
231 // Parse each event
232 for (const auto &eventVal : *events) {
233 auto *eventObj = eventVal.getAsObject();
234 if (!eventObj)
235 continue;
236
237 EventInfo eventInfo;
238 eventInfo.module = moduleName.str();
239
240 if (auto name = eventObj->getString("name"))
241 eventInfo.name = name->str();
242 if (auto number = eventObj->getInteger("number"))
243 eventInfo.number = static_cast<uint32_t>(*number);
244
245 // Store with module::name as key (lowercase for case-insensitive lookup)
246 std::string key = moduleName.str() + "::" + eventInfo.name;
247 llvm::transform(key, key.begin(), ::tolower);
248 events_[key] = eventInfo;
249 }
250 }
251
252 return true;
253}
254
256 StringRef module) const {
257 std::string key = module.str() + "::" + name.str();
258 llvm::transform(key, key.begin(), ::tolower);
259 auto it = registers_.find(key);
260 return it != registers_.end() ? &it->second : nullptr;
261}
262
263void RegisterDatabase::buildOffsetIndex() {
264 registersByOffset_.clear();
265 for (const auto &entry : registers_) {
266 const RegisterInfo &info = entry.second;
267 std::string moduleKey = info.module;
268 llvm::transform(moduleKey, moduleKey.begin(), ::tolower);
269 registersByOffset_[moduleKey][info.offset] = &info;
270 }
271}
272
273const RegisterInfo *
275 StringRef module) const {
276 std::string moduleKey = module.lower();
277 auto modIt = registersByOffset_.find(moduleKey);
278 if (modIt == registersByOffset_.end())
279 return nullptr;
280 auto offIt = modIt->second.find(offset);
281 if (offIt == modIt->second.end())
282 return nullptr;
283 return offIt->second;
284}
285
286std::optional<uint32_t> RegisterDatabase::lookupEvent(StringRef name,
287 StringRef module) const {
288 std::string key = module.str() + "::" + name.str();
289 llvm::transform(key, key.begin(), ::tolower);
290 auto it = events_.find(key);
291 if (it != events_.end()) {
292 return it->second.number;
293 }
294 return std::nullopt;
295}
296
297std::optional<uint32_t>
299 uint32_t value) const {
300 // Validate value fits in field width
301 uint32_t width = field.getWidth();
302 if (width == 0)
303 return std::nullopt;
304
305 uint64_t maxValue = width >= 32 ? std::numeric_limits<uint32_t>::max()
306 : ((1ULL << width) - 1ULL);
307
308 if (value > maxValue)
309 return std::nullopt;
310 if (width < 32)
311 value &= static_cast<uint32_t>(maxValue);
312
313 // Shift to correct bit position
314 uint64_t encoded = (static_cast<uint64_t>(value) << field.bit_start);
315 return static_cast<uint32_t>(encoded);
316}
std::optional< uint32_t > encodeFieldValue(const BitFieldInfo &field, uint32_t value) const
Encode a value for a specific bitfield.
static std::unique_ptr< RegisterDatabase > loadAIE2()
Load database for AIE2 architecture.
const RegisterInfo * lookupRegister(llvm::StringRef name, llvm::StringRef module) const
Lookup register by name and module.
std::optional< uint32_t > lookupEvent(llvm::StringRef name, llvm::StringRef module) const
Lookup event by name and module.
const RegisterInfo * lookupRegisterByOffset(uint32_t offset, llvm::StringRef module) const
Lookup register by tile-relative offset and module name.
Bit field information for a register.
const BitFieldInfo * getField(llvm::StringRef fieldName) const
std::vector< BitFieldInfo > bit_fields