@@ -64,6 +64,139 @@ struct AIETraceToConfigPass : AIETraceToConfigBase<AIETraceToConfigPass> {
6464
6565bool isMem = (packetType == TracePacketType::Mem);
6666
67+ // Process combo/edge events FIRST (before other trace config)
68+ // This ensures COMBO_EVENT_*/EDGE_DETECTION_EVENT_* are configured
69+ // before they can be referenced in trace.event operations
70+
71+ // 0a. Emit combo event configurations
72+ for (auto &op : trace.getBody ().getOps ()) {
73+ if (auto comboOp = dyn_cast<TraceComboEventOp>(op)) {
74+ uint32_t slot = comboOp.getSlot ();
75+
76+ // Get input events
77+ std::string eventAName = comboOp.getEventA ().getName ().str ();
78+ std::string eventBName = comboOp.getEventB ().getName ().str ();
79+ ComboLogic logic = comboOp.getLogic ();
80+
81+ // Lookup event numbers
82+ auto eventANum = regDB->lookupEvent (eventAName, tile, isMem);
83+ auto eventBNum = regDB->lookupEvent (eventBName, tile, isMem);
84+
85+ if (!eventANum) {
86+ comboOp.emitError (" unknown event:" ) << eventAName;
87+ return signalPassFailure ();
88+ }
89+ if (!eventBNum) {
90+ comboOp.emitError (" unknown event:" ) << eventBName;
91+ return signalPassFailure ();
92+ }
93+
94+ // Map slot to input event fields
95+ StringRef eventAField, eventBField, controlField;
96+ if (slot ==0 ) {
97+ eventAField =" eventA" ;
98+ eventBField =" eventB" ;
99+ controlField =" combo0" ;
100+ }else if (slot ==1 ) {
101+ eventAField =" eventC" ;
102+ eventBField =" eventD" ;
103+ controlField =" combo1" ;
104+ }else if (slot ==2 ) {
105+ // Combo2 is hierarchical - reuses eventA/B fields but represents
106+ // combo0/combo1
107+ eventAField =" eventA" ;
108+ eventBField =" eventB" ;
109+ controlField =" combo2" ;
110+ }
111+
112+ // Emit Combo_event_inputs register fields
113+ configBuilder.create <TraceRegOp>(
114+ comboOp.getLoc (), builder.getStringAttr (" Combo_event_inputs" ),
115+ builder.getStringAttr (eventAField),
116+ builder.getI32IntegerAttr (*eventANum),
117+ /* mask=*/ nullptr ,
118+ builder.getStringAttr (" combo" +std::to_string (slot) +
119+ " eventA" ));
120+
121+ configBuilder.create <TraceRegOp>(
122+ comboOp.getLoc (), builder.getStringAttr (" Combo_event_inputs" ),
123+ builder.getStringAttr (eventBField),
124+ builder.getI32IntegerAttr (*eventBNum),
125+ /* mask=*/ nullptr ,
126+ builder.getStringAttr (" combo" +std::to_string (slot) +
127+ " eventB" ));
128+
129+ // Emit Combo_event_control register field
130+ configBuilder.create <TraceRegOp>(
131+ comboOp.getLoc (), builder.getStringAttr (" Combo_event_control" ),
132+ builder.getStringAttr (controlField),
133+ builder.getI32IntegerAttr (static_cast <uint32_t >(logic)),
134+ /* mask=*/ nullptr ,
135+ builder.getStringAttr (" combo" +std::to_string (slot) +
136+ " logic" ));
137+ }
138+ }
139+
140+ // 0b. Emit edge detection configurations
141+ for (auto &op : trace.getBody ().getOps ()) {
142+ if (auto edgeOp = dyn_cast<TraceEdgeEventOp>(op)) {
143+ uint32_t slot = edgeOp.getSlot ();
144+ std::string eventName = edgeOp.getEvent ().getName ().str ();
145+ EdgeTrigger trigger = edgeOp.getTrigger ();
146+
147+ // Lookup event number
148+ auto eventNum = regDB->lookupEvent (eventName, tile, isMem);
149+ if (!eventNum) {
150+ edgeOp.emitError (" unknown event:" ) << eventName;
151+ return signalPassFailure ();
152+ }
153+
154+ // Map slot to field names
155+ StringRef eventField = (slot ==0 ) ?" Edge_Detection_Event_0"
156+ :" Edge_Detection_Event_1" ;
157+ StringRef risingField = (slot ==0 )
158+ ?" Edge_Detection_0_Trigger_Rising"
159+ :" Edge_Detection_1_Trigger_Rising" ;
160+ StringRef fallingField = (slot ==0 )
161+ ?" Edge_Detection_0_Trigger_Falling"
162+ :" Edge_Detection_1_Trigger_Falling" ;
163+
164+ // Source event
165+ configBuilder.create <TraceRegOp>(
166+ edgeOp.getLoc (),
167+ builder.getStringAttr (" Edge_Detection_event_control" ),
168+ builder.getStringAttr (eventField),
169+ builder.getI32IntegerAttr (*eventNum),
170+ /* mask=*/ nullptr ,
171+ builder.getStringAttr (" edge" +std::to_string (slot) +
172+ " source" ));
173+
174+ // Trigger mode
175+ bool rising = (trigger == EdgeTrigger::RISING ||
176+ trigger == EdgeTrigger::BOTH);
177+ bool falling = (trigger == EdgeTrigger::FALLING ||
178+ trigger == EdgeTrigger::BOTH);
179+
180+ configBuilder.create <TraceRegOp>(
181+ edgeOp.getLoc (),
182+ builder.getStringAttr (" Edge_Detection_event_control" ),
183+ builder.getStringAttr (risingField),
184+ builder.getI32IntegerAttr (rising ?1 :0 ),
185+ /* mask=*/ nullptr ,
186+ builder.getStringAttr (" edge" +std::to_string (slot) +
187+ " rising" ));
188+
189+ configBuilder.create <TraceRegOp>(
190+ edgeOp.getLoc (),
191+ builder.getStringAttr (" Edge_Detection_event_control" ),
192+ builder.getStringAttr (fallingField),
193+ builder.getI32IntegerAttr (falling ?1 :0 ),
194+ /* mask=*/ nullptr ,
195+ builder.getStringAttr (" edge" +std::to_string (slot) +
196+ " falling" ));
197+ }
198+ }
199+
67200// 1. Emit Trace_Control0 fields
68201// Check for start/stop events
69202for (auto &op : trace.getBody ().getOps ()) {