MLIR-AIE 1.4.5.dev
AIETargetModel.cpp
Go to the documentation of this file.
1//===- AIETargetModel.cpp ---------------------------------------*- C++ -*-===//
2//
3// Copyright (C) 2019-2022 Xilinx, Inc.
4// Copyright (C) 2023 Advanced Micro Devices, Inc.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
11#include "llvm/ADT/STLExtras.h"
12#include "llvm/Support/ErrorHandling.h"
13#include <cstdint>
14#include <utility>
15
16using namespace llvm;
17
18namespace xilinx {
19namespace AIE {
20
21namespace {
22
23std::string getModuleForTile(const AIETargetModel &model, TileID tile,
24 bool isMem) {
25 if (model.isShimNOCorPLTile(tile.col, tile.row))
26 return "shim";
27 if (model.isMemTile(tile.col, tile.row))
28 return "memory_tile";
29 return isMem ? std::string("memory") : std::string("core");
30}
31
32// Get module name for event lookups (events database uses different names)
33std::string getModuleForTileEvents(const AIETargetModel &model, TileID tile,
34 bool isMem) {
35 if (model.isShimNOCorPLTile(tile.col, tile.row))
36 return "pl"; // Events database uses "pl" for shim tiles
37 if (model.isMemTile(tile.col, tile.row))
38 return "mem_tile"; // Events database uses "mem_tile" instead of
39 // "memory_tile"
40 return isMem ? std::string("memory") : std::string("core");
41}
42
43} // namespace
44
46
47// Base class implementations for register database
48
49std::unique_ptr<RegisterDatabase> AIETargetModel::loadRegisterDatabase() const {
50 // Default: no register database available
51 return nullptr;
52}
53
55 std::call_once(regDBInitFlag, [this]() { regDB = loadRegisterDatabase(); });
56 return regDB.get();
57}
58
59const RegisterInfo *AIETargetModel::lookupRegister(llvm::StringRef name,
60 TileID tile,
61 bool isMem) const {
62 const auto *db = getRegisterDatabase();
63 if (!db)
64 return nullptr;
65 return db->lookupRegister(name, getModuleForTile(*this, tile, isMem));
66}
67
68std::optional<uint32_t> AIETargetModel::lookupEvent(llvm::StringRef name,
69 TileID tile,
70 bool isMem) const {
71 const auto *db = getRegisterDatabase();
72 if (!db)
73 return std::nullopt;
74 return db->lookupEvent(name, getModuleForTileEvents(*this, tile, isMem));
75}
76
77std::optional<uint32_t>
79 uint32_t value) const {
80 const auto *db = getRegisterDatabase();
81 if (!db)
82 return std::nullopt;
83 return db->encodeFieldValue(field, value);
84}
85
86std::optional<uint32_t>
88 uint32_t width = field.getWidth();
89 if (width == 0 || width > 32 || field.bit_end >= 32)
90 return std::nullopt;
91
92 uint64_t mask = (width == 32) ? 0xFFFFFFFFULL : ((1ULL << width) - 1ULL);
93 mask <<= field.bit_start;
94 if (mask > UINT32_MAX)
95 return std::nullopt;
96
97 return static_cast<uint32_t>(mask);
98}
99
100DenseMap<TileID, int>
101AIETargetModel::getTileToControllerIdMap(bool columnWiseUniqueIDs) const {
102 if (rows() <= 6) {
103 // Controller id combinations chosen to avoid packet flow deadlock due to
104 // single-level LUT bit-masking on packet header. Shim tile ids are < 16
105 // because the TCT actor id field is only 4 bits.
106 SmallVector<SmallVector<int>> validTileIds = {{15, 26, 27, 29, 30, 31},
107 {14, 21, 22, 23, 24, 25},
108 {13, 11, 17, 18, 19, 20},
109 {12, 28, 7, 8, 9, 10}};
110 if (!columnWiseUniqueIDs && columns() > (int)validTileIds.size())
111 llvm::report_fatal_error(
112 "Device has " + llvm::Twine(columns()) + " columns but only " +
113 llvm::Twine(validTileIds.size()) +
114 " globally-unique controller ID sets are defined; "
115 "use column-wise unique IDs mode.");
116 DenseMap<TileID, int> tileIDMap;
117 for (int col = 0; col < columns(); col++) {
118 for (int row = 0; row < rows(); row++) {
119 if (columnWiseUniqueIDs)
120 tileIDMap[{col, row}] = validTileIds[0][row];
121 else
122 tileIDMap[{col, row}] = validTileIds[col][row];
123 }
124 }
125 return tileIDMap;
126 }
127
128 // Devices with more than 6 rows use sequential assignment.
129 assert(columnWiseUniqueIDs &&
130 "Device has more tiles than candidate packet ids; "
131 "use column-wise unique IDs mode.");
132 DenseMap<TileID, int> tileIDMap;
133 int unusedPacketIdFrom = 0;
134 for (int col = 0; col < columns(); col++) {
135 if (columnWiseUniqueIDs)
136 unusedPacketIdFrom = 0;
137 for (int row = 0; row < rows(); row++)
138 tileIDMap[{col, row}] = unusedPacketIdFrom++;
139 }
140 return tileIDMap;
141}
142
143std::optional<uint32_t> AIETargetModel::resolvePortValue(llvm::StringRef value,
144 TileID tile,
145 bool master) const {
146 auto colonPos = value.find(':');
147 if (colonPos == StringRef::npos)
148 return std::nullopt;
149
150 StringRef portName = value.substr(0, colonPos);
151 StringRef channelStr = value.substr(colonPos + 1);
152
153 int channel;
154 if (channelStr.getAsInteger(10, channel) || channel < 0)
155 return std::nullopt;
156
157 WireBundle bundle;
158 if (portName.equals_insensitive("north")) {
159 bundle = WireBundle::North;
160 } else if (portName.equals_insensitive("south")) {
161 bundle = WireBundle::South;
162 } else if (portName.equals_insensitive("east")) {
163 bundle = WireBundle::East;
164 } else if (portName.equals_insensitive("west")) {
165 bundle = WireBundle::West;
166 } else if (portName.equals_insensitive("dma")) {
167 bundle = WireBundle::DMA;
168 } else if (portName.equals_insensitive("fifo")) {
169 bundle = WireBundle::FIFO;
170 } else if (portName.equals_insensitive("core")) {
171 bundle = WireBundle::Core;
172 } else if (portName.equals_insensitive("ctrl")) {
173 bundle = WireBundle::TileControl;
174 } else {
175 return std::nullopt;
176 }
177
178 return getStreamSwitchPortIndex(tile.col, tile.row, bundle,
179 static_cast<uint32_t>(channel), master);
180}
181
182///
183/// AIE1 TargetModel
184///
185
186AIEArch AIE1TargetModel::getTargetArch() const { return AIEArch::AIE1; }
187
188// Return the tile ID of the memory to the west of the given tile, if it exists.
189std::optional<TileID> AIE1TargetModel::getMemWest(TileID src) const {
190 bool isEvenRow = ((src.row % 2) == 0);
191 std::optional<TileID> ret;
192 if (isEvenRow)
193 ret = src;
194 else
195 ret = {src.col - 1, src.row};
196 if (!isValidTile(*ret))
197 ret.reset();
198 return ret;
199}
200
201// Return the tile ID of the memory to the west of the given tile, if it exists.
202std::optional<TileID> AIE1TargetModel::getMemEast(TileID src) const {
203 bool isEvenRow = (src.row % 2) == 0;
204 std::optional<TileID> ret;
205 if (isEvenRow)
206 ret = {src.col + 1, src.row};
207 else
208 ret = src;
209 if (!isValidTile(*ret))
210 ret.reset();
211 return ret;
212}
213
214// Return the tile ID of the memory to the west of the given tile, if it exists.
215std::optional<TileID> AIE1TargetModel::getMemNorth(TileID src) const {
216 std::optional<TileID> ret({src.col, src.row + 1});
217 if (!isValidTile(*ret))
218 ret.reset();
219 return ret;
220}
221
222std::optional<TileID> AIE1TargetModel::getMemSouth(TileID src) const {
223 std::optional<TileID> ret({src.col, src.row - 1});
224 // The first row doesn't have a tile memory south
225 if (!isValidTile(*ret) || ret->row == 0)
226 ret.reset();
227 return ret;
228}
229
230bool AIE1TargetModel::isMemWest(int srcCol, int srcRow, int dstCol,
231 int dstRow) const {
232 bool IsEvenRow = (srcRow % 2) == 0;
233 return (IsEvenRow && isInternal(srcCol, srcRow, dstCol, dstRow)) ||
234 (!IsEvenRow && isWest(srcCol, srcRow, dstCol, dstRow));
235}
236
237bool AIE1TargetModel::isMemEast(int srcCol, int srcRow, int dstCol,
238 int dstRow) const {
239 bool IsEvenRow = (srcRow % 2) == 0;
240 return (!IsEvenRow && isInternal(srcCol, srcRow, dstCol, dstRow)) ||
241 (IsEvenRow && isEast(srcCol, srcRow, dstCol, dstRow));
242}
243
244bool AIE1TargetModel::isMemNorth(int srcCol, int srcRow, int dstCol,
245 int dstRow) const {
246 return isNorth(srcCol, srcRow, dstCol, dstRow);
247}
248
249bool AIE1TargetModel::isMemSouth(int srcCol, int srcRow, int dstCol,
250 int dstRow) const {
251 return isSouth(srcCol, srcRow, dstCol, dstRow);
252}
253
254bool AIE1TargetModel::isLegalMemAffinity(int coreCol, int coreRow, int memCol,
255 int memRow) const {
256 bool IsEvenRow = ((coreRow % 2) == 0);
257
258 bool IsMemWest = (isWest(coreCol, coreRow, memCol, memRow) && !IsEvenRow) ||
259 (isInternal(coreCol, coreRow, memCol, memRow) && IsEvenRow);
260
261 bool IsMemEast = (isEast(coreCol, coreRow, memCol, memRow) && IsEvenRow) ||
262 (isInternal(coreCol, coreRow, memCol, memRow) && !IsEvenRow);
263
264 bool IsMemNorth = isNorth(coreCol, coreRow, memCol, memRow);
265 bool IsMemSouth = isSouth(coreCol, coreRow, memCol, memRow);
266
267 return IsMemSouth || IsMemNorth || IsMemWest || IsMemEast;
268}
269
270uint64_t AIE1TargetModel::getDmaBdAddress(int col, int row, uint32_t bd_id,
271 int channel,
272 AIE::DMAChannelDir direction) const {
273 uint32_t offset = 0;
274 if (isShimNOCTile(col, row)) {
275 offset = 0x0001D000 + (bd_id * 0x14);
276 } else if (isCoreTile(col, row)) {
277 offset = 0x0001D000 + (bd_id * 0x20);
278 } else {
279 llvm_unreachable(
280 "AIE1TargetModel::getDmaBdAddress called for non-DMA tile");
281 }
282 return ((col & 0xff) << getColumnShift()) | ((row & 0xff) << getRowShift()) |
283 offset;
284}
285
286uint32_t AIE1TargetModel::getDmaBdAddressOffset(int col, int row) const {
287 if (isShimNOCTile(col, row) || isCoreTile(col, row)) {
288 return 0;
289 }
290 llvm_unreachable(
291 "AIE1TargetModel::getDmaBdAddressOffset called for non-DMA tile");
292}
293
294uint32_t
295AIE1TargetModel::getDmaControlAddress(int col, int row, int channel,
296 AIE::DMAChannelDir direction) const {
297 uint32_t offset = 0;
298 if (isShimNOCTile(col, row))
299 offset = 0x0001D140 + (channel * 0x8);
300 else if (isCoreTile(col, row))
301 offset = 0x0001DE00 + (channel * 0x8);
302 else
303 llvm_unreachable(
304 "AIE1TargetModel::getDmaControlAddress called for non-DMA tile");
305
306 if (direction == AIE::DMAChannelDir::MM2S)
307 offset += 010;
308
309 return ((col & 0xff) << getColumnShift()) | ((row & 0xff) << getRowShift()) |
310 offset;
311}
312
313uint32_t
315 WireBundle bundle) const {
316 if (isShimNOCTile(col, row) || isShimPLTile(col, row))
317 switch (bundle) {
318 case WireBundle::FIFO:
319 return 2;
320 case WireBundle::North:
321 return 6;
322 case WireBundle::West: {
323 if (col == 0)
324 return 0;
325 return 4;
326 }
327 case WireBundle::South:
328 return 6;
329 case WireBundle::East: {
330 if (col == columns() - 1)
331 return 0;
332 return 4;
333 }
334 case WireBundle::TileControl:
335 return isShimNOCTile(col, row) ? 1 : 0;
336 default:
337 return 0;
338 }
339
340 switch (bundle) {
341 case WireBundle::Core:
342 case WireBundle::DMA:
343 case WireBundle::FIFO:
344 return 2;
345 case WireBundle::North: {
346 if (row == rows() - 1)
347 return 0;
348 return 6;
349 }
350 case WireBundle::West: {
351 if (col == 0)
352 return 0;
353 return 4;
354 }
355 case WireBundle::South:
356 return 4;
357 case WireBundle::East: {
358 if (col == columns() - 1)
359 return 0;
360 return 4;
361 }
362 case WireBundle::TileControl:
363 return 1;
364 default:
365 return 0;
366 }
367}
368
369uint32_t
371 WireBundle bundle) const {
372 if (isShimNOCTile(col, row) || isShimPLTile(col, row))
373 switch (bundle) {
374 case WireBundle::FIFO:
375 return 2;
376 case WireBundle::North:
377 return 4;
378 case WireBundle::West: {
379 if (col == 0)
380 return 0;
381 return 4;
382 }
383 case WireBundle::South:
384 return 8;
385 case WireBundle::East: {
386 if (col == columns() - 1)
387 return 0;
388 return 4;
389 }
390 case WireBundle::Trace:
391 return 1;
392 case WireBundle::TileControl:
393 return isShimNOCTile(col, row) ? 1 : 0;
394 default:
395 return 0;
396 }
397
398 switch (bundle) {
399 case WireBundle::Core:
400 case WireBundle::DMA:
401 case WireBundle::FIFO:
402 return 2;
403 case WireBundle::North: {
404 if (row == rows() - 1)
405 return 0;
406 return 4;
407 }
408 case WireBundle::West: {
409 if (col == 0)
410 return 0;
411 return 4;
412 }
413 case WireBundle::South:
414 return 6;
415 case WireBundle::East: {
416 if (col == columns() - 1)
417 return 0;
418 return 4;
419 }
420 case WireBundle::Trace:
421 return 2;
422 case WireBundle::TileControl:
423 return 1;
424 default:
425 return 0;
426 }
427}
428uint32_t
430 WireBundle bundle) const {
431 if (isShimNOCorPLTile(col, row))
432 switch (bundle) {
433 case WireBundle::DMA:
434 return 2;
435 case WireBundle::NOC:
436 return 4;
437 case WireBundle::PLIO:
438 return 6;
439 case WireBundle::South:
440 return 8; // Connection to the south port of the stream switch
441 default:
442 return 0;
443 }
444 return 0;
445}
446uint32_t
448 WireBundle bundle) const {
449 if (isShimNOCorPLTile(col, row))
450 switch (bundle) {
451 case WireBundle::DMA:
452 return 2;
453 case WireBundle::NOC:
454 return 4;
455 case WireBundle::PLIO:
456 return 8;
457 case WireBundle::South:
458 return 6; // Connection to the south port of the stream switch
459 default:
460 return 0;
461 }
462 return 0;
463}
464
466 WireBundle srcBundle, int srcChan,
467 WireBundle dstBundle,
468 int dstChan) const {
469 // Check Channel Id within the range
470 if (srcChan >= int(getNumSourceSwitchboxConnections(col, row, srcBundle)))
471 return false;
472 if (dstChan >= int(getNumDestSwitchboxConnections(col, row, dstBundle)))
473 return false;
474
475 // Memtile
476 if (isMemTile(col, row)) {
477 return false;
478 }
479 // Shimtile and Coretile currently share this trace-routing constraint;
480 // flagged by bugprone-branch-clone -- unconfirmed whether that's
481 // deliberate or a copy-paste that should differ per tile kind, needs
482 // hardware-team confirmation before changing.
483 // NOLINTBEGIN(bugprone-branch-clone)
484 if (isShimNOCorPLTile(col, row)) {
485 if (srcBundle == WireBundle::Trace)
486 return dstBundle == WireBundle::South;
487 return true;
488 }
489 // Coretile
490 if (isCoreTile(col, row)) {
491 if (srcBundle == WireBundle::Trace)
492 return dstBundle == WireBundle::South;
493 return true;
494 }
495 // NOLINTEND(bugprone-branch-clone)
496 return false;
497}
498
499std::vector<std::pair<uint32_t, uint32_t>>
501 return {std::pair(0, 64), std::pair(1, 128), std::pair(2, 256)};
502}
503
504std::optional<uint32_t>
505AIE1TargetModel::getLocalLockAddress(uint32_t lockId, TileID tile) const {
506 // This function is currently not supported for AIE1.
507 // In order to be implemented for this target model, the interface
508 // would need to change given the different way locks are written to in AIE1.
509 return std::nullopt;
510}
511
512namespace {
513namespace aie1_port_id {
514namespace core {
515
516// Slave port offset/size constants
517static constexpr uint32_t S_CORE_OFFSET = 0;
518static constexpr uint32_t S_CORE_SIZE = 2;
519static constexpr uint32_t S_CTRL_OFFSET = 4;
520static constexpr uint32_t S_CTRL_SIZE = 1;
521static constexpr uint32_t S_DMA_OFFSET = 2;
522static constexpr uint32_t S_DMA_SIZE = 2;
523static constexpr uint32_t S_EAST_OFFSET = 21;
524static constexpr uint32_t S_EAST_SIZE = 4;
525static constexpr uint32_t S_FIFO_OFFSET = 5;
526static constexpr uint32_t S_FIFO_SIZE = 2;
527static constexpr uint32_t S_NORTH_OFFSET = 17;
528static constexpr uint32_t S_NORTH_SIZE = 4;
529static constexpr uint32_t S_SOUTH_OFFSET = 7;
530static constexpr uint32_t S_SOUTH_SIZE = 6;
531static constexpr uint32_t S_TRACE_OFFSET = 25;
532static constexpr uint32_t S_TRACE_SIZE = 2;
533static constexpr uint32_t S_WEST_OFFSET = 13;
534static constexpr uint32_t S_WEST_SIZE = 4;
535
536// Master port offset/size constants
537static constexpr uint32_t M_CORE_OFFSET = 0;
538static constexpr uint32_t M_CORE_SIZE = 2;
539static constexpr uint32_t M_CTRL_OFFSET = 4;
540static constexpr uint32_t M_CTRL_SIZE = 1;
541static constexpr uint32_t M_DMA_OFFSET = 2;
542static constexpr uint32_t M_DMA_SIZE = 2;
543static constexpr uint32_t M_EAST_OFFSET = 21;
544static constexpr uint32_t M_EAST_SIZE = 4;
545static constexpr uint32_t M_FIFO_OFFSET = 5;
546static constexpr uint32_t M_FIFO_SIZE = 2;
547static constexpr uint32_t M_NORTH_OFFSET = 15;
548static constexpr uint32_t M_NORTH_SIZE = 6;
549static constexpr uint32_t M_SOUTH_OFFSET = 7;
550static constexpr uint32_t M_SOUTH_SIZE = 4;
551static constexpr uint32_t M_WEST_OFFSET = 11;
552static constexpr uint32_t M_WEST_SIZE = 4;
553
554} // namespace core
555
556namespace shim {
557
558// Slave port offset/size constants
559static constexpr uint32_t S_CTRL_OFFSET = 0;
560static constexpr uint32_t S_CTRL_SIZE = 1;
561static constexpr uint32_t S_EAST_OFFSET = 19;
562static constexpr uint32_t S_EAST_SIZE = 4;
563static constexpr uint32_t S_FIFO_OFFSET = 1;
564static constexpr uint32_t S_FIFO_SIZE = 2;
565static constexpr uint32_t S_NORTH_OFFSET = 15;
566static constexpr uint32_t S_NORTH_SIZE = 4;
567static constexpr uint32_t S_SOUTH_OFFSET = 3;
568static constexpr uint32_t S_SOUTH_SIZE = 8;
569static constexpr uint32_t S_TRACE_OFFSET = 23;
570static constexpr uint32_t S_TRACE_SIZE = 1;
571static constexpr uint32_t S_WEST_OFFSET = 11;
572static constexpr uint32_t S_WEST_SIZE = 4;
573
574// Master port offset/size constants
575static constexpr uint32_t M_CTRL_OFFSET = 0;
576static constexpr uint32_t M_CTRL_SIZE = 1;
577static constexpr uint32_t M_EAST_OFFSET = 19;
578static constexpr uint32_t M_EAST_SIZE = 4;
579static constexpr uint32_t M_FIFO_OFFSET = 1;
580static constexpr uint32_t M_FIFO_SIZE = 2;
581static constexpr uint32_t M_NORTH_OFFSET = 13;
582static constexpr uint32_t M_NORTH_SIZE = 6;
583static constexpr uint32_t M_SOUTH_OFFSET = 3;
584static constexpr uint32_t M_SOUTH_SIZE = 6;
585static constexpr uint32_t M_WEST_OFFSET = 9;
586static constexpr uint32_t M_WEST_SIZE = 4;
587
588} // namespace shim
589} // namespace aie1_port_id
590} // anonymous namespace
591
593 int col, int row, WireBundle bundle, uint32_t port_num, bool master) const {
594 if (master) {
595 if (isCoreTile(col, row)) {
596 switch (bundle) {
597 case WireBundle::Core:
598 if (port_num >= aie1_port_id::core::M_CORE_SIZE)
599 return std::nullopt;
600 return aie1_port_id::core::M_CORE_OFFSET + port_num;
601 case WireBundle::TileControl:
602 if (port_num >= aie1_port_id::core::M_CTRL_SIZE)
603 return std::nullopt;
604 return aie1_port_id::core::M_CTRL_OFFSET + port_num;
605 case WireBundle::DMA:
606 if (port_num >= aie1_port_id::core::M_DMA_SIZE)
607 return std::nullopt;
608 return aie1_port_id::core::M_DMA_OFFSET + port_num;
609 case WireBundle::East:
610 if (port_num >= aie1_port_id::core::M_EAST_SIZE)
611 return std::nullopt;
612 return aie1_port_id::core::M_EAST_OFFSET + port_num;
613 case WireBundle::FIFO:
614 if (port_num >= aie1_port_id::core::M_FIFO_SIZE)
615 return std::nullopt;
616 return aie1_port_id::core::M_FIFO_OFFSET + port_num;
617 case WireBundle::North:
618 if (port_num >= aie1_port_id::core::M_NORTH_SIZE)
619 return std::nullopt;
620 return aie1_port_id::core::M_NORTH_OFFSET + port_num;
621 case WireBundle::South:
622 if (port_num >= aie1_port_id::core::M_SOUTH_SIZE)
623 return std::nullopt;
624 return aie1_port_id::core::M_SOUTH_OFFSET + port_num;
625 case WireBundle::West:
626 if (port_num >= aie1_port_id::core::M_WEST_SIZE)
627 return std::nullopt;
628 return aie1_port_id::core::M_WEST_OFFSET + port_num;
629 default:
630 return std::nullopt;
631 }
632 } else if (isShimNOCorPLTile(col, row)) {
633 switch (bundle) {
634 case WireBundle::TileControl:
635 if (port_num >= aie1_port_id::shim::M_CTRL_SIZE)
636 return std::nullopt;
637 return aie1_port_id::shim::M_CTRL_OFFSET + port_num;
638 case WireBundle::East:
639 if (port_num >= aie1_port_id::shim::M_EAST_SIZE)
640 return std::nullopt;
641 return aie1_port_id::shim::M_EAST_OFFSET + port_num;
642 case WireBundle::FIFO:
643 if (port_num >= aie1_port_id::shim::M_FIFO_SIZE)
644 return std::nullopt;
645 return aie1_port_id::shim::M_FIFO_OFFSET + port_num;
646 case WireBundle::North:
647 if (port_num >= aie1_port_id::shim::M_NORTH_SIZE)
648 return std::nullopt;
649 return aie1_port_id::shim::M_NORTH_OFFSET + port_num;
650 case WireBundle::South:
651 if (port_num >= aie1_port_id::shim::M_SOUTH_SIZE)
652 return std::nullopt;
653 return aie1_port_id::shim::M_SOUTH_OFFSET + port_num;
654 case WireBundle::West:
655 if (port_num >= aie1_port_id::shim::M_WEST_SIZE)
656 return std::nullopt;
657 return aie1_port_id::shim::M_WEST_OFFSET + port_num;
658 default:
659 return std::nullopt;
660 }
661 } else {
662 return std::nullopt;
663 }
664 } else {
665 if (isCoreTile(col, row)) {
666 switch (bundle) {
667 case WireBundle::Core:
668 if (port_num >= aie1_port_id::core::S_CORE_SIZE)
669 return std::nullopt;
670 return aie1_port_id::core::S_CORE_OFFSET + port_num;
671 case WireBundle::TileControl:
672 if (port_num >= aie1_port_id::core::S_CTRL_SIZE)
673 return std::nullopt;
674 return aie1_port_id::core::S_CTRL_OFFSET + port_num;
675 case WireBundle::DMA:
676 if (port_num >= aie1_port_id::core::S_DMA_SIZE)
677 return std::nullopt;
678 return aie1_port_id::core::S_DMA_OFFSET + port_num;
679 case WireBundle::East:
680 if (port_num >= aie1_port_id::core::S_EAST_SIZE)
681 return std::nullopt;
682 return aie1_port_id::core::S_EAST_OFFSET + port_num;
683 case WireBundle::FIFO:
684 if (port_num >= aie1_port_id::core::S_FIFO_SIZE)
685 return std::nullopt;
686 return aie1_port_id::core::S_FIFO_OFFSET + port_num;
687 case WireBundle::North:
688 if (port_num >= aie1_port_id::core::S_NORTH_SIZE)
689 return std::nullopt;
690 return aie1_port_id::core::S_NORTH_OFFSET + port_num;
691 case WireBundle::South:
692 if (port_num >= aie1_port_id::core::S_SOUTH_SIZE)
693 return std::nullopt;
694 return aie1_port_id::core::S_SOUTH_OFFSET + port_num;
695 case WireBundle::Trace:
696 if (port_num >= aie1_port_id::core::S_TRACE_SIZE)
697 return std::nullopt;
698 return aie1_port_id::core::S_TRACE_OFFSET + port_num;
699 case WireBundle::West:
700 if (port_num >= aie1_port_id::core::S_WEST_SIZE)
701 return std::nullopt;
702 return aie1_port_id::core::S_WEST_OFFSET + port_num;
703 default:
704 return std::nullopt;
705 }
706 } else if (isShimNOCorPLTile(col, row)) {
707 switch (bundle) {
708 case WireBundle::TileControl:
709 if (port_num >= aie1_port_id::shim::S_CTRL_SIZE)
710 return std::nullopt;
711 return aie1_port_id::shim::S_CTRL_OFFSET + port_num;
712 case WireBundle::East:
713 if (port_num >= aie1_port_id::shim::S_EAST_SIZE)
714 return std::nullopt;
715 return aie1_port_id::shim::S_EAST_OFFSET + port_num;
716 case WireBundle::FIFO:
717 if (port_num >= aie1_port_id::shim::S_FIFO_SIZE)
718 return std::nullopt;
719 return aie1_port_id::shim::S_FIFO_OFFSET + port_num;
720 case WireBundle::North:
721 if (port_num >= aie1_port_id::shim::S_NORTH_SIZE)
722 return std::nullopt;
723 return aie1_port_id::shim::S_NORTH_OFFSET + port_num;
724 case WireBundle::South:
725 if (port_num >= aie1_port_id::shim::S_SOUTH_SIZE)
726 return std::nullopt;
727 return aie1_port_id::shim::S_SOUTH_OFFSET + port_num;
728 case WireBundle::Trace:
729 if (port_num >= aie1_port_id::shim::S_TRACE_SIZE)
730 return std::nullopt;
731 return aie1_port_id::shim::S_TRACE_OFFSET + port_num;
732 case WireBundle::West:
733 if (port_num >= aie1_port_id::shim::S_WEST_SIZE)
734 return std::nullopt;
735 return aie1_port_id::shim::S_WEST_OFFSET + port_num;
736 default:
737 return std::nullopt;
738 }
739 } else {
740 return std::nullopt;
741 }
742 }
743}
744
745///
746/// AIE2 TargetModel
747///
748
749std::unique_ptr<RegisterDatabase>
753
755
756// Return the tile ID of the memory to the west of the given tile, if it exists.
757std::optional<TileID> AIE2TargetModel::getMemWest(TileID src) const {
758 std::optional<TileID> ret({src.col - 1, src.row});
759 if (!isValidTile(*ret))
760 ret.reset();
761 return ret;
762}
763
764// Return the tile ID of the memory to the east of the given tile (ie self), if
765// it exists.
766std::optional<TileID> AIE2TargetModel::getMemEast(TileID src) const {
767 std::optional ret = src;
768 if (!isValidTile(*ret))
769 ret.reset();
770 return ret;
771}
772
773// Return the tile ID of the memory to the north of the given tile, if it
774// exists.
775std::optional<TileID> AIE2TargetModel::getMemNorth(TileID src) const {
776 std::optional<TileID> ret({src.col, src.row + 1});
777 if (!isValidTile(*ret))
778 ret.reset();
779 return ret;
780}
781
782std::optional<TileID> AIE2TargetModel::getMemSouth(TileID src) const {
783 std::optional<TileID> ret({src.col, src.row - 1});
784 // The first row doesn't have a tile memory south
785 // Memtiles don't have memory adjacency to neighboring core tiles.
786 if (!isValidTile(*ret) || ret->row == 0 || isMemTile(ret->col, ret->row))
787 ret.reset();
788 return ret;
789}
790
791bool AIE2TargetModel::isMemWest(int srcCol, int srcRow, int dstCol,
792 int dstRow) const {
793 return isWest(srcCol, srcRow, dstCol, dstRow);
794}
795
796bool AIE2TargetModel::isMemEast(int srcCol, int srcRow, int dstCol,
797 int dstRow) const {
798 return isInternal(srcCol, srcRow, dstCol, dstRow);
799}
800
801bool AIE2TargetModel::isMemNorth(int srcCol, int srcRow, int dstCol,
802 int dstRow) const {
803 return isNorth(srcCol, srcRow, dstCol, dstRow);
804}
805
806bool AIE2TargetModel::isMemSouth(int srcCol, int srcRow, int dstCol,
807 int dstRow) const {
808 return isSouth(srcCol, srcRow, dstCol, dstRow);
809}
810
811bool AIE2TargetModel::isLegalMemAffinity(int coreCol, int coreRow, int memCol,
812 int memRow) const {
813
814 bool IsMemWest = isMemWest(coreCol, coreRow, memCol, memRow);
815 bool IsMemEast = isMemEast(coreCol, coreRow, memCol, memRow);
816 bool IsMemNorth = isMemNorth(coreCol, coreRow, memCol, memRow);
817 bool IsMemSouth = isMemSouth(coreCol, coreRow, memCol, memRow);
818
819 if (isMemTile(coreCol, coreRow))
820 return isEast(coreCol, coreRow, memCol, memRow) ||
821 isInternal(coreCol, coreRow, memCol, memRow) ||
822 isWest(coreCol, coreRow, memCol, memRow);
823 return (IsMemSouth && !isMemTile(memCol, memRow)) || IsMemNorth ||
824 IsMemWest || IsMemEast;
825}
826
827uint64_t AIE2TargetModel::getDmaBdAddress(int col, int row, uint32_t bd_id,
828 int channel,
829 AIE::DMAChannelDir direction) const {
830 uint64_t offset = 0;
831 // Shimtile and Coretile currently compute the same offset; flagged by
832 // bugprone-branch-clone -- unconfirmed whether the DMA BD register bank
833 // genuinely shares this base across both tile kinds, needs hardware-team
834 // confirmation before changing.
835 // NOLINTBEGIN(bugprone-branch-clone)
836 if (isShimNOCTile(col, row)) {
837 offset = 0x0001D000 + bd_id * 0x20;
838 } else if (isMemTile(col, row)) {
839 offset = 0x000A0000 + bd_id * 0x20;
840 } else if (isCoreTile(col, row)) {
841 offset = 0x0001D000 + bd_id * 0x20;
842 } else {
843 llvm_unreachable(
844 "AIE2TargetModel::getDmaBdAddress called for non-DMA tile");
845 }
846 // NOLINTEND(bugprone-branch-clone)
847 return ((col & 0xff) << getColumnShift()) | ((row & 0xff) << getRowShift()) |
848 offset;
849}
850
851static DmaBdLayout makeAIE2ShimBdLayout() {
852 DmaBdLayout l;
853 l.numWords = 8;
854 l.bufferLength = {0, 0, 32};
855 l.bufferOffset = {1, 0, 32};
856 l.enablePacket = {2, 30, 1};
857 l.outOfOrderId = {2, 24, 6};
858 l.packetId = {2, 19, 5};
859 l.packetType = {2, 16, 3};
860 l.d0Size = {3, 20, 10};
861 l.d0Stride = {3, 0, 20};
862 l.burstLength = {4, 30, 2};
863 l.d1Size = {4, 20, 10};
864 l.d1Stride = {4, 0, 20};
865 l.axcache = {5, 24, 4};
866 l.d2Stride = {5, 0, 20};
867 l.iterationCurrent = {6, 26, 6};
868 l.iterationSize = {6, 20, 6};
869 l.iterationStride = {6, 0, 20};
870 l.nextBd = {7, 27, 4};
871 l.useNextBd = {7, 26, 1};
872 l.validBd = {7, 25, 1};
873 l.lockRelValue = {7, 18, 7};
874 l.lockRelId = {7, 13, 4};
875 l.lockAcqEnable = {7, 12, 1};
876 l.lockAcqValue = {7, 5, 7};
877 l.lockAcqId = {7, 0, 4};
878 return l;
879}
880
881// D2_Wrap and D3_Stepsize are left out: the lowering never programs them, and
882// the d2 extent is carried by buffer_length as on the other tiles.
883static DmaBdLayout makeAIE2MemTileBdLayout() {
884 DmaBdLayout l;
885 l.numWords = 8;
886 l.enablePacket = {0, 31, 1};
887 l.packetType = {0, 28, 3};
888 l.packetId = {0, 23, 5};
889 l.outOfOrderId = {0, 17, 6};
890 l.bufferLength = {0, 0, 17};
891 l.d0ZeroBefore = {1, 26, 6};
892 l.nextBd = {1, 20, 6};
893 l.useNextBd = {1, 19, 1};
894 l.bufferOffset = {1, 0, 19};
895 l.d0Size = {2, 17, 10};
896 l.d0Stride = {2, 0, 17};
897 l.d1ZeroBefore = {3, 27, 5};
898 l.d1Size = {3, 17, 10};
899 l.d1Stride = {3, 0, 17};
900 l.d2ZeroBefore = {4, 27, 4};
901 l.d2Stride = {4, 0, 17};
902 l.d2ZeroAfter = {5, 28, 4};
903 l.d1ZeroAfter = {5, 23, 5};
904 l.d0ZeroAfter = {5, 17, 6};
905 l.iterationCurrent = {6, 23, 6};
906 l.iterationSize = {6, 17, 6};
907 l.iterationStride = {6, 0, 17};
908 l.validBd = {7, 31, 1};
909 l.lockRelValue = {7, 24, 7};
910 l.lockRelId = {7, 16, 8};
911 l.lockAcqEnable = {7, 15, 1};
912 l.lockAcqValue = {7, 8, 7};
913 l.lockAcqId = {7, 0, 8};
914 return l;
915}
916
917// The core tile's buffer offset is its Base_Address field, in 32-bit words.
918static DmaBdLayout makeAIE2CoreTileBdLayout() {
919 DmaBdLayout l;
920 l.numWords = 6;
921 l.bufferOffset = {0, 14, 14};
922 l.bufferLength = {0, 0, 14};
923 l.enablePacket = {1, 30, 1};
924 l.outOfOrderId = {1, 24, 6};
925 l.packetId = {1, 19, 5};
926 l.packetType = {1, 16, 3};
927 l.d1Stride = {2, 13, 13};
928 l.d0Stride = {2, 0, 13};
929 l.d1Size = {3, 21, 8};
930 l.d0Size = {3, 13, 8};
931 l.d2Stride = {3, 0, 13};
932 l.iterationCurrent = {4, 19, 6};
933 l.iterationSize = {4, 13, 6};
934 l.iterationStride = {4, 0, 13};
935 l.nextBd = {5, 27, 4};
936 l.useNextBd = {5, 26, 1};
937 l.validBd = {5, 25, 1};
938 l.lockRelValue = {5, 18, 7};
939 l.lockRelId = {5, 13, 4};
940 l.lockAcqEnable = {5, 12, 1};
941 l.lockAcqValue = {5, 5, 7};
942 l.lockAcqId = {5, 0, 4};
943 return l;
944}
945
946const DmaBdLayout *AIE2TargetModel::getDmaBdLayout(AIETileType tileType) const {
947 static const DmaBdLayout shim = makeAIE2ShimBdLayout();
948 static const DmaBdLayout mem = makeAIE2MemTileBdLayout();
949 static const DmaBdLayout core = makeAIE2CoreTileBdLayout();
950 switch (tileType) {
951 case AIETileType::ShimNOCTile:
952 return &shim;
953 case AIETileType::MemTile:
954 return &mem;
955 case AIETileType::CoreTile:
956 return &core;
957 default:
958 return nullptr;
959 }
960}
961
962uint32_t AIE2TargetModel::getDmaBdAddressOffset(int col, int row) const {
963 if (isCoreTile(col, row))
964 return 0x0;
965 return 0x4;
966}
967
968uint32_t
969AIE2TargetModel::getDmaControlAddress(int col, int row, int channel,
970 AIE::DMAChannelDir direction) const {
971 uint32_t offset = 0;
972 if (isShimNOCTile(col, row)) {
973 offset = 0x0001D200 + (channel * 0x8);
974 if (direction == AIE::DMAChannelDir::MM2S)
975 offset += 0x10;
976 } else if (isMemTile(col, row)) {
977 offset = 0x000A0600 + (channel * 0x8);
978 if (direction == AIE::DMAChannelDir::MM2S)
979 offset += 0x30;
980 } else if (isCoreTile(col, row)) {
981 offset = 0x0001DE00 + (channel * 0x8);
982 if (direction == AIE::DMAChannelDir::MM2S)
983 offset += 0x10;
984 } else {
985 llvm_unreachable(
986 "AIE2TargetModel::getDmaControlAddress called for non-DMA tile");
987 }
988
989 return ((col & 0xff) << getColumnShift()) | ((row & 0xff) << getRowShift()) |
990 offset;
991}
992
993std::optional<uint32_t>
994AIE2TargetModel::getDmaStatusAddress(int col, int row, int channel,
995 AIE::DMAChannelDir direction) const {
996 // Status registers sit one word apart per channel, unlike the task-queue
997 // control registers above, which are two words apart.
998 uint32_t offset = 0;
999 if (isShimNOCTile(col, row)) {
1000 offset = 0x0001D220 + (channel * 0x4);
1001 if (direction == AIE::DMAChannelDir::MM2S)
1002 offset += 0x8;
1003 } else if (isMemTile(col, row)) {
1004 offset = 0x000A0660 + (channel * 0x4);
1005 if (direction == AIE::DMAChannelDir::MM2S)
1006 offset += 0x20;
1007 } else if (isCoreTile(col, row)) {
1008 offset = 0x0001DF00 + (channel * 0x4);
1009 if (direction == AIE::DMAChannelDir::MM2S)
1010 offset += 0x10;
1011 } else {
1012 return std::nullopt;
1013 }
1014
1015 return ((col & 0xff) << getColumnShift()) | ((row & 0xff) << getRowShift()) |
1016 offset;
1017}
1018
1019uint32_t
1021 WireBundle bundle) const {
1022 if (isMemTile(col, row))
1023 switch (bundle) {
1024 case WireBundle::DMA:
1025 case WireBundle::North:
1026 return 6;
1027 case WireBundle::South:
1028 return 4;
1029 case WireBundle::TileControl:
1030 return 1;
1031 default:
1032 return 0;
1033 }
1034
1035 if (isShimNOCTile(col, row) || isShimPLTile(col, row))
1036 switch (bundle) {
1037 case WireBundle::FIFO:
1038 return 1;
1039 case WireBundle::North:
1040 return 6;
1041 case WireBundle::West: {
1042 if (col == 0)
1043 return 0;
1044 return 4;
1045 }
1046 case WireBundle::South:
1047 return 6;
1048 case WireBundle::East: {
1049 if (col == columns() - 1)
1050 return 0;
1051 return 4;
1052 }
1053 case WireBundle::TileControl:
1054 return isShimNOCTile(col, row) ? 1 : 0;
1055 default:
1056 return 0;
1057 }
1058
1059 switch (bundle) {
1060 case WireBundle::Core:
1061 return 1;
1062 case WireBundle::DMA:
1063 return 2;
1064 case WireBundle::FIFO:
1065 return 1;
1066 case WireBundle::North: {
1067 if (row == rows() - 1)
1068 return 0;
1069 return 6;
1070 }
1071 case WireBundle::West: {
1072 if (col == 0)
1073 return 0;
1074 return 4;
1075 }
1076 case WireBundle::South:
1077 return 4;
1078 case WireBundle::East: {
1079 if (col == columns() - 1)
1080 return 0;
1081 return 4;
1082 }
1083 case WireBundle::TileControl:
1084 return 1;
1085 default:
1086 return 0;
1087 }
1088}
1089
1090uint32_t
1092 WireBundle bundle) const {
1093 if (isMemTile(col, row))
1094 switch (bundle) {
1095 case WireBundle::DMA:
1096 return 6;
1097 case WireBundle::North:
1098 return 4;
1099 case WireBundle::South:
1100 return 6;
1101 case WireBundle::Trace:
1102 case WireBundle::TileControl:
1103 return 1;
1104 default:
1105 return 0;
1106 }
1107
1108 if (isShimNOCTile(col, row) || isShimPLTile(col, row))
1109 switch (bundle) {
1110 case WireBundle::FIFO:
1111 return 1;
1112 case WireBundle::North:
1113 return 4;
1114 case WireBundle::West: {
1115 if (col == 0)
1116 return 0;
1117 return 4;
1118 }
1119 case WireBundle::South:
1120 return 8;
1121 case WireBundle::East: {
1122 if (col == columns() - 1)
1123 return 0;
1124 return 4;
1125 }
1126 case WireBundle::Trace:
1127 return 1;
1128 case WireBundle::TileControl:
1129 return isShimNOCTile(col, row) ? 1 : 0;
1130 default:
1131 return 0;
1132 }
1133
1134 // compute/core tile
1135 switch (bundle) {
1136 case WireBundle::Core:
1137 return 1;
1138 case WireBundle::DMA:
1139 return 2;
1140 case WireBundle::FIFO:
1141 return 1;
1142 case WireBundle::North: {
1143 if (row == rows() - 1)
1144 return 0;
1145 return 4;
1146 }
1147 case WireBundle::West: {
1148 if (col == 0)
1149 return 0;
1150 return 4;
1151 }
1152 case WireBundle::South:
1153 return 6;
1154 case WireBundle::East: {
1155 if (col == columns() - 1)
1156 return 0;
1157 return 4;
1158 }
1159 case WireBundle::Trace:
1160 // Port 0: core trace. Port 1: memory trace.
1161 return 2;
1162 case WireBundle::TileControl:
1163 return 1;
1164 default:
1165 return 0;
1166 }
1167}
1168
1169uint32_t
1171 WireBundle bundle) const {
1172 if (isShimNOCorPLTile(col, row))
1173 switch (bundle) {
1174 case WireBundle::DMA:
1175 return 2;
1176 case WireBundle::NOC:
1177 return 4;
1178 case WireBundle::PLIO:
1179 return 6;
1180 case WireBundle::South:
1181 return 8; // Connection to the south port of the stream switch
1182 default:
1183 return 0;
1184 }
1185
1186 return 0;
1187}
1188
1189uint32_t
1191 WireBundle bundle) const {
1192 if (isShimNOCorPLTile(col, row))
1193 switch (bundle) {
1194 case WireBundle::DMA:
1195 return 2;
1196 case WireBundle::NOC:
1197 return 4;
1198 case WireBundle::PLIO:
1199 return 8;
1200 case WireBundle::South:
1201 return 6; // Connection to the south port of the stream switch
1202 default:
1203 return 0;
1204 }
1205
1206 return 0;
1207}
1208
1210 WireBundle srcBundle, int srcChan,
1211 WireBundle dstBundle,
1212 int dstChan) const {
1213 // Check Channel Id within the range
1214 if (srcChan >= int(getNumSourceSwitchboxConnections(col, row, srcBundle)))
1215 return false;
1216 if (dstChan >= int(getNumDestSwitchboxConnections(col, row, dstBundle)))
1217 return false;
1218
1219 // Lambda function to check if a bundle is in a list
1220 auto isBundleInList = [](WireBundle bundle,
1221 std::initializer_list<WireBundle> bundles) {
1222 return llvm::find(bundles, bundle) != bundles.end();
1223 };
1224
1225 // Memtile
1226 if (isMemTile(col, row)) {
1227 if (srcBundle == WireBundle::DMA) {
1228 if (dstBundle == WireBundle::DMA)
1229 return srcChan == dstChan;
1230 if (isBundleInList(dstBundle, {WireBundle::TileControl, WireBundle::South,
1231 WireBundle::North}))
1232 return true;
1233 }
1234 if (srcBundle == WireBundle::TileControl) {
1235 if (dstBundle == WireBundle::DMA)
1236 return dstChan == 5;
1237 if (isBundleInList(dstBundle, {WireBundle::South, WireBundle::North}))
1238 return true;
1239 }
1240 if (isBundleInList(srcBundle, {WireBundle::South, WireBundle::North})) {
1241 if (isBundleInList(dstBundle, {WireBundle::DMA, WireBundle::TileControl}))
1242 return true;
1243 if (isBundleInList(dstBundle, {WireBundle::South, WireBundle::North}))
1244 return srcChan == dstChan;
1245 }
1246 if (srcBundle == WireBundle::Trace) {
1247 if (dstBundle == WireBundle::DMA)
1248 return dstChan == 5;
1249 if (dstBundle == WireBundle::South)
1250 return true;
1251 }
1252 }
1253 // Shimtile
1254 else if (isShimNOCorPLTile(col, row)) {
1255 if (srcBundle == WireBundle::TileControl)
1256 return dstBundle != WireBundle::TileControl;
1257 if (isBundleInList(srcBundle, {WireBundle::FIFO, WireBundle::South}))
1258 return isBundleInList(dstBundle,
1259 {WireBundle::TileControl, WireBundle::FIFO,
1260 WireBundle::South, WireBundle::West,
1261 WireBundle::North, WireBundle::East});
1262 if (isBundleInList(srcBundle,
1263 {WireBundle::West, WireBundle::North, WireBundle::East}))
1264 return (srcBundle == dstBundle)
1265 ? (srcChan == dstChan)
1266 : isBundleInList(dstBundle,
1267 {WireBundle::TileControl, WireBundle::FIFO,
1268 WireBundle::South, WireBundle::West,
1269 WireBundle::North, WireBundle::East});
1270 if (srcBundle == WireBundle::Trace) {
1271 if (isBundleInList(dstBundle, {WireBundle::FIFO, WireBundle::South}))
1272 return true;
1273 if (isBundleInList(dstBundle, {WireBundle::West, WireBundle::East}))
1274 return dstChan == 0;
1275 }
1276 }
1277 // Coretile
1278 if (isCoreTile(col, row)) {
1279 if (isBundleInList(srcBundle,
1280 {WireBundle::DMA, WireBundle::FIFO, WireBundle::South,
1281 WireBundle::West, WireBundle::North, WireBundle::East}))
1282 if (isBundleInList(dstBundle, {WireBundle::Core, WireBundle::DMA,
1283 WireBundle::TileControl, WireBundle::FIFO,
1284 WireBundle::South, WireBundle::West,
1285 WireBundle::North, WireBundle::East}))
1286 return (srcBundle == dstBundle) ? (srcChan == dstChan) : true;
1287 if (srcBundle == WireBundle::Core)
1288 return dstBundle != WireBundle::Core;
1289 if (srcBundle == WireBundle::TileControl)
1290 return dstBundle != WireBundle::TileControl &&
1291 dstBundle != WireBundle::DMA;
1292 if (srcBundle == WireBundle::Trace) {
1293 if (dstBundle == WireBundle::DMA)
1294 return dstChan == 0;
1295 if (isBundleInList(dstBundle, {WireBundle::FIFO, WireBundle::South}))
1296 return true;
1297 }
1298 }
1299 return false;
1300}
1301
1302std::vector<std::pair<uint32_t, uint32_t>>
1304 return {std::pair(0, 64), std::pair(1, 128), std::pair(2, 256)};
1305}
1306
1307std::optional<uint32_t>
1308AIE2TargetModel::getLocalLockAddress(uint32_t lockId, TileID tile) const {
1309 auto computeTileBaseAddress = 0x0001F000;
1310 auto memTileBaseAddress = 0x000C0000;
1311 auto shimTileBaseAddress = 0x00014000;
1312 auto lockAddrOffset = 0x10;
1313
1314 if (isCoreTile(tile.col, tile.row) &&
1315 lockId < getNumLocks(tile.col, tile.row))
1316 return computeTileBaseAddress + lockAddrOffset * lockId;
1317
1318 if (isMemTile(tile.col, tile.row) && lockId < getNumLocks(tile.col, tile.row))
1319 return memTileBaseAddress + lockAddrOffset * lockId;
1320
1321 if (isShimNOCorPLTile(tile.col, tile.row) &&
1322 lockId < getNumLocks(tile.col, tile.row))
1323 return shimTileBaseAddress + lockAddrOffset * lockId;
1324
1325 return std::nullopt;
1326}
1327
1328namespace {
1329namespace aie2_port_id {
1330namespace core {
1331
1332// Slave port offset/size constants
1333static constexpr uint32_t S_CORE_OFFSET = 0;
1334static constexpr uint32_t S_CORE_SIZE = 1;
1335static constexpr uint32_t S_CTRL_OFFSET = 3;
1336static constexpr uint32_t S_CTRL_SIZE = 1;
1337static constexpr uint32_t S_DMA_OFFSET = 1;
1338static constexpr uint32_t S_DMA_SIZE = 2;
1339static constexpr uint32_t S_EAST_OFFSET = 19;
1340static constexpr uint32_t S_EAST_SIZE = 4;
1341static constexpr uint32_t S_FIFO_OFFSET = 4;
1342static constexpr uint32_t S_FIFO_SIZE = 1;
1343static constexpr uint32_t S_NORTH_OFFSET = 15;
1344static constexpr uint32_t S_NORTH_SIZE = 4;
1345static constexpr uint32_t S_SOUTH_OFFSET = 5;
1346static constexpr uint32_t S_SOUTH_SIZE = 6;
1347static constexpr uint32_t S_TRACE_OFFSET = 23;
1348static constexpr uint32_t S_TRACE_SIZE = 2;
1349static constexpr uint32_t S_WEST_OFFSET = 11;
1350static constexpr uint32_t S_WEST_SIZE = 4;
1351
1352// Master port offset/size constants
1353static constexpr uint32_t M_CORE_OFFSET = 0;
1354static constexpr uint32_t M_CORE_SIZE = 1;
1355static constexpr uint32_t M_CTRL_OFFSET = 3;
1356static constexpr uint32_t M_CTRL_SIZE = 1;
1357static constexpr uint32_t M_DMA_OFFSET = 1;
1358static constexpr uint32_t M_DMA_SIZE = 2;
1359static constexpr uint32_t M_EAST_OFFSET = 19;
1360static constexpr uint32_t M_EAST_SIZE = 4;
1361static constexpr uint32_t M_FIFO_OFFSET = 4;
1362static constexpr uint32_t M_FIFO_SIZE = 1;
1363static constexpr uint32_t M_NORTH_OFFSET = 13;
1364static constexpr uint32_t M_NORTH_SIZE = 6;
1365static constexpr uint32_t M_SOUTH_OFFSET = 5;
1366static constexpr uint32_t M_SOUTH_SIZE = 4;
1367static constexpr uint32_t M_WEST_OFFSET = 9;
1368static constexpr uint32_t M_WEST_SIZE = 4;
1369
1370} // namespace core
1371
1372namespace mem {
1373
1374// Slave port offset/size constants
1375static constexpr uint32_t S_CTRL_OFFSET = 6;
1376static constexpr uint32_t S_CTRL_SIZE = 1;
1377static constexpr uint32_t S_DMA_OFFSET = 0;
1378static constexpr uint32_t S_DMA_SIZE = 6;
1379static constexpr uint32_t S_NORTH_OFFSET = 13;
1380static constexpr uint32_t S_NORTH_SIZE = 4;
1381static constexpr uint32_t S_SOUTH_OFFSET = 7;
1382static constexpr uint32_t S_SOUTH_SIZE = 6;
1383static constexpr uint32_t S_TRACE_OFFSET = 17;
1384static constexpr uint32_t S_TRACE_SIZE = 1;
1385
1386// Master port offset/size constants
1387static constexpr uint32_t M_CTRL_OFFSET = 6;
1388static constexpr uint32_t M_CTRL_SIZE = 1;
1389static constexpr uint32_t M_DMA_OFFSET = 0;
1390static constexpr uint32_t M_DMA_SIZE = 6;
1391static constexpr uint32_t M_NORTH_OFFSET = 11;
1392static constexpr uint32_t M_NORTH_SIZE = 6;
1393static constexpr uint32_t M_SOUTH_OFFSET = 7;
1394static constexpr uint32_t M_SOUTH_SIZE = 4;
1395
1396} // namespace mem
1397
1398namespace shim {
1399
1400// Slave port offset/size constants
1401static constexpr uint32_t S_CTRL_OFFSET = 0;
1402static constexpr uint32_t S_CTRL_SIZE = 1;
1403static constexpr uint32_t S_EAST_OFFSET = 18;
1404static constexpr uint32_t S_EAST_SIZE = 4;
1405static constexpr uint32_t S_FIFO_OFFSET = 1;
1406static constexpr uint32_t S_FIFO_SIZE = 1;
1407static constexpr uint32_t S_NORTH_OFFSET = 14;
1408static constexpr uint32_t S_NORTH_SIZE = 4;
1409static constexpr uint32_t S_SOUTH_OFFSET = 2;
1410static constexpr uint32_t S_SOUTH_SIZE = 8;
1411static constexpr uint32_t S_TRACE_OFFSET = 22;
1412static constexpr uint32_t S_TRACE_SIZE = 2;
1413static constexpr uint32_t S_WEST_OFFSET = 10;
1414static constexpr uint32_t S_WEST_SIZE = 4;
1415
1416// Master port offset/size constants
1417static constexpr uint32_t M_CTRL_OFFSET = 0;
1418static constexpr uint32_t M_CTRL_SIZE = 1;
1419static constexpr uint32_t M_EAST_OFFSET = 18;
1420static constexpr uint32_t M_EAST_SIZE = 4;
1421static constexpr uint32_t M_FIFO_OFFSET = 1;
1422static constexpr uint32_t M_FIFO_SIZE = 1;
1423static constexpr uint32_t M_NORTH_OFFSET = 12;
1424static constexpr uint32_t M_NORTH_SIZE = 6;
1425static constexpr uint32_t M_SOUTH_OFFSET = 2;
1426static constexpr uint32_t M_SOUTH_SIZE = 6;
1427static constexpr uint32_t M_WEST_OFFSET = 8;
1428static constexpr uint32_t M_WEST_SIZE = 4;
1429
1430} // namespace shim
1431} // namespace aie2_port_id
1432} // namespace
1433
1435 int col, int row, WireBundle bundle, uint32_t port_num, bool master) const {
1436
1437 if (master) {
1438 if (isCoreTile(col, row)) {
1439 switch (bundle) {
1440 case WireBundle::Core:
1441 if (port_num >= aie2_port_id::core::M_CORE_SIZE)
1442 return std::nullopt;
1443 return aie2_port_id::core::M_CORE_OFFSET + port_num;
1444 case WireBundle::TileControl:
1445 if (port_num >= aie2_port_id::core::M_CTRL_SIZE)
1446 return std::nullopt;
1447 return aie2_port_id::core::M_CTRL_OFFSET + port_num;
1448 case WireBundle::DMA:
1449 if (port_num >= aie2_port_id::core::M_DMA_SIZE)
1450 return std::nullopt;
1451 return aie2_port_id::core::M_DMA_OFFSET + port_num;
1452 case WireBundle::East:
1453 if (port_num >= aie2_port_id::core::M_EAST_SIZE)
1454 return std::nullopt;
1455 return aie2_port_id::core::M_EAST_OFFSET + port_num;
1456 case WireBundle::FIFO:
1457 if (port_num >= aie2_port_id::core::M_FIFO_SIZE)
1458 return std::nullopt;
1459 return aie2_port_id::core::M_FIFO_OFFSET + port_num;
1460 case WireBundle::North:
1461 if (port_num >= aie2_port_id::core::M_NORTH_SIZE)
1462 return std::nullopt;
1463 return aie2_port_id::core::M_NORTH_OFFSET + port_num;
1464 case WireBundle::South:
1465 if (port_num >= aie2_port_id::core::M_SOUTH_SIZE)
1466 return std::nullopt;
1467 return aie2_port_id::core::M_SOUTH_OFFSET + port_num;
1468 case WireBundle::West:
1469 if (port_num >= aie2_port_id::core::M_WEST_SIZE)
1470 return std::nullopt;
1471 return aie2_port_id::core::M_WEST_OFFSET + port_num;
1472 default:
1473 return std::nullopt;
1474 }
1475 } else if (isMemTile(col, row)) {
1476 switch (bundle) {
1477 case WireBundle::TileControl:
1478 if (port_num >= aie2_port_id::mem::M_CTRL_SIZE)
1479 return std::nullopt;
1480 return aie2_port_id::mem::M_CTRL_OFFSET + port_num;
1481 case WireBundle::DMA:
1482 if (port_num >= aie2_port_id::mem::M_DMA_SIZE)
1483 return std::nullopt;
1484 return aie2_port_id::mem::M_DMA_OFFSET + port_num;
1485 case WireBundle::North:
1486 if (port_num >= aie2_port_id::mem::M_NORTH_SIZE)
1487 return std::nullopt;
1488 return aie2_port_id::mem::M_NORTH_OFFSET + port_num;
1489 case WireBundle::South:
1490 if (port_num >= aie2_port_id::mem::M_SOUTH_SIZE)
1491 return std::nullopt;
1492 return aie2_port_id::mem::M_SOUTH_OFFSET + port_num;
1493 default:
1494 return std::nullopt;
1495 }
1496 } else if (isShimNOCTile(col, row)) {
1497 switch (bundle) {
1498 case WireBundle::TileControl:
1499 if (port_num >= aie2_port_id::shim::M_CTRL_SIZE)
1500 return std::nullopt;
1501 return aie2_port_id::shim::M_CTRL_OFFSET + port_num;
1502 case WireBundle::East:
1503 if (port_num >= aie2_port_id::shim::M_EAST_SIZE)
1504 return std::nullopt;
1505 return aie2_port_id::shim::M_EAST_OFFSET + port_num;
1506 case WireBundle::FIFO:
1507 if (port_num >= aie2_port_id::shim::M_FIFO_SIZE)
1508 return std::nullopt;
1509 return aie2_port_id::shim::M_FIFO_OFFSET + port_num;
1510 case WireBundle::North:
1511 if (port_num >= aie2_port_id::shim::M_NORTH_SIZE)
1512 return std::nullopt;
1513 return aie2_port_id::shim::M_NORTH_OFFSET + port_num;
1514 case WireBundle::South:
1515 if (port_num >= aie2_port_id::shim::M_SOUTH_SIZE)
1516 return std::nullopt;
1517 return aie2_port_id::shim::M_SOUTH_OFFSET + port_num;
1518 case WireBundle::West:
1519 if (port_num >= aie2_port_id::shim::M_WEST_SIZE)
1520 return std::nullopt;
1521 return aie2_port_id::shim::M_WEST_OFFSET + port_num;
1522 default:
1523 return std::nullopt;
1524 }
1525 }
1526 // Slave ports
1527 } else {
1528
1529 if (isCoreTile(col, row)) {
1530 switch (bundle) {
1531 case WireBundle::Core:
1532 if (port_num >= aie2_port_id::core::S_CORE_SIZE)
1533 return std::nullopt;
1534 return aie2_port_id::core::S_CORE_OFFSET + port_num;
1535 case WireBundle::TileControl:
1536 if (port_num >= aie2_port_id::core::S_CTRL_SIZE)
1537 return std::nullopt;
1538 return aie2_port_id::core::S_CTRL_OFFSET + port_num;
1539 case WireBundle::DMA:
1540 if (port_num >= aie2_port_id::core::S_DMA_SIZE)
1541 return std::nullopt;
1542 return aie2_port_id::core::S_DMA_OFFSET + port_num;
1543 case WireBundle::East:
1544 if (port_num >= aie2_port_id::core::S_EAST_SIZE)
1545 return std::nullopt;
1546 return aie2_port_id::core::S_EAST_OFFSET + port_num;
1547 case WireBundle::FIFO:
1548 if (port_num >= aie2_port_id::core::S_FIFO_SIZE)
1549 return std::nullopt;
1550 return aie2_port_id::core::S_FIFO_OFFSET + port_num;
1551 case WireBundle::North:
1552 if (port_num >= aie2_port_id::core::S_NORTH_SIZE)
1553 return std::nullopt;
1554 return aie2_port_id::core::S_NORTH_OFFSET + port_num;
1555 case WireBundle::South:
1556 if (port_num >= aie2_port_id::core::S_SOUTH_SIZE)
1557 return std::nullopt;
1558 return aie2_port_id::core::S_SOUTH_OFFSET + port_num;
1559 case WireBundle::Trace:
1560 if (port_num >= aie2_port_id::core::S_TRACE_SIZE)
1561 return std::nullopt;
1562 return aie2_port_id::core::S_TRACE_OFFSET + port_num;
1563 case WireBundle::West:
1564 if (port_num >= aie2_port_id::core::S_WEST_SIZE)
1565 return std::nullopt;
1566 return aie2_port_id::core::S_WEST_OFFSET + port_num;
1567 default:
1568 return std::nullopt;
1569 }
1570 } else if (isMemTile(col, row)) {
1571 switch (bundle) {
1572 case WireBundle::TileControl:
1573 if (port_num >= aie2_port_id::mem::S_CTRL_SIZE)
1574 return std::nullopt;
1575 return aie2_port_id::mem::S_CTRL_OFFSET + port_num;
1576 case WireBundle::DMA:
1577 if (port_num >= aie2_port_id::mem::S_DMA_SIZE)
1578 return std::nullopt;
1579 return aie2_port_id::mem::S_DMA_OFFSET + port_num;
1580 case WireBundle::North:
1581 if (port_num >= aie2_port_id::mem::S_NORTH_SIZE)
1582 return std::nullopt;
1583 return aie2_port_id::mem::S_NORTH_OFFSET + port_num;
1584 case WireBundle::South:
1585 if (port_num >= aie2_port_id::mem::S_SOUTH_SIZE)
1586 return std::nullopt;
1587 return aie2_port_id::mem::S_SOUTH_OFFSET + port_num;
1588 case WireBundle::Trace:
1589 if (port_num >= aie2_port_id::mem::S_TRACE_SIZE)
1590 return std::nullopt;
1591 return aie2_port_id::mem::S_TRACE_OFFSET + port_num;
1592 default:
1593 return std::nullopt;
1594 }
1595 } else if (isShimNOCTile(col, row)) {
1596 switch (bundle) {
1597 case WireBundle::TileControl:
1598 if (port_num >= aie2_port_id::shim::S_CTRL_SIZE)
1599 return std::nullopt;
1600 return aie2_port_id::shim::S_CTRL_OFFSET + port_num;
1601 case WireBundle::East:
1602 if (port_num >= aie2_port_id::shim::S_EAST_SIZE)
1603 return std::nullopt;
1604 return aie2_port_id::shim::S_EAST_OFFSET + port_num;
1605 case WireBundle::FIFO:
1606 if (port_num >= aie2_port_id::shim::S_FIFO_SIZE)
1607 return std::nullopt;
1608 return aie2_port_id::shim::S_FIFO_OFFSET + port_num;
1609 case WireBundle::North:
1610 if (port_num >= aie2_port_id::shim::S_NORTH_SIZE)
1611 return std::nullopt;
1612 return aie2_port_id::shim::S_NORTH_OFFSET + port_num;
1613 case WireBundle::South:
1614 if (port_num >= aie2_port_id::shim::S_SOUTH_SIZE)
1615 return std::nullopt;
1616 return aie2_port_id::shim::S_SOUTH_OFFSET + port_num;
1617 case WireBundle::Trace:
1618 if (port_num >= aie2_port_id::shim::S_TRACE_SIZE)
1619 return std::nullopt;
1620 return aie2_port_id::shim::S_TRACE_OFFSET + port_num;
1621 case WireBundle::West:
1622 if (port_num >= aie2_port_id::shim::S_WEST_SIZE)
1623 return std::nullopt;
1624 return aie2_port_id::shim::S_WEST_OFFSET + port_num;
1625 default:
1626 return std::nullopt;
1627 }
1628 }
1629 }
1630 return std::nullopt;
1631}
1632
1634 // Every tile in a shimtile row must be a shimtile, and can only be one type
1635 // of shim tile.
1636 for (int j = 0; j < columns(); j++) {
1637 assert(!isMemTile(j, 0) && (isShimPLTile(j, 0) || isShimNOCTile(j, 0)) &&
1638 !isCoreTile(j, 0));
1639 assert(isShimPLTile(j, 0) ^ isShimNOCTile(j, 0));
1640 }
1641
1642 // Every tile in a memtile row must be a memtile.
1643 for (int i = 1; i < 1 + static_cast<int>(getNumMemTileRows()); i++)
1644 for (int j = 0; j < columns(); j++)
1645 assert(isMemTile(j, i) && !isShimPLTile(j, i) && !isShimNOCTile(j, i) &&
1646 !isCoreTile(j, i));
1647
1648 // Every other tile is a coretile.
1649 for (int i = 1 + getNumMemTileRows(); i < rows(); i++)
1650 for (int j = 0; j < columns(); j++)
1651 assert(!isMemTile(j, i) && !isShimPLTile(j, i) && !isShimNOCTile(j, i) &&
1652 isCoreTile(j, i));
1653
1654 // Looking North, buses must match
1655 for (int i = 0; i < rows() - 1; i++)
1656 for (int j = 0; j < columns(); j++)
1657 assert(getNumSourceSwitchboxConnections(j, i, WireBundle::North) ==
1658 getNumDestSwitchboxConnections(j, i + 1, WireBundle::South));
1659 // Looking South, buses must match
1660 for (int i = 1; i < rows(); i++)
1661 for (int j = 0; j < columns(); j++)
1662 assert(getNumSourceSwitchboxConnections(j, i, WireBundle::South) ==
1663 getNumDestSwitchboxConnections(j, i - 1, WireBundle::North));
1664 // Looking East, buses must match
1665 for (int i = 0; i < rows(); i++)
1666 for (int j = 0; j < columns() - 1; j++)
1667 assert(getNumSourceSwitchboxConnections(j, i, WireBundle::East) ==
1668 getNumDestSwitchboxConnections(j + 1, i, WireBundle::West));
1669 // Looking West, buses must match
1670 for (int i = 0; i < rows(); i++)
1671 for (int j = 1; j < columns(); j++)
1672 assert(getNumSourceSwitchboxConnections(j, i, WireBundle::West) ==
1673 getNumDestSwitchboxConnections(j - 1, i, WireBundle::East));
1674 // Edges have no connections
1675 for (int j = 0; j < columns(); j++)
1676 assert(getNumSourceSwitchboxConnections(j, rows() - 1, WireBundle::North) ==
1677 0);
1678 for (int i = 0; i < rows(); i++)
1680 WireBundle::East) == 0);
1681 for (int i = 0; i < rows(); i++)
1682 assert(getNumSourceSwitchboxConnections(0, i, WireBundle::West) == 0);
1683
1684 // FIFOS are consistent
1685 for (int i = 0; i < rows(); i++)
1686 for (int j = 0; j < columns(); j++)
1687 assert(getNumSourceSwitchboxConnections(j, i, WireBundle::FIFO) ==
1688 getNumDestSwitchboxConnections(j, i, WireBundle::FIFO));
1689}
1690
1691std::optional<uint32_t>
1692AIETargetModel::getLockLocalBaseIndex(int localCol, int localRow, int lockCol,
1693 int lockRow) const {
1694 if (isCoreTile(localCol, localRow)) {
1695 if (isMemSouth(localCol, localRow, lockCol, lockRow))
1696 return 0;
1697 if (isMemWest(localCol, localRow, lockCol, lockRow))
1698 return getNumLocks(localCol, localRow);
1699 if (isMemNorth(localCol, localRow, lockCol, lockRow))
1700 return getNumLocks(localCol, localRow) * 2;
1701 if (isMemEast(localCol, localRow, lockCol, lockRow))
1702 return getNumLocks(localCol, localRow) * 3;
1703 }
1704
1705 if (isMemTile(localCol, localRow)) {
1706 if (isWest(localCol, localRow, lockCol, lockRow))
1707 return 0;
1708 if (isInternal(localCol, localRow, lockCol, lockRow))
1709 return getNumLocks(localCol, localRow);
1710 if (isEast(localCol, localRow, lockCol, lockRow))
1711 return getNumLocks(localCol, localRow) * 2;
1712 }
1713
1714 return std::nullopt;
1715}
1716
1717std::optional<uint32_t>
1718AIETargetModel::getMemLocalBaseAddress(int localCol, int localRow, int memCol,
1719 int memRow) const {
1720 if (isCoreTile(localCol, localRow)) {
1721 if (isMemSouth(localCol, localRow, memCol, memRow))
1722 return getMemSouthBaseAddress();
1723 if (isMemWest(localCol, localRow, memCol, memRow))
1724 return getMemWestBaseAddress();
1725 if (isMemNorth(localCol, localRow, memCol, memRow))
1726 return getMemNorthBaseAddress();
1727 if (isMemEast(localCol, localRow, memCol, memRow))
1728 return getMemEastBaseAddress();
1729 }
1730
1731 if (isMemTile(localCol, localRow)) {
1732 if (isWest(localCol, localRow, memCol, memRow))
1733 return 0;
1734 if (isInternal(localCol, localRow, memCol, memRow))
1735 return getMemTileSize();
1736 if (isEast(localCol, localRow, memCol, memRow))
1737 return getMemTileSize() * 2;
1738 }
1739
1740 return std::nullopt;
1741}
1742
1743bool AIETargetModel::isSupportedBlockFormat(std::string const &format) const {
1744 return false;
1745}
1746
1747AIEArch BaseNPU2TargetModel::getTargetArch() const { return AIEArch::AIE2p; }
1748
1749std::vector<std::pair<uint32_t, uint32_t>>
1751 return {std::pair(0, 64), std::pair(1, 128), std::pair(2, 256),
1752 std::pair(3, 512)};
1753}
1754
1756 std::string const &format) const {
1757 std::set<std::string> supportedTypes = {"v8bfp16ebs8", "v16bfp16ebs16"};
1758 return static_cast<bool>(supportedTypes.find(format) != supportedTypes.end());
1759}
1760
1761// AIE2PS overrides: shim DMA registers are at different offsets than AIE2.
1762// Memtile and core tile DMA addresses are identical to AIE2.
1763uint64_t
1764AIE2PSTargetModel::getDmaBdAddress(int col, int row, uint32_t bd_id,
1765 int channel,
1766 AIE::DMAChannelDir direction) const {
1767 if (isShimNOCTile(col, row)) {
1768 uint64_t offset = 0x00009000 + bd_id * 0x30;
1769 return ((col & 0xff) << getColumnShift()) |
1770 ((row & 0xff) << getRowShift()) | offset;
1771 }
1772 // Memtile and core tile use same addresses as AIE2.
1773 return AIE2TargetModel::getDmaBdAddress(col, row, bd_id, channel, direction);
1774}
1775
1776uint32_t
1777AIE2PSTargetModel::getDmaControlAddress(int col, int row, int channel,
1778 AIE::DMAChannelDir direction) const {
1779 if (isShimNOCTile(col, row)) {
1780 uint32_t offset = 0x00009300 + (channel * 0x8);
1781 if (direction == AIE::DMAChannelDir::MM2S)
1782 offset += 0x10;
1783 return ((col & 0xff) << getColumnShift()) |
1784 ((row & 0xff) << getRowShift()) | offset;
1785 }
1786 // Memtile and core tile use same addresses as AIE2.
1787 return AIE2TargetModel::getDmaControlAddress(col, row, channel, direction);
1788}
1789
1790std::optional<uint32_t>
1791AIE2PSTargetModel::getDmaStatusAddress(int col, int row, int channel,
1792 AIE::DMAChannelDir direction) const {
1793 // The AIE2PS shim relocates its DMA registers (control is at 0x9300, not
1794 // 0x1D200), and the status block has not been confirmed against a register
1795 // spec. Report "unknown" rather than guess an address a maskpoll would then
1796 // read garbage from; memtile and core tiles match AIE2.
1797 if (isShimNOCTile(col, row))
1798 return std::nullopt;
1799 return AIE2TargetModel::getDmaStatusAddress(col, row, channel, direction);
1800}
1801
1802// AIE2PS shim tiles have uC stream switch port for routing TCT to CERT uC.
1803uint32_t
1805 WireBundle bundle) const {
1806 if (isShimNOCTile(col, row) && bundle == WireBundle::Controller32)
1807 return 1;
1808 return AIE2TargetModel::getNumDestSwitchboxConnections(col, row, bundle);
1809}
1810
1811uint32_t
1813 WireBundle bundle) const {
1814 if (isShimNOCTile(col, row) && bundle == WireBundle::Controller32)
1815 return 1;
1817}
1818
1820 int col, int row, WireBundle bundle, uint32_t channel, bool master) const {
1821 // AIE2PS shim: Controller32 maps to hw master port 22 / slave port 23.
1822 if (isShimNOCTile(col, row) && bundle == WireBundle::Controller32) {
1823 if (channel > 0)
1824 return std::nullopt;
1825 return master ? 22 : 23;
1826 }
1827 return AIE2TargetModel::getStreamSwitchPortIndex(col, row, bundle, channel,
1828 master);
1829}
1830
1831} // namespace AIE
1832} // 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.
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.
std::optional< uint32_t > getStreamSwitchPortIndex(int col, int row, WireBundle bundle, uint32_t port_num, bool master) const override
Get stream switch port index for a given port specification Return port index for Stream_Switch_Event...
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 getNumSourceSwitchboxConnections(int col, int row, WireBundle bundle) const override
Return the number of sources of connections inside a switchbox.
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...
uint32_t getNumDestSwitchboxConnections(int col, int row, WireBundle bundle) const override
Return the number of destinations of connections inside a switchbox.
std::optional< uint32_t > getDmaStatusAddress(int col, int row, int channel, AIE::DMAChannelDir direction) const override
Return the address of the DMA status register for a channel, or nullopt when this target's layout has...
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,...
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 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< uint32_t > getDmaStatusAddress(int col, int row, int channel, AIE::DMAChannelDir direction) const override
Return the address of the DMA status register for a channel, or nullopt when this target's layout has...
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::optional< uint32_t > getStreamSwitchPortIndex(int col, int row, WireBundle bundle, uint32_t port_num, bool master) const override
Get stream switch port index for a given port specification Return port index for Stream_Switch_Event...
std::unique_ptr< RegisterDatabase > loadRegisterDatabase() const override
AIE2 TargetModel.
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.
const DmaBdLayout * getDmaBdLayout(AIETileType tileType) const override
Return the register layout of a buffer descriptor on the given tile type, or null if the target has n...
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 > encodeFieldValue(const BitFieldInfo &field, uint32_t value) const
Encode a field value with proper bit shifting.
std::optional< uint32_t > resolvePortValue(llvm::StringRef value, TileID tile, bool master) const
Resolve stream switch port specification to port index.
llvm::DenseMap< TileID, int > getTileToControllerIdMap(bool columnWiseUniqueIDs=true) const
Return a mapping from tile coordinates to controller IDs.
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.
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.
struct TileID { friend std::ostream &operator<<(std::ostream &os, const TileID &s) { os<< "TileID("<< s.col<< ", "<< s.row<< ")"; return os; } friend std::string to_string(const TileID &s) { std::ostringstream ss; ss<< s; return ss.str(); } friend llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const TileID &s) { os<< to_string(s); return os; } inline bool operator<(const TileID &rhs) const { return std::tie(col, row)< std::tie(rhs.col, rhs.row); } bool operator==(const TileID &rhs) const { return std::tie(col, row)==std::tie(rhs.col, rhs.row); } bool operator!=(const TileID &rhs) const { return !(*this==rhs);} int col, row;} TileID
AIEArch
Definition Passes.h:19
Bit field information for a register.
The register layout of one tile type's DMA buffer descriptor.