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->DevInst)"; // TODO
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 xilinx::AIE::AIETranslateToXAIEV2(ModuleOp module,
304 raw_ostream &output) {
305 // StringRef ctx = "ctx"; // TODO
306 StringRef ctx_p = "aie_libxaie_ctx_t* ctx"; // TODO
307 // StringRef deviceInst = "ctx->DevInst"; // TODO
308 StringRef deviceInstRef = "&(ctx->DevInst)"; // TODO
309
310 DenseMap<TileID, Operation *> tiles;
311 DenseMap<Operation *, SmallVector<BufferOp, 4>> buffers;
312
313 if (module.getOps<DeviceOp>().empty())
314 return module.emitOpError("expected AIE.device operation at toplevel");
315 DeviceOp targetOp = *(module.getOps<DeviceOp>().begin());
316 const auto &targetModel = targetOp.getTargetModel();
317
318 collectTiles(targetOp, tiles);
319 collectBuffers(targetOp, buffers);
320
321 //---------------------------------------------------------------------------
322 // mlir_aie_init_libxaie
323 //---------------------------------------------------------------------------
324 output << xaie_cpp_file_header;
325 output << "aie_libxaie_ctx_t* mlir_aie_init_libxaie() {\n";
326 output << " aie_libxaie_ctx_t *ctx = new aie_libxaie_ctx_t;\n";
327 output << " if (!ctx)\n";
328 output << " return 0;\n";
329 auto arch = targetModel.getTargetArch();
330 std::string AIE1_device("XAIE_DEV_GEN_AIE");
331 std::string AIE2_device("XAIE_DEV_GEN_AIEML");
332 std::string AIE2p_device("XAIE_DEV_GEN_AIE2P");
333 std::string device;
334 switch (arch) {
335 case AIEArch::AIE1:
336 device = AIE1_device;
337 break;
338 case AIEArch::AIE2:
339 device = AIE2_device;
340 break;
341 case AIEArch::AIE2p:
342 device = AIE2p_device;
343 break;
344 default:
345 return module.emitOpError("Unsupported aie.device");
346 }
347 output << " ctx->AieConfigPtr.AieGen = " << device << ";\n";
348 output << " ctx->AieConfigPtr.BaseAddr = 0x20000000000;\n";
349 output << " ctx->AieConfigPtr.ColShift = " << targetModel.getColumnShift()
350 << ";\n";
351 output << " ctx->AieConfigPtr.RowShift = " << targetModel.getRowShift()
352 << ";\n";
353 output << " ctx->AieConfigPtr.NumRows = " << targetModel.rows() << ";\n";
354 output << " ctx->AieConfigPtr.NumCols = " << targetModel.columns() << ";\n";
355 output << " ctx->AieConfigPtr.ShimRowNum = 0;\n";
356 output << " ctx->AieConfigPtr.MemTileRowStart = 1;\n";
357 output << " ctx->AieConfigPtr.MemTileNumRows = "
358 << targetModel.getNumMemTileRows() << ";\n";
359 output << " // ctx->AieConfigPtr.ReservedRowStart = "
360 "XAIE_RES_TILE_ROW_START;\n";
361 output
362 << " // ctx->AieConfigPtr.ReservedNumRows = XAIE_RES_TILE_NUM_ROWS;\n";
363 output << " ctx->AieConfigPtr.AieTileRowStart = "
364 << (1 + targetModel.getNumMemTileRows()) << ";\n";
365 output << " ctx->AieConfigPtr.AieTileNumRows = "
366 << (targetModel.rows() - 1 - targetModel.getNumMemTileRows()) << ";\n";
367 output << " ctx->AieConfigPtr.PartProp = {0};\n";
368 output << " ctx->DevInst = {0};\n";
369 output << " return ctx;\n";
370 output << "}\n";
371 output << "\n";
372
373 //---------------------------------------------------------------------------
374 // mlir_aie_configure_cores
375 //---------------------------------------------------------------------------
376 output << "int mlir_aie_configure_cores(" << ctx_p << ") {\n";
377 // Reset each core. Load the corresponding ELF file, if necessary.
378 for (auto tileOp : targetOp.getOps<TileOp>()) {
379 int col = tileOp.colIndex();
380 int row = tileOp.rowIndex();
381 if (tileOp.isShimTile() || tileOp.isMemTile()) {
382 // Resets no needed with V2 kernel driver
383 } else {
384 // Resets no needed with V2 kernel driver
385 output << "__mlir_aie_try(XAie_CoreReset(" << deviceInstRef << ", "
386 << tileLocStr(col, row) << "));\n";
387 output << "__mlir_aie_try(XAie_CoreDisable(" << deviceInstRef << ", "
388 << tileLocStr(col, row) << "));\n";
389 // Release locks
390 int numLocks = targetModel.getNumLocks(col, row);
391 output << "for (int l = 0; l < " << numLocks << "; ++l)\n"
392 << " __mlir_aie_try(XAie_LockRelease(" << deviceInstRef << ", "
393 << tileLocStr(col, row) << ", XAie_LockInit(l, 0x0), 0));\n";
394 if (auto coreOp = tileOp.getCoreOp()) {
395 std::string fileName;
396 if (auto fileAttr = coreOp.getElfFile())
397 fileName = fileAttr.value().str();
398 else
399 fileName = std::string("core_") + std::to_string(col) + "_" +
400 std::to_string(row) + ".elf";
401 output << "{\n"
402 << "AieRC RC = XAie_LoadElf(" << deviceInstRef << ", "
403 << tileLocStr(col, row) << ", "
404 << "(const char*)\"" << fileName << "\",0);\n";
405 output << "if (RC != XAIE_OK)\n"
406 << " __mlir_aie_verbose(fprintf(stderr, \"Failed to load elf "
407 "for Core[%d,%d], ret is %d\\n\", "
408 << std::to_string(col) << ", " << std::to_string(row)
409 << ", RC));\n"
410 << "assert(RC == XAIE_OK);\n"
411 << "}\n";
412 }
413 }
414 }
415 output << "return XAIE_OK;\n";
416 output << "} // mlir_aie_configure_cores\n\n";
417
418 //---------------------------------------------------------------------------
419 // mlir_aie_start_cores
420 //---------------------------------------------------------------------------
421 output << "int mlir_aie_start_cores(" << ctx_p << ") {\n";
422 // Start execution of all the cores.
423 for (auto tileOp : targetOp.getOps<TileOp>()) {
424 int col = tileOp.colIndex();
425 int row = tileOp.rowIndex();
426 if (!tileOp.isShimTile() && !tileOp.isMemTile()) {
427 output << "__mlir_aie_try(XAie_CoreUnreset(" << deviceInstRef << ", "
428 << tileLocStr(col, row) << "));\n";
429 output << "__mlir_aie_try(XAie_CoreEnable(" << deviceInstRef << ", "
430 << tileLocStr(col, row) << "));\n";
431 }
432 }
433 output << "return XAIE_OK;\n";
434 output << "} // mlir_aie_start_cores\n\n";
435
436 //---------------------------------------------------------------------------
437 // mlir_aie_configure_dmas
438 //---------------------------------------------------------------------------
439 output << "int mlir_aie_configure_dmas(" << ctx_p << ") {\n";
440
441 for (auto memOp : targetOp.getOps<MemOp>()) {
442 DenseMap<Block *, int> blockMap;
443
444 // Assign each block a BD number
445 int bdNum = 0;
446 for (auto &block : memOp.getBody()) {
447 if (!block.getOps<DMABDOp>().empty()) {
448 blockMap[&block] = bdNum;
449 bdNum++;
450 }
451 }
452 auto result = generateDMAConfig(memOp, output, targetModel, blockMap);
453 if (result.failed())
454 return result;
455 }
456 for (auto memOp : targetOp.getOps<MemTileDMAOp>()) {
457 DenseMap<Block *, int> blockMap;
458 // Memtiles have restrictions on which channels can access which BDs
459 DenseMap<Block *, int> channelMap;
460
461 for (auto &block : memOp.getBody()) {
462 for (auto op : block.getOps<DMAStartOp>()) {
463 int chNum = op.getChannelIndex();
464 channelMap[&block] = chNum;
465 auto dest = op.getDest();
466 while (dest) {
467 channelMap[dest] = chNum;
468 if (dest->getSuccessors().size() < 1)
469 break;
470 dest = dest->getSuccessors()[0];
471 if (channelMap.count(dest))
472 break;
473 }
474 }
475 }
476
477 // Assign each block a BD number
478 int evenBdNum = 0;
479 int oddBdNum = 24;
480 for (auto &block : memOp.getBody()) {
481 if (block.getOps<DMABDOp>().empty())
482 continue;
483 assert(channelMap.count(&block));
484 if (channelMap[&block] & 1)
485 blockMap[&block] = oddBdNum++;
486 else
487 blockMap[&block] = evenBdNum++;
488 }
489 auto result = generateDMAConfig(memOp, output, targetModel, blockMap);
490 if (result.failed())
491 return result;
492 }
493
494 output << "return XAIE_OK;\n";
495 output << "} // mlir_aie_configure_dmas\n\n";
496
497 for (auto op : targetOp.getOps<ExternalBufferOp>()) {
498 if (op.hasName()) {
499 output << "static u64 _mlir_aie_external_" << op.name().getValue()
500 << ";\n";
501 output << "static bool _mlir_aie_external_set_" << op.name().getValue()
502 << " = false;\n";
503
504 output << "void mlir_aie_external_set_addr_" << op.name().getValue()
505 << "(" << ctx_p << ", u64 VA) {\n"
506 << " u64 device_address = mlir_aie_get_device_address(ctx, (void "
507 "*)VA);\n"
508 << " _mlir_aie_external_set_" << op.name().getValue()
509 << " = true;\n"
510 << " _mlir_aie_external_" << op.name().getValue()
511 << " = device_address;\n"
512 << "}\n";
513 }
514 }
515
516 // ShimDMA Config
517 // int index = 0;
518 for (auto op : targetOp.getOps<ShimDMAOp>()) {
519 int col = op.colIndex();
520 int row = op.rowIndex();
521
522 DenseMap<Block *, int> blockMap;
523 {
524 // Assign each block a BD number
525 int bdNum = 0;
526 for (auto &block : op.getBody()) {
527 if (!block.getOps<DMABDOp>().empty()) {
528 blockMap[&block] = bdNum;
529 uint64_t offset = 0;
530 for (auto op : block.getOps<DMABDOp>()) {
531 offset = op.getOffsetInBytes();
532 auto buffer =
533 cast<ExternalBufferOp>(op.getBuffer().getDefiningOp());
534
535 output << "u64 mlir_aie_external_get_addr_myBuffer_" << col << row
536 << "_" << bdNum << "(void) {\n"
537 << " assert(_mlir_aie_external_set_"
538 << buffer.name().getValue() << ");\n"
539 << " return _mlir_aie_external_"
540 << buffer.name().getValue() << " + "
541 << llvm::utohexstr(offset) << ";\n"
542 << "}\n";
543 }
544
545 bdNum++;
546 }
547 }
548 }
549
550 output << "int mlir_aie_configure_shimdma_" << col << row << "(" << ctx_p
551 << ") {\n";
552 auto result = generateDMAConfig(op, output, targetModel, blockMap);
553 if (result.failed())
554 return result;
555 output << "return XAIE_OK;\n";
556 output << "} // mlir_aie_configure_shimdma\n\n";
557 }
558
559 //---------------------------------------------------------------------------
560 // mlir_aie_initialize_locks
561 //---------------------------------------------------------------------------
562 output << "int mlir_aie_initialize_locks(" << ctx_p << ") {\n";
563 // Lock configuration
564 targetOp.walk<WalkOrder::PreOrder>([&](LockOp lock) {
565 TileOp tile = lock.getTileOp();
566 int col = tile.colIndex();
567 int row = tile.rowIndex();
568 int lockID = lock.getLockIDValue();
569 auto init = lock.getInit();
570 if (init)
571 output << "__mlir_aie_try(XAie_LockSetValue(" << deviceInstRef << ", "
572 << tileLocStr(col, row) << ", "
573 << "XAie_LockInit(" << lockID << ", " << *init << ")));\n";
574 });
575 output << "return XAIE_OK;\n";
576 output << "} // mlir_aie_initialize_locks\n";
577
578 //---------------------------------------------------------------------------
579 // mlir_aie_configure_switchboxes
580 //---------------------------------------------------------------------------
581 output << "int mlir_aie_configure_switchboxes(" << ctx_p << ") {\n";
582 output << " int x, y;\n";
583
584 // StreamSwitch (switchbox) configuration
585 for (auto switchboxOp : targetOp.getOps<SwitchboxOp>()) {
586 Region &r = switchboxOp.getConnections();
587 Block &b = r.front();
588 bool isEmpty = b.getOps<ConnectOp>().empty() &&
589 b.getOps<MasterSetOp>().empty() &&
590 b.getOps<PacketRulesOp>().empty();
591 bool isParam = false;
592
593 if (isa<TileOp>(switchboxOp.getTile().getDefiningOp())) {
594 int col = switchboxOp.colIndex();
595 int row = switchboxOp.rowIndex();
596 if (!isEmpty) {
597 output << "// Core Stream Switch column " << col << " row " << row
598 << "\n";
599 output << "x = " << col << ";\n";
600 output << "y = " << row << ";\n";
601 }
602 } else if (auto sel =
603 dyn_cast<SelectOp>(switchboxOp.getTile().getDefiningOp())) {
604 // parameterize streamswitch's configuration
605 isParam = true;
606 HerdOp sourceHerd = cast<HerdOp>(sel.getStartHerd().getDefiningOp());
607 std::string sourceHerdName(sourceHerd.name().getValue());
608
609 IterOp iterX = cast<IterOp>(sel.getIterX().getDefiningOp());
610 IterOp iterY = cast<IterOp>(sel.getIterY().getDefiningOp());
611 int startXValue = iterX.getStartValue();
612 int endXValue = iterX.getEndValue();
613 int strideXValue = iterX.getStrideValue();
614 int startYValue = iterY.getStartValue();
615 int endYValue = iterY.getEndValue();
616 int strideYValue = iterY.getStrideValue();
617
618 std::string startX(sourceHerdName + "_X + " +
619 std::to_string(startXValue));
620 std::string endX(sourceHerdName + "_X + " + std::to_string(endXValue));
621 std::string startY(sourceHerdName + "_Y + " +
622 std::to_string(startYValue));
623 std::string endY(sourceHerdName + "_Y + " + std::to_string(endYValue));
624
625 output << "for (x = " << startX << "; x < " << endX
626 << "; x += " << strideXValue << ") {\n";
627 output << "for (y = " << startY << "; y < " << endY
628 << "; y += " << strideYValue << ") {\n";
629 }
630
631 for (auto connectOp : b.getOps<ConnectOp>())
632 output << "__mlir_aie_try(XAie_StrmConnCctEnable(" << deviceInstRef
633 << ", " << tileLocStr("x", "y") << ", "
634 << wireBundleToPortType(connectOp.getSourceBundle()) << ", "
635 << connectOp.sourceIndex() << ", "
636 << wireBundleToPortType(connectOp.getDestBundle()) << ", "
637 << connectOp.destIndex() << "));\n";
638
639 for (auto connectOp : b.getOps<MasterSetOp>()) {
640 int mask = 0;
641 int arbiter = -1;
642 for (auto val : connectOp.getAmsels()) {
643 AMSelOp amsel = cast<AMSelOp>(val.getDefiningOp());
644 arbiter = amsel.arbiterIndex();
645 int msel = amsel.getMselValue();
646 mask |= (1 << msel);
647 }
648 bool isdma = (connectOp.getDestBundle() == WireBundle::DMA);
649
650 output << "__mlir_aie_try(XAie_StrmPktSwMstrPortEnable(" << deviceInstRef
651 << ", " << tileLocStr("x", "y") << ", "
652 << wireBundleToPortType(connectOp.getDestBundle()) << ", "
653 << connectOp.destIndex() << ", "
654 << "/* drop_header */ "
655 << (isdma ? "XAIE_SS_PKT_DROP_HEADER"
656 : "XAIE_SS_PKT_DONOT_DROP_HEADER")
657 << ", "
658 << "/* arbiter */ " << arbiter << ", "
659 << "/* MSelEn */ "
660 << "0x" << llvm::utohexstr(mask) << "));\n";
661 }
662
663 for (auto connectOp : b.getOps<PacketRulesOp>()) {
664 int slot = 0;
665 Block &block = connectOp.getRules().front();
666 for (auto slotOp : block.getOps<PacketRuleOp>()) {
667 AMSelOp amselOp = cast<AMSelOp>(slotOp.getAmsel().getDefiningOp());
668 int arbiter = amselOp.arbiterIndex();
669 int msel = amselOp.getMselValue();
670 output << "__mlir_aie_try(XAie_StrmPktSwSlavePortEnable("
671 << deviceInstRef << ", " << tileLocStr("x", "y") << ", "
672 << wireBundleToPortType(connectOp.getSourceBundle()) << ", "
673 << connectOp.sourceIndex() << "));\n";
674
675 // TODO Need to better define packet id,type used here
676 output << "__mlir_aie_try(XAie_StrmPktSwSlaveSlotEnable("
677 << deviceInstRef << ", " << tileLocStr("x", "y") << ", "
678 << wireBundleToPortType(connectOp.getSourceBundle()) << ", "
679 << connectOp.sourceIndex() << ", "
680 << "/* slot */ " << slot << ", "
681 << "/* packet */ " << packetStr(slotOp.valueInt(), /*type*/ 0)
682 << ", "
683 << "/* mask */ "
684 << "0x" << llvm::utohexstr(slotOp.maskInt()) << ", "
685 << "/* msel */ " << msel << ", "
686 << "/* arbiter */ " << arbiter << "));\n";
687 slot++;
688 }
689 }
690
691 if (isParam) {
692 output << "}\n";
693 output << "}\n";
694 }
695 }
696 for (auto op : targetOp.getOps<ShimMuxOp>()) {
697 Region &r = op.getConnections();
698 Block &b = r.front();
699 bool isEmpty = b.getOps<ConnectOp>().empty();
700
701 if (isa<TileOp>(op.getTile().getDefiningOp())) {
702 int col = op.colIndex();
703 int row = op.rowIndex();
704 if (!isEmpty) {
705 output << "// ShimMux column " << col << " row " << row << "\n";
706 output << "// NOTE ShimMux always connects from the south as "
707 << "directions are defined relative to the tile stream "
708 << "switch\n";
709 output << "x = " << col << ";\n";
710 output << "y = " << row << ";\n";
711 }
712 }
713
714 for (auto connectOp : b.getOps<ConnectOp>()) {
715
716 if (connectOp.getSourceBundle() == WireBundle::DMA ||
717 connectOp.getDestBundle() == WireBundle::DMA) {
718 if (connectOp.getSourceBundle() == WireBundle::North)
719 // demux!
720 output << "__mlir_aie_try(XAie_EnableAieToShimDmaStrmPort("
721 << deviceInstRef << ", " << tileLocStr("x", "y") << ", "
722 << connectOp.sourceIndex() << "));\n";
723 else if (connectOp.getDestBundle() == WireBundle::North)
724 // mux
725 output << "__mlir_aie_try(XAie_EnableShimDmaToAieStrmPort("
726 << deviceInstRef << ", " << tileLocStr("x", "y") << ", "
727 << connectOp.destIndex() << "));\n";
728 }
729
730 else if (connectOp.getSourceBundle() == WireBundle::PLIO ||
731 connectOp.getDestBundle() == WireBundle::PLIO) {
732 if (connectOp.getSourceBundle() == WireBundle::North) {
733 // mux
734 output << "__mlir_aie_try(XAie_AieToPlIntfEnable(" << deviceInstRef
735 << ", " << tileLocStr("x", "y") << ", "
736 << connectOp.destIndex() << ", PLIF_WIDTH_64));\n";
737 } else if (connectOp.getDestBundle() == WireBundle::North) {
738 // mux
739 output << "__mlir_aie_try(XAie_PlToAieIntfEnable(" << deviceInstRef
740 << ", " << tileLocStr("x", "y") << ", "
741 << connectOp.destIndex() << ", PLIF_WIDTH_64));\n";
742 }
743 }
744 }
745 }
746 for (auto switchboxOp : targetOp.getOps<ShimSwitchboxOp>()) {
747 Region &r = switchboxOp.getConnections();
748 Block &b = r.front();
749 bool isEmpty = b.getOps<ConnectOp>().empty();
750 int col = switchboxOp.getCol();
751 if (!isEmpty)
752 output << "// Shim Switch column " << col << "\n";
753 for (auto connectOp : b.getOps<ConnectOp>())
754 output << "__mlir_aie_try(XAie_StrmConnCctEnable(" << deviceInstRef
755 << ", " << tileLocStr(col, 0) << ", "
756 << wireBundleToPortType(connectOp.getSourceBundle()) << ", "
757 << connectOp.sourceIndex() << ", "
758 << wireBundleToPortType(connectOp.getDestBundle()) << ", "
759 << connectOp.destIndex() << "));\n";
760 }
761
762 output << "return XAIE_OK;\n";
763 output << "} // mlir_aie_configure_switchboxes\n\n";
764
765 //---------------------------------------------------------------------------
766 // mlir_aie_configure_cascade
767 //---------------------------------------------------------------------------
768 output << "int mlir_aie_configure_cascade(" << ctx_p << ") {\n";
769 for (auto configOp : targetOp.getOps<ConfigureCascadeOp>()) {
770 TileOp tile = cast<TileOp>(configOp.getTile().getDefiningOp());
771 int col = tile.colIndex();
772 int row = tile.rowIndex();
773 output << "XAie_CoreConfigAccumulatorControl(" << deviceInstRef << ", "
774 << "XAie_TileLoc(" << col << ", " << row << "), "
775 << stringifyCascadeDir(configOp.getInputDir()).upper() << ", "
776 << stringifyCascadeDir(configOp.getOutputDir()).upper() << ");\n";
777 }
778 output << "return XAIE_OK;\n";
779 output << "} // mlir_aie_configure_cascade\n\n";
780
781 //---------------------------------------------------------------------------
782 // Output Buffer Accessors
783 //---------------------------------------------------------------------------
784 for (auto tile : tiles) {
785 Operation *tileOp = tile.second;
786 TileID coord = cast<TileOp>(tileOp).getTileID();
787 int col = coord.col;
788 int row = coord.row;
789 auto loc = tileLocStr(col, row);
790
791 auto bufferAccessor = [&](BufferOp buf) {
792 // int32_t mlir_aie_read_buffer_a13(int index) {
793 // void mlir_aie_write_buffer_a13(int index, int32_t value) {
794 std::string bufName(buf.name().getValue());
795 Type t = buf.getType();
796 Type et;
797 std::string typestr;
798 if (auto memrefType = llvm::dyn_cast<MemRefType>(t)) {
799 et = memrefType.getElementType();
800 if (et.isInteger(32))
801 typestr = "int32_t";
802 else if (et.isF32())
803 typestr = "float";
804 else {
805 output << "// buffer " << bufName << " with unsupported type " << t
806 << ";\n";
807 return; // Unsupported type
808 }
809
810 } else {
811 output << "// buffer " << bufName << " with unsupported type " << t
812 << ";\n";
813 return; // Unsupported type
814 }
815 assert(buf.getAddress().has_value() && "buffer must have address");
816 output << "const int " << bufName
817 << "_offset = " << buf.getAddress().value() << ";\n";
818 output << typestr << " mlir_aie_read_buffer_" << bufName << "(" << ctx_p
819 << ", int index) {\n";
820 output << "u32 value; auto rc = XAie_DataMemRdWord(" << deviceInstRef
821 << ", " << loc << ", " << bufName
822 << "_offset + (index*4), &value);\n";
823 if (et.isInteger(32))
824 output << " return value;\n";
825 else if (et.isF32()) {
826 output << " union caster { int32_t i; float f; };\n";
827 output << " caster c; c.i = value;\n";
828 output << " return c.f;\n";
829 }
830 output << "}\n";
831 output << "int mlir_aie_write_buffer_" << bufName << "(" << ctx_p
832 << ", int index, " << typestr << " value) {\n";
833 if (et.isInteger(32))
834 output << " int32_t int_value = value;\n";
835 else if (et.isF32()) {
836 output << " union caster { int32_t i; float f; };\n";
837 output << " caster c; c.f = value;\n";
838 output << " int32_t int_value = c.i;\n";
839 }
840 output << "AieRC rc = XAie_DataMemWrWord(" << deviceInstRef << ", "
841 << loc << ", " << bufName << "_offset + (index*4), int_value);\n";
842 output << "return rc;\n";
843 output << "}\n";
844 };
845
846 // if(tiles.count(tile.getValue()))
847 for (auto buf : buffers[tileOp])
848 bufferAccessor(buf);
849 }
850
851 auto lockAccessor = [&](LockOp lock) {
852 int col = lock.colIndex();
853 int row = lock.rowIndex();
854 if (!lock.hasName())
855 return;
856 std::string lockName(lock.name().getValue());
857 output << "int mlir_aie_acquire_" << lockName << "(" << ctx_p
858 << ", int value, int timeout) {\n";
859 output << " const int id = " << lock.getLockIDValue() << ";\n";
860 output << " return XAie_LockAcquire(" << deviceInstRef << ", "
861 << tileLocStr(col, row) << ", " << tileLockStr("id", "value")
862 << ", timeout);\n";
863 output << "}\n";
864 output << "int mlir_aie_release_" << lockName << "(" << ctx_p
865 << ", int value, int timeout) {\n";
866 output << " const int id = " << lock.getLockIDValue() << ";\n";
867 output << " return XAie_LockRelease(" << deviceInstRef << ", "
868 << tileLocStr(col, row) << ", " << tileLockStr("id", "value")
869 << ", timeout);\n";
870 output << "}\n";
871 };
872
873 targetOp.walk<WalkOrder::PreOrder>([&](LockOp lock) { lockAccessor(lock); });
874
875 return success();
876}
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.
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 bool isMemTile(int col, int row) const =0
Return true if the given tile is an AIE2 'Memory' tile.
virtual uint32_t getNumLocks(int col, int row) const =0
Return the number of lock objects.
virtual int rows() const =0
Return the number of rows in the device.
virtual bool isShimNOCTile(int col, int row) const =0
Return true if the given tile is a Shim NOC 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
Include the generated interface declarations.
mlir::LogicalResult AIETranslateToXAIEV2(mlir::ModuleOp module, llvm::raw_ostream &output)
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)
std::string tileLocStr(llvm::StringRef col, llvm::StringRef row)
std::string packetStr(llvm::StringRef id, llvm::StringRef type)