13#include "mlir/IR/Attributes.h"
14#include "mlir/Pass/Pass.h"
17#define GEN_PASS_DEF_AIETRACETOCONFIG
18#define GEN_PASS_DEF_AIETRACEREGPACKWRITES
19#include "aie/Dialect/AIE/Transforms/AIEPasses.h.inc"
28struct AIETraceToConfigPass
29 : xilinx::AIE::impl::AIETraceToConfigBase<AIETraceToConfigPass> {
30 void runOnOperation()
override {
31 DeviceOp device = getOperation();
32 OpBuilder builder(device);
33 const auto &targetModel = device.getTargetModel();
36 SmallVector<TraceOp> traces;
37 device.walk([&](TraceOp trace) { traces.push_back(trace); });
39 for (
auto trace : traces) {
41 std::string configName = (trace.getSymName().str() +
"_config");
42 auto tile = cast<TileOp>(trace.getTile().getDefiningOp());
43 TileID tileID = tile.getTileID();
46 TracePacketType packetType = TracePacketType::Core;
47 for (
auto &op : trace.getBody().getOps()) {
48 if (
auto packetOp = dyn_cast<TracePacketOp>(op)) {
49 packetType = packetOp.getType();
55 builder.setInsertionPointAfter(trace);
56 auto configOp = TraceConfigOp::create(
57 builder, trace.getLoc(), trace.getTile(),
58 builder.getStringAttr(configName),
59 TracePacketTypeAttr::get(builder.getContext(), packetType));
62 Block *configBody =
new Block();
63 configOp.getBody().push_back(configBody);
64 OpBuilder configBuilder = OpBuilder::atBlockEnd(configBody);
66 bool isMem = (packetType == TracePacketType::Mem);
73 for (
auto &op : trace.getBody().getOps()) {
74 if (
auto comboOp = dyn_cast<TraceComboEventOp>(op)) {
75 uint32_t slot = comboOp.getSlot();
78 std::string eventAName = comboOp.getEventA().getEventName();
79 std::string eventBName = comboOp.getEventB().getEventName();
80 ComboLogic logic = comboOp.getLogic();
83 std::optional<uint32_t> eventANum, eventBNum;
85 if (
auto enumValA = comboOp.getEventA().getEnumValue()) {
86 eventANum =
static_cast<uint32_t
>(*enumValA);
88 eventANum = targetModel.lookupEvent(eventAName, tileID, isMem);
91 if (
auto enumValB = comboOp.getEventB().getEnumValue()) {
92 eventBNum =
static_cast<uint32_t
>(*enumValB);
94 eventBNum = targetModel.lookupEvent(eventBName, tileID, isMem);
98 comboOp.emitError(
"unknown trace event '") << eventAName <<
"'";
99 return signalPassFailure();
102 comboOp.emitError(
"unknown trace event '") << eventBName <<
"'";
103 return signalPassFailure();
107 StringRef eventAField, eventBField, controlField;
109 eventAField =
"eventA";
110 eventBField =
"eventB";
111 controlField =
"combo0";
112 }
else if (slot == 1) {
113 eventAField =
"eventC";
114 eventBField =
"eventD";
115 controlField =
"combo1";
116 }
else if (slot == 2) {
119 eventAField =
"eventA";
120 eventBField =
"eventB";
121 controlField =
"combo2";
125 TraceRegOp::create(configBuilder, comboOp.getLoc(),
126 builder.getStringAttr(
"Combo_event_inputs"),
127 builder.getStringAttr(eventAField),
130 builder.getStringAttr(
131 "combo" + std::to_string(slot) +
" eventA"));
133 TraceRegOp::create(configBuilder, comboOp.getLoc(),
134 builder.getStringAttr(
"Combo_event_inputs"),
135 builder.getStringAttr(eventBField),
138 builder.getStringAttr(
139 "combo" + std::to_string(slot) +
" eventB"));
143 configBuilder, comboOp.getLoc(),
144 builder.getStringAttr(
"Combo_event_control"),
145 builder.getStringAttr(controlField),
146 builder.getI32IntegerAttr(
static_cast<uint32_t
>(logic)),
148 builder.getStringAttr(
"combo" + std::to_string(slot) +
" logic"));
153 for (
auto &op : trace.getBody().getOps()) {
154 if (
auto edgeOp = dyn_cast<TraceEdgeEventOp>(op)) {
155 uint32_t slot = edgeOp.getSlot();
156 std::string eventName = edgeOp.getEvent().getEventName();
157 EdgeTrigger trigger = edgeOp.getTrigger();
160 std::optional<uint32_t> eventNum;
162 if (
auto enumVal = edgeOp.getEvent().getEnumValue()) {
163 eventNum =
static_cast<uint32_t
>(*enumVal);
165 eventNum = targetModel.lookupEvent(eventName, tileID, isMem);
169 edgeOp.emitError(
"unknown trace event '") << eventName <<
"'";
170 return signalPassFailure();
174 StringRef eventField =
175 (slot == 0) ?
"Edge_Detection_Event_0" :
"Edge_Detection_Event_1";
176 StringRef risingField = (slot == 0)
177 ?
"Edge_Detection_0_Trigger_Rising"
178 :
"Edge_Detection_1_Trigger_Rising";
179 StringRef fallingField = (slot == 0)
180 ?
"Edge_Detection_0_Trigger_Falling"
181 :
"Edge_Detection_1_Trigger_Falling";
185 configBuilder, edgeOp.getLoc(),
186 builder.getStringAttr(
"Edge_Detection_event_control"),
187 builder.getStringAttr(eventField), edgeOp.getEvent(),
189 builder.getStringAttr(
"edge" + std::to_string(slot) +
" source"));
193 (trigger == EdgeTrigger::RISING || trigger == EdgeTrigger::BOTH);
195 (trigger == EdgeTrigger::FALLING || trigger == EdgeTrigger::BOTH);
198 configBuilder, edgeOp.getLoc(),
199 builder.getStringAttr(
"Edge_Detection_event_control"),
200 builder.getStringAttr(risingField),
201 builder.getI32IntegerAttr(rising ? 1 : 0),
203 builder.getStringAttr(
"edge" + std::to_string(slot) +
" rising"));
206 configBuilder, edgeOp.getLoc(),
207 builder.getStringAttr(
"Edge_Detection_event_control"),
208 builder.getStringAttr(fallingField),
209 builder.getI32IntegerAttr(falling ? 1 : 0),
211 builder.getStringAttr(
"edge" + std::to_string(slot) +
218 for (
auto &op : trace.getBody().getOps()) {
219 if (
auto startOp = dyn_cast<TraceStartEventOp>(op)) {
220 uint32_t startEvent = 0;
221 if (
auto broadcast = startOp.getBroadcast()) {
222 uint32_t broadcastNum = *broadcast;
224 std::string eventName;
225 if (tile.isShimTile()) {
226 eventName =
"BROADCAST_A_" + std::to_string(broadcastNum);
228 eventName =
"BROADCAST_" + std::to_string(broadcastNum);
230 auto eventNum = targetModel.lookupEvent(eventName, tileID, isMem);
232 startEvent = *eventNum;
234 startOp.emitError(
"unknown broadcast event '")
236 return signalPassFailure();
238 }
else if (
auto eventAttr = startOp.getEvent()) {
240 std::string eventName = eventAttr->getEventName();
242 std::optional<uint32_t> eventNum;
243 if (
auto enumVal = eventAttr->getEnumValue()) {
244 eventNum =
static_cast<uint32_t
>(*enumVal);
246 eventNum = targetModel.lookupEvent(eventName, tileID, isMem);
250 startEvent = *eventNum;
252 startOp.emitError(
"unknown trace event '") << eventName <<
"'";
253 return signalPassFailure();
257 TraceRegOp::create(configBuilder, trace.getLoc(),
258 builder.getStringAttr(
"Trace_Control0"),
259 builder.getStringAttr(
"Trace_Start_Event"),
260 builder.getI32IntegerAttr(startEvent),
262 builder.getStringAttr(
"start event"));
265 if (
auto stopOp = dyn_cast<TraceStopEventOp>(op)) {
266 uint32_t stopEvent = 0;
267 if (
auto broadcast = stopOp.getBroadcast()) {
268 uint32_t broadcastNum = *broadcast;
270 std::string eventName;
271 if (tile.isShimTile()) {
272 eventName =
"BROADCAST_A_" + std::to_string(broadcastNum);
274 eventName =
"BROADCAST_" + std::to_string(broadcastNum);
276 auto eventNum = targetModel.lookupEvent(eventName, tileID, isMem);
278 stopEvent = *eventNum;
280 stopOp.emitError(
"unknown broadcast event '") << eventName <<
"'";
281 return signalPassFailure();
283 }
else if (
auto eventAttr = stopOp.getEvent()) {
285 std::string eventName = eventAttr->getEventName();
287 std::optional<uint32_t> eventNum;
288 if (
auto enumVal = eventAttr->getEnumValue()) {
289 eventNum =
static_cast<uint32_t
>(*enumVal);
291 eventNum = targetModel.lookupEvent(eventName, tileID, isMem);
295 stopEvent = *eventNum;
297 stopOp.emitError(
"unknown trace event '") << eventName <<
"'";
298 return signalPassFailure();
302 TraceRegOp::create(configBuilder, trace.getLoc(),
303 builder.getStringAttr(
"Trace_Control0"),
304 builder.getStringAttr(
"Trace_Stop_Event"),
305 builder.getI32IntegerAttr(stopEvent),
307 builder.getStringAttr(
"stop event"));
313 bool isCore = (packetType == TracePacketType::Core);
314 if (
auto modeOp = dyn_cast<TraceModeOp>(op); modeOp && isCore) {
315 TraceRegOp::create(configBuilder, trace.getLoc(),
316 builder.getStringAttr(
"Trace_Control0"),
317 builder.getStringAttr(
"Mode"),
318 builder.getI32IntegerAttr(
319 static_cast<uint32_t
>(modeOp.getMode())),
321 builder.getStringAttr(
"trace mode"));
327 if (
auto packetOp = dyn_cast<TracePacketOp>(op)) {
328 auto packetId = packetOp.getId();
329 assert(packetId.has_value() &&
330 "TracePacketOp id should be assigned by "
331 "-aie-insert-trace-flows");
333 configBuilder, trace.getLoc(),
334 builder.getStringAttr(
"Trace_Control1"),
335 builder.getStringAttr(
"ID"), builder.getI32IntegerAttr(*packetId),
336 nullptr, builder.getStringAttr(
"packet ID"));
338 TraceRegOp::create(configBuilder, trace.getLoc(),
339 builder.getStringAttr(
"Trace_Control1"),
340 builder.getStringAttr(
"Packet_Type"),
341 builder.getI32IntegerAttr(
342 static_cast<uint32_t
>(packetOp.getType())),
344 builder.getStringAttr(
"packet type"));
349 for (
auto &op : trace.getBody().getOps()) {
350 if (
auto portOp = dyn_cast<TracePortOp>(op)) {
351 uint32_t slot = portOp.getSlot();
354 StringRef registerName = (slot < 4)
355 ?
"Stream_Switch_Event_Port_Selection_0"
356 :
"Stream_Switch_Event_Port_Selection_1";
359 std::string idFieldName =
"Port_" + std::to_string(slot) +
"_ID";
360 std::string masterSlaveFieldName =
361 "Port_" + std::to_string(slot) +
"_Master_Slave";
364 std::string portValue = stringifyWireBundle(portOp.getPort()).str() +
365 ":" + std::to_string(portOp.getChannel());
368 int masterSlaveValue =
369 (portOp.getDirection() == DMAChannelDir::S2MM) ? 1 : 0;
373 configBuilder, portOp.getLoc(),
374 builder.getStringAttr(registerName),
375 builder.getStringAttr(idFieldName),
376 builder.getStringAttr(portValue),
378 builder.getStringAttr(
"port " + std::to_string(slot) +
" ID"));
381 TraceRegOp::create(configBuilder, portOp.getLoc(),
382 builder.getStringAttr(registerName),
383 builder.getStringAttr(masterSlaveFieldName),
384 builder.getI32IntegerAttr(masterSlaveValue),
386 builder.getStringAttr(
"port " +
387 std::to_string(slot) +
393 SmallVector<TraceEventOp> events;
394 for (
auto &op : trace.getBody().getOps()) {
395 if (
auto eventOp = dyn_cast<TraceEventOp>(op)) {
396 events.push_back(eventOp);
400 for (
size_t i = 0; i < events.size() && i < 8; ++i) {
401 std::string eventName = events[i].getEvent().getEventName();
404 std::optional<uint32_t> eventNum;
406 if (
auto enumVal = events[i].getEvent().getEnumValue()) {
407 eventNum =
static_cast<uint32_t
>(*enumVal);
409 eventNum = targetModel.lookupEvent(eventName, tileID, isMem);
413 events[i].emitError(
"unknown trace event '") << eventName <<
"'";
414 return signalPassFailure();
418 StringRef registerName = (i < 4) ?
"Trace_Event0" :
"Trace_Event1";
419 std::string fieldName =
"Trace_Event" + std::to_string(i);
423 configBuilder, trace.getLoc(), builder.getStringAttr(registerName),
424 builder.getStringAttr(fieldName),
425 events[i].getEvent(),
426 nullptr, builder.getStringAttr(eventName));
430 EndOp::create(configBuilder, trace.getLoc());
433 device.walk([&](TraceStartConfigOp startConfig) {
434 if (startConfig.getTraceConfig() == trace.getSymName()) {
435 startConfig.setTraceConfigAttr(
436 SymbolRefAttr::get(builder.getContext(), configName));
448std::unique_ptr<OperationPass<DeviceOp>>
450 return std::make_unique<AIETraceToConfigPass>();
459struct AIETraceRegPackWritesPass
460 : xilinx::AIE::impl::AIETraceRegPackWritesBase<AIETraceRegPackWritesPass> {
461 void runOnOperation()
override {
462 DeviceOp device = getOperation();
463 const auto &targetModel = device.getTargetModel();
466 device.walk([&](TraceConfigOp configOp) {
468 auto tile = cast<TileOp>(configOp.getTile().getDefiningOp());
472 if (
auto packetType = configOp.getPacketType()) {
473 isMem = (*packetType == TracePacketType::Mem);
477 SmallVector<TraceRegOp> regsToConvert;
478 for (
auto &op : configOp.getBody().front()) {
479 if (
auto regOp = dyn_cast<TraceRegOp>(op)) {
480 if (regOp.getField() && !regOp.getMask()) {
481 regsToConvert.push_back(regOp);
486 OpBuilder builder(&configOp.getBody().front(),
487 configOp.getBody().front().begin());
489 TileID tileID = tile.getTileID();
490 for (
auto regOp : regsToConvert) {
492 const RegisterInfo *regInfo =
493 targetModel.lookupRegister(regOp.getRegName(), tileID, isMem);
496 regOp.emitError(
"Register not found in database: ")
497 << regOp.getRegName();
498 return signalPassFailure();
501 const BitFieldInfo *fieldInfo = regInfo->
getField(*regOp.getField());
503 regOp.emitError(
"Field not found in register: ")
504 << *regOp.getField() <<
" in " << regOp.getRegName();
505 return signalPassFailure();
510 Attribute valAttr = regOp.getValue();
511 if (
auto traceEventAttr = dyn_cast<TraceEventAttr>(valAttr)) {
512 if (
auto enumVal = traceEventAttr.getEnumValue()) {
513 value =
static_cast<uint32_t
>(*enumVal);
514 valAttr = builder.getI32IntegerAttr(value);
516 std::string eventName = traceEventAttr.getEventName();
517 std::optional<uint32_t> eventNum =
518 targetModel.lookupEvent(eventName, tileID, isMem);
520 regOp.emitError(
"unknown trace event '") << eventName <<
"'";
521 return signalPassFailure();
524 valAttr = builder.getI32IntegerAttr(value);
527 if (
auto intAttr = dyn_cast<IntegerAttr>(valAttr)) {
529 value = intAttr.getInt();
530 }
else if (
auto strAttr = dyn_cast<StringAttr>(valAttr)) {
532 StringRef valueStr = strAttr.getValue();
537 bool isMasterSlaveField =
538 fieldInfo->
name.find(
"Master_Slave") != std::string::npos;
540 if (!isMasterSlaveField && valueStr.contains(
':')) {
548 StringRef fieldName(fieldInfo->
name);
549 StringRef portSlotPrefix;
550 if (fieldName.starts_with(
"Port_")) {
551 size_t idSuffixPos = fieldName.find(
"_ID");
552 if (idSuffixPos != std::string::npos)
553 portSlotPrefix = fieldName.take_front(idSuffixPos);
557 for (
auto &siblingOp : configOp.getBody().front()) {
558 if (
auto siblingReg = dyn_cast<TraceRegOp>(siblingOp)) {
559 if (siblingReg.getRegName() != regOp.getRegName() ||
560 !siblingReg.getField())
562 StringRef siblingFieldName = *siblingReg.getField();
565 if (!portSlotPrefix.empty()) {
566 if (!siblingFieldName.starts_with(portSlotPrefix) ||
567 !siblingFieldName.contains(
"Master_Slave"))
571 if (!siblingFieldName.contains(
"Master_Slave"))
575 if (
auto siblingInt =
576 dyn_cast<IntegerAttr>(siblingReg.getValue())) {
577 master = (siblingInt.getInt() != 0);
585 targetModel.resolvePortValue(valueStr, tileID, master);
587 regOp.emitError(
"Failed to resolve port value: ") << valueStr;
588 return signalPassFailure();
592 regOp.emitError(
"Unsupported string value: ") << valueStr;
593 return signalPassFailure();
596 regOp.emitError(
"Unsupported value type in pack pass");
597 return signalPassFailure();
601 auto mask = targetModel.getFieldMask(*fieldInfo);
603 regOp.emitError(
"Invalid field bit range for register write: ")
604 << regOp.getRegName() <<
"." << fieldInfo->
name <<
" ["
606 <<
"], width=" << fieldInfo->
getWidth();
607 return signalPassFailure();
609 auto shiftedValue = targetModel.encodeFieldValue(*fieldInfo, value);
611 regOp.emitError(
"Value ")
612 << value <<
" does not fit in field " << regOp.getRegName() <<
"."
613 << fieldInfo->
name <<
" (width " << fieldInfo->
getWidth() <<
")";
614 return signalPassFailure();
617 builder.setInsertionPoint(regOp);
618 TraceRegOp::create(builder, regOp.getLoc(), regOp.getRegNameAttr(),
620 builder.getI32IntegerAttr(*shiftedValue),
621 builder.getI32IntegerAttr(*mask),
622 regOp.getCommentAttr());
634 SmallVector<TraceRegOp> regWrites;
635 for (TraceRegOp op : configOp.getBody().front().getOps<TraceRegOp>()) {
637 regWrites.push_back(op);
642 for (
size_t i = 0; i < regWrites.size() && !changed; ++i) {
643 for (
size_t j = i + 1; j < regWrites.size() && !changed; ++j) {
644 TraceRegOp reg1 = regWrites[i];
645 TraceRegOp reg2 = regWrites[j];
648 if (reg1.getRegName() != reg2.getRegName())
651 auto mask1Attr = reg1.getMask();
652 auto mask2Attr = reg2.getMask();
653 if (!mask1Attr || !mask2Attr)
656 uint32_t mask1 = *mask1Attr;
657 uint32_t mask2 = *mask2Attr;
661 reg1.emitError(
"Overlapping masks for register ")
662 << reg1.getRegName() <<
": mask1=" << mask1
663 <<
" mask2=" << mask2;
664 return signalPassFailure();
668 auto value1Attr = dyn_cast<IntegerAttr>(reg1.getValue());
669 auto value2Attr = dyn_cast<IntegerAttr>(reg2.getValue());
670 if (!value1Attr || !value2Attr) {
672 "Expected integer values for packed register writes");
673 return signalPassFailure();
675 uint32_t value1 = value1Attr.getInt();
676 uint32_t value2 = value2Attr.getInt();
677 uint32_t mergedValue = value1 | value2;
678 uint32_t mergedMask = mask1 | mask2;
681 builder.setInsertionPoint(reg1);
683 if (reg1.getComment())
684 comment += reg1.getComment()->str();
685 if (reg2.getComment()) {
686 if (!comment.empty())
688 comment += reg2.getComment()->str();
692 builder, reg1.getLoc(), reg1.getRegNameAttr(),
nullptr,
693 builder.getI32IntegerAttr(mergedValue),
694 builder.getI32IntegerAttr(mergedMask),
695 comment.empty() ?
nullptr : builder.getStringAttr(comment));
710std::unique_ptr<OperationPass<DeviceOp>>
712 return std::make_unique<AIETraceRegPackWritesPass>();
std::unique_ptr< mlir::OperationPass< DeviceOp > > createAIETraceRegPackWritesPass()
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
std::unique_ptr< mlir::OperationPass< DeviceOp > > createAIETraceToConfigPass()
uint32_t getWidth() const
const BitFieldInfo * getField(llvm::StringRef fieldName) const