13#include "mlir/Dialect/Func/IR/FuncOps.h"
14#include "mlir/Tools/mlir-translate/MlirTranslateMain.h"
16#include "llvm/ADT/ArrayRef.h"
17#include "llvm/ADT/StringSet.h"
18#include "llvm/ADT/TypeSwitch.h"
19#include "llvm/Support/FileSystem.h"
20#include "llvm/Support/Format.h"
21#include "llvm/Support/Path.h"
41void emitNop(CertNopOp op, std::string &text) { text +=
" NOP\n"; }
44void emitMaskWrite32(CertMaskWrite32Op op, std::string &text) {
46 llvm::raw_string_ostream ss(s);
47 ss <<
" MASK_WRITE_32 ";
48 ss << llvm::format(
"0x%08x, ", op.getAddress());
49 ss << llvm::format(
"0x%08x, ", op.getMask());
50 ss << llvm::format(
"0x%08x\n", op.getValue());
54void emitMaskPoll32(CertMaskPoll32Op op, std::string &text) {
56 llvm::raw_string_ostream ss(s);
57 ss <<
" MASK_POLL_32 ";
58 ss << llvm::format(
"0x%08x, ", op.getAddress());
59 ss << llvm::format(
"0x%08x, ", op.getMask());
60 ss << llvm::format(
"0x%08x\n", op.getValue());
65void emitWrite32(CertWrite32Op op, std::string &text) {
67 llvm::raw_string_ostream ss(s);
69 ss << llvm::format(
"0x%08x, ", op.getAddress());
70 ss << llvm::format(
"0x%08x\n", op.getValue());
75void emitUcDmaWriteDesSync(CertUcDmaWriteDesSyncOp op, std::string &text) {
76 text +=
" uC_DMA_WRITE_DES_SYNC ";
77 text +=
"@" + op.getSymbol().str() +
"\n";
81void emitWaitTCTS(CertWaitTCTSOp op, std::string &text) {
82 uint32_t tileId = op.getTileId();
83 uint32_t channelId = op.getChannelId();
84 text +=
" WAIT_TCTS ";
85 text += std::to_string(tileId) +
", ";
86 text += std::to_string(channelId) +
", ";
87 text += std::to_string(op.getTargetTcts()) +
"\n";
91void emitApplyOffset57(CertApplyOffset57Op op, std::string &text) {
92 uint16_t num_entries = op.getNumEntries();
93 uint16_t offset = op.getOffset();
95 llvm::raw_string_ostream ss(s);
96 ss <<
" APPLY_OFFSET_57 ";
97 ss <<
"@" << op.getSymbol().str() <<
", ";
98 ss << num_entries <<
", ";
104void emitLocalBarrier(CertLocalBarrierOp op, std::string &text) {
105 text +=
" LOCAL_BARRIER ";
106 text +=
"$lb" + std::to_string(op.getLocalBarrierId()) +
", ";
107 text += std::to_string(op.getNumParticipants()) +
"\n";
111void emitRemoteBarrier(CertRemoteBarrierOp op, std::string &text) {
112 text +=
" REMOTE_BARRIER ";
113 text +=
"$rb" + std::to_string(op.getRemoteBarrierId()) +
", ";
114 text += std::to_string(op.getPartyMask()) +
"\n";
118void emitRelAcqSync(CertRelAcqSyncOp op, std::string &text) {
120 llvm::raw_string_ostream ss(s);
121 ss <<
" REL_ACQ_SYNC ";
122 ss << llvm::format(
"0x%08x, ", op.getRelAddress());
123 ss << llvm::format(
"0x%08x\n", op.getAcqAddress());
128void emitLoadPdi(CertLoadPdiOp op, std::string &text) {
129 text +=
" LOAD_PDI ";
130 text += std::to_string(op.getPdiId()) +
", ";
131 text +=
"@" + op.getSymbol().str() +
"\n";
135void emitPreempt(CertPreemptOp op, std::string &text) {
137 llvm::raw_string_ostream ss(s);
139 ss << llvm::format(
"0x%04x, ", op.getId());
140 ss <<
"@" << op.getSaveSection().str() <<
", ";
141 ss <<
"@" << op.getRestoreSection().str() <<
"\n";
148LogicalResult emitJob(CertJobOp jobOp, std::string &text, std::string &data) {
149 LogicalResult result = success();
151 text +=
"START_JOB ";
152 text += std::to_string(jobOp.getJobId()) +
"\n";
154 for (
auto &o : jobOp.getBody().front()) {
155 llvm::TypeSwitch<Operation *>(&o)
156 .Case<CertApplyOffset57Op>(
157 [&](
auto op) { emitApplyOffset57(op, text); })
158 .Case<CertLocalBarrierOp>([&](
auto op) { emitLocalBarrier(op, text); })
159 .Case<CertLoadPdiOp>([&](
auto op) { emitLoadPdi(op, text); })
160 .Case<CertPreemptOp>([&](
auto op) { emitPreempt(op, text); })
161 .Case<CertRemoteBarrierOp>(
162 [&](
auto op) { emitRemoteBarrier(op, text); })
163 .Case<CertRelAcqSyncOp>([&](
auto op) { emitRelAcqSync(op, text); })
164 .Case<CertMaskWrite32Op>([&](
auto op) { emitMaskWrite32(op, text); })
165 .Case<CertMaskPoll32Op>([&](
auto op) { emitMaskPoll32(op, text); })
166 .Case<CertNopOp>([&](
auto op) { emitNop(op, text); })
167 .Case<CertUcDmaWriteDesSyncOp>(
168 [&](
auto op) { emitUcDmaWriteDesSync(op, text); })
169 .Case<CertWaitTCTSOp>([&](
auto op) { emitWaitTCTS(op, text); })
170 .Case<CertWrite32Op>([&](
auto op) { emitWrite32(op, text); })
171 .Case<AIE::EndOp>([](
auto) { })
172 .Default([&](Operation *op) {
173 op->emitError(
"Unsupported operation in CertJobOp");
178 text +=
"END_JOB\n\n";
182LogicalResult emitJobs(llvm::SmallVector<CertJobOp> &jobs, std::string &text,
184 LogicalResult result = success();
189 for (
auto job : jobs) {
190 if (failed(emitJob(job, text, data)))
200LogicalResult emitPage(CertPageOp pageOp, std::string &text,
202 LogicalResult result = success();
203 text +=
".align 16\n";
208 for (
auto job : pageOp.getBody().getOps<CertJobOp>()) {
209 if (failed(emitJob(job, text, data)))
222LogicalResult emitSection(CertSectionOp sectionOp, std::string &text,
223 llvm::StringRef outputPath) {
224 LogicalResult result = success();
225 std::string sectionName = sectionOp.getSymName().str();
226 std::string sectionFileName = sectionName +
".asm";
229 std::string sectionText;
230 std::string sectionData;
233 for (
auto page : sectionOp.getBody().getOps<CertPageOp>()) {
234 if (failed(emitPage(page, sectionText, sectionData)))
240 llvm::to_vector_of<CertJobOp>(sectionOp.getBody().getOps<CertJobOp>());
241 for (
auto job : jobs) {
242 if (failed(emitJob(job, sectionText, sectionData)))
244 sectionText +=
".eop\n\n";
248 std::string sectionFilePath;
249 if (!outputPath.empty()) {
250 llvm::SmallString<128> path(outputPath);
251 llvm::sys::path::remove_filename(path);
252 llvm::sys::path::append(path, sectionFileName);
253 sectionFilePath = path.str().str();
255 sectionFilePath = sectionFileName;
259 llvm::raw_fd_ostream sectionFile(sectionFilePath, EC);
262 return sectionOp.emitError(
"failed to open section file '")
263 << sectionFilePath <<
"': " << EC.message();
267 if (!sectionText.empty()) {
268 sectionFile <<
";\n;text\n;\n";
269 sectionFile << sectionText;
273 sectionFile <<
"EOF\n\n";
276 if (!sectionData.empty()) {
277 sectionFile <<
";\n;data\n;\n";
278 sectionFile << sectionData;
282 if (sectionFile.has_error()) {
283 std::error_code writeEC = sectionFile.error();
285 sectionFile.clear_error();
286 return sectionOp.emitError(
"failed to write section file '")
287 << sectionFilePath <<
"': " << writeEC.message();
291 text += sectionName +
":\n";
292 text +=
".include " + sectionFileName +
"\n";
293 text +=
".endl " + sectionName +
"\n\n";
297LogicalResult emitAttachToGroupOp(CertAttachToGroupOp groupOp,
298 std::string &text, std::string &data,
299 llvm::StringRef outputPath) {
300 LogicalResult result = success();
303 for (
auto section : groupOp.getBody().getOps<CertSectionOp>()) {
304 if (failed(emitSection(section, text, outputPath)))
308 if (groupOp.getGroupId())
309 text +=
".attach_to_group " + std::to_string(groupOp.getGroupId()) +
"\n\n";
312 for (
auto page : groupOp.getBody().getOps<CertPageOp>()) {
313 if (failed(emitPage(page, text, data)))
319 llvm::to_vector_of<CertJobOp>(groupOp.getBody().getOps<CertJobOp>());
320 if (failed(emitJobs(jobs, text, data)))
325void emitUcDmaBdData(CertUcDmaBdOp op, std::string &data,
326 llvm::StringSet<> &emittedGlobals) {
328 auto dataSymbol = op.getRemoteAddress();
329 if (emittedGlobals.contains(dataSymbol))
332 auto global = dyn_cast_if_present<memref::GlobalOp>(
333 op->getParentOfType<AIE::DeviceOp>().lookupSymbol(dataSymbol));
335 op.emitError(
"Global symbol not found");
339 auto initVal = global.getInitialValue();
341 op.emitError(
"Global symbol has no initial value");
345 auto initData = dyn_cast<DenseIntElementsAttr>(*initVal);
347 op.emitError(
"Global symbol initial value is not a dense int array");
354 llvm::raw_string_ostream ss(s);
355 ss <<
" .align 16\n";
356 ss << dataSymbol.str() <<
":\n";
357 for (
auto d : initData)
358 ss << llvm::format(
" .long 0x%08x\n", d.getZExtValue());
360 emittedGlobals.insert(dataSymbol);
364void emitUcDmaBd(CertUcDmaBdOp op, std::string &chains, std::string &data,
365 llvm::StringSet<> &emittedGlobals) {
367 llvm::raw_string_ostream ss(s);
368 ss <<
" UC_DMA_BD 0, ";
369 ss << llvm::format(
"0x%08x, ", op.getLocalAddress());
370 ss <<
"@" + op.getRemoteAddress().str() +
", ";
371 ss << op.getLength() <<
", ";
373 ss << (op.getNextBd() ?
"1\n" :
"0\n");
375 emitUcDmaBdData(op, data, emittedGlobals);
381void emitUcDmaChain(CertUcDmaChainOp op, std::string &chains, std::string &data,
382 llvm::StringSet<> &emittedGlobals) {
383 chains +=
" .align 16\n";
384 chains += op.getName().str() +
":\n";
385 for (
auto &o : op.getBody().front()) {
386 llvm::TypeSwitch<Operation *>(&o).Case<CertUcDmaBdOp>(
387 [&](
auto op) { emitUcDmaBd(op, chains, data, emittedGlobals); });
394 std::string &assembly,
395 llvm::StringRef outputPath) {
397 DeviceOp deviceOp = *
module.getOps<DeviceOp>().begin();
399 std::vector<std::string> text;
400 std::vector<std::string> data;
401 std::vector<std::string> chains;
402 llvm::StringSet<> emittedGlobals;
404 text.emplace_back(
"\n;\n; Code\n;\n\n");
405 data.emplace_back(
"\n;\n; Data\n;\n\n");
406 chains.emplace_back(
"\n;\n; Data (chains)\n;\n\n");
408 auto &tm = deviceOp.getTargetModel();
409 text[0] +=
".partition " + std::to_string(tm.columns()) +
"column\n";
412 text[0] +=
".attach_to_group 0\n\n";
414 LogicalResult result = success();
420 std::map<uint32_t, size_t> groupIdToBlock;
421 groupIdToBlock[0] = 0;
422 auto blockFor = [&](uint32_t gid) ->
size_t {
423 auto it = groupIdToBlock.find(gid);
424 if (it != groupIdToBlock.end())
426 text.emplace_back(
"\n;\n; Code\n;\n\n");
427 data.emplace_back(
"\n;\n; Data\n;\n\n");
428 chains.emplace_back(
"\n;\n; Data (chains)\n;\n\n");
429 size_t block = text.size() - 1;
430 groupIdToBlock[gid] = block;
438 for (
auto section : deviceOp.getBody()->getOps<CertSectionOp>()) {
439 if (failed(emitSection(section, text[0], outputPath)))
445 for (Operation &op : *deviceOp.getBody()) {
446 if (
auto page = dyn_cast<CertPageOp>(&op)) {
447 if (failed(emitPage(page, text[0], data[0])))
449 }
else if (
auto job = dyn_cast<CertJobOp>(&op)) {
450 if (failed(emitJob(job, text[0], data[0])))
452 }
else if (
auto grp = dyn_cast<CertAttachToGroupOp>(&op)) {
453 size_t block = blockFor(grp.getGroupId());
455 emitAttachToGroupOp(grp, text[block], data[block], outputPath)))
457 }
else if (
auto chain = dyn_cast<CertUcDmaChainOp>(&op)) {
458 emitUcDmaChain(chain, chains[0], data[0], emittedGlobals);
467 for (
auto const &entry : groupIdToBlock) {
468 size_t block = entry.second;
469 if (!text[block].empty()) {
470 assembly += text[block];
474 if (!chains[block].empty())
475 assembly += chains[block];
476 if (!data[block].empty())
477 assembly +=
"\n" + data[block];
483 raw_ostream &output) {
484 std::string assembly;
488 llvm::StringRef outputPath =
"";
mlir::LogicalResult AIETranslateToUcDma(mlir::ModuleOp module, llvm::raw_ostream &output)