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/CommandLine.h"
20#include "llvm/Support/FileSystem.h"
21#include "llvm/Support/Format.h"
22#include "llvm/Support/Path.h"
43void emitNop(CertNopOp op, std::string &text) { text +=
" NOP\n"; }
46void emitMaskWrite32(CertMaskWrite32Op op, std::string &text) {
48 llvm::raw_string_ostream ss(s);
49 ss <<
" MASK_WRITE_32 ";
50 ss << llvm::format(
"0x%08x, ", op.getAddress());
51 ss << llvm::format(
"0x%08x, ", op.getMask());
52 ss << llvm::format(
"0x%08x\n", op.getValue());
56void emitMaskPoll32(CertMaskPoll32Op op, std::string &text) {
58 llvm::raw_string_ostream ss(s);
59 ss <<
" MASK_POLL_32 ";
60 ss << llvm::format(
"0x%08x, ", op.getAddress());
61 ss << llvm::format(
"0x%08x, ", op.getMask());
62 ss << llvm::format(
"0x%08x\n", op.getValue());
67void emitWrite32(CertWrite32Op op, std::string &text) {
69 llvm::raw_string_ostream ss(s);
71 ss << llvm::format(
"0x%08x, ", op.getAddress());
72 ss << llvm::format(
"0x%08x\n", op.getValue());
77void emitUcDmaWriteDesSync(CertUcDmaWriteDesSyncOp op, std::string &text) {
78 text +=
" uC_DMA_WRITE_DES_SYNC ";
79 text +=
"@" + op.getSymbol().str() +
"\n";
83void emitRead32(CertRead32Op op, std::string &text) {
85 llvm::raw_string_ostream ss(s);
86 ss <<
" READ_32 $r" << op.getValue() <<
", ";
87 ss << llvm::format(
"0x%08x\n", op.getAddress());
92void emitRead32D(CertRead32DOp op, std::string &text) {
93 text +=
" READ_32_D $r" + std::to_string(op.getAddress()) +
94 ", $r" + std::to_string(op.getValue()) +
"\n";
100void emitWrite32D(CertWrite32DOp op, std::string &text) {
102 (op.getAddressIsReg() ? 1 : 0) | (op.getValueIsReg() ? 2 : 0);
104 llvm::raw_string_ostream ss(s);
105 ss <<
" WRITE_32_D " << flags <<
", ";
106 ss << llvm::format(
"0x%08x, ", op.getAddress());
107 ss << llvm::format(
"0x%08x\n", op.getValue());
112void emitSaveTimestamps(CertSaveTimestampsOp op, std::string &text) {
113 text +=
" SAVE_TIMESTAMPS " + std::to_string(op.getUnqId()) +
"\n";
117void emitSaveRegister(CertSaveRegisterOp op, std::string &text) {
119 llvm::raw_string_ostream ss(s);
120 ss <<
" SAVE_REGISTER ";
121 ss << llvm::format(
"0x%08x, ", op.getAddress());
122 ss << op.getUnqId() <<
"\n";
127void emitUcDmaWriteDes(CertUcDmaWriteDesOp op, std::string &text) {
128 text +=
" UC_DMA_WRITE_DES $r" + std::to_string(op.getWaitHandle()) +
129 ", @" + op.getSymbol().str() +
"\n";
133void emitWaitUcDma(CertWaitUcDmaOp op, std::string &text) {
135 " WAIT_UC_DMA $r" + std::to_string(op.getWaitHandle()) +
"\n";
139void emitWaitTCTS(CertWaitTCTSOp op, std::string &text) {
140 uint32_t tileId = op.getTileId();
141 uint32_t channelId = op.getChannelId();
142 text +=
" WAIT_TCTS ";
143 text += std::to_string(tileId) +
", ";
144 text += std::to_string(channelId) +
", ";
145 text += std::to_string(op.getTargetTcts()) +
"\n";
149void emitApplyOffset57(CertApplyOffset57Op op, std::string &text) {
150 uint16_t num_entries = op.getNumEntries();
151 uint16_t offset = op.getOffset();
153 llvm::raw_string_ostream ss(s);
154 ss <<
" APPLY_OFFSET_57 ";
155 ss <<
"@" << op.getSymbol().str() <<
", ";
156 ss << num_entries <<
", ";
157 ss << offset <<
"\n";
162void emitLocalBarrier(CertLocalBarrierOp op, std::string &text) {
163 text +=
" LOCAL_BARRIER ";
165 "$" + stringifyCertLocalBarrierId(op.getLocalBarrierId()).str() +
", ";
166 text += std::to_string(op.getNumParticipants()) +
"\n";
170void emitRemoteBarrier(CertRemoteBarrierOp op, std::string &text) {
171 text +=
" REMOTE_BARRIER ";
173 "$" + stringifyCertRemoteBarrierId(op.getRemoteBarrierId()).str() +
", ";
174 text += std::to_string(op.getPartyMask()) +
"\n";
178void emitRelAcqSync(CertRelAcqSyncOp op, std::string &text) {
180 llvm::raw_string_ostream ss(s);
181 ss <<
" REL_ACQ_SYNC ";
182 ss << llvm::format(
"0x%08x, ", op.getRelAddress());
183 ss << llvm::format(
"0x%08x\n", op.getAcqAddress());
188void emitLoadPdi(CertLoadPdiOp op, std::string &text) {
189 text +=
" LOAD_PDI ";
190 text += std::to_string(op.getPdiId()) +
", ";
191 text +=
"@" + op.getSymbol().str() +
"\n";
195void emitPreempt(CertPreemptOp op, std::string &text) {
197 llvm::raw_string_ostream ss(s);
199 ss << llvm::format(
"0x%04x, ", op.getId());
200 ss <<
"@" << op.getSaveSection().str() <<
", ";
201 ss <<
"@" << op.getRestoreSection().str() <<
"\n";
208LogicalResult emitJob(CertJobOp jobOp, std::string &text, std::string &data) {
209 LogicalResult result = success();
211 text +=
"START_JOB ";
212 text += std::to_string(jobOp.getJobId()) +
"\n";
214 for (
auto &o : jobOp.getBody().front()) {
215 llvm::TypeSwitch<Operation *>(&o)
216 .Case<CertApplyOffset57Op>(
217 [&](
auto op) { emitApplyOffset57(op, text); })
218 .Case<CertLocalBarrierOp>([&](
auto op) { emitLocalBarrier(op, text); })
219 .Case<CertLoadPdiOp>([&](
auto op) { emitLoadPdi(op, text); })
220 .Case<CertPreemptOp>([&](
auto op) { emitPreempt(op, text); })
221 .Case<CertRemoteBarrierOp>(
222 [&](
auto op) { emitRemoteBarrier(op, text); })
223 .Case<CertRelAcqSyncOp>([&](
auto op) { emitRelAcqSync(op, text); })
224 .Case<CertMaskWrite32Op>([&](
auto op) { emitMaskWrite32(op, text); })
225 .Case<CertMaskPoll32Op>([&](
auto op) { emitMaskPoll32(op, text); })
226 .Case<CertNopOp>([&](
auto op) { emitNop(op, text); })
227 .Case<CertUcDmaWriteDesSyncOp>(
228 [&](
auto op) { emitUcDmaWriteDesSync(op, text); })
229 .Case<CertUcDmaWriteDesOp>(
230 [&](
auto op) { emitUcDmaWriteDes(op, text); })
231 .Case<CertWaitUcDmaOp>([&](
auto op) { emitWaitUcDma(op, text); })
232 .Case<CertRead32Op>([&](
auto op) { emitRead32(op, text); })
233 .Case<CertRead32DOp>([&](
auto op) { emitRead32D(op, text); })
234 .Case<CertWrite32DOp>([&](
auto op) { emitWrite32D(op, text); })
235 .Case<CertSaveTimestampsOp>(
236 [&](
auto op) { emitSaveTimestamps(op, text); })
237 .Case<CertSaveRegisterOp>([&](
auto op) { emitSaveRegister(op, text); })
238 .Case<CertWaitTCTSOp>([&](
auto op) { emitWaitTCTS(op, text); })
239 .Case<CertWrite32Op>([&](
auto op) { emitWrite32(op, text); })
240 .Case<AIE::EndOp>([](
auto) { })
241 .Default([&](Operation *op) {
242 op->emitError(
"Unsupported operation in CertJobOp");
247 text +=
"END_JOB\n\n";
251LogicalResult emitJobs(llvm::SmallVector<CertJobOp> &jobs, std::string &text,
253 LogicalResult result = success();
258 for (
auto job : jobs) {
259 if (failed(emitJob(job, text, data)))
269LogicalResult emitPage(CertPageOp pageOp, std::string &text,
271 LogicalResult result = success();
272 text +=
".align 16\n";
277 for (
auto job : pageOp.getBody().getOps<CertJobOp>()) {
278 if (failed(emitJob(job, text, data)))
291LogicalResult emitUcDmaChain(CertUcDmaChainOp op, std::string &chains,
293 llvm::StringSet<> &emittedGlobals);
294LogicalResult emitGlobalData(Operation *op, StringRef dataSymbol,
296 llvm::StringSet<> &emittedGlobals);
298StringRef referencedChain(Operation *op) {
299 if (
auto write = dyn_cast<CertUcDmaWriteDesSyncOp>(op))
300 return write.getSymbol();
301 if (
auto write = dyn_cast<CertUcDmaWriteDesOp>(op))
302 return write.getSymbol();
306LogicalResult emitSection(CertSectionOp sectionOp, std::string &text,
307 llvm::StringRef outputPath) {
308 LogicalResult result = success();
309 std::string sectionName = sectionOp.getSymName().str();
310 std::string sectionFileName = sectionName +
".asm";
313 std::string sectionText;
314 std::string sectionData;
315 std::string sectionChains;
316 llvm::StringSet<> emittedChains;
317 llvm::StringSet<> emittedGlobals;
318 auto device = sectionOp->getParentOfType<DeviceOp>();
322 sectionOp.walk([&](Operation *op) {
323 if (
auto patch = dyn_cast<CertApplyOffset57Op>(op)) {
324 if (failed(emitGlobalData(op, patch.getSymbol(), sectionData,
329 StringRef name = referencedChain(op);
330 if (name.empty() || !emittedChains.insert(name).second)
333 dyn_cast_if_present<CertUcDmaChainOp>(device.lookupSymbol(name));
335 op->emitError(
"uC DMA chain symbol not found: ") << name;
337 }
else if (failed(emitUcDmaChain(chain, sectionChains, sectionData,
346 for (
auto page : sectionOp.getBody().getOps<CertPageOp>()) {
347 if (failed(emitPage(page, sectionText, sectionData)))
353 llvm::to_vector_of<CertJobOp>(sectionOp.getBody().getOps<CertJobOp>());
354 for (
auto job : jobs) {
355 if (failed(emitJob(job, sectionText, sectionData)))
357 sectionText +=
".eop\n\n";
361 std::string sectionFilePath;
362 if (!outputPath.empty()) {
363 llvm::SmallString<128> path(outputPath);
364 llvm::sys::path::remove_filename(path);
365 llvm::sys::path::append(path, sectionFileName);
366 sectionFilePath = path.str().str();
368 sectionFilePath = sectionFileName;
372 llvm::raw_fd_ostream sectionFile(sectionFilePath, EC);
375 return sectionOp.emitError(
"failed to open section file '")
376 << sectionFilePath <<
"': " << EC.message();
380 if (!sectionText.empty()) {
381 sectionFile <<
";\n;text\n;\n";
382 sectionFile << sectionText;
386 sectionFile <<
"EOF\n\n";
387 sectionFile << sectionChains;
390 if (!sectionData.empty()) {
391 sectionFile <<
";\n;data\n;\n";
392 sectionFile << sectionData;
396 if (sectionFile.has_error()) {
397 std::error_code writeEC = sectionFile.error();
399 sectionFile.clear_error();
400 return sectionOp.emitError(
"failed to write section file '")
401 << sectionFilePath <<
"': " << writeEC.message();
405 text += sectionName +
":\n";
406 text +=
".include " + sectionFileName +
"\n";
407 text +=
".endl " + sectionName +
"\n\n";
411LogicalResult emitAttachToGroupOp(CertAttachToGroupOp groupOp,
412 std::string &text, std::string &data,
413 llvm::StringRef outputPath) {
414 LogicalResult result = success();
417 for (
auto section : groupOp.getBody().getOps<CertSectionOp>()) {
418 if (failed(emitSection(section, text, outputPath)))
422 if (groupOp.getGroupId())
423 text +=
".attach_to_group " + std::to_string(groupOp.getGroupId()) +
"\n\n";
426 for (
auto page : groupOp.getBody().getOps<CertPageOp>()) {
427 if (failed(emitPage(page, text, data)))
433 llvm::to_vector_of<CertJobOp>(groupOp.getBody().getOps<CertJobOp>());
434 if (failed(emitJobs(jobs, text, data)))
439LogicalResult emitGlobalData(Operation *op, StringRef dataSymbol,
441 llvm::StringSet<> &emittedGlobals) {
442 if (emittedGlobals.contains(dataSymbol))
445 auto global = dyn_cast_if_present<memref::GlobalOp>(
446 op->getParentOfType<AIE::DeviceOp>().lookupSymbol(dataSymbol));
448 return op->emitError(
"Global symbol not found");
451 auto initVal = global.getInitialValue();
453 return op->emitError(
"Global symbol has no initial value");
456 auto initData = dyn_cast<DenseIntElementsAttr>(*initVal);
458 return op->emitError(
459 "Global symbol initial value is not a dense int array");
465 llvm::raw_string_ostream ss(s);
466 ss <<
" .align 16\n";
467 ss << dataSymbol.str() <<
":\n";
468 for (
auto d : initData)
469 ss << llvm::format(
" .long 0x%08x\n", d.getZExtValue());
471 emittedGlobals.insert(dataSymbol);
476LogicalResult emitUcDmaBd(CertUcDmaBdOp op, std::string &chains,
478 llvm::StringSet<> &emittedGlobals) {
480 llvm::raw_string_ostream ss(s);
481 ss <<
" UC_DMA_BD 0, ";
482 ss << llvm::format(
"0x%08x, ", op.getLocalAddress());
483 ss <<
"@" + op.getRemoteAddress().str() +
", ";
484 ss << op.getLength() <<
", ";
486 ss << (op.getNextBd() ?
"1\n" :
"0\n");
488 return emitGlobalData(op, op.getRemoteAddress(), data, emittedGlobals);
494LogicalResult emitUcDmaChain(CertUcDmaChainOp op, std::string &chains,
496 llvm::StringSet<> &emittedGlobals) {
497 chains +=
" .align 16\n";
498 chains += op.getName().str() +
":\n";
499 for (
auto &o : op.getBody().front()) {
500 if (
auto bd = dyn_cast<CertUcDmaBdOp>(&o))
501 if (failed(emitUcDmaBd(bd, chains, data, emittedGlobals)))
510 std::string &assembly,
511 llvm::StringRef outputPath) {
513 DeviceOp deviceOp = *
module.getOps<DeviceOp>().begin();
515 std::vector<std::string> text;
516 std::vector<std::string> data;
517 std::vector<std::string> chains;
518 std::map<uint32_t, llvm::StringSet<>> emittedGlobals;
520 text.emplace_back(
"\n;\n; Code\n;\n\n");
521 data.emplace_back(
"\n;\n; Data\n;\n\n");
522 chains.emplace_back(
"\n;\n; Data (chains)\n;\n\n");
524 auto &tm = deviceOp.getTargetModel();
525 text[0] +=
".partition " + std::to_string(tm.columns()) +
"column\n";
528 text[0] +=
".attach_to_group 0\n\n";
530 LogicalResult result = success();
536 std::map<uint32_t, size_t> groupIdToBlock;
537 groupIdToBlock[0] = 0;
538 auto blockFor = [&](uint32_t gid) ->
size_t {
539 auto it = groupIdToBlock.find(gid);
540 if (it != groupIdToBlock.end())
542 text.emplace_back(
"\n;\n; Code\n;\n\n");
543 data.emplace_back(
"\n;\n; Data\n;\n\n");
544 chains.emplace_back(
"\n;\n; Data (chains)\n;\n\n");
545 size_t block = text.size() - 1;
546 groupIdToBlock[gid] = block;
552 llvm::StringSet<> sectionReferences;
553 std::map<std::string, std::set<uint32_t>> chainUsers;
554 deviceOp.walk([&](Operation *op) {
555 StringRef name = referencedChain(op);
556 auto patch = dyn_cast<CertApplyOffset57Op>(op);
557 if (name.empty() && !patch)
559 if (op->getParentOfType<CertSectionOp>()) {
561 sectionReferences.insert(name);
564 auto group = op->getParentOfType<CertAttachToGroupOp>();
565 uint32_t groupId = group ? group.getGroupId() : 0;
567 size_t block = blockFor(groupId);
568 if (failed(emitGlobalData(op, patch.getSymbol(), data[block],
569 emittedGlobals[groupId])))
573 if (!deviceOp.lookupSymbol<CertUcDmaChainOp>(name)) {
574 op->emitError(
"uC DMA chain symbol not found: ") << name;
578 chainUsers[name.str()].insert(groupId);
585 for (
auto section : deviceOp.getBody()->getOps<CertSectionOp>()) {
586 if (failed(emitSection(section, text[0], outputPath)))
592 for (Operation &op : *deviceOp.getBody()) {
593 if (
auto page = dyn_cast<CertPageOp>(&op)) {
594 if (failed(emitPage(page, text[0], data[0])))
596 }
else if (
auto job = dyn_cast<CertJobOp>(&op)) {
597 if (failed(emitJob(job, text[0], data[0])))
599 }
else if (
auto grp = dyn_cast<CertAttachToGroupOp>(&op)) {
600 size_t block = blockFor(grp.getGroupId());
602 emitAttachToGroupOp(grp, text[block], data[block], outputPath)))
604 }
else if (
auto chain = dyn_cast<CertUcDmaChainOp>(&op)) {
605 std::set<uint32_t> users = {0};
606 auto it = chainUsers.find(chain.getName().str());
607 if (it != chainUsers.end())
609 else if (sectionReferences.contains(chain.getName()))
611 for (uint32_t groupId : users) {
612 size_t block = blockFor(groupId);
613 if (failed(emitUcDmaChain(chain, chains[block], data[block],
614 emittedGlobals[groupId])))
625 for (
auto const &entry : groupIdToBlock) {
626 size_t block = entry.second;
627 if (!text[block].empty()) {
628 assembly += text[block];
632 if (!chains[block].empty())
633 assembly += chains[block];
634 if (!data[block].empty())
635 assembly +=
"\n" + data[block];
642static llvm::cl::opt<std::string>
643 certSectionDir(
"cert-section-dir",
644 llvm::cl::desc(
"Directory for aiex.cert.section .asm files "
645 "(default: current directory)"),
649 raw_ostream &output) {
650 std::string assembly;
652 llvm::SmallString<128> outputPath;
653 if (!certSectionDir.empty()) {
654 outputPath = StringRef(certSectionDir);
655 llvm::sys::path::append(outputPath,
"main.asm");
mlir::LogicalResult AIETranslateToUcDma(mlir::ModuleOp module, llvm::raw_ostream &output)