Skip to content

Commit 87500b7

Browse files
committed
[cert] Add page/section-based CERT lowering: NpuToCert pass + UcCert emission
Adopt the page-based CERT representation in the AIEX dialect and lower aie.runtime_sequence into it for emission to uC control code. - CERTOps.td: add CertPageOp, CertSectionOp, CertPreemptOp, CertLoadPdiOp; widen CertJobOp parents to pages/sections. - AIENpuToCert (aie-npu-to-cert): page-based lowering with Run-op inlining, Configure->Section, page wrapping/splitting (fixes the page-split infinite loop), and PDI-id assignment. - AIETargetUcCert (aie-cert-to-asm): emit page/section/preempt/load_pdi and a .partition header; outputPath plumbing. - Tests (npu2): page_legalize, split_blockwrite, cert_to_asm. The lowering and emission are device-neutral and exercised on npu2 via aie-opt/aie-translate. CERT full-ELF generation in aiecc and the AIE2PS/AIE4 device glue depend on a CERT-capable device target that is not yet upstream; they are deferred to land alongside device enablement.
1 parent 6a9b115 commit 87500b7

10 files changed

Lines changed: 1552 additions & 128 deletions

File tree

include/aie/Dialect/AIEX/IR/CERTOps.td

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,34 @@ def AIE_CertUcDmaBdOp : AIEX_Op<"cert.uc_dma_bd", [HasParent<"CertUcDmaChainOp">
6868
}];
6969
}
7070

71-
def AIE_CertJobOp: AIEX_Op<"cert.job", [ParentOneOf<["AIE::DeviceOp", "CertAttachToGroupOp"]>,
71+
def AIE_CertPageOp: AIEX_Op<"cert.page",
72+
[ParentOneOf<["AIE::DeviceOp", "CertAttachToGroupOp", "CertSectionOp"]>,
73+
SingleBlockImplicitTerminator<"AIE::EndOp">]> {
74+
let summary = "A control code page";
75+
let description = [{
76+
This operation represents a page of control code. Pages are the basic unit
77+
of control code organization, with a maximum size of 8192 bytes. Each page
78+
typically contains one job along with its associated data.
79+
80+
Corresponds to the `.eop` (end of page) directive in assembly.
81+
82+
Example:
83+
```
84+
cert.page {
85+
cert.job(0) {
86+
cert.write32(0x1000, 42)
87+
}
88+
}
89+
```
90+
}];
91+
let regions = (region
92+
AnyRegion:$body
93+
);
94+
let assemblyFormat = [{ $body attr-dict }];
95+
}
96+
97+
def AIE_CertJobOp: AIEX_Op<"cert.job", [ParentOneOf<["AIE::DeviceOp", "CertAttachToGroupOp",
98+
"CertPageOp", "CertSectionOp"]>,
7299
SingleBlockImplicitTerminator<"AIE::EndOp">]> {
73100
let summary = "Start a job with a given job ID";
74101
let description = [{
@@ -241,6 +268,34 @@ def AIE_CertRemoteBarrierOp: AIEX_Op<"cert.remote_barrier", [HasParent<"CertJobO
241268
}];
242269
}
243270

271+
def AIE_CertPreemptOp: AIEX_Op<"cert.preempt", [HasParent<"CertJobOp">]> {
272+
let summary = "Preemption point with save/restore control code references";
273+
let description = [{
274+
This operation defines a preemption point in control code. If preemption is
275+
required, the runtime will execute either the save or restore control code
276+
section depending on the context switch direction.
277+
278+
- `id`: Preemption point index (must be consistent across all uCs in multi-uC case)
279+
- `save_section`: Symbol reference to control code section for saving state
280+
- `restore_section`: Symbol reference to control code section for restoring state
281+
282+
This opcode should take one whole job which in turn should take one whole page.
283+
284+
Example:
285+
```
286+
cert.preempt(0, @save0, @restore0)
287+
```
288+
}];
289+
let arguments = (
290+
ins I32Attr:$id,
291+
FlatSymbolRefAttr:$save_section,
292+
FlatSymbolRefAttr:$restore_section
293+
);
294+
let assemblyFormat = [{
295+
`(` $id `,` $save_section `,` $restore_section `)` attr-dict
296+
}];
297+
}
298+
244299
def AIE_CertNopOp: AIEX_Op<"cert.nop", []> {
245300
let summary = "No operation (NOP)";
246301
let description = [{
@@ -254,6 +309,68 @@ def AIE_CertNopOp: AIEX_Op<"cert.nop", []> {
254309
let assemblyFormat = [{ attr-dict }];
255310
}
256311

312+
def AIE_CertSectionOp: AIEX_Op<"cert.section",
313+
[Symbol,
314+
ParentOneOf<["AIE::DeviceOp", "CertAttachToGroupOp"]>,
315+
SingleBlockImplicitTerminator<"AIE::EndOp">]> {
316+
let summary = "Named control code section";
317+
let description = [{
318+
This operation defines a named section of control code that can be referenced
319+
by other operations (like cert.load_pdi or cert.preempt). It corresponds to the
320+
assembly pattern of `label: ... .endl label`.
321+
322+
The section contains one or more jobs and can be loaded/executed by referencing
323+
its symbol.
324+
325+
Example:
326+
```
327+
cert.section @pdi0 {
328+
cert.job(10) {
329+
cert.write32(0x6A3000, 0x2)
330+
}
331+
}
332+
333+
cert.job(0) {
334+
cert.load_pdi(0, @pdi0)
335+
}
336+
```
337+
}];
338+
let arguments = (
339+
ins SymbolNameAttr:$sym_name
340+
);
341+
let regions = (region
342+
AnyRegion:$body
343+
);
344+
let assemblyFormat = [{
345+
$sym_name $body attr-dict
346+
}];
347+
}
348+
349+
def AIE_CertLoadPdiOp: AIEX_Op<"cert.load_pdi", [HasParent<"CertJobOp">]> {
350+
let summary = "Load PDI (Platform Device Image)";
351+
let description = [{
352+
This operation loads a PDI (Platform Device Image), which is a piece of control code.
353+
It can be loaded by other control code at any time. The `pdi_id` is an ELF-wide unique
354+
identifier that specifies a unique PDI. Consecutive loading of the same PDI results in
355+
subsequent loads being skipped by the microcontroller. The `symbol` operand refers to
356+
a cert.section containing the PDI jobs.
357+
358+
This opcode should take one whole job which in turn should take one whole page.
359+
360+
Example:
361+
```
362+
cert.load_pdi(0, @pdi_section)
363+
```
364+
}];
365+
let arguments = (
366+
ins UI32Attr:$pdi_id,
367+
FlatSymbolRefAttr:$symbol
368+
);
369+
let assemblyFormat = [{
370+
`(` $pdi_id `,` $symbol `)` attr-dict
371+
}];
372+
}
373+
257374
def AIE_CertAttachToGroupOp: AIEX_Op<"cert.attach_to_group", [SingleBlockImplicitTerminator<"AIE::EndOp">]> {
258375
let summary = "Attach to a group operation";
259376
let description = [{

include/aie/Dialect/AIEX/Transforms/AIEXPasses.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ createAIELowerMulticastPass();
3030
std::unique_ptr<mlir::OperationPass<AIE::DeviceOp>>
3131
createAIEBroadcastPacketPass();
3232
std::unique_ptr<mlir::OperationPass<AIE::DeviceOp>> createAIEDmaToNpuPass();
33-
std::unique_ptr<mlir::OperationPass<AIE::DeviceOp>> createAIENpuToCertPass();
33+
std::unique_ptr<mlir::OperationPass<mlir::ModuleOp>> createAIENpuToCertPass();
3434
std::unique_ptr<mlir::OperationPass<AIE::DeviceOp>> createAIECertPagesPass();
3535
std::unique_ptr<mlir::OperationPass<mlir::ModuleOp>> createAIEXToStandardPass();
3636
std::unique_ptr<mlir::OperationPass<AIE::DeviceOp>>

include/aie/Dialect/AIEX/Transforms/AIEXPasses.td

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,15 +148,23 @@ def AIEDmaToNpu : Pass<"aie-dma-to-npu", "AIE::DeviceOp"> {
148148
];
149149
}
150150

151-
def AIENpuToCert : Pass<"aie-npu-to-cert", "AIE::DeviceOp"> {
151+
def AIENpuToCert : Pass<"aie-npu-to-cert", "mlir::ModuleOp"> {
152152
let summary = "transform aiex.npu operations to aiex.cert operations";
153153
let description = [{
154154
This pass transforms low level aiex.npu operations contained in
155155
aie.runtime_sequence operations into aiex.cert operations enclosed in
156156
aiex.cert.job operations. The write32, maskwrite32, blockwrite and sync
157157
operations are supported.
158+
159+
Referenced devices are absorbed into cert.section operations and removed
160+
from the output, keeping only the main device.
158161
}];
159162

163+
let options = [
164+
Option<"deviceName", "device-name", "std::string", /*default=*/"\"main\"",
165+
"Name of the main device to emit (other devices are removed after absorption)">
166+
];
167+
160168
let constructor = "xilinx::AIEX::createAIENpuToCertPass()";
161169
let dependentDialects = [
162170
"mlir::func::FuncDialect",

include/aie/Targets/AIETargets.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,9 @@ AIETranslateNpuToBinary(mlir::ModuleOp, std::vector<uint32_t> &,
7777
std::vector<TxnLocEntry> *locmap = nullptr);
7878
mlir::LogicalResult AIETranslateToUcDma(mlir::ModuleOp module,
7979
llvm::raw_ostream &output);
80-
mlir::LogicalResult AIETranslateToUcDma(mlir::ModuleOp, std::string &assembly);
80+
mlir::LogicalResult AIETranslateToUcDma(mlir::ModuleOp module,
81+
std::string &assembly,
82+
llvm::StringRef outputPath = "");
8183
mlir::LogicalResult
8284
AIETranslateControlPacketsToUI32Vec(mlir::ModuleOp, std::vector<uint32_t> &,
8385
llvm::StringRef deviceName = "",

0 commit comments

Comments
 (0)