80 LogicalResult
generate(ArrayRef<DeviceOp> users) {
81 ModuleOp module = getOperation();
82 AIEDialect::IsCtrlPktOverlayAttrHelper marker(&getContext());
83 DeviceOp first = users.front();
84 auto target = first.getDevice();
86 std::set<int> columns;
88 for (DeviceOp device : users)
89 for (TileOp tile : device.getOps<TileOp>())
90 columns.insert(tile.colIndex());
91 for (
TileID tile : tokenTiles)
92 columns.insert(tile.col);
94 for (DeviceOp device : users)
95 device.walk([&](AIEX::NpuControlPacketOp packet) {
96 columns.insert(packet.getColumnFromAddr());
98 columns.insert(coverColumns.begin(), coverColumns.end());
101 SymbolTable symbols(module);
102 OpBuilder builder(module.getContext());
103 builder.setInsertionPointToEnd(module.getBody());
105 DeviceOp::create(builder, module.getLoc(), target,
106 builder.getStringAttr(
"ctrl_pkt_overlay"),
nullptr);
107 symbols.insert(overlay);
108 overlay.getRegion().emplaceBlock();
109 builder.setInsertionPointToEnd(overlay.getBody());
110 EndOp::create(builder, overlay.getLoc());
111 marker.setAttr(overlay, builder.getUnitAttr());
112 builder.setInsertionPointToStart(overlay.getBody());
113 for (DeviceOp device : users)
114 for (TileOp tile : device.getOps<TileOp>()) {
115 TileOp dest = TileOp::getOrCreate(builder, overlay, tile.colIndex(),
117 if (
auto id = tile->getAttr(
"controller_id")) {
118 if (
auto other = dest->getAttr(
"controller_id");
119 other && other !=
id) {
121 "has a different controller ID in another configuration");
124 dest->setAttr(
"controller_id",
id);
127 const auto &model = overlay.getTargetModel();
128 auto ids = model.getTileToControllerIdMap(
true);
129 auto flow = [&](TileOp source,
Port src, TileOp dest,
Port dst,
131 builder.setInsertionPoint(overlay.getBody()->getTerminator());
132 int id = ids[controller.getTileID()];
134 controller->getAttrOfType<PacketInfoAttr>(
"controller_id"))
135 id = attr.assignedId();
136 auto packet = PacketFlowOp::create(builder, controller.getLoc(),
id,
137 builder.getBoolAttr(
true),
138 builder.getBoolAttr(
true));
139 OpBuilder::InsertionGuard guard(builder);
140 builder.createBlock(&packet.getPorts());
141 PacketSourceOp::create(builder, packet.getLoc(), source, src.bundle,
143 PacketDestOp::create(builder, packet.getLoc(), dest, dst.bundle,
145 EndOp::create(builder, packet.getLoc());
147 for (
int col : columns) {
148 if (col < 0 || col >= model.columns()) {
149 overlay.emitOpError(
"control coverage column is outside the target");
152 builder.setInsertionPointToStart(overlay.getBody());
153 TileOp shim = TileOp::getOrCreate(builder, overlay, col, 0);
154 flow(shim, {WireBundle::TileControl, 0}, shim, {WireBundle::South, 0},
156 for (
TileID tile : tokenTiles)
157 if (tile.col == col && tile.row != 0) {
158 builder.setInsertionPointToStart(overlay.getBody());
159 TileOp source = TileOp::getOrCreate(builder, overlay, col, tile.row);
160 flow(source, {WireBundle::TileControl, 0}, shim,
161 {WireBundle::South, 0}, source);
166 unsigned best = std::numeric_limits<unsigned>::max();
169 ? model.getNumSourceShimMuxConnections(col, 0, WireBundle::DMA)
171 for (
int ch = 0; ch < count; ++ch)
178 overlay.emitOpError(
"failed to generate control overlay: no available "
179 "shim MM2S channel in column ")
183 builder.setInsertionPoint(overlay.getBody()->getTerminator());
184 auto alloc = ShimDMAAllocationOp::create(
185 builder, shim.getLoc(), getCtrlPktAllocName(col, channel), shim,
186 DMAChannelDir::MM2S, channel,
false,
nullptr);
187 marker.setAttr(alloc, builder.getUnitAttr());
188 for (
int row = 0; row < model.rows(); ++row) {
189 builder.setInsertionPointToStart(overlay.getBody());
190 TileOp dest = TileOp::getOrCreate(builder, overlay, col, row);
191 flow(shim, {WireBundle::DMA, channel}, dest,
192 {WireBundle::TileControl, 0}, dest);
195 for (DeviceOp device : users) {
196 device.setOverlayAttr(FlatSymbolRefAttr::get(overlay.getSymNameAttr()));
198 AIEDialect::ReserveControllerPacketIdsAttrHelper(&getContext())
199 .setAttr(device, builder.getUnitAttr());
203 std::vector<std::pair<TileID, Port>> avoided;
206 OpPassManager routing(DeviceOp::getOperationName());
209 if (failed(runPipeline(routing, overlay)))
213 for (
auto box : overlay.getOps<SwitchboxOp>()) {
214 auto amsels = llvm::to_vector(box.getConnections().getOps<AMSelOp>());
215 std::set<std::pair<int, int>> slots;
216 for (
auto amsel : amsels)
217 slots.emplace(amsel.arbiterIndex(), amsel.getMselValue());
218 builder.setInsertionPoint(box.getConnections().front().getTerminator());
219 for (
auto amsel : amsels)
220 for (
unsigned msel = 0; msel < model.getNumMselsPerArbiter(); ++msel)
221 if (slots.emplace(amsel.arbiterIndex(), msel).second)
222 AMSelOp::create(builder, amsel.getLoc(), amsel.arbiterIndex(),
225 overlay.walk([&](Operation *op) {
226 op->removeAttr(
"aie.priority_route");
227 if (!isa<DeviceOp, EndOp, PacketRulesOp>(op))
228 marker.setAttr(op, builder.getUnitAttr());
235 auto shimCol = [](Value tile) -> std::optional<int> {
236 auto tOp = dyn_cast_or_null<TileOp>(tile.getDefiningOp());
237 if (!tOp || !tOp.isShimNOCorPLTile())
239 return tOp.colIndex();
241 for (DeviceOp device : devices) {
242 for (
auto endpoint : device.getOps<RouteEndpointOp>()) {
243 auto col = shimCol(endpoint.getTile());
244 auto channel = endpoint.getChannelIndex();
245 if (!col || endpoint.getBundle() != WireBundle::DMA ||
246 endpoint.getRouteDirection() != DMAChannelDir::MM2S || !channel)
249 llvm::any_of(device.getOps<RouteOp>(), [&](RouteOp route) {
250 return route.namesAsSource(endpoint.getSymName()) &&
258 for (
auto alloc : device.getOps<AIE::ShimDMAAllocationOp>()) {
259 if (alloc.getChannelDir() != AIE::DMAChannelDir::MM2S)
261 int col = alloc.getTileOp().colIndex();
262 int chan =
static_cast<int>(alloc.getChannelIndex());
265 for (
auto flow : device.getOps<AIE::FlowOp>())
266 if (flow.getSourceBundle() == WireBundle::DMA)
267 if (
auto col = shimCol(flow.getSource())) {
270 for (
auto flow : device.getOps<AIE::PacketFlowOp>()) {
271 for (
auto src : flow.getOps<AIE::PacketSourceOp>())
272 if (src.getBundle() == WireBundle::DMA)
273 if (
auto col = shimCol(src.getTile())) {
277 for (
auto mux : device.getOps<AIE::ShimMuxOp>())
279 mux.getConnections().front().getOps<AIE::ConnectOp>())
280 if (connect.getSourceBundle() == WireBundle::DMA) {
281 int col = mux.getTileOp().colIndex();
289 llvm::SmallSet<AIE::TileID, 4> tiles;
290 auto addTile = [&](Value tileValue) {
293 if (
auto tile = dyn_cast_or_null<TileOp>(tileValue.getDefiningOp()))
294 tiles.insert({tile.colIndex(), tile.rowIndex()});
296 for (DeviceOp device : devices) {
297 for (TileOp tile : device.getOps<TileOp>())
298 if (tile.isShimNOCorPLTile())
299 tiles.insert(tile.getTileID());
300 device.walk([&](Operation *op) {
301 if (
auto task = dyn_cast<AIEX::DMAConfigureTaskOp>(op)) {
302 if (task.getIssueToken())
303 addTile(task.getTile());
304 }
else if (
auto task = dyn_cast<AIEX::DMAConfigureTaskForOp>(op)) {
305 if (!task.getIssueToken())
307 Operation *endpoint =
308 SymbolTable::lookupSymbolIn(device, task.getAlloc());
309 if (
auto route = dyn_cast_or_null<RouteEndpointOp>(endpoint))
310 addTile(route.getTile());
311 else if (
auto alloc = dyn_cast_or_null<ShimDMAAllocationOp>(endpoint))
312 addTile(alloc.getTile());
313 }
else if (
auto push = dyn_cast<AIEX::NpuPushQueueOp>(op)) {
314 if (push.getIssueToken())
315 tiles.insert({
static_cast<int>(push.getColumn()),
316 static_cast<int>(push.getRow())});
325 std::vector<std::pair<TileID, Port>> &avoided) {
326 OwningOpRef<ModuleOp> trial = cast<ModuleOp>(module->clone());
327 for (DeviceOp device :
328 llvm::make_early_inc_range(trial->getOps<DeviceOp>())) {
329 if (device->hasAttr(
"aie.is_ctrl_pkt_overlay"))
332 device.removeOverlayAttr();
334 PassManager pm(&getContext());
335 auto &dpm = pm.nest<DeviceOp>();
339 if (failed(pm.run(*trial))) {
340 module.emitError("failed to analyze application resources for adaptive "
344 std::set<std::pair<TileID, Port>> ports;
345 for (DeviceOp device : trial->getOps<DeviceOp>()) {
346 for (SwitchboxOp box : device.getOps<SwitchboxOp>()) {
347 for (ConnectOp connect : box.getOps<ConnectOp>())
348 ports.insert({box.getTileOp().getTileID(), connect.destPort()});
349 for (MasterSetOp master : box.getOps<MasterSetOp>())
350 ports.insert({box.getTileOp().getTileID(), master.destPort()});
355 device.emitOpError(
"cannot plan adaptive control overlay: ")
356 << llvm::toString(std::move(error));
360 for (
const auto &[tile, setting] : settings)
361 for (
Port output : setting.dsts)
362 ports.insert({tile, output});
369 avoided.assign(ports.begin(), ports.end());