MLIR-AIE
AIETargetModel.cpp
Go to the documentation of this file.
1//===- AIETargetModel.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 2019 Xilinx Inc.
8// (c) Copyright 2023 Advanced Micro Devices, Inc.
9//
10//===----------------------------------------------------------------------===//
11
14#include "llvm/Support/ErrorHandling.h"
15#include <cstdint>
16#include <utility>
17
18using namespace llvm;
19
20namespace xilinx {
21namespace AIE {
22
23namespace {
24
25std::string getModuleForTile(const AIETargetModel &model, TileID tile,
26 bool isMem) {
27 if (model.isShimNOCorPLTile(tile.col, tile.row))
28 return "shim";
29 if (model.isMemTile(tile.col, tile.row))
30 return "memory_tile";
31 return isMem ? std::string("memory") : std::string("core");
32}
33
34// Get module name for event lookups (events database uses different names)
35std::string getModuleForTileEvents(const AIETargetModel &model, TileID tile,
36 bool isMem) {
37 if (model.isShimNOCorPLTile(tile.col, tile.row))
38 return "pl"; // Events database uses "pl" for shim tiles
39 if (model.isMemTile(tile.col, tile.row))
40 return "mem_tile"; // Events database uses "mem_tile" instead of
41 // "memory_tile"
42 return isMem ? std::string("memory") : std::string("core");
43}
44
45} // namespace
46
48
49// Base class implementations for register database
50
51std::unique_ptr<RegisterDatabase> AIETargetModel::loadRegisterDatabase() const {
52 // Default: no register database available
53 return nullptr;
54}
55
57 std::call_once(regDBInitFlag, [this]() { regDB = loadRegisterDatabase(); });
58 return regDB.get();
59}
60
61const RegisterInfo *AIETargetModel::lookupRegister(llvm::StringRef name,
62 TileID tile,
63 bool isMem) const {
64 const auto *db = getRegisterDatabase();
65 if (!db)
66 return nullptr;
67 return db->lookupRegister(name, getModuleForTile(*this, tile, isMem));
68}
69
70std::optional<uint32_t> AIETargetModel::lookupEvent(llvm::StringRef name,
71 TileID tile,
72 bool isMem) const {
73 const auto *db = getRegisterDatabase();
74 if (!db)
75 return std::nullopt;
76 return db->lookupEvent(name, getModuleForTileEvents(*this, tile, isMem));
77}
78
80 uint32_t value) const {
81 const auto *db = getRegisterDatabase();
82 if (!db)
83 return 0;
84 return db->encodeFieldValue(field, value);
85}
86
87std::optional<uint32_t>
89 uint32_t width = field.getWidth();
90 if (width == 0 || width > 32 || field.bit_end >= 32)
91 return std::nullopt;
92
93 uint64_t mask = (width == 32) ? 0xFFFFFFFFULL : ((1ULL << width) - 1ULL);
94 mask <<= field.bit_start;
95 if (mask > UINT32_MAX)
96 return std::nullopt;
97
98 return static_cast<uint32_t>(mask);
99}
100
101std::optional<uint32_t> AIETargetModel::resolvePortValue(llvm::StringRef value,
102 TileID tile,
103 bool master) const {
104 auto colonPos = value.find(':');
105 if (colonPos == StringRef::npos)
106 return std::nullopt;
107
108 StringRef portName = value.substr(0, colonPos);
109 StringRef channelStr = value.substr(colonPos + 1);
110
111 int channel;
112 if (channelStr.getAsInteger(10, channel) || channel < 0)
113 return std::nullopt;
114
115 WireBundle bundle;
116 if (portName.equals_insensitive("north")) {
117 bundle = WireBundle::North;
118 } else if (portName.equals_insensitive("south")) {
119 bundle = WireBundle::South;
120 } else if (portName.equals_insensitive("east")) {
121 bundle = WireBundle::East;
122 } else if (portName.equals_insensitive("west")) {
123 bundle = WireBundle::West;
124 } else if (portName.equals_insensitive("dma")) {
125 bundle = WireBundle::DMA;
126 } else if (portName.equals_insensitive("fifo")) {
127 bundle = WireBundle::FIFO;
128 } else if (portName.equals_insensitive("core")) {
129 bundle = WireBundle::Core;
130 } else if (portName.equals_insensitive("ctrl")) {
131 bundle = WireBundle::TileControl;
132 } else {
133 return std::nullopt;
134 }
135
136 return getStreamSwitchPortIndex(tile.col, tile.row, bundle,
137 static_cast<uint32_t>(channel), master);
138}
139
140///
141/// AIE1 TargetModel
142///
143
144AIEArch AIE1TargetModel::getTargetArch() const { return AIEArch::AIE1; }
145
146// Return the tile ID of the memory to the west of the given tile, if it exists.
147std::optional<TileID> AIE1TargetModel::getMemWest(TileID src) const {
148 bool isEvenRow = ((src.row % 2) == 0);
149 std::optional<TileID> ret;
150 if (isEvenRow)
151 ret = src;
152 else
153 ret = {src.col - 1, src.row};
154 if (!isValidTile(*ret))
155 ret.reset();
156 return ret;
157}
158
159// Return the tile ID of the memory to the west of the given tile, if it exists.
160std::optional<TileID> AIE1TargetModel::getMemEast(TileID src) const {
161 bool isEvenRow = (src.row % 2) == 0;
162 std::optional<TileID> ret;
163 if (isEvenRow)
164 ret = {src.col + 1, src.row};
165 else
166 ret = src;
167 if (!isValidTile(*ret))
168 ret.reset();
169 return ret;
170}
171
172// Return the tile ID of the memory to the west of the given tile, if it exists.
173std::optional<TileID> AIE1TargetModel::getMemNorth(TileID src) const {
174 std::optional<TileID> ret({src.col, src.row + 1});
175 if (!isValidTile(*ret))
176 ret.reset();
177 return ret;
178}
179
180std::optional<TileID> AIE1TargetModel::getMemSouth(TileID src) const {
181 std::optional<TileID> ret({src.col, src.row - 1});
182 // The first row doesn't have a tile memory south
183 if (!isValidTile(*ret) || ret->row == 0)
184 ret.reset();
185 return ret;
186}
187
188bool AIE1TargetModel::isMemWest(int srcCol, int srcRow, int dstCol,
189 int dstRow) const {
190 bool IsEvenRow = (srcRow % 2) == 0;
191 return (IsEvenRow && isInternal(srcCol, srcRow, dstCol, dstRow)) ||
192 (!IsEvenRow && isWest(srcCol, srcRow, dstCol, dstRow));
193}
194
195bool AIE1TargetModel::isMemEast(int srcCol, int srcRow, int dstCol,
196 int dstRow) const {
197 bool IsEvenRow = (srcRow % 2) == 0;
198 return (!IsEvenRow && isInternal(srcCol, srcRow, dstCol, dstRow)) ||
199 (IsEvenRow && isEast(srcCol, srcRow, dstCol, dstRow));
200}
201
202bool AIE1TargetModel::isMemNorth(int srcCol, int srcRow, int dstCol,
203 int dstRow) const {
204 return isNorth(srcCol, srcRow, dstCol, dstRow);
205}
206
207bool AIE1TargetModel::isMemSouth(int srcCol, int srcRow, int dstCol,
208 int dstRow) const {
209 return isSouth(srcCol, srcRow, dstCol, dstRow);
210}
211
212bool AIE1TargetModel::isLegalMemAffinity(int coreCol, int coreRow, int memCol,
213 int memRow) const {
214 bool IsEvenRow = ((coreRow % 2) == 0);
215
216 bool IsMemWest = (isWest(coreCol, coreRow, memCol, memRow) && !IsEvenRow) ||
217 (isInternal(coreCol, coreRow, memCol, memRow) && IsEvenRow);
218
219 bool IsMemEast = (isEast(coreCol, coreRow, memCol, memRow) && IsEvenRow) ||
220 (isInternal(coreCol, coreRow, memCol, memRow) && !IsEvenRow);
221
222 bool IsMemNorth = isNorth(coreCol, coreRow, memCol, memRow);
223 bool IsMemSouth = isSouth(coreCol, coreRow, memCol, memRow);
224
225 return IsMemSouth || IsMemNorth || IsMemWest || IsMemEast;
226}
227
228uint64_t AIE1TargetModel::getDmaBdAddress(int col, int row, uint32_t bd_id,
229 int channel,
230 AIE::DMAChannelDir direction) const {
231 uint32_t offset = 0;
232 if (isShimNOCTile(col, row)) {
233 offset = 0x0001D000 + (bd_id * 0x14);
234 } else if (isCoreTile(col, row)) {
235 offset = 0x0001D000 + (bd_id * 0x20);
236 } else {
237 llvm_unreachable(
238 "AIE1TargetModel::getDmaBdAddress called for non-DMA tile");
239 }
240 return ((col & 0xff) << getColumnShift()) | ((row & 0xff) << getRowShift()) |
241 offset;
242}
243
245 if (isShimNOCTile(col, row) || isCoreTile(col, row)) {
246 return 0;
247 }
248 llvm_unreachable(
249 "AIE1TargetModel::getDmaBdAddressOffset called for non-DMA tile");
250}
251
252uint32_t
254 AIE::DMAChannelDir direction) const {
255 uint32_t offset = 0;
256 if (isShimNOCTile(col, row))
257 offset = 0x0001D140 + (channel * 0x8);
258 else if (isCoreTile(col, row))
259 offset = 0x0001DE00 + (channel * 0x8);
260 else
261 llvm_unreachable(
262 "AIE1TargetModel::getDmaControlAddress called for non-DMA tile");
263
264 if (direction == AIE::DMAChannelDir::MM2S)
265 offset += 010;
266
267 return ((col & 0xff) << getColumnShift()) | ((row & 0xff) << getRowShift()) |
268 offset;
269}
270
271uint32_t
273 WireBundle bundle) const {
275 switch (bundle) {
276 case WireBundle::FIFO:
277 return 2;
278 case WireBundle::North:
279 return 6;
280 case WireBundle::West: {
281 if (col == 0)
282 return 0;
283 return 4;
284 }
285 case WireBundle::South:
286 return 6;
287 case WireBundle::East: {
288 if (col == columns() - 1)
289 return 0;
290 return 4;
291 }
292 case WireBundle::TileControl:
293 return isShimNOCTile(col, row) ? 1 : 0;
294 default:
295 return 0;
296 }
297
298 switch (bundle) {
299 case WireBundle::Core:
300 case WireBundle::DMA:
301 case WireBundle::FIFO:
302 return 2;
303 case WireBundle::North: {
304 if (row == rows() - 1)
305 return 0;
306 return 6;
307 }
308 case WireBundle::West: {
309 if (col == 0)
310 return 0;
311 return 4;
312 }
313 case WireBundle::South:
314 return 4;
315 case WireBundle::East: {
316 if (col == columns() - 1)
317 return 0;
318 return 4;
319 }
320 case WireBundle::TileControl:
321 return 1;
322 default:
323 return 0;
324 }
325}
326
327uint32_t
329 WireBundle bundle) const {
331 switch (bundle) {
332 case WireBundle::FIFO:
333 return 2;
334 case WireBundle::North:
335 return 4;
336 case WireBundle::West: {
337 if (col == 0)
338 return 0;
339 return 4;
340 }
341 case WireBundle::South:
342 return 8;
343 case WireBundle::East: {
344 if (col == columns() - 1)
345 return 0;
346 return 4;
347 }
348 case WireBundle::Trace:
349 return 1;
350 case WireBundle::TileControl:
351 return isShimNOCTile(col, row) ? 1 : 0;
352 default:
353 return 0;
354 }
355
356 switch (bundle) {
357 case WireBundle::Core:
358 case WireBundle::DMA:
359 case WireBundle::FIFO:
360 return 2;
361 case WireBundle::North: {
362 if (row == rows() - 1)
363 return 0;
364 return 4;
365 }
366 case WireBundle::West: {
367 if (col == 0)
368 return 0;
369 return 4;
370 }
371 case WireBundle::South:
372 return 6;
373 case WireBundle::East: {
374 if (col == columns() - 1)
375 return 0;
376 return 4;
377 }
378 case WireBundle::Trace:
379 return 2;
380 case WireBundle::TileControl:
381 return 1;
382 default:
383 return 0;
384 }
385}
386uint32_t
388 WireBundle bundle) const {
390 switch (bundle) {
391 case WireBundle::DMA:
392 return 2;
393 case WireBundle::NOC:
394 return 4;
395 case WireBundle::PLIO:
396 return 6;
397 case WireBundle::South:
398 return 8; // Connection to the south port of the stream switch
399 default:
400 return 0;
401 }
402 return 0;
403}
404uint32_t
406 WireBundle bundle) const {
408 switch (bundle) {
409 case WireBundle::DMA:
410 return 2;
411 case WireBundle::NOC:
412 return 4;
413 case WireBundle::PLIO:
414 return 8;
415 case WireBundle::South:
416 return 6; // Connection to the south port of the stream switch
417 default:
418 return 0;
419 }
420 return 0;
421}
422
424 WireBundle srcBundle, int srcChan,
425 WireBundle dstBundle,
426 int dstChan) const {
427 // Check Channel Id within the range
428 if (srcChan >= int(getNumSourceSwitchboxConnections(col, row, srcBundle)))
429 return false;
430 if (dstChan >= int(getNumDestSwitchboxConnections(col, row, dstBundle)))
431 return false;
432
433 // Memtile
434 if (isMemTile(col, row)) {
435 return false;
436 }
437 // Shimtile
438 else if (isShimNOCorPLTile(col, row)) {
439 if (srcBundle == WireBundle::Trace)
440 return dstBundle == WireBundle::South;
441 else
442 return true;
443 }
444 // Coretile
445 else if (isCoreTile(col, row)) {
446 if (srcBundle == WireBundle::Trace)
447 return dstBundle == WireBundle::South;
448 else
449 return true;
450 }
451 return false;
452}
453
454std::vector<std::pair<uint32_t, uint32_t>>
456 return {std::pair(0, 64), std::pair(1, 128), std::pair(2, 256)};
457}
458
459std::optional<uint32_t>
460AIE1TargetModel::getLocalLockAddress(uint32_t lockId, TileID tile) const {
461 // This function is currently not supported for AIE1.
462 // In order to be implemented for this target model, the interface
463 // would need to change given the different way locks are written to in AIE1.
464 return std::nullopt;
465}
466
467namespace {
468namespace aie1_port_id {
469namespace core {
470
471// Slave port offset/size constants
472static constexpr uint32_t S_CORE_OFFSET = 0;
473static constexpr uint32_t S_CORE_SIZE = 2;
474static constexpr uint32_t S_CTRL_OFFSET = 4;
475static constexpr uint32_t S_CTRL_SIZE = 1;
476static constexpr uint32_t S_DMA_OFFSET = 2;
477static constexpr uint32_t S_DMA_SIZE = 2;
478static constexpr uint32_t S_EAST_OFFSET = 21;
479static constexpr uint32_t S_EAST_SIZE = 4;
480static constexpr uint32_t S_FIFO_OFFSET = 5;
481static constexpr uint32_t S_FIFO_SIZE = 2;
482static constexpr uint32_t S_NORTH_OFFSET = 17;
483static constexpr uint32_t S_NORTH_SIZE = 4;
484static constexpr uint32_t S_SOUTH_OFFSET = 7;
485static constexpr uint32_t S_SOUTH_SIZE = 6;
486static constexpr uint32_t S_TRACE_OFFSET = 25;
487static constexpr uint32_t S_TRACE_SIZE = 2;
488static constexpr uint32_t S_WEST_OFFSET = 13;
489static constexpr uint32_t S_WEST_SIZE = 4;
490
491// Master port offset/size constants
492static constexpr uint32_t M_CORE_OFFSET = 0;
493static constexpr uint32_t M_CORE_SIZE = 2;
494static constexpr uint32_t M_CTRL_OFFSET = 4;
495static constexpr uint32_t M_CTRL_SIZE = 1;
496static constexpr uint32_t M_DMA_OFFSET = 2;
497static constexpr uint32_t M_DMA_SIZE = 2;
498static constexpr uint32_t M_EAST_OFFSET = 21;
499static constexpr uint32_t M_EAST_SIZE = 4;
500static constexpr uint32_t M_FIFO_OFFSET = 5;
501static constexpr uint32_t M_FIFO_SIZE = 2;
502static constexpr uint32_t M_NORTH_OFFSET = 15;
503static constexpr uint32_t M_NORTH_SIZE = 6;
504static constexpr uint32_t M_SOUTH_OFFSET = 7;
505static constexpr uint32_t M_SOUTH_SIZE = 4;
506static constexpr uint32_t M_WEST_OFFSET = 11;
507static constexpr uint32_t M_WEST_SIZE = 4;
508
509} // namespace core
510
511namespace shim {
512
513// Slave port offset/size constants
514static constexpr uint32_t S_CTRL_OFFSET = 0;
515static constexpr uint32_t S_CTRL_SIZE = 1;
516static constexpr uint32_t S_EAST_OFFSET = 19;
517static constexpr uint32_t S_EAST_SIZE = 4;
518static constexpr uint32_t S_FIFO_OFFSET = 1;
519static constexpr uint32_t S_FIFO_SIZE = 2;
520static constexpr uint32_t S_NORTH_OFFSET = 15;
521static constexpr uint32_t S_NORTH_SIZE = 4;
522static constexpr uint32_t S_SOUTH_OFFSET = 3;
523static constexpr uint32_t S_SOUTH_SIZE = 8;
524static constexpr uint32_t S_TRACE_OFFSET = 23;
525static constexpr uint32_t S_TRACE_SIZE = 1;
526static constexpr uint32_t S_WEST_OFFSET = 11;
527static constexpr uint32_t S_WEST_SIZE = 4;
528
529// Master port offset/size constants
530static constexpr uint32_t M_CTRL_OFFSET = 0;
531static constexpr uint32_t M_CTRL_SIZE = 1;
532static constexpr uint32_t M_EAST_OFFSET = 19;
533static constexpr uint32_t M_EAST_SIZE = 4;
534static constexpr uint32_t M_FIFO_OFFSET = 1;
535static constexpr uint32_t M_FIFO_SIZE = 2;
536static constexpr uint32_t M_NORTH_OFFSET = 13;
537static constexpr uint32_t M_NORTH_SIZE = 6;
538static constexpr uint32_t M_SOUTH_OFFSET = 3;
539static constexpr uint32_t M_SOUTH_SIZE = 6;
540static constexpr uint32_t M_WEST_OFFSET = 9;
541static constexpr uint32_t M_WEST_SIZE = 4;
542
543} // namespace shim
544} // namespace aie1_port_id
545} // anonymous namespace
546
548 int col, int row, WireBundle bundle, uint32_t port_num, bool master) const {
549 if (master) {
550 if (isCoreTile(col, row)) {
551 switch (bundle) {
552 case WireBundle::Core:
553 if (port_num >= aie1_port_id::core::M_CORE_SIZE)
554 return std::nullopt;
555 return aie1_port_id::core::M_CORE_OFFSET + port_num;
556 case WireBundle::TileControl:
557 if (port_num >= aie1_port_id::core::M_CTRL_SIZE)
558 return std::nullopt;
559 return aie1_port_id::core::M_CTRL_OFFSET + port_num;
560 case WireBundle::DMA:
561 if (port_num >= aie1_port_id::core::M_DMA_SIZE)
562 return std::nullopt;
563 return aie1_port_id::core::M_DMA_OFFSET + port_num;
564 case WireBundle::East:
565 if (port_num >= aie1_port_id::core::M_EAST_SIZE)
566 return std::nullopt;
567 return aie1_port_id::core::M_EAST_OFFSET + port_num;
568 case WireBundle::FIFO:
569 if (port_num >= aie1_port_id::core::M_FIFO_SIZE)
570 return std::nullopt;
571 return aie1_port_id::core::M_FIFO_OFFSET + port_num;
572 case WireBundle::North:
573 if (port_num >= aie1_port_id::core::M_NORTH_SIZE)
574 return std::nullopt;
575 return aie1_port_id::core::M_NORTH_OFFSET + port_num;
576 case WireBundle::South:
577 if (port_num >= aie1_port_id::core::M_SOUTH_SIZE)
578 return std::nullopt;
579 return aie1_port_id::core::M_SOUTH_OFFSET + port_num;
580 case WireBundle::West:
581 if (port_num >= aie1_port_id::core::M_WEST_SIZE)
582 return std::nullopt;
583 return aie1_port_id::core::M_WEST_OFFSET + port_num;
584 default:
585 return std::nullopt;
586 }
587 } else if (isShimNOCorPLTile(col, row)) {
588 switch (bundle) {
589 case WireBundle::TileControl:
590 if (port_num >= aie1_port_id::shim::M_CTRL_SIZE)
591 return std::nullopt;
592 return aie1_port_id::shim::M_CTRL_OFFSET + port_num;
593 case WireBundle::East:
594 if (port_num >= aie1_port_id::shim::M_EAST_SIZE)
595 return std::nullopt;
596 return aie1_port_id::shim::M_EAST_OFFSET + port_num;
597 case WireBundle::FIFO:
598 if (port_num >= aie1_port_id::shim::M_FIFO_SIZE)
599 return std::nullopt;
600 return aie1_port_id::shim::M_FIFO_OFFSET + port_num;
601 case WireBundle::North:
602 if (port_num >= aie1_port_id::shim::M_NORTH_SIZE)
603 return std::nullopt;
604 return aie1_port_id::shim::M_NORTH_OFFSET + port_num;
605 case WireBundle::South:
606 if (port_num >= aie1_port_id::shim::M_SOUTH_SIZE)
607 return std::nullopt;
608 return aie1_port_id::shim::M_SOUTH_OFFSET + port_num;
609 case WireBundle::West:
610 if (port_num >= aie1_port_id::shim::M_WEST_SIZE)
611 return std::nullopt;
612 return aie1_port_id::shim::M_WEST_OFFSET + port_num;
613 default:
614 return std::nullopt;
615 }
616 } else {
617 return std::nullopt;
618 }
619 } else {
620 if (isCoreTile(col, row)) {
621 switch (bundle) {
622 case WireBundle::Core:
623 if (port_num >= aie1_port_id::core::S_CORE_SIZE)
624 return std::nullopt;
625 return aie1_port_id::core::S_CORE_OFFSET + port_num;
626 case WireBundle::TileControl:
627 if (port_num >= aie1_port_id::core::S_CTRL_SIZE)
628 return std::nullopt;
629 return aie1_port_id::core::S_CTRL_OFFSET + port_num;
630 case WireBundle::DMA:
631 if (port_num >= aie1_port_id::core::S_DMA_SIZE)
632 return std::nullopt;
633 return aie1_port_id::core::S_DMA_OFFSET + port_num;
634 case WireBundle::East:
635 if (port_num >= aie1_port_id::core::S_EAST_SIZE)
636 return std::nullopt;
637 return aie1_port_id::core::S_EAST_OFFSET + port_num;
638 case WireBundle::FIFO:
639 if (port_num >= aie1_port_id::core::S_FIFO_SIZE)
640 return std::nullopt;
641 return aie1_port_id::core::S_FIFO_OFFSET + port_num;
642 case WireBundle::North:
643 if (port_num >= aie1_port_id::core::S_NORTH_SIZE)
644 return std::nullopt;
645 return aie1_port_id::core::S_NORTH_OFFSET + port_num;
646 case WireBundle::South:
647 if (port_num >= aie1_port_id::core::S_SOUTH_SIZE)
648 return std::nullopt;
649 return aie1_port_id::core::S_SOUTH_OFFSET + port_num;
650 case WireBundle::Trace:
651 if (port_num >= aie1_port_id::core::S_TRACE_SIZE)
652 return std::nullopt;
653 return aie1_port_id::core::S_TRACE_OFFSET + port_num;
654 case WireBundle::West:
655 if (port_num >= aie1_port_id::core::S_WEST_SIZE)
656 return std::nullopt;
657 return aie1_port_id::core::S_WEST_OFFSET + port_num;
658 default:
659 return std::nullopt;
660 }
661 } else if (isShimNOCorPLTile(col, row)) {
662 switch (bundle) {
663 case WireBundle::TileControl:
664 if (port_num >= aie1_port_id::shim::S_CTRL_SIZE)
665 return std::nullopt;
666 return aie1_port_id::shim::S_CTRL_OFFSET + port_num;
667 case WireBundle::East:
668 if (port_num >= aie1_port_id::shim::S_EAST_SIZE)
669 return std::nullopt;
670 return aie1_port_id::shim::S_EAST_OFFSET + port_num;
671 case WireBundle::FIFO:
672 if (port_num >= aie1_port_id::shim::S_FIFO_SIZE)
673 return std::nullopt;
674 return aie1_port_id::shim::S_FIFO_OFFSET + port_num;
675 case WireBundle::North:
676 if (port_num >= aie1_port_id::shim::S_NORTH_SIZE)
677 return std::nullopt;
678 return aie1_port_id::shim::S_NORTH_OFFSET + port_num;
679 case WireBundle::South:
680 if (port_num >= aie1_port_id::shim::S_SOUTH_SIZE)
681 return std::nullopt;
682 return aie1_port_id::shim::S_SOUTH_OFFSET + port_num;
683 case WireBundle::Trace:
684 if (port_num >= aie1_port_id::shim::S_TRACE_SIZE)
685 return std::nullopt;
686 return aie1_port_id::shim::S_TRACE_OFFSET + port_num;
687 case WireBundle::West:
688 if (port_num >= aie1_port_id::shim::S_WEST_SIZE)
689 return std::nullopt;
690 return aie1_port_id::shim::S_WEST_OFFSET + port_num;
691 default:
692 return std::nullopt;
693 }
694 } else {
695 return std::nullopt;
696 }
697 }
698}
699
700///
701/// AIE2 TargetModel
702///
703
704std::unique_ptr<RegisterDatabase>
708
710
711// Return the tile ID of the memory to the west of the given tile, if it exists.
712std::optional<TileID> AIE2TargetModel::getMemWest(TileID src) const {
713 std::optional<TileID> ret({src.col - 1, src.row});
714 if (!isValidTile(*ret))
715 ret.reset();
716 return ret;
717}
718
719// Return the tile ID of the memory to the east of the given tile (ie self), if
720// it exists.
721std::optional<TileID> AIE2TargetModel::getMemEast(TileID src) const {
722 std::optional ret = src;
723 if (!isValidTile(*ret))
724 ret.reset();
725 return ret;
726}
727
728// Return the tile ID of the memory to the north of the given tile, if it
729// exists.
730std::optional<TileID> AIE2TargetModel::getMemNorth(TileID src) const {
731 std::optional<TileID> ret({src.col, src.row + 1});
732 if (!isValidTile(*ret))
733 ret.reset();
734 return ret;
735}
736
737std::optional<TileID> AIE2TargetModel::getMemSouth(TileID src) const {
738 std::optional<TileID> ret({src.col, src.row - 1});
739 // The first row doesn't have a tile memory south
740 // Memtiles don't have memory adjacency to neighboring core tiles.
741 if (!isValidTile(*ret) || ret->row == 0 || isMemTile(ret->col, ret->row))
742 ret.reset();
743 return ret;
744}
745
746bool AIE2TargetModel::isMemWest(int srcCol, int srcRow, int dstCol,
747 int dstRow) const {
748 return isWest(srcCol, srcRow, dstCol, dstRow);
749}
750
751bool AIE2TargetModel::isMemEast(int srcCol, int srcRow, int dstCol,
752 int dstRow) const {
753 return isInternal(srcCol, srcRow, dstCol, dstRow);
754}
755
756bool AIE2TargetModel::isMemNorth(int srcCol, int srcRow, int dstCol,
757 int dstRow) const {
758 return isNorth(srcCol, srcRow, dstCol, dstRow);
759}
760
761bool AIE2TargetModel::isMemSouth(int srcCol, int srcRow, int dstCol,
762 int dstRow) const {
763 return isSouth(srcCol, srcRow, dstCol, dstRow);
764}
765
766bool AIE2TargetModel::isLegalMemAffinity(int coreCol, int coreRow, int memCol,
767 int memRow) const {
768
769 bool IsMemWest = isMemWest(coreCol, coreRow, memCol, memRow);
770 bool IsMemEast = isMemEast(coreCol, coreRow, memCol, memRow);
771 bool IsMemNorth = isMemNorth(coreCol, coreRow, memCol, memRow);
772 bool IsMemSouth = isMemSouth(coreCol, coreRow, memCol, memRow);
773
774 if (isMemTile(coreCol, coreRow))
775 return isEast(coreCol, coreRow, memCol, memRow) ||
776 isInternal(coreCol, coreRow, memCol, memRow) ||
777 isWest(coreCol, coreRow, memCol, memRow);
778 return (IsMemSouth && !isMemTile(memCol, memRow)) || IsMemNorth ||
779 IsMemWest || IsMemEast;
780}
781
782uint64_t AIE2TargetModel::getDmaBdAddress(int col, int row, uint32_t bd_id,
783 int channel,
784 AIE::DMAChannelDir direction) const {
785 uint64_t offset = 0;
786 if (isShimNOCTile(col, row)) {
787 offset = 0x0001D000 + bd_id * 0x20;
788 } else if (isMemTile(col, row)) {
789 offset = 0x000A0000 + bd_id * 0x20;
790 } else if (isCoreTile(col, row)) {
791 offset = 0x0001D000 + bd_id * 0x20;
792 } else {
793 llvm_unreachable(
794 "AIE2TargetModel::getDmaBdAddress called for non-DMA tile");
795 }
796 return ((col & 0xff) << getColumnShift()) | ((row & 0xff) << getRowShift()) |
797 offset;
798}
799
801 if (isCoreTile(col, row))
802 return 0x0;
803 return 0x4;
804}
805
806uint32_t
808 AIE::DMAChannelDir direction) const {
809 uint32_t offset = 0;
810 if (isShimNOCTile(col, row)) {
811 offset = 0x0001D200 + (channel * 0x8);
812 if (direction == AIE::DMAChannelDir::MM2S)
813 offset += 0x10;
814 } else if (isMemTile(col, row)) {
815 offset = 0x000A0600 + (channel * 0x8);
816 if (direction == AIE::DMAChannelDir::MM2S)
817 offset += 0x30;
818 } else if (isCoreTile(col, row)) {
819 offset = 0x0001DE00 + (channel * 0x8);
820 if (direction == AIE::DMAChannelDir::MM2S)
821 offset += 0x10;
822 } else {
823 llvm_unreachable(
824 "AIE2TargetModel::getDmaControlAddress called for non-DMA tile");
825 }
826
827 return ((col & 0xff) << getColumnShift()) | ((row & 0xff) << getRowShift()) |
828 offset;
829}
830
831uint32_t
833 WireBundle bundle) const {
834 if (isMemTile(col, row))
835 switch (bundle) {
836 case WireBundle::DMA:
837 case WireBundle::North:
838 return 6;
839 case WireBundle::South:
840 return 4;
841 case WireBundle::TileControl:
842 return 1;
843 default:
844 return 0;
845 }
846
848 switch (bundle) {
849 case WireBundle::FIFO:
850 return 1;
851 case WireBundle::North:
852 return 6;
853 case WireBundle::West: {
854 if (col == 0)
855 return 0;
856 return 4;
857 }
858 case WireBundle::South:
859 return 6;
860 case WireBundle::East: {
861 if (col == columns() - 1)
862 return 0;
863 return 4;
864 }
865 case WireBundle::TileControl:
866 return isShimNOCTile(col, row) ? 1 : 0;
867 default:
868 return 0;
869 }
870
871 switch (bundle) {
872 case WireBundle::Core:
873 return 1;
874 case WireBundle::DMA:
875 return 2;
876 case WireBundle::FIFO:
877 return 1;
878 case WireBundle::North: {
879 if (row == rows() - 1)
880 return 0;
881 return 6;
882 }
883 case WireBundle::West: {
884 if (col == 0)
885 return 0;
886 return 4;
887 }
888 case WireBundle::South:
889 return 4;
890 case WireBundle::East: {
891 if (col == columns() - 1)
892 return 0;
893 return 4;
894 }
895 case WireBundle::TileControl:
896 return 1;
897 default:
898 return 0;
899 }
900}
901
902uint32_t
904 WireBundle bundle) const {
905 if (isMemTile(col, row))
906 switch (bundle) {
907 case WireBundle::DMA:
908 return 6;
909 case WireBundle::North:
910 return 4;
911 case WireBundle::South:
912 return 6;
913 case WireBundle::Trace:
914 case WireBundle::TileControl:
915 return 1;
916 default:
917 return 0;
918 }
919
921 switch (bundle) {
922 case WireBundle::FIFO:
923 return 1;
924 case WireBundle::North:
925 return 4;
926 case WireBundle::West: {
927 if (col == 0)
928 return 0;
929 return 4;
930 }
931 case WireBundle::South:
932 return 8;
933 case WireBundle::East: {
934 if (col == columns() - 1)
935 return 0;
936 return 4;
937 }
938 case WireBundle::Trace:
939 return 1;
940 case WireBundle::TileControl:
941 return isShimNOCTile(col, row) ? 1 : 0;
942 default:
943 return 0;
944 }
945
946 // compute/core tile
947 switch (bundle) {
948 case WireBundle::Core:
949 return 1;
950 case WireBundle::DMA:
951 return 2;
952 case WireBundle::FIFO:
953 return 1;
954 case WireBundle::North: {
955 if (row == rows() - 1)
956 return 0;
957 return 4;
958 }
959 case WireBundle::West: {
960 if (col == 0)
961 return 0;
962 return 4;
963 }
964 case WireBundle::South:
965 return 6;
966 case WireBundle::East: {
967 if (col == columns() - 1)
968 return 0;
969 return 4;
970 }
971 case WireBundle::Trace:
972 // Port 0: core trace. Port 1: memory trace.
973 return 2;
974 case WireBundle::TileControl:
975 return 1;
976 default:
977 return 0;
978 }
979}
980
981uint32_t
983 WireBundle bundle) const {
985 switch (bundle) {
986 case WireBundle::DMA:
987 return 2;
988 case WireBundle::NOC:
989 return 4;
990 case WireBundle::PLIO:
991 return 6;
992 case WireBundle::South:
993 return 8; // Connection to the south port of the stream switch
994 default:
995 return 0;
996 }
997
998 return 0;
999}
1000
1001uint32_t
1003 WireBundle bundle) const {
1005 switch (bundle) {
1006 case WireBundle::DMA:
1007 return 2;
1008 case WireBundle::NOC:
1009 return 4;
1010 case WireBundle::PLIO:
1011 return 8;
1012 case WireBundle::South:
1013 return 6; // Connection to the south port of the stream switch
1014 default:
1015 return 0;
1016 }
1017
1018 return 0;
1019}
1020
1022 WireBundle srcBundle, int srcChan,
1023 WireBundle dstBundle,
1024 int dstChan) const {
1025 // Check Channel Id within the range
1026 if (srcChan >= int(getNumSourceSwitchboxConnections(col, row, srcBundle)))
1027 return false;
1028 if (dstChan >= int(getNumDestSwitchboxConnections(col, row, dstBundle)))
1029 return false;
1030
1031 // Lambda function to check if a bundle is in a list
1032 auto isBundleInList = [](WireBundle bundle,
1033 std::initializer_list<WireBundle> bundles) {
1034 return std::find(bundles.begin(), bundles.end(), bundle) != bundles.end();
1035 };
1036
1037 // Memtile
1038 if (isMemTile(col, row)) {
1039 if (srcBundle == WireBundle::DMA) {
1040 if (dstBundle == WireBundle::DMA)
1041 return srcChan == dstChan;
1042 if (isBundleInList(dstBundle, {WireBundle::TileControl, WireBundle::South,
1043 WireBundle::North}))
1044 return true;
1045 }
1046 if (srcBundle == WireBundle::TileControl) {
1047 if (dstBundle == WireBundle::DMA)
1048 return dstChan == 5;
1049 if (isBundleInList(dstBundle, {WireBundle::South, WireBundle::North}))
1050 return true;
1051 }
1052 if (isBundleInList(srcBundle, {WireBundle::South, WireBundle::North})) {
1053 if (isBundleInList(dstBundle, {WireBundle::DMA, WireBundle::TileControl}))
1054 return true;
1055 if (isBundleInList(dstBundle, {WireBundle::South, WireBundle::North}))
1056 return srcChan == dstChan;
1057 }
1058 if (srcBundle == WireBundle::Trace) {
1059 if (dstBundle == WireBundle::DMA)
1060 return dstChan == 5;
1061 if (dstBundle == WireBundle::South)
1062 return true;
1063 }
1064 }
1065 // Shimtile
1066 else if (isShimNOCorPLTile(col, row)) {
1067 if (srcBundle == WireBundle::TileControl)
1068 return dstBundle != WireBundle::TileControl;
1069 if (isBundleInList(srcBundle, {WireBundle::FIFO, WireBundle::South}))
1070 return isBundleInList(dstBundle,
1071 {WireBundle::TileControl, WireBundle::FIFO,
1072 WireBundle::South, WireBundle::West,
1073 WireBundle::North, WireBundle::East});
1074 if (isBundleInList(srcBundle,
1075 {WireBundle::West, WireBundle::North, WireBundle::East}))
1076 return (srcBundle == dstBundle)
1077 ? (srcChan == dstChan)
1078 : isBundleInList(dstBundle,
1079 {WireBundle::TileControl, WireBundle::FIFO,
1080 WireBundle::South, WireBundle::West,
1081 WireBundle::North, WireBundle::East});
1082 if (srcBundle == WireBundle::Trace) {
1083 if (isBundleInList(dstBundle, {WireBundle::FIFO, WireBundle::South}))
1084 return true;
1085 if (isBundleInList(dstBundle, {WireBundle::West, WireBundle::East}))
1086 return dstChan == 0;
1087 }
1088 }
1089 // Coretile
1090 else if (isCoreTile(col, row)) {
1091 if (isBundleInList(srcBundle,
1092 {WireBundle::DMA, WireBundle::FIFO, WireBundle::South,
1093 WireBundle::West, WireBundle::North, WireBundle::East}))
1094 if (isBundleInList(dstBundle, {WireBundle::Core, WireBundle::DMA,
1095 WireBundle::TileControl, WireBundle::FIFO,
1096 WireBundle::South, WireBundle::West,
1097 WireBundle::North, WireBundle::East}))
1098 return (srcBundle == dstBundle) ? (srcChan == dstChan) : true;
1099 if (srcBundle == WireBundle::Core)
1100 return dstBundle != WireBundle::Core;
1101 if (srcBundle == WireBundle::TileControl)
1102 return dstBundle != WireBundle::TileControl &&
1103 dstBundle != WireBundle::DMA;
1104 if (srcBundle == WireBundle::Trace) {
1105 if (dstBundle == WireBundle::DMA)
1106 return dstChan == 0;
1107 if (isBundleInList(dstBundle, {WireBundle::FIFO, WireBundle::South}))
1108 return true;
1109 }
1110 }
1111 return false;
1112}
1113
1114std::vector<std::pair<uint32_t, uint32_t>>
1116 return {std::pair(0, 64), std::pair(1, 128), std::pair(2, 256)};
1117}
1118
1119std::optional<uint32_t>
1120AIE2TargetModel::getLocalLockAddress(uint32_t lockId, TileID tile) const {
1121 auto computeTileBaseAddress = 0x0001F000;
1122 auto memTileBaseAddress = 0x000C0000;
1123 auto shimTileBaseAddress = 0x00014000;
1124 auto lockAddrOffset = 0x10;
1125
1126 if (isCoreTile(tile.col, tile.row) &&
1127 lockId < getNumLocks(tile.col, tile.row))
1128 return computeTileBaseAddress + lockAddrOffset * lockId;
1129
1130 if (isMemTile(tile.col, tile.row) && lockId < getNumLocks(tile.col, tile.row))
1131 return memTileBaseAddress + lockAddrOffset * lockId;
1132
1133 if (isShimNOCorPLTile(tile.col, tile.row) &&
1134 lockId < getNumLocks(tile.col, tile.row))
1135 return shimTileBaseAddress + lockAddrOffset * lockId;
1136
1137 return std::nullopt;
1138}
1139
1140namespace {
1141namespace aie2_port_id {
1142namespace core {
1143
1144// Slave port offset/size constants
1145static constexpr uint32_t S_CORE_OFFSET = 0;
1146static constexpr uint32_t S_CORE_SIZE = 1;
1147static constexpr uint32_t S_CTRL_OFFSET = 3;
1148static constexpr uint32_t S_CTRL_SIZE = 1;
1149static constexpr uint32_t S_DMA_OFFSET = 1;
1150static constexpr uint32_t S_DMA_SIZE = 2;
1151static constexpr uint32_t S_EAST_OFFSET = 19;
1152static constexpr uint32_t S_EAST_SIZE = 4;
1153static constexpr uint32_t S_FIFO_OFFSET = 4;
1154static constexpr uint32_t S_FIFO_SIZE = 1;
1155static constexpr uint32_t S_NORTH_OFFSET = 15;
1156static constexpr uint32_t S_NORTH_SIZE = 4;
1157static constexpr uint32_t S_SOUTH_OFFSET = 5;
1158static constexpr uint32_t S_SOUTH_SIZE = 6;
1159static constexpr uint32_t S_TRACE_OFFSET = 23;
1160static constexpr uint32_t S_TRACE_SIZE = 2;
1161static constexpr uint32_t S_WEST_OFFSET = 11;
1162static constexpr uint32_t S_WEST_SIZE = 4;
1163
1164// Master port offset/size constants
1165static constexpr uint32_t M_CORE_OFFSET = 0;
1166static constexpr uint32_t M_CORE_SIZE = 1;
1167static constexpr uint32_t M_CTRL_OFFSET = 3;
1168static constexpr uint32_t M_CTRL_SIZE = 1;
1169static constexpr uint32_t M_DMA_OFFSET = 1;
1170static constexpr uint32_t M_DMA_SIZE = 2;
1171static constexpr uint32_t M_EAST_OFFSET = 19;
1172static constexpr uint32_t M_EAST_SIZE = 4;
1173static constexpr uint32_t M_FIFO_OFFSET = 4;
1174static constexpr uint32_t M_FIFO_SIZE = 1;
1175static constexpr uint32_t M_NORTH_OFFSET = 13;
1176static constexpr uint32_t M_NORTH_SIZE = 6;
1177static constexpr uint32_t M_SOUTH_OFFSET = 5;
1178static constexpr uint32_t M_SOUTH_SIZE = 4;
1179static constexpr uint32_t M_WEST_OFFSET = 9;
1180static constexpr uint32_t M_WEST_SIZE = 4;
1181
1182} // namespace core
1183
1184namespace mem {
1185
1186// Slave port offset/size constants
1187static constexpr uint32_t S_CTRL_OFFSET = 6;
1188static constexpr uint32_t S_CTRL_SIZE = 1;
1189static constexpr uint32_t S_DMA_OFFSET = 0;
1190static constexpr uint32_t S_DMA_SIZE = 6;
1191static constexpr uint32_t S_NORTH_OFFSET = 13;
1192static constexpr uint32_t S_NORTH_SIZE = 4;
1193static constexpr uint32_t S_SOUTH_OFFSET = 7;
1194static constexpr uint32_t S_SOUTH_SIZE = 6;
1195static constexpr uint32_t S_TRACE_OFFSET = 17;
1196static constexpr uint32_t S_TRACE_SIZE = 1;
1197
1198// Master port offset/size constants
1199static constexpr uint32_t M_CTRL_OFFSET = 6;
1200static constexpr uint32_t M_CTRL_SIZE = 1;
1201static constexpr uint32_t M_DMA_OFFSET = 0;
1202static constexpr uint32_t M_DMA_SIZE = 6;
1203static constexpr uint32_t M_NORTH_OFFSET = 11;
1204static constexpr uint32_t M_NORTH_SIZE = 6;
1205static constexpr uint32_t M_SOUTH_OFFSET = 7;
1206static constexpr uint32_t M_SOUTH_SIZE = 4;
1207
1208} // namespace mem
1209
1210namespace shim {
1211
1212// Slave port offset/size constants
1213static constexpr uint32_t S_CTRL_OFFSET = 0;
1214static constexpr uint32_t S_CTRL_SIZE = 1;
1215static constexpr uint32_t S_EAST_OFFSET = 18;
1216static constexpr uint32_t S_EAST_SIZE = 4;
1217static constexpr uint32_t S_FIFO_OFFSET = 1;
1218static constexpr uint32_t S_FIFO_SIZE = 1;
1219static constexpr uint32_t S_NORTH_OFFSET = 14;
1220static constexpr uint32_t S_NORTH_SIZE = 4;
1221static constexpr uint32_t S_SOUTH_OFFSET = 2;
1222static constexpr uint32_t S_SOUTH_SIZE = 8;
1223static constexpr uint32_t S_TRACE_OFFSET = 22;
1224static constexpr uint32_t S_TRACE_SIZE = 2;
1225static constexpr uint32_t S_WEST_OFFSET = 10;
1226static constexpr uint32_t S_WEST_SIZE = 4;
1227
1228// Master port offset/size constants
1229static constexpr uint32_t M_CTRL_OFFSET = 0;
1230static constexpr uint32_t M_CTRL_SIZE = 1;
1231static constexpr uint32_t M_EAST_OFFSET = 18;
1232static constexpr uint32_t M_EAST_SIZE = 4;
1233static constexpr uint32_t M_FIFO_OFFSET = 1;
1234static constexpr uint32_t M_FIFO_SIZE = 1;
1235static constexpr uint32_t M_NORTH_OFFSET = 12;
1236static constexpr uint32_t M_NORTH_SIZE = 6;
1237static constexpr uint32_t M_SOUTH_OFFSET = 2;
1238static constexpr uint32_t M_SOUTH_SIZE = 6;
1239static constexpr uint32_t M_WEST_OFFSET = 8;
1240static constexpr uint32_t M_WEST_SIZE = 4;
1241
1242} // namespace shim
1243} // namespace aie2_port_id
1244} // namespace
1245
1247 int col, int row, WireBundle bundle, uint32_t port_num, bool master) const {
1248
1249 if (master) {
1250 if (isCoreTile(col, row)) {
1251 switch (bundle) {
1252 case WireBundle::Core:
1253 if (port_num >= aie2_port_id::core::M_CORE_SIZE)
1254 return std::nullopt;
1255 return aie2_port_id::core::M_CORE_OFFSET + port_num;
1256 case WireBundle::TileControl:
1257 if (port_num >= aie2_port_id::core::M_CTRL_SIZE)
1258 return std::nullopt;
1259 return aie2_port_id::core::M_CTRL_OFFSET + port_num;
1260 case WireBundle::DMA:
1261 if (port_num >= aie2_port_id::core::M_DMA_SIZE)
1262 return std::nullopt;
1263 return aie2_port_id::core::M_DMA_OFFSET + port_num;
1264 case WireBundle::East:
1265 if (port_num >= aie2_port_id::core::M_EAST_SIZE)
1266 return std::nullopt;
1267 return aie2_port_id::core::M_EAST_OFFSET + port_num;
1268 case WireBundle::FIFO:
1269 if (port_num >= aie2_port_id::core::M_FIFO_SIZE)
1270 return std::nullopt;
1271 return aie2_port_id::core::M_FIFO_OFFSET + port_num;
1272 case WireBundle::North:
1273 if (port_num >= aie2_port_id::core::M_NORTH_SIZE)
1274 return std::nullopt;
1275 return aie2_port_id::core::M_NORTH_OFFSET + port_num;
1276 case WireBundle::South:
1277 if (port_num >= aie2_port_id::core::M_SOUTH_SIZE)
1278 return std::nullopt;
1279 return aie2_port_id::core::M_SOUTH_OFFSET + port_num;
1280 case WireBundle::West:
1281 if (port_num >= aie2_port_id::core::M_WEST_SIZE)
1282 return std::nullopt;
1283 return aie2_port_id::core::M_WEST_OFFSET + port_num;
1284 default:
1285 return std::nullopt;
1286 }
1287 } else if (isMemTile(col, row)) {
1288 switch (bundle) {
1289 case WireBundle::TileControl:
1290 if (port_num >= aie2_port_id::mem::M_CTRL_SIZE)
1291 return std::nullopt;
1292 return aie2_port_id::mem::M_CTRL_OFFSET + port_num;
1293 case WireBundle::DMA:
1294 if (port_num >= aie2_port_id::mem::M_DMA_SIZE)
1295 return std::nullopt;
1296 return aie2_port_id::mem::M_DMA_OFFSET + port_num;
1297 case WireBundle::North:
1298 if (port_num >= aie2_port_id::mem::M_NORTH_SIZE)
1299 return std::nullopt;
1300 return aie2_port_id::mem::M_NORTH_OFFSET + port_num;
1301 case WireBundle::South:
1302 if (port_num >= aie2_port_id::mem::M_SOUTH_SIZE)
1303 return std::nullopt;
1304 return aie2_port_id::mem::M_SOUTH_OFFSET + port_num;
1305 default:
1306 return std::nullopt;
1307 }
1308 } else if (isShimNOCTile(col, row)) {
1309 switch (bundle) {
1310 case WireBundle::TileControl:
1311 if (port_num >= aie2_port_id::shim::M_CTRL_SIZE)
1312 return std::nullopt;
1313 return aie2_port_id::shim::M_CTRL_OFFSET + port_num;
1314 case WireBundle::East:
1315 if (port_num >= aie2_port_id::shim::M_EAST_SIZE)
1316 return std::nullopt;
1317 return aie2_port_id::shim::M_EAST_OFFSET + port_num;
1318 case WireBundle::FIFO:
1319 if (port_num >= aie2_port_id::shim::M_FIFO_SIZE)
1320 return std::nullopt;
1321 return aie2_port_id::shim::M_FIFO_OFFSET + port_num;
1322 case WireBundle::North:
1323 if (port_num >= aie2_port_id::shim::M_NORTH_SIZE)
1324 return std::nullopt;
1325 return aie2_port_id::shim::M_NORTH_OFFSET + port_num;
1326 case WireBundle::South:
1327 if (port_num >= aie2_port_id::shim::M_SOUTH_SIZE)
1328 return std::nullopt;
1329 return aie2_port_id::shim::M_SOUTH_OFFSET + port_num;
1330 case WireBundle::West:
1331 if (port_num >= aie2_port_id::shim::M_WEST_SIZE)
1332 return std::nullopt;
1333 return aie2_port_id::shim::M_WEST_OFFSET + port_num;
1334 default:
1335 return std::nullopt;
1336 }
1337 }
1338 // Slave ports
1339 } else {
1340
1341 if (isCoreTile(col, row)) {
1342 switch (bundle) {
1343 case WireBundle::Core:
1344 if (port_num >= aie2_port_id::core::S_CORE_SIZE)
1345 return std::nullopt;
1346 return aie2_port_id::core::S_CORE_OFFSET + port_num;
1347 case WireBundle::TileControl:
1348 if (port_num >= aie2_port_id::core::S_CTRL_SIZE)
1349 return std::nullopt;
1350 return aie2_port_id::core::S_CTRL_OFFSET + port_num;
1351 case WireBundle::DMA:
1352 if (port_num >= aie2_port_id::core::S_DMA_SIZE)
1353 return std::nullopt;
1354 return aie2_port_id::core::S_DMA_OFFSET + port_num;
1355 case WireBundle::East:
1356 if (port_num >= aie2_port_id::core::S_EAST_SIZE)
1357 return std::nullopt;
1358 return aie2_port_id::core::S_EAST_OFFSET + port_num;
1359 case WireBundle::FIFO:
1360 if (port_num >= aie2_port_id::core::S_FIFO_SIZE)
1361 return std::nullopt;
1362 return aie2_port_id::core::S_FIFO_OFFSET + port_num;
1363 case WireBundle::North:
1364 if (port_num >= aie2_port_id::core::S_NORTH_SIZE)
1365 return std::nullopt;
1366 return aie2_port_id::core::S_NORTH_OFFSET + port_num;
1367 case WireBundle::South:
1368 if (port_num >= aie2_port_id::core::S_SOUTH_SIZE)
1369 return std::nullopt;
1370 return aie2_port_id::core::S_SOUTH_OFFSET + port_num;
1371 case WireBundle::Trace:
1372 if (port_num >= aie2_port_id::core::S_TRACE_SIZE)
1373 return std::nullopt;
1374 return aie2_port_id::core::S_TRACE_OFFSET + port_num;
1375 case WireBundle::West:
1376 if (port_num >= aie2_port_id::core::S_WEST_SIZE)
1377 return std::nullopt;
1378 return aie2_port_id::core::S_WEST_OFFSET + port_num;
1379 default:
1380 return std::nullopt;
1381 }
1382 } else if (isMemTile(col, row)) {
1383 switch (bundle) {
1384 case WireBundle::TileControl:
1385 if (port_num >= aie2_port_id::mem::S_CTRL_SIZE)
1386 return std::nullopt;
1387 return aie2_port_id::mem::S_CTRL_OFFSET + port_num;
1388 case WireBundle::DMA:
1389 if (port_num >= aie2_port_id::mem::S_DMA_SIZE)
1390 return std::nullopt;
1391 return aie2_port_id::mem::S_DMA_OFFSET + port_num;
1392 case WireBundle::North:
1393 if (port_num >= aie2_port_id::mem::S_NORTH_SIZE)
1394 return std::nullopt;
1395 return aie2_port_id::mem::S_NORTH_OFFSET + port_num;
1396 case WireBundle::South:
1397 if (port_num >= aie2_port_id::mem::S_SOUTH_SIZE)
1398 return std::nullopt;
1399 return aie2_port_id::mem::S_SOUTH_OFFSET + port_num;
1400 case WireBundle::Trace:
1401 if (port_num >= aie2_port_id::mem::S_TRACE_SIZE)
1402 return std::nullopt;
1403 return aie2_port_id::mem::S_TRACE_OFFSET + port_num;
1404 default:
1405 return std::nullopt;
1406 }
1407 } else if (isShimNOCTile(col, row)) {
1408 switch (bundle) {
1409 case WireBundle::TileControl:
1410 if (port_num >= aie2_port_id::shim::S_CTRL_SIZE)
1411 return std::nullopt;
1412 return aie2_port_id::shim::S_CTRL_OFFSET + port_num;
1413 case WireBundle::East:
1414 if (port_num >= aie2_port_id::shim::S_EAST_SIZE)
1415 return std::nullopt;
1416 return aie2_port_id::shim::S_EAST_OFFSET + port_num;
1417 case WireBundle::FIFO:
1418 if (port_num >= aie2_port_id::shim::S_FIFO_SIZE)
1419 return std::nullopt;
1420 return aie2_port_id::shim::S_FIFO_OFFSET + port_num;
1421 case WireBundle::North:
1422 if (port_num >= aie2_port_id::shim::S_NORTH_SIZE)
1423 return std::nullopt;
1424 return aie2_port_id::shim::S_NORTH_OFFSET + port_num;
1425 case WireBundle::South:
1426 if (port_num >= aie2_port_id::shim::S_SOUTH_SIZE)
1427 return std::nullopt;
1428 return aie2_port_id::shim::S_SOUTH_OFFSET + port_num;
1429 case WireBundle::Trace:
1430 if (port_num >= aie2_port_id::shim::S_TRACE_SIZE)
1431 return std::nullopt;
1432 return aie2_port_id::shim::S_TRACE_OFFSET + port_num;
1433 case WireBundle::West:
1434 if (port_num >= aie2_port_id::shim::S_WEST_SIZE)
1435 return std::nullopt;
1436 return aie2_port_id::shim::S_WEST_OFFSET + port_num;
1437 default:
1438 return std::nullopt;
1439 }
1440 }
1441 }
1442 return std::nullopt;
1443}
1444
1446 // Every tile in a shimtile row must be a shimtile, and can only be one type
1447 // of shim tile.
1448 for (int j = 0; j < columns(); j++) {
1449 assert(!isMemTile(j, 0) && (isShimPLTile(j, 0) || isShimNOCTile(j, 0)) &&
1450 !isCoreTile(j, 0));
1451 assert(isShimPLTile(j, 0) ^ isShimNOCTile(j, 0));
1452 }
1453
1454 // Every tile in a memtile row must be a memtile.
1455 for (int i = 1; i < 1 + static_cast<int>(getNumMemTileRows()); i++)
1456 for (int j = 0; j < columns(); j++)
1457 assert(isMemTile(j, i) && !isShimPLTile(j, i) && !isShimNOCTile(j, i) &&
1458 !isCoreTile(j, i));
1459
1460 // Every other tile is a coretile.
1461 for (int i = 1 + getNumMemTileRows(); i < rows(); i++)
1462 for (int j = 0; j < columns(); j++)
1463 assert(!isMemTile(j, i) && !isShimPLTile(j, i) && !isShimNOCTile(j, i) &&
1464 isCoreTile(j, i));
1465
1466 // Looking North, buses must match
1467 for (int i = 0; i < rows() - 1; i++)
1468 for (int j = 0; j < columns(); j++)
1469 assert(getNumSourceSwitchboxConnections(j, i, WireBundle::North) ==
1470 getNumDestSwitchboxConnections(j, i + 1, WireBundle::South));
1471 // Looking South, buses must match
1472 for (int i = 1; i < rows(); i++)
1473 for (int j = 0; j < columns(); j++)
1474 assert(getNumSourceSwitchboxConnections(j, i, WireBundle::South) ==
1475 getNumDestSwitchboxConnections(j, i - 1, WireBundle::North));
1476 // Looking East, buses must match
1477 for (int i = 0; i < rows(); i++)
1478 for (int j = 0; j < columns() - 1; j++)
1479 assert(getNumSourceSwitchboxConnections(j, i, WireBundle::East) ==
1480 getNumDestSwitchboxConnections(j + 1, i, WireBundle::West));
1481 // Looking West, buses must match
1482 for (int i = 0; i < rows(); i++)
1483 for (int j = 1; j < columns(); j++)
1484 assert(getNumSourceSwitchboxConnections(j, i, WireBundle::West) ==
1485 getNumDestSwitchboxConnections(j - 1, i, WireBundle::East));
1486 // Edges have no connections
1487 for (int j = 0; j < columns(); j++)
1488 assert(getNumSourceSwitchboxConnections(j, rows() - 1, WireBundle::North) ==
1489 0);
1490 for (int i = 0; i < rows(); i++)
1492 WireBundle::East) == 0);
1493 for (int i = 0; i < rows(); i++)
1494 assert(getNumSourceSwitchboxConnections(0, i, WireBundle::West) == 0);
1495
1496 // FIFOS are consistent
1497 for (int i = 0; i < rows(); i++)
1498 for (int j = 0; j < columns(); j++)
1499 assert(getNumSourceSwitchboxConnections(j, i, WireBundle::FIFO) ==
1500 getNumDestSwitchboxConnections(j, i, WireBundle::FIFO));
1501}
1502
1503std::optional<uint32_t>
1504AIETargetModel::getLockLocalBaseIndex(int localCol, int localRow, int lockCol,
1505 int lockRow) const {
1506 if (isCoreTile(localCol, localRow)) {
1507 if (isMemSouth(localCol, localRow, lockCol, lockRow))
1508 return 0;
1509 if (isMemWest(localCol, localRow, lockCol, lockRow))
1510 return getNumLocks(localCol, localRow);
1511 if (isMemNorth(localCol, localRow, lockCol, lockRow))
1512 return getNumLocks(localCol, localRow) * 2;
1513 if (isMemEast(localCol, localRow, lockCol, lockRow))
1514 return getNumLocks(localCol, localRow) * 3;
1515 }
1516
1517 if (isMemTile(localCol, localRow)) {
1518 if (isWest(localCol, localRow, lockCol, lockRow))
1519 return 0;
1520 if (isInternal(localCol, localRow, lockCol, lockRow))
1521 return getNumLocks(localCol, localRow);
1522 if (isEast(localCol, localRow, lockCol, lockRow))
1523 return getNumLocks(localCol, localRow) * 2;
1524 }
1525
1526 return std::nullopt;
1527}
1528
1529std::optional<uint32_t>
1530AIETargetModel::getMemLocalBaseAddress(int localCol, int localRow, int memCol,
1531 int memRow) const {
1532 if (isCoreTile(localCol, localRow)) {
1533 if (isMemSouth(localCol, localRow, memCol, memRow))
1534 return getMemSouthBaseAddress();
1535 if (isMemWest(localCol, localRow, memCol, memRow))
1536 return getMemWestBaseAddress();
1537 if (isMemNorth(localCol, localRow, memCol, memRow))
1538 return getMemNorthBaseAddress();
1539 if (isMemEast(localCol, localRow, memCol, memRow))
1540 return getMemEastBaseAddress();
1541 }
1542
1543 if (isMemTile(localCol, localRow)) {
1544 if (isWest(localCol, localRow, memCol, memRow))
1545 return 0;
1546 if (isInternal(localCol, localRow, memCol, memRow))
1547 return getMemTileSize();
1548 if (isEast(localCol, localRow, memCol, memRow))
1549 return getMemTileSize() * 2;
1550 }
1551
1552 return std::nullopt;
1553}
1554
1555bool AIETargetModel::isSupportedBlockFormat(std::string const &format) const {
1556 return false;
1557}
1558
1559AIEArch BaseNPU2TargetModel::getTargetArch() const { return AIEArch::AIE2p; }
1560
1561std::vector<std::pair<uint32_t, uint32_t>>
1563 return {std::pair(0, 64), std::pair(1, 128), std::pair(2, 256),
1564 std::pair(3, 512)};
1565}
1566
1568 std::string const &format) const {
1569 std::set<std::string> supportedTypes = {"v8bfp16ebs8", "v16bfp16ebs16"};
1570 return static_cast<bool>(supportedTypes.find(format) != supportedTypes.end());
1571}
1572
1573} // namespace AIE
1574} // namespace xilinx
bool isMemNorth(int srcCol, int srcRow, int dstCol, int dstRow) const override
Return true if src has a memory tile which is North of dst.
std::optional< uint32_t > getStreamSwitchPortIndex(int col, int row, WireBundle bundle, uint32_t channel, bool master) const override
Get stream switch port index for a given port specification Return port index for Stream_Switch_Event...
uint32_t getDmaControlAddress(int col, int row, int channel, AIE::DMAChannelDir direction) const override
Return the array address of the dma task queue register for the given col, row, channel and direction...
std::optional< TileID > getMemSouth(TileID src) const override
Return the tile ID of the memory to the south of the given tile, if it exists.
std::optional< uint32_t > getLocalLockAddress(uint32_t lockId, TileID tile) const override
std::optional< TileID > getMemNorth(TileID src) const override
Return the tile ID of the memory to the north of the given tile, if it exists.
bool isMemSouth(int srcCol, int srcRow, int dstCol, int dstRow) const override
Return true if src has a memory tile which is South of dst.
std::optional< TileID > getMemWest(TileID src) const override
Return the tile ID of the memory to the west of the given tile, if it exists.
bool isLegalMemAffinity(int coreCol, int coreRow, int memCol, int memRow) const override
Return true if core can access the memory in mem.
uint64_t getDmaBdAddress(int col, int row, uint32_t bd_id, int channel, AIE::DMAChannelDir direction) const override
Return the array address of the dma buffer descriptor for the given col, row, buffer descriptor id,...
uint32_t getRowShift() const override
uint32_t getNumSourceShimMuxConnections(int col, int row, WireBundle bundle) const override
Return the number of sources of connections inside a shimmux.
uint32_t getNumDestSwitchboxConnections(int col, int row, WireBundle bundle) const override
Return the number of destinations of connections inside a switchbox.
uint32_t getColumnShift() const override
bool isMemEast(int srcCol, int srcRow, int dstCol, int dstRow) const override
Return true if src has a memory tile which is East of dst.
bool isMemWest(int srcCol, int srcRow, int dstCol, int dstRow) const override
Return true if src has a memory tile which is West of dst.
uint32_t getDmaBdAddressOffset(int col, int row) const override
Return the offset of the base address field within the shim dma buffer descriptor.
std::vector< std::pair< uint32_t, uint32_t > > getShimBurstEncodingsAndLengths() const override
AIEArch getTargetArch() const override
AIE1 TargetModel.
uint32_t getNumDestShimMuxConnections(int col, int row, WireBundle bundle) const override
Return the number of destinations of connections inside a shimmux.
std::optional< TileID > getMemEast(TileID src) const override
Return the tile ID of the memory to the east of the given tile, if it exists.
bool isLegalTileConnection(int col, int row, WireBundle srcBundle, int srcChan, WireBundle dstBundle, int dstChan) const override
uint32_t getNumSourceSwitchboxConnections(int col, int row, WireBundle bundle) const override
Return the number of sources of connections inside a switchbox.
uint32_t getRowShift() const override
bool isLegalTileConnection(int col, int row, WireBundle srcBundle, int srcChan, WireBundle dstBundle, int dstChan) const override
uint32_t getNumSourceSwitchboxConnections(int col, int row, WireBundle bundle) const override
Return the number of sources of connections inside a switchbox.
std::vector< std::pair< uint32_t, uint32_t > > getShimBurstEncodingsAndLengths() const override
uint32_t getNumLocks(AIETileType tileType) const override
Return the number of lock objects for a given tile type.
std::optional< TileID > getMemWest(TileID src) const override
Return the tile ID of the memory to the west of the given tile, if it exists.
std::unique_ptr< RegisterDatabase > loadRegisterDatabase() const override
AIE2 TargetModel.
std::optional< uint32_t > getStreamSwitchPortIndex(int col, int row, WireBundle bundle, uint32_t channel, bool master) const override
Get stream switch port index for a given port specification Return port index for Stream_Switch_Event...
AIEArch getTargetArch() const override
Return the target architecture.
bool isLegalMemAffinity(int coreCol, int coreRow, int memCol, int memRow) const override
Return true if core can access the memory in mem.
std::optional< TileID > getMemEast(TileID src) const override
Return the tile ID of the memory to the east of the given tile, if it exists.
bool isMemNorth(int srcCol, int srcRow, int dstCol, int dstRow) const override
Return true if src has a memory tile which is North of dst.
uint32_t getNumDestShimMuxConnections(int col, int row, WireBundle bundle) const override
Return the number of destinations of connections inside a shimmux.
uint32_t getColumnShift() const override
uint64_t getDmaBdAddress(int col, int row, uint32_t bd_id, int channel, AIE::DMAChannelDir direction) const override
Return the array address of the dma buffer descriptor for the given col, row, buffer descriptor id,...
uint32_t getDmaControlAddress(int col, int row, int channel, AIE::DMAChannelDir direction) const override
Return the array address of the dma task queue register for the given col, row, channel and direction...
std::optional< uint32_t > getLocalLockAddress(uint32_t lockId, TileID tile) const override
std::optional< TileID > getMemSouth(TileID src) const override
Return the tile ID of the memory to the south of the given tile, if it exists.
uint32_t getNumDestSwitchboxConnections(int col, int row, WireBundle bundle) const override
Return the number of destinations of connections inside a switchbox.
bool isMemWest(int srcCol, int srcRow, int dstCol, int dstRow) const override
Return true if src has a memory tile which is West of dst.
bool isMemSouth(int srcCol, int srcRow, int dstCol, int dstRow) const override
Return true if src has a memory tile which is South of dst.
std::optional< TileID > getMemNorth(TileID src) const override
Return the tile ID of the memory to the north of the given tile, if it exists.
bool isMemEast(int srcCol, int srcRow, int dstCol, int dstRow) const override
Return true if src has a memory tile which is East of dst.
uint32_t getNumSourceShimMuxConnections(int col, int row, WireBundle bundle) const override
Return the number of sources of connections inside a shimmux.
uint32_t getDmaBdAddressOffset(int col, int row) const override
Return the offset of the base address field within the shim dma buffer descriptor.
std::optional< uint32_t > resolvePortValue(llvm::StringRef value, TileID tile, bool master) const
Resolve stream switch port specification to port index.
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...
bool isNorth(int srcCol, int srcRow, int dstCol, int dstRow) const
Return true if src is North of dst.
bool isSouth(int srcCol, int srcRow, int dstCol, int dstRow) const
Return true if src is South of dst.
bool isWest(int srcCol, int srcRow, int dstCol, int dstRow) const
Return true if src is West of dst.
virtual bool isSupportedBlockFormat(std::string const &format) const
bool isCoreTile(int col, int row) const
Return true if the given tile is a Core tile.
virtual bool isMemNorth(int srcCol, int srcRow, int dstCol, int dstRow) const =0
Return true if src has a memory tile which is North of dst.
bool isMemTile(int col, int row) const
Return true if the given tile is a Mem tile.
virtual uint32_t getMemSouthBaseAddress() const =0
Return the base address in the local address map for a core.
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...
std::optional< uint32_t > getFieldMask(const BitFieldInfo &field) const
Compute a 32-bit mask for a register field.
virtual uint32_t getNumLocks(AIETileType tileType) const =0
Return the number of lock objects for a given tile type.
uint32_t encodeFieldValue(const BitFieldInfo &field, uint32_t value) const
Encode a field value with proper bit shifting.
std::optional< uint32_t > lookupEvent(llvm::StringRef name, TileID tile, bool isMem=false) const
Lookup event number by name and tile.
const RegisterInfo * lookupRegister(llvm::StringRef name, TileID tile, bool isMem=false) const
Register Database API - provides access to register and event information for trace configuration and...
const RegisterDatabase * getRegisterDatabase() const
Get the register database, loading it lazily on first access.
virtual bool isMemEast(int srcCol, int srcRow, int dstCol, int dstRow) const =0
Return true if src has a memory tile which is East of dst.
bool isShimPLTile(int col, int row) const
Return true if the given tile is a ShimPL tile.
virtual bool isValidTile(TileID src) const
Return true if the given tile ID is valid.
bool isEast(int srcCol, int srcRow, int dstCol, int dstRow) const
Return true if src is East of dst.
virtual bool isMemSouth(int srcCol, int srcRow, int dstCol, int dstRow) const =0
Return true if src has a memory tile which is South of dst.
bool isShimNOCorPLTile(int col, int row) const
Return true if the given tile is either a ShimNOC or ShimPL tile.
virtual uint32_t getMemWestBaseAddress() const =0
Return the base address in the local address map for a core.
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 std::unique_ptr< RegisterDatabase > loadRegisterDatabase() const
Subclasses override to provide architecture-specific database loading.
virtual uint32_t getMemNorthBaseAddress() const =0
Return the base address in the local address map for a core.
virtual int columns() const =0
Return the number of columns in the device.
virtual uint32_t getMemEastBaseAddress() const =0
Return the base address in the local address map for a core.
virtual uint32_t getNumMemTileRows() const =0
virtual bool isMemWest(int srcCol, int srcRow, int dstCol, int dstRow) const =0
Return true if src has a memory tile which is West of dst.
virtual uint32_t getNumDestSwitchboxConnections(int col, int row, WireBundle bundle) const =0
Return the number of destinations of connections inside a switchbox.
bool isInternal(int srcCol, int srcRow, int dstCol, int dstRow) const
Return true if src is the internal memory of dst.
virtual uint32_t getMemTileSize() const =0
Return the size (in bytes) of a MemTile.
virtual std::optional< uint32_t > getStreamSwitchPortIndex(int col, int row, WireBundle bundle, uint32_t channel, bool master) const =0
Get stream switch port index for a given port specification Return port index for Stream_Switch_Event...
virtual uint32_t getNumSourceSwitchboxConnections(int col, int row, WireBundle bundle) const =0
Return the number of sources of connections inside a switchbox.
std::vector< std::pair< uint32_t, uint32_t > > getShimBurstEncodingsAndLengths() const override
AIEArch getTargetArch() const override
Return the target architecture.
bool isSupportedBlockFormat(std::string const &format) const override
Register and event database for a specific architecture.
static std::unique_ptr< RegisterDatabase > loadAIE2()
Load database for AIE2 architecture.
TileID { friend std::ostream &operator<<(std::ostream &os, const TileID &s) { os<< "TileID("<< s.col<< ", "<< s.row<< ")" TileID
PathEndPoint src
AIEArch
Definition Passes.h:21
Bit field information for a register.