MLIR-AIE
AIETargetXAIEV2.cpp
Go to the documentation of this file.
1//===- AIETargetXAIEV2.cpp --------------------------------------*- C++ -*-===//
2//
3// This file is licensed 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// (c) Copyright 2021 Xilinx Inc.
8// (c) Copyright 2021-2023, Advanced Micro Devices, Inc.
9//
10//===----------------------------------------------------------------------===//
12
16
17#include "mlir/IR/Attributes.h"
18#include "mlir/IR/IRMapping.h"
19#include "mlir/Pass/Pass.h"
20#include "mlir/Tools/mlir-translate/MlirTranslateMain.h"
21
22#include "llvm/ADT/StringExtras.h"
23#include "llvm/IR/Module.h"
24
25using namespace mlir;
26using namespace xilinx;
27using namespace xilinx::AIE;
28using namespace xilinx::AIEX;
29
30// This string is output at the top of the lowered C++ code.
31static const char *xaie_cpp_file_header = R"code(
32// This file was auto-generated by aiecc.py --aie-generate-xaie.
33
34#ifndef MLIR_AIE_QUIET
35#define __mlir_aie_verbose(x) x
36#else
37#define __mlir_aie_verbose(x)
38#endif
39
40// The following is a wrapper for the common "if(call() != 0) return 1" pattern.
41// Use this only in functions that return int. If the call this wrapper is used
42// on does not succeed, the expanded code will exit out of the function
43// containing this macro with an error code.
44#define __mlir_aie_try(x) do { \
45 AieRC ret = (x); \
46 if(ret != XAIE_OK) { \
47 return x; \
48 } \
49} while(0)
50
51static XAie_DmaDimDesc *__mlir_aie_alloc_dim_desc(size_t ndims) {
52 XAie_DmaDimDesc *ret = NULL;
53 ret = (XAie_DmaDimDesc *)calloc(sizeof(XAie_DmaDimDesc), ndims);
54 if(NULL == ret) {
55 __mlir_aie_verbose(fprintf(stderr, "Allocating DmaDimDesc failed.\n"));
56 }
57 return ret;
58}
59
60)code";
61
62static std::string tileLockStr(StringRef id, StringRef val) {
63 std::string str;
64 llvm::raw_string_ostream rss(str);
65 // rss << "XAie_Lock(" << id << "," << val << ")";
66 rss << "XAie_LockInit(" << id << "," << val << ")";
67 return str;
68}
69
70// Translate mlir-aie WireBundle enum to string of aie-rt StrmSwPortType enum
71static std::string wireBundleToPortType(WireBundle bundle) {
72 switch (bundle) {
73 case WireBundle::PLIO:
74 return "PL";
75 case WireBundle::TileControl:
76 return "CTRL";
77 default:
78 return stringifyWireBundle(bundle).upper();
79 }
80}
81
82// FIXME: code bloat. this shouldn't really be a template, but need
83// a proper DMA-like interface
84// blockMap: A map that gives a unique bd ID assignment for every block.
85template <typename OpType>
86static mlir::LogicalResult generateDMAConfig(OpType memOp, raw_ostream &output,
87 const AIETargetModel &targetModel,
88 DenseMap<Block *, int> blockMap) {
89 StringRef enable = "XAIE_ENABLE";
90 StringRef disable = "XAIE_DISABLE";
91 StringRef deviceInstRef = "ctx->XAieDevInst";
92
93 int col = memOp.colIndex();
94 int row = memOp.rowIndex();
95
96 // Get the region's entry block, then start traversing through the chain of
97 // blocks.
98 llvm::SetVector<Block *> blockVector =
99 getOrderedChainOfBlocks(&memOp.getBody());
100
101 for (auto block : blockVector) {
102 bool foundBdPacket = false;
103 int packetType = 0;
104 int packetID = 0;
105 bool foundBd = false;
106 int lenA = 0;
107 int offsetA = 0;
108 int BaseAddrA = 0;
109 int elementWidthInBytes = 0;
110 int ndims = 0;
111 ArrayRef<BDDimLayoutAttr> dims;
112 // StringRef FifoMode = disable; // FIXME: when to enable FIFO mode?
113 for (auto op : block->getOps<DMABDOp>()) {
114 foundBd = true;
115 if (!targetModel.isShimNOCTile(col, row)) {
116 assert(op.getBufferOp().getAddress() &&
117 "buffer must have address assigned");
118 BaseAddrA = op.getBufferOp().getAddress().value();
119 int bufferCol = op.getBufferOp().getTileOp().colIndex();
120 int bufferRow = op.getBufferOp().getTileOp().rowIndex();
121
122 // Memtile DMAs can access neighboring tiles.
123 if (targetModel.isMemTile(col, row)) {
124 auto addrOffset = targetModel.getMemLocalBaseAddress(
125 col, row, bufferCol, bufferRow);
126 if (addrOffset)
127 BaseAddrA += addrOffset.value();
128 }
129 }
130
131 lenA = op.getLenInBytes();
132 offsetA = op.getOffsetInBytes();
133 elementWidthInBytes = op.getBufferElementTypeWidthInBytes();
134 if (op.getDimensions()) {
135 dims = *op.getDimensions();
136 ndims = dims.size();
137 }
138 }
139
140 if (0 != ndims)
142 return memOp.emitOpError("DMA contains at least one multi-dimensional "
143 "buffer descriptor. This is currently only "
144 "supported for AIE-ML and later devices.");
145
146 int acqValue = 0, relValue = 0;
147 bool hasAcq = false, hasRel = false;
148 int acqLockID = 0, relLockID = 0;
149 for (auto op : block->getOps<UseLockOp>()) {
150 LockOp lock = cast<LockOp>(op.getLock().getDefiningOp());
151 int lockCol = lock.colIndex();
152 int lockRow = lock.rowIndex();
153 int lockID = lock.getLockIDValue();
154 // Memtile DMAs can access neighboring tiles.
155 if (targetModel.isMemTile(col, row)) {
156 auto lockOffset =
157 targetModel.getLockLocalBaseIndex(col, row, lockCol, lockRow);
158 if (lockOffset)
159 lockID += lockOffset.value();
160 }
161
162 if (op.acquire() || op.acquireGE()) {
163 hasAcq = true;
164 acqLockID = lockID;
165 acqValue = op.getLockValue();
166 if (op.acquireGE())
167 acqValue = -acqValue;
168 } else if (op.release()) {
169 hasRel = true;
170 relLockID = lockID;
171 relValue = op.getLockValue();
172 } else {
173 // unreachable for current targets
174 return op.emitOpError("unsupported lock action");
175 }
176 }
177
178 for (auto op : block->getOps<DMABDPACKETOp>()) {
179 foundBdPacket = true;
180 packetType = op.getPacketType();
181 packetID = op.getPacketID();
182 }
183
184 int bdNum = blockMap[block];
185 if (foundBd) {
186 // TODO For now, we are going to name each dma desc with loc and bd
187 // which we assume is unique. This is strictly not enforced but in
188 // practice, this is true
189 output << "XAie_DmaDesc " << tileDMAInstStr(col, row, bdNum) << ";\n";
190 output << "__mlir_aie_try(XAie_DmaDescInit(" << deviceInstRef << ", "
191 << tileDMAInstRefStr(col, row, bdNum) << ", "
192 << tileLocStr(col, row) << "));\n";
193 if (hasAcq || hasRel) {
194 output << "__mlir_aie_try(XAie_DmaSetLock("
195 << tileDMAInstRefStr(col, row, bdNum) << ", "
196 << "XAie_LockInit(" << acqLockID << "," << acqValue << "),"
197 << "XAie_LockInit(" << relLockID << "," << relValue << ")));\n";
198 if (!hasAcq)
199 output << tileDMAInstStr(col, row, bdNum)
200 << ".LockDesc.LockAcqEn = " << disable << ";\n";
201 if (!hasRel)
202 output << tileDMAInstStr(col, row, bdNum)
203 << ".LockDesc.LockRelEn = " << disable << ";\n";
204 }
205
206 if (0 == ndims) {
207 if (targetModel.isShimNOCTile(col, row)) {
208 output << "__mlir_aie_try(XAie_DmaSetAddrLen("
209 << tileDMAInstRefStr(col, row, bdNum) << ", /* addrA */ "
210 << "mlir_aie_external_get_addr_myBuffer_" << col << row << "_"
211 << bdNum << "(), "
212 << " /* len */ " << lenA << "));\n";
213 output << "__mlir_aie_try(XAie_DmaSetAxi("
214 << tileDMAInstRefStr(col, row, bdNum) << ", "
215 << "/* smid */ 0, "
216 << "/* burstlen */ 4, "
217 << "/* QoS */ 0, "
218 << "/* Cache */ 0, "
219 << "/* Secure */ " << enable << "));\n";
220 } else {
221 if ((BaseAddrA + offsetA) % 4)
222 return memOp.emitError("bd address must be 4B (32b) aligned");
223 output << "__mlir_aie_try(XAie_DmaSetAddrLen("
224 << tileDMAInstRefStr(col, row, bdNum) << ", /* addrA */ "
225 << "0x" << llvm::utohexstr(BaseAddrA + offsetA) << ", "
226 << " /* len */ " << lenA << "));\n";
227 }
228 } else
229 generateXAieDmaSetMultiDimAddr(output, ndims, dims, col, row, bdNum,
230 BaseAddrA, offsetA, lenA,
231 elementWidthInBytes, "1");
232
233 if (block->getNumSuccessors() > 0) {
234 Block *nextBlock = block->getSuccessors()[0]; // should have only one
235 // successor block
236
237 int enableNextBd = 1;
238 if (!nextBlock->getOps<EndOp>().empty())
239 enableNextBd = 0;
240
241 int nextBdNum = blockMap[nextBlock];
242 output << "__mlir_aie_try(XAie_DmaSetNextBd("
243 << tileDMAInstRefStr(col, row, bdNum) << ", "
244 << " /* nextbd */ " << nextBdNum << ", "
245 << " /* enableNextBd */ " << enableNextBd << "));\n";
246 }
247
248 if (foundBdPacket) {
249 output << "__mlir_aie_try(XAie_DmaSetPkt("
250 << tileDMAInstRefStr(col, row, bdNum) << ", "
251 << packetStr(packetID, packetType) << "));\n";
252 }
253 output << "__mlir_aie_try(XAie_DmaEnableBd("
254 << tileDMAInstRefStr(col, row, bdNum) << "));\n";
255 output << "__mlir_aie_try(XAie_DmaWriteBd(" << deviceInstRef << ", "
256 << tileDMAInstRefStr(col, row, bdNum) << ", "
257 << tileLocStr(col, row) << ", "
258 << " /* bd */ " << bdNum << "));\n";
259 }
260 }
261
262 for (auto block : blockVector) {
263 for (auto op : block->getOps<DMAStartOp>()) {
264 int bdNum = blockMap[op.getDest()];
265 StringRef dmaDir = stringifyDMAChannelDir(op.getChannelDir());
266 int chNum = op.getChannelIndex();
267 const auto &target_model = xilinx::AIE::getTargetModel(op);
268 if (target_model.getTargetArch() == AIEArch::AIE1) {
269 output << "__mlir_aie_try(XAie_DmaChannelPushBdToQueue("
270 << deviceInstRef << ", " << tileLocStr(col, row) << ", "
271 << "/* ChNum */" << chNum
272 << ", "
273 // TODO hack until physical dialect changes
274 << "/* dmaDir */ DMA_" << dmaDir << ", "
275 << "/* BdNum */" << bdNum << "));\n";
276 } else {
277 // in english repeat_count==0 means "do it once" and don't repeat but
278 // libxaie treats repeat_count=1 as do it once.
279 int repeatCount = op.getRepeatCount() + 1;
280 output << "__mlir_aie_try(XAie_DmaChannelSetStartQueue("
281 << deviceInstRef << ", " << tileLocStr(col, row) << ", "
282 << "/* ChNum */" << chNum
283 << ", "
284 // TODO hack until physical dialect changes
285 << "/* dmaDir */ DMA_" << dmaDir << ", "
286 << "/* BdNum */" << bdNum << ", "
287 << "/* Repeat */ " << repeatCount << ", "
288 << "/* EnToken */ "
289 << "XAIE_DISABLE"
290 << "));\n";
291 }
292 output << "__mlir_aie_try(XAie_DmaChannelEnable(" << deviceInstRef << ", "
293 << tileLocStr(col, row) << ", "
294 << "/* ChNum */ " << chNum
295 << ", "
296 // TODO hack until physical dialect changes
297 << "/* dmaDir */ DMA_" << dmaDir << "));\n";
298 }
299 }
300 return success();
301}
302
303mlir::LogicalResult
304xilinx::AIE::AIETranslateToXAIEV2(ModuleOp module, raw_ostream &output,
305 llvm::StringRef deviceName) {
306 StringRef ctx_p = "aie_libxaie_ctx_t* ctx";
307 StringRef deviceInstRef = "ctx->XAieDevInst";
308
309 DenseMap<TileID, Operation *> tiles;
310 DenseMap<Operation *, SmallVector<BufferOp, 4>> buffers;
311
312 DeviceOp targetOp = AIE::DeviceOp::getForSymbolInModule(module, deviceName);
313 if (!targetOp)
314 return module.emitOpError("expected AIE.device operation at toplevel");
315 const auto &targetModel = targetOp.getTargetModel();
316
317 collectTiles(targetOp, tiles);
318 collectBuffers(targetOp, buffers);
319
320 //---------------------------------------------------------------------------
321 // mlir_aie_init_libxaie
322 //---------------------------------------------------------------------------
323 output << xaie_cpp_file_header;
324 output << "aie_libxaie_ctx_t* mlir_aie_init_libxaie() {\n";
325 output << " aie_libxaie_ctx_t *ctx = new aie_libxaie_ctx_t;\n";
326 output << " if (!ctx)\n";
327 output << " return 0;\n";
328 output << " ctx->XAieConfig = new XAie_Config;\n";
329 output << " if (!ctx->XAieConfig)\n";
330 output << " return 0;\n";
331 output << " ctx->XAieDevInst = new XAie_DevInst;\n";
332 output << " if (!ctx->XAieDevInst)\n";
333 output << " return 0;\n";
334 auto arch = targetModel.getTargetArch();
335 std::string AIE1_device("XAIE_DEV_GEN_AIE");
336 std::string AIE2_device("XAIE_DEV_GEN_AIEML");
337 std::string AIE2p_device("XAIE_DEV_GEN_AIE2P");
338 std::string device;
339 switch (arch) {
340 case AIEArch::AIE1:
341 device = AIE1_device;
342 break;
343 case AIEArch::AIE2:
344 device = AIE2_device;
345 break;
346 case AIEArch::AIE2p:
347 device = AIE2p_device;
348 break;
349 default:
350 return module.emitOpError("Unsupported aie.device");
351 }
352 output << " ctx->XAieConfig->AieGen = " << device << ";\n";
353 output << " ctx->XAieConfig->BaseAddr = 0x20000000000;\n";
354 output << " ctx->XAieConfig->ColShift = " << targetModel.getColumnShift()
355 << ";\n";
356 output << " ctx->XAieConfig->RowShift = " << targetModel.getRowShift()
357 << ";\n";
358 output << " ctx->XAieConfig->NumRows = " << targetModel.rows() << ";\n";
359 output << " ctx->XAieConfig->NumCols = " << targetModel.columns() << ";\n";
360 output << " ctx->XAieConfig->ShimRowNum = 0;\n";
361 output << " ctx->XAieConfig->MemTileRowStart = 1;\n";
362 output << " ctx->XAieConfig->MemTileNumRows = "
363 << targetModel.getNumMemTileRows() << ";\n";
364 output << " // ctx->XAieConfig->ReservedRowStart = "
365 "XAIE_RES_TILE_ROW_START;\n";
366 output
367 << " // ctx->XAieConfig->ReservedNumRows = XAIE_RES_TILE_NUM_ROWS;\n";
368 output << " ctx->XAieConfig->AieTileRowStart = "
369 << (1 + targetModel.getNumMemTileRows()) << ";\n";
370 output << " ctx->XAieConfig->AieTileNumRows = "
371 << (targetModel.rows() - 1 - targetModel.getNumMemTileRows()) << ";\n";
372 output << " memset(ctx->XAieDevInst, 0, sizeof(XAie_DevInst));\n";
373 output << " return ctx;\n";
374 output << "}\n";
375 output << "\n";
376
377 //---------------------------------------------------------------------------
378 // mlir_aie_configure_cores
379 //---------------------------------------------------------------------------
380 output << "int mlir_aie_configure_cores(" << ctx_p << ") {\n";
381 // Reset each core. Load the corresponding ELF file, if necessary.
382 for (auto tileOp : targetOp.getOps<TileOp>()) {
383 int col = tileOp.colIndex();
384 int row = tileOp.rowIndex();
385 if (tileOp.isShimTile() || tileOp.isMemTile()) {
386 // Resets no needed with V2 kernel driver
387 } else {
388 // Resets no needed with V2 kernel driver
389 output << "__mlir_aie_try(XAie_CoreReset(" << deviceInstRef << ", "
390 << tileLocStr(col, row) << "));\n";
391 output << "__mlir_aie_try(XAie_CoreDisable(" << deviceInstRef << ", "
392 << tileLocStr(col, row) << "));\n";
393 // Release locks
394 int numLocks = targetModel.getNumLocks(col, row);
395 output << "for (int l = 0; l < " << numLocks << "; ++l)\n"
396 << " __mlir_aie_try(XAie_LockRelease(" << deviceInstRef << ", "
397 << tileLocStr(col, row) << ", XAie_LockInit(l, 0x0), 0));\n";
398 if (auto coreOp = tileOp.getCoreOp()) {
399 if (coreOp.isEmpty() && coreOp.getElfFile() == std::nullopt) {
400 // This core has no MLIR code and references no ELF file -- it is
401 // completely empty, so don't generate any code for it.
402 continue;
403 }
404 std::string fileName;
405 if (auto fileAttr = coreOp.getElfFile()) {
406 fileName = fileAttr.value().str();
407 } else {
408 return coreOp.emitOpError()
409 << "Expected lowered ELF file to be given as attribute "
410 "`elf_file` for this core. Compile cores first.";
411 }
412 output << "{\n"
413 << "AieRC RC = XAie_LoadElf(" << deviceInstRef << ", "
414 << tileLocStr(col, row) << ", "
415 << "(const char*)\"" << fileName << "\",0);\n";
416 output << "if (RC != XAIE_OK)\n"
417 << " __mlir_aie_verbose(fprintf(stderr, \"Failed to load elf "
418 "for Core[%d,%d], ret is %d\\n\", "
419 << std::to_string(col) << ", " << std::to_string(row)
420 << ", RC));\n"
421 << "assert(RC == XAIE_OK);\n"
422 << "}\n";
423 }
424 }
425 }
426 output << "return XAIE_OK;\n";
427 output << "} // mlir_aie_configure_cores\n\n";
428
429 //---------------------------------------------------------------------------
430 // mlir_aie_start_cores
431 //---------------------------------------------------------------------------
432 output << "int mlir_aie_start_cores(" << ctx_p << ") {\n";
433 // Start execution of all the cores.
434 for (auto tileOp : targetOp.getOps<TileOp>()) {
435 int col = tileOp.colIndex();
436 int row = tileOp.rowIndex();
437 if (!tileOp.isShimTile() && !tileOp.isMemTile()) {
438 output << "__mlir_aie_try(XAie_CoreUnreset(" << deviceInstRef << ", "
439 << tileLocStr(col, row) << "));\n";
440 output << "__mlir_aie_try(XAie_CoreEnable(" << deviceInstRef << ", "
441 << tileLocStr(col, row) << "));\n";
442 }
443 }
444 output << "return XAIE_OK;\n";
445 output << "} // mlir_aie_start_cores\n\n";
446
447 //---------------------------------------------------------------------------
448 // mlir_aie_configure_dmas
449 //---------------------------------------------------------------------------
450 output << "int mlir_aie_configure_dmas(" << ctx_p << ") {\n";
451
452 for (auto memOp : targetOp.getOps<MemOp>()) {
453 DenseMap<Block *, int> blockMap;
454
455 // Assign each block a BD number
456 int bdNum = 0;
457 for (auto &block : memOp.getBody()) {
458 if (!block.getOps<DMABDOp>().empty()) {
459 blockMap[&block] = bdNum;
460 bdNum++;
461 }
462 }
463 auto result = generateDMAConfig(memOp, output, targetModel, blockMap);
464 if (result.failed())
465 return result;
466 }
467 for (auto memOp : targetOp.getOps<MemTileDMAOp>()) {
468 DenseMap<Block *, int> blockMap;
469 // Memtiles have restrictions on which channels can access which BDs
470 DenseMap<Block *, int> channelMap;
471
472 for (auto &block : memOp.getBody()) {
473 for (auto op : block.getOps<DMAStartOp>()) {
474 int chNum = op.getChannelIndex();
475 channelMap[&block] = chNum;
476 auto dest = op.getDest();
477 while (dest) {
478 channelMap[dest] = chNum;
479 if (dest->getSuccessors().size() < 1)
480 break;
481 dest = dest->getSuccessors()[0];
482 if (channelMap.count(dest))
483 break;
484 }
485 }
486 }
487
488 // Assign each block a BD number
489 int evenBdNum = 0;
490 int oddBdNum = 24;
491 for (auto &block : memOp.getBody()) {
492 if (block.getOps<DMABDOp>().empty())
493 continue;
494 assert(channelMap.count(&block));
495 if (channelMap[&block] & 1)
496 blockMap[&block] = oddBdNum++;
497 else
498 blockMap[&block] = evenBdNum++;
499 }
500 auto result = generateDMAConfig(memOp, output, targetModel, blockMap);
501 if (result.failed())
502 return result;
503 }
504
505 output << "return XAIE_OK;\n";
506 output << "} // mlir_aie_configure_dmas\n\n";
507
508 for (auto op : targetOp.getOps<ExternalBufferOp>()) {
509 if (op.hasName()) {
510 output << "static u64 _mlir_aie_external_" << op.name().getValue()
511 << ";\n";
512 output << "static bool _mlir_aie_external_set_" << op.name().getValue()
513 << " = false;\n";
514
515 output << "void mlir_aie_external_set_addr_" << op.name().getValue()
516 << "(" << ctx_p << ", u64 VA) {\n"
517 << " u64 device_address = mlir_aie_get_device_address(ctx, (void "
518 "*)VA);\n"
519 << " _mlir_aie_external_set_" << op.name().getValue()
520 << " = true;\n"
521 << " _mlir_aie_external_" << op.name().getValue()
522 << " = device_address;\n"
523 << "}\n";
524 }
525 }
526
527 // ShimDMA Config
528 // int index = 0;
529 for (auto op : targetOp.getOps<ShimDMAOp>()) {
530 int col = op.colIndex();
531 int row = op.rowIndex();
532
533 DenseMap<Block *, int> blockMap;
534 {
535 // Assign each block a BD number
536 int bdNum = 0;
537 for (auto &block : op.getBody()) {
538 if (!block.getOps<DMABDOp>().empty()) {
539 blockMap[&block] = bdNum;
540 uint64_t offset = 0;
541 for (auto op : block.getOps<DMABDOp>()) {
542 offset = op.getOffsetInBytes();
543 auto buffer =
544 cast<ExternalBufferOp>(op.getBuffer().getDefiningOp());
545
546 output << "u64 mlir_aie_external_get_addr_myBuffer_" << col << row
547 << "_" << bdNum << "(void) {\n"
548 << " assert(_mlir_aie_external_set_"
549 << buffer.name().getValue() << ");\n"
550 << " return _mlir_aie_external_"
551 << buffer.name().getValue() << " + "
552 << llvm::utohexstr(offset) << ";\n"
553 << "}\n";
554 }
555
556 bdNum++;
557 }
558 }
559 }
560
561 output << "int mlir_aie_configure_shimdma_" << col << row << "(" << ctx_p
562 << ") {\n";
563 auto result = generateDMAConfig(op, output, targetModel, blockMap);
564 if (result.failed())
565 return result;
566 output << "return XAIE_OK;\n";
567 output << "} // mlir_aie_configure_shimdma\n\n";
568 }
569
570 //---------------------------------------------------------------------------
571 // mlir_aie_initialize_locks
572 //---------------------------------------------------------------------------
573 output << "int mlir_aie_initialize_locks(" << ctx_p << ") {\n";
574 // Lock configuration
575 targetOp.walk<WalkOrder::PreOrder>([&](LockOp lock) {
576 TileOp tile = lock.getTileOp();
577 int col = tile.colIndex();
578 int row = tile.rowIndex();
579 int lockID = lock.getLockIDValue();
580 auto init = lock.getInit();
581 if (init)
582 output << "__mlir_aie_try(XAie_LockSetValue(" << deviceInstRef << ", "
583 << tileLocStr(col, row) << ", "
584 << "XAie_LockInit(" << lockID << ", " << *init << ")));\n";
585 });
586 output << "return XAIE_OK;\n";
587 output << "} // mlir_aie_initialize_locks\n";
588
589 //---------------------------------------------------------------------------
590 // mlir_aie_configure_switchboxes
591 //---------------------------------------------------------------------------
592 output << "int mlir_aie_configure_switchboxes(" << ctx_p << ") {\n";
593 output << " int x, y;\n";
594
595 // StreamSwitch (switchbox) configuration
596 for (auto switchboxOp : targetOp.getOps<SwitchboxOp>()) {
597 Region &r = switchboxOp.getConnections();
598 Block &b = r.front();
599 bool isEmpty = b.getOps<ConnectOp>().empty() &&
600 b.getOps<MasterSetOp>().empty() &&
601 b.getOps<PacketRulesOp>().empty();
602 bool isParam = false;
603
604 if (isa<TileOp>(switchboxOp.getTile().getDefiningOp())) {
605 int col = switchboxOp.colIndex();
606 int row = switchboxOp.rowIndex();
607 if (!isEmpty) {
608 output << "// Core Stream Switch column " << col << " row " << row
609 << "\n";
610 output << "x = " << col << ";\n";
611 output << "y = " << row << ";\n";
612 }
613 } else if (auto sel =
614 dyn_cast<SelectOp>(switchboxOp.getTile().getDefiningOp())) {
615 // parameterize streamswitch's configuration
616 isParam = true;
617 HerdOp sourceHerd = cast<HerdOp>(sel.getStartHerd().getDefiningOp());
618 std::string sourceHerdName(sourceHerd.name().getValue());
619
620 IterOp iterX = cast<IterOp>(sel.getIterX().getDefiningOp());
621 IterOp iterY = cast<IterOp>(sel.getIterY().getDefiningOp());
622 int startXValue = iterX.getStartValue();
623 int endXValue = iterX.getEndValue();
624 int strideXValue = iterX.getStrideValue();
625 int startYValue = iterY.getStartValue();
626 int endYValue = iterY.getEndValue();
627 int strideYValue = iterY.getStrideValue();
628
629 std::string startX(sourceHerdName + "_X + " +
630 std::to_string(startXValue));
631 std::string endX(sourceHerdName + "_X + " + std::to_string(endXValue));
632 std::string startY(sourceHerdName + "_Y + " +
633 std::to_string(startYValue));
634 std::string endY(sourceHerdName + "_Y + " + std::to_string(endYValue));
635
636 output << "for (x = " << startX << "; x < " << endX
637 << "; x += " << strideXValue << ") {\n";
638 output << "for (y = " << startY << "; y < " << endY
639 << "; y += " << strideYValue << ") {\n";
640 }
641
642 for (auto connectOp : b.getOps<ConnectOp>())
643 output << "__mlir_aie_try(XAie_StrmConnCctEnable(" << deviceInstRef
644 << ", " << tileLocStr("x", "y") << ", "
645 << wireBundleToPortType(connectOp.getSourceBundle()) << ", "
646 << connectOp.sourceIndex() << ", "
647 << wireBundleToPortType(connectOp.getDestBundle()) << ", "
648 << connectOp.destIndex() << "));\n";
649
650 for (auto connectOp : b.getOps<MasterSetOp>()) {
651 int mask = 0;
652 int arbiter = -1;
653 for (auto val : connectOp.getAmsels()) {
654 AMSelOp amsel = cast<AMSelOp>(val.getDefiningOp());
655 arbiter = amsel.arbiterIndex();
656 int msel = amsel.getMselValue();
657 mask |= (1 << msel);
658 }
659 bool isdma = (connectOp.getDestBundle() == WireBundle::DMA);
660
661 output << "__mlir_aie_try(XAie_StrmPktSwMstrPortEnable(" << deviceInstRef
662 << ", " << tileLocStr("x", "y") << ", "
663 << wireBundleToPortType(connectOp.getDestBundle()) << ", "
664 << connectOp.destIndex() << ", "
665 << "/* drop_header */ "
666 << (isdma ? "XAIE_SS_PKT_DROP_HEADER"
667 : "XAIE_SS_PKT_DONOT_DROP_HEADER")
668 << ", "
669 << "/* arbiter */ " << arbiter << ", "
670 << "/* MSelEn */ "
671 << "0x" << llvm::utohexstr(mask) << "));\n";
672 }
673
674 for (auto connectOp : b.getOps<PacketRulesOp>()) {
675 int slot = 0;
676 Block &block = connectOp.getRules().front();
677 for (auto slotOp : block.getOps<PacketRuleOp>()) {
678 AMSelOp amselOp = cast<AMSelOp>(slotOp.getAmsel().getDefiningOp());
679 int arbiter = amselOp.arbiterIndex();
680 int msel = amselOp.getMselValue();
681 output << "__mlir_aie_try(XAie_StrmPktSwSlavePortEnable("
682 << deviceInstRef << ", " << tileLocStr("x", "y") << ", "
683 << wireBundleToPortType(connectOp.getSourceBundle()) << ", "
684 << connectOp.sourceIndex() << "));\n";
685
686 // TODO Need to better define packet id,type used here
687 output << "__mlir_aie_try(XAie_StrmPktSwSlaveSlotEnable("
688 << deviceInstRef << ", " << tileLocStr("x", "y") << ", "
689 << wireBundleToPortType(connectOp.getSourceBundle()) << ", "
690 << connectOp.sourceIndex() << ", "
691 << "/* slot */ " << slot << ", "
692 << "/* packet */ " << packetStr(slotOp.valueInt(), /*type*/ 0)
693 << ", "
694 << "/* mask */ "
695 << "0x" << llvm::utohexstr(slotOp.maskInt()) << ", "
696 << "/* msel */ " << msel << ", "
697 << "/* arbiter */ " << arbiter << "));\n";
698 slot++;
699 }
700 }
701
702 if (isParam) {
703 output << "}\n";
704 output << "}\n";
705 }
706 }
707 for (auto op : targetOp.getOps<ShimMuxOp>()) {
708 Region &r = op.getConnections();
709 Block &b = r.front();
710 bool isEmpty = b.getOps<ConnectOp>().empty();
711
712 if (isa<TileOp>(op.getTile().getDefiningOp())) {
713 int col = op.colIndex();
714 int row = op.rowIndex();
715 if (!isEmpty) {
716 output << "// ShimMux column " << col << " row " << row << "\n";
717 output << "// NOTE ShimMux always connects from the south as "
718 << "directions are defined relative to the tile stream "
719 << "switch\n";
720 output << "x = " << col << ";\n";
721 output << "y = " << row << ";\n";
722 }
723 }
724
725 for (auto connectOp : b.getOps<ConnectOp>()) {
726
727 if (connectOp.getSourceBundle() == WireBundle::DMA ||
728 connectOp.getDestBundle() == WireBundle::DMA) {
729 if (connectOp.getSourceBundle() == WireBundle::North)
730 // demux!
731 output << "__mlir_aie_try(XAie_EnableAieToShimDmaStrmPort("
732 << deviceInstRef << ", " << tileLocStr("x", "y") << ", "
733 << connectOp.sourceIndex() << "));\n";
734 else if (connectOp.getDestBundle() == WireBundle::North)
735 // mux
736 output << "__mlir_aie_try(XAie_EnableShimDmaToAieStrmPort("
737 << deviceInstRef << ", " << tileLocStr("x", "y") << ", "
738 << connectOp.destIndex() << "));\n";
739 }
740
741 else if (connectOp.getSourceBundle() == WireBundle::PLIO ||
742 connectOp.getDestBundle() == WireBundle::PLIO) {
743 if (connectOp.getSourceBundle() == WireBundle::North) {
744 // mux
745 output << "__mlir_aie_try(XAie_AieToPlIntfEnable(" << deviceInstRef
746 << ", " << tileLocStr("x", "y") << ", "
747 << connectOp.destIndex() << ", PLIF_WIDTH_64));\n";
748 } else if (connectOp.getDestBundle() == WireBundle::North) {
749 // mux
750 output << "__mlir_aie_try(XAie_PlToAieIntfEnable(" << deviceInstRef
751 << ", " << tileLocStr("x", "y") << ", "
752 << connectOp.destIndex() << ", PLIF_WIDTH_64));\n";
753 }
754 }
755 }
756 }
757 for (auto switchboxOp : targetOp.getOps<ShimSwitchboxOp>()) {
758 Region &r = switchboxOp.getConnections();
759 Block &b = r.front();
760 bool isEmpty = b.getOps<ConnectOp>().empty();
761 int col = switchboxOp.getCol();
762 if (!isEmpty)
763 output << "// Shim Switch column " << col << "\n";
764 for (auto connectOp : b.getOps<ConnectOp>())
765 output << "__mlir_aie_try(XAie_StrmConnCctEnable(" << deviceInstRef
766 << ", " << tileLocStr(col, 0) << ", "
767 << wireBundleToPortType(connectOp.getSourceBundle()) << ", "
768 << connectOp.sourceIndex() << ", "
769 << wireBundleToPortType(connectOp.getDestBundle()) << ", "
770 << connectOp.destIndex() << "));\n";
771 }
772
773 output << "return XAIE_OK;\n";
774 output << "} // mlir_aie_configure_switchboxes\n\n";
775
776 //---------------------------------------------------------------------------
777 // mlir_aie_configure_cascade
778 //---------------------------------------------------------------------------
779 output << "int mlir_aie_configure_cascade(" << ctx_p << ") {\n";
780 for (auto configOp : targetOp.getOps<ConfigureCascadeOp>()) {
781 TileOp tile = cast<TileOp>(configOp.getTile().getDefiningOp());
782 int col = tile.colIndex();
783 int row = tile.rowIndex();
784 output << "XAie_CoreConfigAccumulatorControl(" << deviceInstRef << ", "
785 << "XAie_TileLoc(" << col << ", " << row << "), "
786 << stringifyCascadeDir(configOp.getInputDir()).upper() << ", "
787 << stringifyCascadeDir(configOp.getOutputDir()).upper() << ");\n";
788 }
789 output << "return XAIE_OK;\n";
790 output << "} // mlir_aie_configure_cascade\n\n";
791
792 //---------------------------------------------------------------------------
793 // Output Buffer Accessors
794 //---------------------------------------------------------------------------
795 for (auto tile : tiles) {
796 Operation *tileOp = tile.second;
797 TileID coord = cast<TileOp>(tileOp).getTileID();
798 int col = coord.col;
799 int row = coord.row;
800 auto loc = tileLocStr(col, row);
801
802 auto bufferAccessor = [&](BufferOp buf) {
803 // int32_t mlir_aie_read_buffer_a13(int index) {
804 // void mlir_aie_write_buffer_a13(int index, int32_t value) {
805 std::string bufName(buf.name().getValue());
806 Type t = buf.getType();
807 Type et;
808 std::string typestr;
809 if (auto memrefType = llvm::dyn_cast<MemRefType>(t)) {
810 et = memrefType.getElementType();
811 if (et.isInteger(32))
812 typestr = "int32_t";
813 else if (et.isF32())
814 typestr = "float";
815 else {
816 output << "// buffer " << bufName << " with unsupported type " << t
817 << ";\n";
818 return; // Unsupported type
819 }
820
821 } else {
822 output << "// buffer " << bufName << " with unsupported type " << t
823 << ";\n";
824 return; // Unsupported type
825 }
826 assert(buf.getAddress().has_value() && "buffer must have address");
827 output << "const int " << bufName
828 << "_offset = " << buf.getAddress().value() << ";\n";
829 output << typestr << " mlir_aie_read_buffer_" << bufName << "(" << ctx_p
830 << ", int index) {\n";
831 output << "u32 value; auto rc = XAie_DataMemRdWord(" << deviceInstRef
832 << ", " << loc << ", " << bufName
833 << "_offset + (index*4), &value);\n";
834 if (et.isInteger(32))
835 output << " return value;\n";
836 else if (et.isF32()) {
837 output << " union caster { int32_t i; float f; };\n";
838 output << " caster c; c.i = value;\n";
839 output << " return c.f;\n";
840 }
841 output << "}\n";
842 output << "int mlir_aie_write_buffer_" << bufName << "(" << ctx_p
843 << ", int index, " << typestr << " value) {\n";
844 if (et.isInteger(32))
845 output << " int32_t int_value = value;\n";
846 else if (et.isF32()) {
847 output << " union caster { int32_t i; float f; };\n";
848 output << " caster c; c.f = value;\n";
849 output << " int32_t int_value = c.i;\n";
850 }
851 output << "AieRC rc = XAie_DataMemWrWord(" << deviceInstRef << ", "
852 << loc << ", " << bufName << "_offset + (index*4), int_value);\n";
853 output << "return rc;\n";
854 output << "}\n";
855 };
856
857 // if(tiles.count(tile.getValue()))
858 for (auto buf : buffers[tileOp])
859 bufferAccessor(buf);
860 }
861
862 auto lockAccessor = [&](LockOp lock) {
863 int col = lock.colIndex();
864 int row = lock.rowIndex();
865 if (!lock.hasName())
866 return;
867 std::string lockName(lock.name().getValue());
868 output << "int mlir_aie_acquire_" << lockName << "(" << ctx_p
869 << ", int value, int timeout) {\n";
870 output << " const int id = " << lock.getLockIDValue() << ";\n";
871 output << " return XAie_LockAcquire(" << deviceInstRef << ", "
872 << tileLocStr(col, row) << ", " << tileLockStr("id", "value")
873 << ", timeout);\n";
874 output << "}\n";
875 output << "int mlir_aie_release_" << lockName << "(" << ctx_p
876 << ", int value, int timeout) {\n";
877 output << " const int id = " << lock.getLockIDValue() << ";\n";
878 output << " return XAie_LockRelease(" << deviceInstRef << ", "
879 << tileLocStr(col, row) << ", " << tileLockStr("id", "value")
880 << ", timeout);\n";
881 output << "}\n";
882 };
883
884 targetOp.walk<WalkOrder::PreOrder>([&](LockOp lock) { lockAccessor(lock); });
885
886 return success();
887}
std::optional< uint32_t > getMemLocalBaseAddress(int localCol, int localRow, int memCol, int memRow) const
Return the memory base address (or offset) in the local tile when accessing a neighbor's memory or an...
virtual AIEArch getTargetArch() const =0
Return the target architecture.
bool isMemTile(int col, int row) const
Return true if the given tile is a Mem tile.
std::optional< uint32_t > getLockLocalBaseIndex(int localCol, int localRow, int lockCol, int lockRow) const
Return the lock base index (or offset) in the local tile when accessing a neighbor's lock or an empty...
virtual uint32_t getNumLocks(AIETileType tileType) const =0
Return the number of lock objects for a given tile type.
virtual int rows() const =0
Return the number of rows in the device.
bool isShimNOCTile(int col, int row) const
Return true if the given tile is a ShimNOC tile.
virtual uint32_t getColumnShift() const =0
bool hasProperty(ModelProperty Prop) const
virtual int columns() const =0
Return the number of columns in the device.
virtual uint32_t getNumMemTileRows() const =0
virtual uint32_t getRowShift() const =0
bool empty(const std::string &s)
Definition cxxopts.hpp:275
Include the generated interface declarations.
void collectTiles(DeviceOp &device, llvm::DenseMap< TileID, mlir::Operation * > &tiles)
void collectBuffers(DeviceOp &device, llvm::DenseMap< mlir::Operation *, llvm::SmallVector< BufferOp, 4 > > &buffers)
std::string tileDMAInstStr(llvm::StringRef col, llvm::StringRef row, llvm::StringRef bdNum)
TileID { friend std::ostream &operator<<(std::ostream &os, const TileID &s) { os<< "TileID("<< s.col<< ", "<< s.row<< ")" TileID
const AIETargetModel & getTargetModel(mlir::Operation *op)
void generateXAieDmaSetMultiDimAddr(llvm::raw_ostream &output, int ndims, llvm::ArrayRef< BDDimLayoutAttr > dims, int col, int row, int bdNum, int baseAddrA, int offsetA, int lenA, int elementWidthInBytes, const char *errorRet)
std::string tileDMAInstRefStr(llvm::StringRef col, llvm::StringRef row, llvm::StringRef bdNum)
llvm::SetVector< mlir::Block * > getOrderedChainOfBlocks(mlir::Region *region)
mlir::LogicalResult AIETranslateToXAIEV2(mlir::ModuleOp module, llvm::raw_ostream &output, llvm::StringRef deviceName="")
std::string tileLocStr(llvm::StringRef col, llvm::StringRef row)
std::string packetStr(llvm::StringRef id, llvm::StringRef type)