264 ConversionTarget target(getContext());
267 DenseMap<std::pair<PhysPort, int>, SmallVector<PhysPort, 4>> packetFlows;
268 DenseMap<std::pair<PhysPort, int>, SmallVector<PhysPort, 4>> ctrlPacketFlows;
269 SmallVector<std::pair<PhysPort, int>, 4> slavePorts;
270 DenseMap<std::pair<PhysPort, int>,
int> slaveAMSels;
272 DenseMap<PhysPort, BoolAttr> keepPktHeaderAttr;
274 DenseMap<std::pair<PhysPort, int>,
bool> ctrlPktFlows;
276 for (
auto tileOp : device.getOps<TileOp>()) {
277 int col = tileOp.colIndex();
278 int row = tileOp.rowIndex();
283 DenseMap<TileID, SmallVector<std::pair<Connect, int>, 8>> switchboxes;
284 for (PacketFlowOp pktFlowOp : device.getOps<PacketFlowOp>()) {
285 Region &r = pktFlowOp.getPorts();
286 Block &b = r.front();
287 int flowID = pktFlowOp.IDInt();
288 Port srcPort, destPort;
289 TileOp srcTile, destTile;
292 for (Operation &Op : b.getOperations()) {
293 if (
auto pktSource = dyn_cast<PacketSourceOp>(Op)) {
294 srcTile = dyn_cast<TileOp>(pktSource.getTile().getDefiningOp());
295 srcPort = pktSource.port();
296 srcCoords = {srcTile.colIndex(), srcTile.rowIndex()};
297 }
else if (
auto pktDest = dyn_cast<PacketDestOp>(Op)) {
298 destTile = dyn_cast<TileOp>(pktDest.getTile().getDefiningOp());
299 destPort = pktDest.port();
300 destCoords = {destTile.colIndex(), destTile.rowIndex()};
302 auto keep = pktFlowOp.getKeepPktHeader();
303 keepPktHeaderAttr[{destTile, destPort}] =
304 keep ? BoolAttr::get(Op.getContext(), *keep) :
nullptr;
311 for (
const auto &[curr, setting] : settings) {
312 assert(setting.srcs.size() == setting.dsts.size());
313 TileID currTile = {curr.col, curr.row};
314 for (
size_t i = 0; i < setting.srcs.size(); i++) {
316 Port dest = setting.dsts[i];
318 if (!
findPathToDest(settings, currTile, dest.bundle, dest.channel,
319 destCoords, destPort.bundle,
323 {dest.bundle, dest.channel}};
324 if (std::find(switchboxes[currTile].begin(),
325 switchboxes[currTile].end(),
326 std::pair{connect, flowID}) ==
327 switchboxes[currTile].end())
328 switchboxes[currTile].push_back({connect, flowID});
331 auto ctrlPkt = pktFlowOp.getPriorityRoute();
334 flowID}] = ctrlPkt ? *ctrlPkt :
false;
342 LLVM_DEBUG(llvm::dbgs() <<
"Check switchboxes\n");
344 for (
const auto &[tileId, connects] : switchboxes) {
345 int col = tileId.col;
346 int row = tileId.row;
348 Operation *tileOp = tile.getOperation();
349 LLVM_DEBUG(llvm::dbgs() <<
"***switchbox*** " <<
col <<
" " <<
row <<
'\n');
350 for (
const auto &[conn, flowID] : connects) {
351 Port sourcePort = conn.src;
352 Port destPort = conn.dst;
354 std::make_pair(std::make_pair(tileOp, sourcePort), flowID);
355 if (ctrlPktFlows[{{tileOp, destPort}, flowID}])
356 ctrlPacketFlows[sourceFlow].push_back({tileOp, destPort});
358 packetFlows[sourceFlow].push_back({tileOp, destPort});
359 slavePorts.push_back(sourceFlow);
360 LLVM_DEBUG(llvm::dbgs() <<
"flowID " << flowID <<
':'
361 << stringifyWireBundle(sourcePort.bundle) <<
" "
362 << sourcePort.channel <<
" -> "
363 << stringifyWireBundle(destPort.bundle) <<
" "
364 << destPort.channel <<
"\n");
379 DenseMap<std::pair<Operation *, int>, SmallVector<Port, 4>> masterAMSels;
382 DenseMap<Operation *, int> amselValues;
387 auto getArbiterIDFromAmsel = [numArbiters](
int amsel) {
388 return amsel % numArbiters;
391 auto getAmselFromArbiterIDAndMsel = [numArbiters](
int arbiter,
int msel) {
392 return arbiter + msel * numArbiters;
396 auto getNewUniqueAmsel = [&](DenseMap<std::pair<Operation *, int>,
397 SmallVector<Port, 4>>
399 Operation *tileOp,
bool isCtrlPkt) {
401 for (
int i = numMsels - 1; i >= 0; i--)
402 for (
int a = numArbiters - 1; a >= 0; a--)
403 if (!masterAMSels.count({tileOp, getAmselFromArbiterIDAndMsel(a, i)}))
404 return getAmselFromArbiterIDAndMsel(a, i);
406 for (
int i = 0; i < numMsels; i++)
407 for (
int a = 0; a < numArbiters; a++)
408 if (!masterAMSels.count({tileOp, getAmselFromArbiterIDAndMsel(a, i)}))
409 return getAmselFromArbiterIDAndMsel(a, i);
411 tileOp->emitOpError(
"tile op has used up all arbiter-msel combinations");
415 auto getNewUniqueAmselPerArbiterID =
416 [&](DenseMap<std::pair<Operation *, int>, SmallVector<Port, 4>>
418 Operation *tileOp,
int arbiter) {
419 for (
int i = 0; i < numMsels; i++)
420 if (!masterAMSels.count(
421 {tileOp, getAmselFromArbiterIDAndMsel(arbiter, i)}))
422 return getAmselFromArbiterIDAndMsel(arbiter, i);
423 tileOp->emitOpError(
"tile op arbiter ")
424 << std::to_string(arbiter) <<
"has used up all its msels";
431 auto getUniqueIdPerFlowPerSB = [](
int flowID, WireBundle srcBundle,
432 SmallVector<PhysPort, 4> dests) {
433 int totalNumOfWireBundles = AIE::getMaxEnumValForWireBundle();
434 int currMultiplier = totalNumOfWireBundles;
435 int uniqueId = flowID;
437 currMultiplier += totalNumOfWireBundles;
438 for (
auto dst : dests) {
439 uniqueId += currMultiplier;
441 currMultiplier += totalNumOfWireBundles;
445 auto getSortedPacketFlows =
446 [&](DenseMap<std::pair<PhysPort, int>, SmallVector<PhysPort, 4>> pktFlows,
447 DenseMap<std::pair<PhysPort, int>, SmallVector<PhysPort, 4>>
450 std::pair<std::pair<PhysPort, int>, SmallVector<PhysPort, 4>>>
451 sortedpktFlows(pktFlows.begin(), pktFlows.end());
453 sortedpktFlows.begin(), sortedpktFlows.end(),
454 [getUniqueIdPerFlowPerSB](
const auto &lhs,
const auto &rhs) {
455 int lhsUniqueID = getUniqueIdPerFlowPerSB(
456 lhs.first.second, lhs.first.first.second.bundle, lhs.second);
457 int rhsUniqueID = getUniqueIdPerFlowPerSB(
458 rhs.first.second, rhs.first.first.second.bundle, rhs.second);
459 return lhsUniqueID < rhsUniqueID;
462 std::pair<std::pair<PhysPort, int>, SmallVector<PhysPort, 4>>>
463 sortedctrlpktFlows(ctrlPktFlows.begin(), ctrlPktFlows.end());
465 sortedctrlpktFlows.begin(), sortedctrlpktFlows.end(),
466 [getUniqueIdPerFlowPerSB](
const auto &lhs,
const auto &rhs) {
467 int lhsUniqueID = getUniqueIdPerFlowPerSB(
468 lhs.first.second, lhs.first.first.second.bundle, lhs.second);
469 int rhsUniqueID = getUniqueIdPerFlowPerSB(
470 rhs.first.second, rhs.first.first.second.bundle, rhs.second);
471 return lhsUniqueID < rhsUniqueID;
473 sortedctrlpktFlows.insert(sortedctrlpktFlows.end(),
474 sortedpktFlows.begin(), sortedpktFlows.end());
475 return sortedctrlpktFlows;
478 std::vector<std::pair<std::pair<PhysPort, int>, SmallVector<PhysPort, 4>>>
479 sortedPacketFlows = getSortedPacketFlows(packetFlows, ctrlPacketFlows);
481 packetFlows.insert(ctrlPacketFlows.begin(), ctrlPacketFlows.end());
488 for (
const auto &packetFlow : sortedPacketFlows) {
490 Operation *tileOp = packetFlow.first.first.first;
491 if (amselValues.count(tileOp) == 0)
492 amselValues[tileOp] = 0;
501 int amselValue = amselValues[tileOp];
502 assert(amselValue < numArbiters &&
"Could not allocate new arbiter!");
508 bool foundMatchedDest =
511 int foundPartialMatchArbiter =
514 for (
const auto &map : masterAMSels) {
515 if (map.first.first != tileOp)
517 amselValue = map.first.second;
520 SmallVector<Port, 4> ports(masterAMSels[{tileOp, amselValue}]);
526 bool mismatched =
false;
528 for (
auto dest : packetFlow.second) {
530 if (std::find(ports.begin(), ports.end(),
port) == ports.end())
537 foundMatchedDest =
true;
539 foundPartialMatchArbiter = getArbiterIDFromAmsel(amselValue);
540 else if (ports.size() != packetFlow.second.size())
541 foundPartialMatchArbiter = getArbiterIDFromAmsel(amselValue);
546 if (!foundMatchedDest) {
554 llvm::any_of(packetFlow.second, [&](PhysPort destPhysPort) {
555 Port port = destPhysPort.second;
556 return ctrlPktFlows[{{tileOp, port}, packetFlow.first.second}];
559 amselValue = getNewUniqueAmsel(masterAMSels, tileOp, ctrlPktAMsel);
561 for (
auto dest : packetFlow.second) {
563 masterAMSels[{tileOp, amselValue}].push_back(
port);
565 }
else if (foundPartialMatchArbiter >= 0) {
568 amselValue = getNewUniqueAmselPerArbiterID(masterAMSels, tileOp,
569 foundPartialMatchArbiter);
571 for (
auto dest : packetFlow.second) {
573 masterAMSels[{tileOp, amselValue}].push_back(
port);
577 slaveAMSels[packetFlow.first] = amselValue;
578 amselValues[tileOp] = getArbiterIDFromAmsel(amselValue);
583 DenseMap<PhysPort, SmallVector<int, 4>> mastersets;
584 for (
const auto &[physPort, ports] : masterAMSels) {
585 Operation *tileOp = physPort.first;
587 int amselValue = physPort.second;
588 for (
auto port : ports) {
589 PhysPort pp = {tileOp,
port};
590 mastersets[pp].push_back(amselValue);
594 LLVM_DEBUG(llvm::dbgs() <<
"CHECK mastersets\n");
596 for (
const auto &[physPort, values] : mastersets) {
597 Operation *tileOp = physPort.first;
598 WireBundle bundle = physPort.second.bundle;
599 int channel = physPort.second.channel;
601 auto tile = dyn_cast<TileOp>(tileOp);
602 LLVM_DEBUG(llvm::dbgs()
603 <<
"master " << tile <<
" " << stringifyWireBundle(bundle)
605 for (
auto value : values)
606 LLVM_DEBUG(
llvm::dbgs() <<
"amsel: " << value <<
'\n');
614 SmallVector<SmallVector<std::pair<PhysPort, int>, 4>, 4> slaveGroups;
615 SmallVector<std::pair<PhysPort, int>, 4> workList(slavePorts);
616 while (!workList.empty()) {
617 auto slave1 = workList.pop_back_val();
618 Port slavePort1 = slave1.first.second;
620 bool foundgroup =
false;
621 for (
auto &group : slaveGroups) {
622 auto slave2 = group.front();
623 if (
Port slavePort2 = slave2.first.second; slavePort1 != slavePort2)
627 auto dests1 = packetFlows[slave1];
628 auto dests2 = packetFlows[slave2];
629 if (dests1.size() != dests2.size())
632 for (
auto dest1 : dests1) {
633 if (std::find(dests2.begin(), dests2.end(), dest1) == dests2.end()) {
640 group.push_back(slave1);
647 SmallVector<std::pair<PhysPort, int>, 4> group({slave1});
648 slaveGroups.push_back(group);
652 DenseMap<std::pair<PhysPort, int>,
int> slaveMasks;
653 for (
const auto &group : slaveGroups) {
658 int mask[5] = {-1, -1, -1, -1, -1};
659 for (
auto port : group) {
660 int ID =
port.second;
661 for (
int i = 0; i < 5; i++) {
663 mask[i] = ID >> i & 0x1;
664 else if (mask[i] != (ID >> i & 0x1))
670 for (
int i = 4; i >= 0; i--) {
675 maskValue = (maskValue << 1) + mask[i];
677 for (
auto port : group)
678 slaveMasks[
port] = maskValue;
682 LLVM_DEBUG(llvm::dbgs() <<
"CHECK Slave Masks\n");
683 for (
auto map : slaveMasks) {
684 auto port = map.first.first;
685 auto tile = dyn_cast<TileOp>(
port.first);
686 WireBundle bundle =
port.second.bundle;
688 int ID = map.first.second;
689 int mask = map.second;
691 LLVM_DEBUG(llvm::dbgs()
692 <<
"Port " << tile <<
" " << stringifyWireBundle(bundle) <<
" "
694 LLVM_DEBUG(llvm::dbgs() <<
"Mask "
695 <<
"0x" << llvm::Twine::utohexstr(mask) <<
'\n');
696 LLVM_DEBUG(llvm::dbgs() <<
"ID "
697 <<
"0x" << llvm::Twine::utohexstr(ID) <<
'\n');
698 for (
int i = 0; i < 31; i++) {
699 if ((i & mask) == (ID & mask))
700 LLVM_DEBUG(llvm::dbgs() <<
"matches flow ID "
701 <<
"0x" << llvm::Twine::utohexstr(i) <<
'\n');
710 for (
const auto &swMap : mastersets) {
714 std::pair<xilinx::AIE::TileID, Operation *> &tileMapEntry) {
715 return tileMapEntry.second == swMap.first.first;
717 auto newTileOp = dyn_cast<TileOp>(swMap.first.first);
718 tiles[{newTileOp.colIndex(), newTileOp.rowIndex()}] = newTileOp;
722 for (
auto map : tiles) {
723 Operation *tileOp = map.second;
724 auto tile = dyn_cast<TileOp>(tileOp);
727 builder.setInsertionPointAfter(tileOp);
729 analyzer.getSwitchbox(builder, tile.colIndex(), tile.rowIndex());
730 SwitchboxOp::ensureTerminator(swbox.getConnections(), builder,
731 builder.getUnknownLoc());
732 Block &b = swbox.getConnections().front();
733 builder.setInsertionPoint(b.getTerminator());
735 std::vector<bool> amselOpNeededVector(numMsels * numArbiters);
736 for (
const auto &map : mastersets) {
737 if (tileOp != map.first.first)
740 for (
auto value : map.second) {
741 amselOpNeededVector[value] =
true;
745 DenseMap<int, AMSelOp> amselOps;
746 for (
int i = 0; i < numMsels; i++) {
747 for (
int a = 0; a < numArbiters; a++) {
748 auto amselValue = getAmselFromArbiterIDAndMsel(a, i);
749 if (amselOpNeededVector[amselValue]) {
753 builder.create<AMSelOp>(builder.getUnknownLoc(), arbiterID, msel);
754 amselOps[amselValue] = amsel;
760 SmallVector<Port, 4> tileMasters;
761 for (
const auto &map : mastersets) {
762 if (tileOp != map.first.first)
764 tileMasters.push_back(map.first.second);
767 std::sort(tileMasters.begin(), tileMasters.end());
768 for (
auto tileMaster : tileMasters) {
769 WireBundle bundle = tileMaster.bundle;
770 int channel = tileMaster.channel;
771 SmallVector<int, 4> msels = mastersets[{tileOp, tileMaster}];
772 SmallVector<Value, 4> amsels;
773 for (
auto msel : msels) {
774 assert(amselOps.count(msel) == 1);
775 amsels.push_back(amselOps[msel]);
778 builder.create<MasterSetOp>(
779 builder.getUnknownLoc(), builder.getIndexType(), bundle,
channel,
780 amsels, keepPktHeaderAttr[{tileOp, tileMaster}]);
784 DenseMap<Port, PacketRulesOp> slaveRules;
785 for (
auto group : slaveGroups) {
786 builder.setInsertionPoint(b.getTerminator());
788 auto port = group.front().first;
789 if (tileOp !=
port.first)
792 WireBundle bundle =
port.second.bundle;
794 auto slave =
port.second;
796 int mask = slaveMasks[group.front()];
797 int ID = group.front().second & mask;
801 for (
auto slave : group)
802 assert((slave.second & mask) == ID);
804 Value amsel = amselOps[slaveAMSels[group.front()]];
806 PacketRulesOp packetrules;
807 if (slaveRules.count(slave) == 0) {
808 packetrules = builder.create<PacketRulesOp>(builder.getUnknownLoc(),
810 PacketRulesOp::ensureTerminator(packetrules.getRules(), builder,
811 builder.getUnknownLoc());
812 slaveRules[slave] = packetrules;
814 packetrules = slaveRules[slave];
816 Block &rules = packetrules.getRules().front();
819 for (
auto rule : rules.getOps<PacketRuleOp>()) {
820 auto verifyMask = rule.maskInt();
821 auto verifyValue = rule.valueInt();
822 if ((group.front().second & verifyMask) == verifyValue) {
823 rule->emitOpError(
"can lead to false packet id match for id ")
824 << ID <<
", which is not supposed to pass through this port.";
825 rule->emitRemark(
"Please consider changing all uses of packet id ")
826 << ID <<
" to avoid deadlock.";
830 builder.setInsertionPoint(rules.getTerminator());
831 builder.create<PacketRuleOp>(builder.getUnknownLoc(), mask, ID, amsel);
841 for (
auto switchbox : make_early_inc_range(device.getOps<SwitchboxOp>())) {
842 auto retVal = switchbox->getOperand(0);
843 auto tileOp = retVal.getDefiningOp<TileOp>();
846 if (!tileOp.isShimNOCTile())
850 if (&switchbox.getBody()->front() == switchbox.getBody()->getTerminator())
853 Region &r = switchbox.getConnections();
854 Block &b = r.front();
859 for (
auto shimmux : device.getOps<ShimMuxOp>()) {
860 if (shimmux.getTile() == tileOp) {
867 for (Operation &Op : b.getOperations()) {
868 if (
auto pktrules = dyn_cast<PacketRulesOp>(Op)) {
871 if (pktrules.getSourceBundle() == WireBundle::DMA) {
876 builder.setInsertionPointAfter(tileOp);
877 shimOp = analyzer.getShimMux(builder, tileOp.colIndex());
881 Region &r0 = shimOp.getConnections();
882 Block &b0 = r0.front();
883 builder.setInsertionPointToStart(&b0);
885 pktrules.setSourceBundle(WireBundle::South);
886 if (pktrules.getSourceChannel() == 0) {
887 pktrules.setSourceChannel(3);
888 builder.create<ConnectOp>(builder.getUnknownLoc(), WireBundle::DMA,
889 0, WireBundle::North, 3);
891 if (pktrules.getSourceChannel() == 1) {
892 pktrules.setSourceChannel(7);
893 builder.create<ConnectOp>(builder.getUnknownLoc(), WireBundle::DMA,
894 1, WireBundle::North, 7);
899 if (
auto mtset = dyn_cast<MasterSetOp>(Op)) {
902 if (mtset.getDestBundle() == WireBundle::DMA) {
907 builder.setInsertionPointAfter(tileOp);
908 shimOp = analyzer.getShimMux(builder, tileOp.colIndex());
912 Region &r0 = shimOp.getConnections();
913 Block &b0 = r0.front();
914 builder.setInsertionPointToStart(&b0);
916 mtset.setDestBundle(WireBundle::South);
917 if (mtset.getDestChannel() == 0) {
918 mtset.setDestChannel(2);
919 builder.create<ConnectOp>(builder.getUnknownLoc(),
920 WireBundle::North, 2, WireBundle::DMA, 0);
922 if (mtset.getDestChannel() == 1) {
923 mtset.setDestChannel(3);
924 builder.create<ConnectOp>(builder.getUnknownLoc(),
925 WireBundle::North, 3, WireBundle::DMA, 1);
932 RewritePatternSet patterns(&getContext());
934 if (failed(applyPartialConversion(device, target, std::move(patterns))))