MLIR-AIE
AIETargetUcCert.cpp
Go to the documentation of this file.
1//===- AIETargetUcCert.cpp --------------------------------------*- C++ -*-===//
2//
3// This file is licensed under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7// (c) Copyright 2025 Advanced Micro Devices, Inc.
8//
9//===----------------------------------------------------------------------===//
10
12
15
16#include "mlir/Dialect/Func/IR/FuncOps.h"
17#include "mlir/Tools/mlir-translate/MlirTranslateMain.h"
18
19#include "llvm/ADT/ArrayRef.h"
20#include "llvm/ADT/StringSet.h"
21#include "llvm/ADT/TypeSwitch.h"
22#include "llvm/Support/Format.h"
23
24#include <vector>
25
26using namespace mlir;
27using namespace xilinx;
28using namespace xilinx::AIE;
29using namespace xilinx::AIEX;
30
31namespace {
32
33// NOP
34void emitNop(CertNopOp op, std::string &text) { text += " NOP\n"; }
35
36// MASK_WRITE_32 0x6838000, 0x2, 0x2
37void emitMaskWrite32(CertMaskWrite32Op op, std::string &text) {
38 std::string s;
39 llvm::raw_string_ostream ss(s);
40 ss << " MASK_WRITE_32 ";
41 ss << llvm::format("0x%08x, ", op.getAddress());
42 ss << llvm::format("0x%08x, ", op.getMask());
43 ss << llvm::format("0x%08x\n", op.getValue());
44 text += ss.str();
45}
46
47// WRITE_32 0x01A0634, 0x80000004
48void emitWrite32(CertWrite32Op op, std::string &text) {
49 std::string s;
50 llvm::raw_string_ostream ss(s);
51 ss << " WRITE_32 ";
52 ss << llvm::format("0x%08x, ", op.getAddress());
53 ss << llvm::format("0x%08x\n", op.getValue());
54 text += ss.str();
55}
56
57// uC_DMA_WRITE_DES_SYNC @INPUT_row1_actor6_task6_ucbds
58void emitUcDmaWriteDesSync(CertUcDmaWriteDesSyncOp op, std::string &text) {
59 text += " uC_DMA_WRITE_DES_SYNC ";
60 text += "@" + op.getSymbol().str() + "\n";
61}
62
63// WAIT_TCTS TILE_0_1, MEM_MM2S_0, 1
64void emitWaitTCTS(CertWaitTCTSOp op, std::string &text) {
65 uint32_t tileId = op.getTileId();
66 uint32_t channelId = op.getChannelId();
67 text += " WAIT_TCTS ";
68 text += std::to_string(tileId) + ", ";
69 text += std::to_string(channelId) + ", ";
70 text += std::to_string(op.getTargetTcts()) + "\n";
71}
72
73// APPLY_OFFSET_57 @mem21_bd0, 1, 0xffff
74void emitApplyOffset57(CertApplyOffset57Op op, std::string &text) {
75 uint16_t num_entries = op.getNumEntries();
76 uint16_t offset = op.getOffset();
77 std::string s;
78 llvm::raw_string_ostream ss(s);
79 ss << " APPLY_OFFSET_57 ";
80 ss << "@" << op.getSymbol().str() << ", ";
81 ss << num_entries << ", ";
82 ss << llvm::format("0x%04x", offset) << "\n";
83 text += ss.str();
84}
85
86// LOCAL_BARRIER $lb0, 2
87void emitLocalBarrier(CertLocalBarrierOp op, std::string &text) {
88 text += " LOCAL_BARRIER ";
89 text += "$lb" + std::to_string(op.getLocalBarrierId()) + ", ";
90 text += std::to_string(op.getNumParticipants()) + "\n";
91}
92
93// REMOTE_BARRIER $rb3, 3
94void emitRemoteBarrier(CertRemoteBarrierOp op, std::string &text) {
95 text += " REMOTE_BARRIER ";
96 text += "$rb" + std::to_string(op.getRemoteBarrierId()) + ", ";
97 text += std::to_string(op.getPartyMask()) + "\n";
98}
99
100// START_JOB 0
101// <body>
102// END_JOB
103void emitJob(CertJobOp jobOp, std::string &text, std::string &data) {
104
105 text += "START_JOB ";
106 text += std::to_string(jobOp.getJobId()) + "\n";
107
108 for (auto &o : jobOp.getBody().front()) {
109 llvm::TypeSwitch<Operation *>(&o)
110 .Case<CertApplyOffset57Op>(
111 [&](auto op) { emitApplyOffset57(op, text); })
112 .Case<CertLocalBarrierOp>([&](auto op) { emitLocalBarrier(op, text); })
113 .Case<CertRemoteBarrierOp>(
114 [&](auto op) { emitRemoteBarrier(op, text); })
115 .Case<CertMaskWrite32Op>([&](auto op) { emitMaskWrite32(op, text); })
116 .Case<CertNopOp>([&](auto op) { emitNop(op, text); })
117 .Case<CertUcDmaWriteDesSyncOp>(
118 [&](auto op) { emitUcDmaWriteDesSync(op, text); })
119 .Case<CertWaitTCTSOp>([&](auto op) { emitWaitTCTS(op, text); })
120 .Case<CertWrite32Op>([&](auto op) { emitWrite32(op, text); })
121 .Default([&](Operation *op) {
122 op->emitError("Unsupported operation in CertJobOp");
123 });
124 }
125
126 text += "END_JOB\n\n";
127}
128
129void emitJobs(llvm::SmallVector<CertJobOp> &jobs, std::string &text,
130 std::string &data) {
131
132 llvm::sort(jobs, [](CertJobOp a, CertJobOp b) {
133 return a.getJobId() < b.getJobId();
134 });
135
136 for (auto job : jobs) {
137 emitJob(job, text, data);
138 text += ".eop\n\n";
139 }
140}
141
142void emitAttachToGroupOp(CertAttachToGroupOp groupOp, std::string &text,
143 std::string &data) {
144 if (groupOp.getGroupId())
145 text += ".attach_to_group " + std::to_string(groupOp.getGroupId()) + "\n\n";
146 auto jobs =
147 llvm::to_vector_of<CertJobOp>(groupOp.getBody().getOps<CertJobOp>());
148 emitJobs(jobs, text, data);
149}
150
151void emitUcDmaBdData(CertUcDmaBdOp op, std::string &data,
152 llvm::StringSet<> &emittedGlobals) {
153 // lookup data from operation
154 auto dataSymbol = op.getRemoteAddress();
155 if (emittedGlobals.contains(dataSymbol))
156 return;
157
158 auto global = dyn_cast_if_present<memref::GlobalOp>(
159 op->getParentOfType<AIE::DeviceOp>().lookupSymbol(dataSymbol));
160 if (!global) {
161 op.emitError("Global symbol not found");
162 return;
163 }
164
165 auto initVal = global.getInitialValue();
166 if (!initVal) {
167 op.emitError("Global symbol has no initial value");
168 return;
169 }
170
171 auto initData = dyn_cast<DenseIntElementsAttr>(*initVal);
172 if (!initData) {
173 op.emitError("Global symbol initial value is not a dense int array");
174 return;
175 }
176
177 // data0:
178 // .long 0x00005A00
179 std::string s;
180 llvm::raw_string_ostream ss(s);
181 ss << " .align 16\n";
182 ss << dataSymbol.str() << ":\n";
183 for (auto d : initData)
184 ss << llvm::format(" .long 0x%08x\n", d.getZExtValue());
185 data += ss.str();
186 emittedGlobals.insert(dataSymbol);
187}
188
189// UC_DMA_BD 0, 0x001A05C0, @data, 8, 0, 1
190void emitUcDmaBd(CertUcDmaBdOp op, std::string &chains, std::string &data,
191 llvm::StringSet<> &emittedGlobals) {
192 std::string s;
193 llvm::raw_string_ostream ss(s);
194 ss << " UC_DMA_BD ";
195 ss << "0, ";
196 ss << llvm::format("0x%08x, ", op.getLocalAddress());
197 ss << "@" + op.getRemoteAddress().str() + ", ";
198 ss << op.getLength() << ", ";
199 ss << "0, ";
200 ss << (op.getNextBd() ? "1\n" : "0\n");
201 chains += ss.str();
202 emitUcDmaBdData(op, data, emittedGlobals);
203}
204
205// .align 16
206// name_of_chain:
207// UC_DMA_BD 0, 0x001A05C0, @data0, 8, 0, 1
208void emitUcDmaChain(CertUcDmaChainOp op, std::string &chains, std::string &data,
209 llvm::StringSet<> &emittedGlobals) {
210 chains += " .align 16\n";
211 chains += op.getName().str() + ":\n";
212 for (auto &o : op.getBody().front()) {
213 llvm::TypeSwitch<Operation *>(&o).Case<CertUcDmaBdOp>(
214 [&](auto op) { emitUcDmaBd(op, chains, data, emittedGlobals); });
215 }
216}
217
218} // namespace
219
220LogicalResult xilinx::AIE::AIETranslateToUcDma(ModuleOp module,
221 std::string &assembly) {
222
223 DeviceOp deviceOp = *module.getOps<DeviceOp>().begin();
224
225 std::vector<std::string> text;
226 std::vector<std::string> data;
227 std::vector<std::string> chains;
228 llvm::StringSet<> emittedGlobals;
229
230 text.push_back("\n;\n; Code\n;\n\n");
231 data.push_back("\n;\n; Data\n;\n\n");
232 chains.push_back("\n;\n; Data (chains)\n;\n\n");
233
234 text[0] += ".attach_to_group 0\n\n";
235 auto jobs = llvm::to_vector_of<CertJobOp>(deviceOp.getOps<CertJobOp>());
236 emitJobs(jobs, text[0], data[0]);
237
238 auto groups = llvm::to_vector_of<CertAttachToGroupOp>(
239 deviceOp.getOps<CertAttachToGroupOp>());
240 llvm::sort(groups, [](CertAttachToGroupOp a, CertAttachToGroupOp b) {
241 return a.getGroupId() < b.getGroupId();
242 });
243
244 for (auto o : deviceOp.getBody()->getOps<CertUcDmaChainOp>())
245 emitUcDmaChain(o, chains[0], data[0], emittedGlobals);
246
247 int group_id = 0;
248 for (auto &groupOp : groups) {
249 if (group_id) {
250 text.push_back("\n;\n; Code\n;\n\n");
251 data.push_back("\n;\n; Data\n;\n\n");
252 chains.push_back("\n;\n; Data (chains)\n;\n\n");
253 }
254 emitAttachToGroupOp(groupOp, text[group_id], data[group_id]);
255 group_id++;
256 }
257
258 for (auto const &[t, c, d] : llvm::zip(text, chains, data)) {
259 if (t.size()) {
260 assembly += t + "EOF\n";
261 }
262 if (c.size()) {
263 assembly += c;
264 }
265 if (d.size())
266 assembly += "\n" + d;
267 }
268 return success();
269}
270
271LogicalResult xilinx::AIE::AIETranslateToUcDma(ModuleOp module,
272 raw_ostream &output) {
273 std::string assembly;
274 auto r = AIETranslateToUcDma(module, assembly);
275 if (failed(r))
276 return r;
277 output << assembly;
278 return success();
279}
Include the generated interface declarations.
mlir::LogicalResult AIETranslateToUcDma(mlir::ModuleOp module, llvm::raw_ostream &output)