263 ConversionTarget target(getContext());
266 DenseMap<std::pair<PhysPort, int>, SmallVector<PhysPort, 4>> packetFlows;
267 DenseMap<std::pair<PhysPort, int>, SmallVector<PhysPort, 4>> ctrlPacketFlows;
268 SmallVector<std::pair<PhysPort, int>, 4> slavePorts;
269 DenseMap<std::pair<PhysPort, int>,
int> slaveAMSels;
271 DenseMap<PhysPort, BoolAttr> keepPktHeaderAttr;
273 DenseMap<std::pair<PhysPort, int>,
bool> ctrlPktFlows;
275 for (
auto tileOp : device.getOps<TileOp>()) {
276 int col = tileOp.colIndex();
277 int row = tileOp.rowIndex();
282 DenseMap<TileID, SmallVector<std::pair<Connect, int>, 8>> switchboxes;
283 for (PacketFlowOp pktFlowOp : device.getOps<PacketFlowOp>()) {
284 Region &r = pktFlowOp.getPorts();
285 Block &b = r.front();
286 int flowID = pktFlowOp.IDInt();
287 Port srcPort, destPort;
288 TileOp srcTile, destTile;
291 for (Operation &Op : b.getOperations()) {
292 if (
auto pktSource = dyn_cast<PacketSourceOp>(Op)) {
293 srcTile = dyn_cast<TileOp>(pktSource.getTile().getDefiningOp());
294 srcPort = pktSource.port();
295 srcCoords = {srcTile.colIndex(), srcTile.rowIndex()};
296 }
else if (
auto pktDest = dyn_cast<PacketDestOp>(Op)) {
297 destTile = dyn_cast<TileOp>(pktDest.getTile().getDefiningOp());
298 destPort = pktDest.port();
299 destCoords = {destTile.colIndex(), destTile.rowIndex()};
301 auto keep = pktFlowOp.getKeepPktHeader();
302 keepPktHeaderAttr[{destTile, destPort}] =
303 keep ? BoolAttr::get(Op.getContext(), *keep) :
nullptr;
310 for (
const auto &[curr, setting] : settings) {
311 assert(setting.srcs.size() == setting.dsts.size());
312 TileID currTile = {curr.col, curr.row};
313 for (
size_t i = 0; i < setting.srcs.size(); i++) {
315 Port dest = setting.dsts[i];
317 if (!
findPathToDest(settings, currTile, dest.bundle, dest.channel,
318 destCoords, destPort.bundle,
322 {dest.bundle, dest.channel}};
323 if (std::find(switchboxes[currTile].begin(),
324 switchboxes[currTile].end(),
325 std::pair{connect, flowID}) ==
326 switchboxes[currTile].end())
327 switchboxes[currTile].push_back({connect, flowID});
330 auto ctrlPkt = pktFlowOp.getPriorityRoute();
333 flowID}] = ctrlPkt ? *ctrlPkt :
false;
341 LLVM_DEBUG(llvm::dbgs() <<
"Check switchboxes\n");
343 for (
const auto &[tileId, connects] : switchboxes) {
344 int col = tileId.col;
345 int row = tileId.row;
347 Operation *tileOp = tile.getOperation();
348 LLVM_DEBUG(llvm::dbgs() <<
"***switchbox*** " <<
col <<
" " <<
row <<
'\n');
349 for (
const auto &[conn, flowID] : connects) {
350 Port sourcePort = conn.src;
351 Port destPort = conn.dst;
353 std::make_pair(std::make_pair(tileOp, sourcePort), flowID);
354 if (ctrlPktFlows[{{tileOp, destPort}, flowID}])
355 ctrlPacketFlows[sourceFlow].push_back({tileOp, destPort});
357 packetFlows[sourceFlow].push_back({tileOp, destPort});
358 slavePorts.push_back(sourceFlow);
359 LLVM_DEBUG(llvm::dbgs() <<
"flowID " << flowID <<
':'
360 << stringifyWireBundle(sourcePort.bundle) <<
" "
361 << sourcePort.channel <<
" -> "
362 << stringifyWireBundle(destPort.bundle) <<
" "
363 << destPort.channel <<
"\n");
378 DenseMap<std::pair<Operation *, int>, SmallVector<Port, 4>> masterAMSels;
381 DenseMap<Operation *, int> amselValues;
386 auto getArbiterIDFromAmsel = [numArbiters](
int amsel) {
387 return amsel % numArbiters;
390 auto getAmselFromArbiterIDAndMsel = [numArbiters](
int arbiter,
int msel) {
391 return arbiter + msel * numArbiters;
395 auto getNewUniqueAmsel = [&](DenseMap<std::pair<Operation *, int>,
396 SmallVector<Port, 4>>
398 Operation *tileOp,
bool isCtrlPkt) {
400 for (
int i = numMsels - 1; i >= 0; i--)
401 for (
int a = numArbiters - 1; a >= 0; a--)
402 if (!masterAMSels.count({tileOp, getAmselFromArbiterIDAndMsel(a, i)}))
403 return getAmselFromArbiterIDAndMsel(a, i);
405 for (
int i = 0; i < numMsels; i++)
406 for (
int a = 0; a < numArbiters; a++)
407 if (!masterAMSels.count({tileOp, getAmselFromArbiterIDAndMsel(a, i)}))
408 return getAmselFromArbiterIDAndMsel(a, i);
410 tileOp->emitOpError(
"tile op has used up all arbiter-msel combinations");
414 auto getNewUniqueAmselPerArbiterID =
415 [&](DenseMap<std::pair<Operation *, int>, SmallVector<Port, 4>>
417 Operation *tileOp,
int arbiter) {
418 for (
int i = 0; i < numMsels; i++)
419 if (!masterAMSels.count(
420 {tileOp, getAmselFromArbiterIDAndMsel(arbiter, i)}))
421 return getAmselFromArbiterIDAndMsel(arbiter, i);
422 tileOp->emitOpError(
"tile op arbiter ")
423 << std::to_string(arbiter) <<
"has used up all its msels";
430 auto getUniqueIdPerFlowPerSB = [](
int flowID, WireBundle srcBundle,
431 SmallVector<PhysPort, 4> dests) {
432 int totalNumOfWireBundles = AIE::getMaxEnumValForWireBundle();
433 int currMultiplier = totalNumOfWireBundles;
434 int uniqueId = flowID;
436 currMultiplier += totalNumOfWireBundles;
437 for (
auto dst : dests) {
438 uniqueId += currMultiplier;
440 currMultiplier += totalNumOfWireBundles;
444 auto getSortedPacketFlows =
445 [&](DenseMap<std::pair<PhysPort, int>, SmallVector<PhysPort, 4>> pktFlows,
446 DenseMap<std::pair<PhysPort, int>, SmallVector<PhysPort, 4>>
449 std::pair<std::pair<PhysPort, int>, SmallVector<PhysPort, 4>>>
450 sortedpktFlows(pktFlows.begin(), pktFlows.end());
452 sortedpktFlows.begin(), sortedpktFlows.end(),
453 [getUniqueIdPerFlowPerSB](
const auto &lhs,
const auto &rhs) {
454 int lhsUniqueID = getUniqueIdPerFlowPerSB(
455 lhs.first.second, lhs.first.first.second.bundle, lhs.second);
456 int rhsUniqueID = getUniqueIdPerFlowPerSB(
457 rhs.first.second, rhs.first.first.second.bundle, rhs.second);
458 return lhsUniqueID < rhsUniqueID;
461 std::pair<std::pair<PhysPort, int>, SmallVector<PhysPort, 4>>>
462 sortedctrlpktFlows(ctrlPktFlows.begin(), ctrlPktFlows.end());
464 sortedctrlpktFlows.begin(), sortedctrlpktFlows.end(),
465 [getUniqueIdPerFlowPerSB](
const auto &lhs,
const auto &rhs) {
466 int lhsUniqueID = getUniqueIdPerFlowPerSB(
467 lhs.first.second, lhs.first.first.second.bundle, lhs.second);
468 int rhsUniqueID = getUniqueIdPerFlowPerSB(
469 rhs.first.second, rhs.first.first.second.bundle, rhs.second);
470 return lhsUniqueID < rhsUniqueID;
472 sortedctrlpktFlows.insert(sortedctrlpktFlows.end(),
473 sortedpktFlows.begin(), sortedpktFlows.end());
474 return sortedctrlpktFlows;
477 std::vector<std::pair<std::pair<PhysPort, int>, SmallVector<PhysPort, 4>>>
478 sortedPacketFlows = getSortedPacketFlows(packetFlows, ctrlPacketFlows);
480 packetFlows.insert(ctrlPacketFlows.begin(), ctrlPacketFlows.end());
487 for (
const auto &packetFlow : sortedPacketFlows) {
489 Operation *tileOp = packetFlow.first.first.first;
490 if (amselValues.count(tileOp) == 0)
491 amselValues[tileOp] = 0;
500 int amselValue = amselValues[tileOp];
501 assert(amselValue < numArbiters &&
"Could not allocate new arbiter!");
507 bool foundMatchedDest =
510 int foundPartialMatchArbiter =
513 for (
const auto &map : masterAMSels) {
514 if (map.first.first != tileOp)
516 amselValue = map.first.second;
519 SmallVector<Port, 4> ports(masterAMSels[{tileOp, amselValue}]);
525 bool mismatched =
false;
527 for (
auto dest : packetFlow.second) {
529 if (std::find(ports.begin(), ports.end(),
port) == ports.end())
536 foundMatchedDest =
true;
538 foundPartialMatchArbiter = getArbiterIDFromAmsel(amselValue);
539 else if (ports.size() != packetFlow.second.size())
540 foundPartialMatchArbiter = getArbiterIDFromAmsel(amselValue);
545 if (!foundMatchedDest) {
553 llvm::any_of(packetFlow.second, [&](PhysPort destPhysPort) {
554 Port port = destPhysPort.second;
555 return ctrlPktFlows[{{tileOp, port}, packetFlow.first.second}];
558 amselValue = getNewUniqueAmsel(masterAMSels, tileOp, ctrlPktAMsel);
560 for (
auto dest : packetFlow.second) {
562 masterAMSels[{tileOp, amselValue}].push_back(
port);
564 }
else if (foundPartialMatchArbiter >= 0) {
567 amselValue = getNewUniqueAmselPerArbiterID(masterAMSels, tileOp,
568 foundPartialMatchArbiter);
570 for (
auto dest : packetFlow.second) {
572 masterAMSels[{tileOp, amselValue}].push_back(
port);
576 slaveAMSels[packetFlow.first] = amselValue;
577 amselValues[tileOp] = getArbiterIDFromAmsel(amselValue);
582 DenseMap<PhysPort, SmallVector<int, 4>> mastersets;
583 for (
const auto &[physPort, ports] : masterAMSels) {
584 Operation *tileOp = physPort.first;
586 int amselValue = physPort.second;
587 for (
auto port : ports) {
588 PhysPort pp = {tileOp,
port};
589 mastersets[pp].push_back(amselValue);
593 LLVM_DEBUG(llvm::dbgs() <<
"CHECK mastersets\n");
595 for (
const auto &[physPort, values] : mastersets) {
596 Operation *tileOp = physPort.first;
597 WireBundle bundle = physPort.second.bundle;
598 int channel = physPort.second.channel;
600 auto tile = dyn_cast<TileOp>(tileOp);
601 LLVM_DEBUG(llvm::dbgs()
602 <<
"master " << tile <<
" " << stringifyWireBundle(bundle)
604 for (
auto value : values)
605 LLVM_DEBUG(
llvm::dbgs() <<
"amsel: " <<
value <<
'\n');
613 SmallVector<SmallVector<std::pair<PhysPort, int>, 4>, 4> slaveGroups;
614 SmallVector<std::pair<PhysPort, int>, 4> workList(slavePorts);
615 while (!workList.empty()) {
616 auto slave1 = workList.pop_back_val();
617 Port slavePort1 = slave1.first.second;
619 bool foundgroup =
false;
620 for (
auto &group : slaveGroups) {
621 auto slave2 = group.front();
622 if (
Port slavePort2 = slave2.first.second; slavePort1 != slavePort2)
626 auto dests1 = packetFlows[slave1];
627 auto dests2 = packetFlows[slave2];
628 if (dests1.size() != dests2.size())
631 for (
auto dest1 : dests1) {
632 if (std::find(dests2.begin(), dests2.end(), dest1) == dests2.end()) {
639 group.push_back(slave1);
646 SmallVector<std::pair<PhysPort, int>, 4> group({slave1});
647 slaveGroups.push_back(group);
651 DenseMap<std::pair<PhysPort, int>,
int> slaveMasks;
652 for (
const auto &group : slaveGroups) {
657 int mask[5] = {-1, -1, -1, -1, -1};
658 for (
auto port : group) {
659 int ID =
port.second;
660 for (
int i = 0; i < 5; i++) {
662 mask[i] = ID >> i & 0x1;
663 else if (mask[i] != (ID >> i & 0x1))
669 for (
int i = 4; i >= 0; i--) {
674 maskValue = (maskValue << 1) + mask[i];
676 for (
auto port : group)
677 slaveMasks[
port] = maskValue;
681 LLVM_DEBUG(llvm::dbgs() <<
"CHECK Slave Masks\n");
682 for (
auto map : slaveMasks) {
683 auto port = map.first.first;
684 auto tile = dyn_cast<TileOp>(
port.first);
685 WireBundle bundle =
port.second.bundle;
687 int ID = map.first.second;
688 int mask = map.second;
690 LLVM_DEBUG(llvm::dbgs()
691 <<
"Port " << tile <<
" " << stringifyWireBundle(bundle) <<
" "
693 LLVM_DEBUG(llvm::dbgs()
694 <<
"Mask " <<
"0x" << llvm::Twine::utohexstr(mask) <<
'\n');
695 LLVM_DEBUG(llvm::dbgs()
696 <<
"ID " <<
"0x" << llvm::Twine::utohexstr(ID) <<
'\n');
697 for (
int i = 0; i < 31; i++) {
698 if ((i & mask) == (ID & mask))
699 LLVM_DEBUG(llvm::dbgs() <<
"matches flow ID " <<
"0x"
700 << llvm::Twine::utohexstr(i) <<
'\n');
709 for (
const auto &swMap : mastersets) {
713 std::pair<xilinx::AIE::TileID, Operation *> &tileMapEntry) {
714 return tileMapEntry.second == swMap.first.first;
716 auto newTileOp = dyn_cast<TileOp>(swMap.first.first);
717 tiles[{newTileOp.colIndex(), newTileOp.rowIndex()}] = newTileOp;
721 for (
auto map : tiles) {
722 Operation *tileOp = map.second;
723 auto tile = dyn_cast<TileOp>(tileOp);
726 builder.setInsertionPointAfter(tileOp);
728 analyzer.getSwitchbox(builder, tile.colIndex(), tile.rowIndex());
729 SwitchboxOp::ensureTerminator(swbox.getConnections(), builder,
730 builder.getUnknownLoc());
731 Block &b = swbox.getConnections().front();
732 builder.setInsertionPoint(b.getTerminator());
734 std::vector<bool> amselOpNeededVector(numMsels * numArbiters);
735 for (
const auto &map : mastersets) {
736 if (tileOp != map.first.first)
739 for (
auto value : map.second) {
740 amselOpNeededVector[
value] =
true;
744 DenseMap<int, AMSelOp> amselOps;
745 for (
int i = 0; i < numMsels; i++) {
746 for (
int a = 0; a < numArbiters; a++) {
747 auto amselValue = getAmselFromArbiterIDAndMsel(a, i);
748 if (amselOpNeededVector[amselValue]) {
752 builder.create<AMSelOp>(builder.getUnknownLoc(), arbiterID, msel);
753 amselOps[amselValue] = amsel;
759 SmallVector<Port, 4> tileMasters;
760 for (
const auto &map : mastersets) {
761 if (tileOp != map.first.first)
763 tileMasters.push_back(map.first.second);
766 std::sort(tileMasters.begin(), tileMasters.end());
767 for (
auto tileMaster : tileMasters) {
768 WireBundle bundle = tileMaster.bundle;
769 int channel = tileMaster.channel;
770 SmallVector<int, 4> msels = mastersets[{tileOp, tileMaster}];
771 SmallVector<Value, 4> amsels;
772 for (
auto msel : msels) {
773 assert(amselOps.count(msel) == 1);
774 amsels.push_back(amselOps[msel]);
777 builder.create<MasterSetOp>(
778 builder.getUnknownLoc(), builder.getIndexType(), bundle,
channel,
779 amsels, keepPktHeaderAttr[{tileOp, tileMaster}]);
783 DenseMap<Port, PacketRulesOp> slaveRules;
784 for (
auto group : slaveGroups) {
785 builder.setInsertionPoint(b.getTerminator());
787 auto port = group.front().first;
788 if (tileOp !=
port.first)
791 WireBundle bundle =
port.second.bundle;
793 auto slave =
port.second;
795 int mask = slaveMasks[group.front()];
796 int ID = group.front().second & mask;
800 for (
auto slave : group)
801 assert((slave.second & mask) == ID);
803 Value amsel = amselOps[slaveAMSels[group.front()]];
805 PacketRulesOp packetrules;
806 if (slaveRules.count(slave) == 0) {
807 packetrules = builder.create<PacketRulesOp>(builder.getUnknownLoc(),
809 PacketRulesOp::ensureTerminator(packetrules.getRules(), builder,
810 builder.getUnknownLoc());
811 slaveRules[slave] = packetrules;
813 packetrules = slaveRules[slave];
815 Block &rules = packetrules.getRules().front();
818 for (
auto rule : rules.getOps<PacketRuleOp>()) {
819 auto verifyMask = rule.maskInt();
820 auto verifyValue = rule.valueInt();
821 if ((group.front().second & verifyMask) == verifyValue) {
822 rule->emitOpError(
"can lead to false packet id match for id ")
823 << ID <<
", which is not supposed to pass through this port.";
824 rule->emitRemark(
"Please consider changing all uses of packet id ")
825 << ID <<
" to avoid deadlock.";
829 builder.setInsertionPoint(rules.getTerminator());
830 builder.create<PacketRuleOp>(builder.getUnknownLoc(), mask, ID, amsel);
840 for (
auto switchbox : make_early_inc_range(device.getOps<SwitchboxOp>())) {
841 auto retVal = switchbox->getOperand(0);
842 auto tileOp = retVal.getDefiningOp<TileOp>();
845 if (!tileOp.isShimNOCTile())
849 if (&switchbox.getBody()->front() == switchbox.getBody()->getTerminator())
852 Region &r = switchbox.getConnections();
853 Block &b = r.front();
858 for (
auto shimmux : device.getOps<ShimMuxOp>()) {
859 if (shimmux.getTile() == tileOp) {
866 for (Operation &Op : b.getOperations()) {
867 if (
auto pktrules = dyn_cast<PacketRulesOp>(Op)) {
870 if (pktrules.getSourceBundle() == WireBundle::DMA) {
875 builder.setInsertionPointAfter(tileOp);
876 shimOp = analyzer.getShimMux(builder, tileOp.colIndex());
880 Region &r0 = shimOp.getConnections();
881 Block &b0 = r0.front();
882 builder.setInsertionPointToStart(&b0);
884 pktrules.setSourceBundle(WireBundle::South);
885 if (pktrules.getSourceChannel() == 0) {
886 pktrules.setSourceChannel(3);
887 builder.create<ConnectOp>(builder.getUnknownLoc(), WireBundle::DMA,
888 0, WireBundle::North, 3);
890 if (pktrules.getSourceChannel() == 1) {
891 pktrules.setSourceChannel(7);
892 builder.create<ConnectOp>(builder.getUnknownLoc(), WireBundle::DMA,
893 1, WireBundle::North, 7);
898 if (
auto mtset = dyn_cast<MasterSetOp>(Op)) {
901 if (mtset.getDestBundle() == WireBundle::DMA) {
906 builder.setInsertionPointAfter(tileOp);
907 shimOp = analyzer.getShimMux(builder, tileOp.colIndex());
911 Region &r0 = shimOp.getConnections();
912 Block &b0 = r0.front();
913 builder.setInsertionPointToStart(&b0);
915 mtset.setDestBundle(WireBundle::South);
916 if (mtset.getDestChannel() == 0) {
917 mtset.setDestChannel(2);
918 builder.create<ConnectOp>(builder.getUnknownLoc(),
919 WireBundle::North, 2, WireBundle::DMA, 0);
921 if (mtset.getDestChannel() == 1) {
922 mtset.setDestChannel(3);
923 builder.create<ConnectOp>(builder.getUnknownLoc(),
924 WireBundle::North, 3, WireBundle::DMA, 1);
931 RewritePatternSet patterns(&getContext());
933 if (failed(applyPartialConversion(device, target, std::move(patterns))))