MLIR-AIE
AIETargetCDODirect.cpp
Go to the documentation of this file.
1//===- AIETargetCDODirect.cpp -----------------------------------*- C++ -*-===//
2//
3// Copyright (C) 2023, Advanced Micro Devices, Inc. All rights reserved.
4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5//
6//===----------------------------------------------------------------------===//
7
8#include "aie/Targets/AIERT.h"
10extern "C" {
11#include "cdo-driver/cdo_driver.h"
12}
13
17
18#include "mlir/IR/Block.h"
19#include "mlir/IR/BuiltinOps.h"
20#include "mlir/IR/Operation.h"
21#include "mlir/Support/LLVM.h"
22#include "mlir/Support/LogicalResult.h"
23
24#include "llvm/ADT/STLExtras.h"
25#include "llvm/ADT/SmallVector.h"
26#include "llvm/ADT/Twine.h"
27#include "llvm/Support/Debug.h"
28
29#include <algorithm>
30#include <cassert>
31#include <filesystem>
32#include <functional>
33#include <string>
34#include <vector>
35
36#ifndef NDEBUG
37#define XAIE_DEBUG
38#endif
39
40extern "C" {
41#include "xaiengine/xaie_elfloader.h"
42#include "xaiengine/xaie_interrupt.h"
43#include "xaiengine/xaiegbl.h"
44}
45
46#define DEBUG_TYPE "aie-generate-cdo"
47
48using namespace mlir;
49using namespace xilinx;
50using namespace xilinx::AIE;
51
52static void initializeCDOGenerator(byte_ordering endianness, bool cdoDebug) {
53 // Enables AXI-MM prints for configs being added in CDO
54 if (cdoDebug)
55 EnAXIdebug();
56 setEndianness(endianness);
57};
58
59static LogicalResult
60generateCDOBinary(const StringRef outputPath,
61 const std::function<LogicalResult()> &cb) {
62 startCDOFileStream(outputPath.str().c_str());
63 FileHeader();
64 // Never generate a completely empty CDO file. If the file only contains a
65 // header, then bootgen flags it as invalid.
66 insertNoOpCommand(4);
67 if (failed(cb()))
68 return failure();
69 configureHeader();
70 endCurrentCDOFileStream();
71 return success();
72}
73
74static LogicalResult generateCDOBinariesSeparately(AIERTControl &ctl,
75 const StringRef workDirPath,
76 DeviceOp &targetOp,
77 bool aieSim,
78 bool enableCores) {
79 auto ps = std::filesystem::path::preferred_separator;
80
81 LLVM_DEBUG(llvm::dbgs() << "Generating aie_cdo_elfs.bin");
82 if (failed(generateCDOBinary((llvm::Twine(workDirPath) + std::string(1, ps) +
83 targetOp.getSymName() + "_aie_cdo_elfs.bin")
84 .str(),
85 [&ctl, &targetOp, &workDirPath, &aieSim] {
86 return ctl.addAieElfs(targetOp, workDirPath,
87 aieSim);
88 })))
89 return failure();
90
91 LLVM_DEBUG(llvm::dbgs() << "Generating aie_cdo_init.bin");
92 if (failed(generateCDOBinary(
93 (llvm::Twine(workDirPath) + std::string(1, ps) +
94 targetOp.getSymName() + "_aie_cdo_init.bin")
95 .str(),
96 [&ctl, &targetOp] { return ctl.addInitConfig(targetOp); })))
97 return failure();
98
99 LLVM_DEBUG(llvm::dbgs() << "Generating aie_cdo_enable.bin");
100 if (enableCores &&
101 failed(generateCDOBinary(
102 (llvm::Twine(workDirPath) + std::string(1, ps) +
103 targetOp.getSymName() + "_aie_cdo_enable.bin")
104 .str(),
105 [&ctl, &targetOp] { return ctl.addCoreEnable(targetOp); })))
106 return failure();
107
108 return success();
109}
110
111static LogicalResult generateCDOUnified(AIERTControl &ctl,
112 const StringRef workDirPath,
113 DeviceOp &targetOp, bool aieSim,
114 bool enableCores) {
115 auto ps = std::filesystem::path::preferred_separator;
116
117 return generateCDOBinary(
118 (llvm::Twine(workDirPath) + std::string(1, ps) + targetOp.getSymName() +
119 "_aie_cdo.bin")
120 .str(),
121 [&ctl, &targetOp, &workDirPath, &aieSim, &enableCores] {
122 if (!targetOp.getOps<CoreOp>().empty() &&
123 failed(ctl.addAieElfs(targetOp, workDirPath, aieSim)))
124 return failure();
125 if (failed(ctl.addInitConfig(targetOp)))
126 return failure();
127 if (enableCores && !targetOp.getOps<CoreOp>().empty() &&
128 failed(ctl.addCoreEnable(targetOp)))
129 return failure();
130 return success();
131 });
132}
133
134static LogicalResult
135translateToCDODirect(ModuleOp m, llvm::StringRef workDirPath,
136 llvm::StringRef deviceName, byte_ordering endianness,
137 bool emitUnified, bool cdoDebug, bool aieSim,
138 bool xaieDebug, bool enableCores) {
139
140 DeviceOp targetOp = AIE::DeviceOp::getForSymbolInModuleOrError(m, deviceName);
141 if (!targetOp) {
142 return failure();
143 }
144 const AIETargetModel &targetModel =
145 (const AIETargetModel &)targetOp.getTargetModel();
146
147 // things like XAIE_MEM_TILE_ROW_START and the missing
148 // shim dma on tile (0,0) are hard-coded assumptions about NPU...
149 assert(targetModel.hasProperty(AIETargetModel::IsNPU) &&
150 "Only NPU currently supported");
151
152 AIERTControl ctl(targetModel);
153 if (failed(ctl.setIOBackend(aieSim, xaieDebug)))
154 return failure();
155 initializeCDOGenerator(endianness, cdoDebug);
156
157 auto result = [&]() {
158 if (emitUnified) {
159 return generateCDOUnified(ctl, workDirPath, targetOp, aieSim,
160 enableCores);
161 }
162 return generateCDOBinariesSeparately(ctl, workDirPath, targetOp, aieSim,
163 enableCores);
164 }();
165 return result;
166}
167
169 ModuleOp m, llvm::StringRef workDirPath, llvm::StringRef deviceName,
170 bool bigEndian, bool emitUnified, bool cdoDebug, bool aieSim,
171 bool xaieDebug, bool enableCores) {
172 byte_ordering endianness =
173 bigEndian ? byte_ordering::Big_Endian : byte_ordering::Little_Endian;
174 return translateToCDODirect(m, workDirPath, deviceName, endianness,
175 emitUnified, cdoDebug, aieSim, xaieDebug,
176 enableCores);
177}
bool hasProperty(ModelProperty Prop) const
Include the generated interface declarations.
mlir::LogicalResult AIETranslateToCDODirect(mlir::ModuleOp m, llvm::StringRef workDirPath, llvm::StringRef deviceName, bool bigEndian=false, bool emitUnified=false, bool cdoDebug=false, bool aieSim=false, bool xaieDebug=false, bool enableCores=true)
mlir::LogicalResult setIOBackend(bool aieSim, bool xaieDebug)
Definition AIERT.cpp:257