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
63 // TODO(newling): Get bootgen team to remove print statement in this function.
64 startCDOFileStream(outputPath.str().c_str());
65 FileHeader();
66 // Never generate a completely empty CDO file. If the file only contains a
67 // header, then bootgen flags it as invalid.
68 insertNoOpCommand(4);
69 if (failed(cb()))
70 return failure();
71 configureHeader();
72 endCurrentCDOFileStream();
73 return success();
74}
75
76static LogicalResult generateCDOBinariesSeparately(AIERTControl &ctl,
77 const StringRef workDirPath,
78 DeviceOp &targetOp,
79 bool aieSim,
80 bool enableCores) {
81 auto ps = std::filesystem::path::preferred_separator;
82
83 LLVM_DEBUG(llvm::dbgs() << "Generating aie_cdo_elfs.bin");
84 if (failed(generateCDOBinary(
85 (llvm::Twine(workDirPath) + std::string(1, ps) + "aie_cdo_elfs.bin")
86 .str(),
87 [&ctl, &targetOp, &workDirPath, &aieSim] {
88 return ctl.addAieElfs(targetOp, workDirPath, aieSim);
89 })))
90 return failure();
91
92 LLVM_DEBUG(llvm::dbgs() << "Generating aie_cdo_init.bin");
93 if (failed(generateCDOBinary(
94 (llvm::Twine(workDirPath) + std::string(1, ps) + "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) + "aie_cdo_enable.bin")
103 .str(),
104 [&ctl, &targetOp] { return ctl.addCoreEnable(targetOp); })))
105 return failure();
106
107 return success();
108}
109
110static LogicalResult generateCDOUnified(AIERTControl &ctl,
111 const StringRef workDirPath,
112 DeviceOp &targetOp, bool aieSim,
113 bool enableCores) {
114 auto ps = std::filesystem::path::preferred_separator;
115
116 return generateCDOBinary(
117 (llvm::Twine(workDirPath) + std::string(1, ps) + "aie_cdo.bin").str(),
118 [&ctl, &targetOp, &workDirPath, &aieSim, &enableCores] {
119 if (!targetOp.getOps<CoreOp>().empty() &&
120 failed(ctl.addAieElfs(targetOp, workDirPath, aieSim)))
121 return failure();
122 if (failed(ctl.addInitConfig(targetOp)))
123 return failure();
124 if (enableCores && !targetOp.getOps<CoreOp>().empty() &&
125 failed(ctl.addCoreEnable(targetOp)))
126 return failure();
127 return success();
128 });
129}
130
131static LogicalResult
132translateToCDODirect(ModuleOp m, llvm::StringRef workDirPath,
133 byte_ordering endianness, bool emitUnified, bool cdoDebug,
134 bool aieSim, bool xaieDebug, bool enableCores) {
135
136 auto devOps = m.getOps<DeviceOp>();
137 assert(llvm::range_size(devOps) == 1 &&
138 "only exactly 1 device op supported.");
139 DeviceOp targetOp = *devOps.begin();
140 const BaseNPUTargetModel &targetModel =
141 (const BaseNPUTargetModel &)targetOp.getTargetModel();
142
143 // things like XAIE_MEM_TILE_ROW_START and the missing
144 // shim dma on tile (0,0) are hard-coded assumptions about NPU...
145 assert(targetModel.hasProperty(AIETargetModel::IsNPU) &&
146 "Only NPU currently supported");
147
148 AIERTControl ctl(targetModel);
149 if (failed(ctl.setIOBackend(aieSim, xaieDebug)))
150 return failure();
151 initializeCDOGenerator(endianness, cdoDebug);
152
153 auto result = [&]() {
154 if (emitUnified) {
155 return generateCDOUnified(ctl, workDirPath, targetOp, aieSim,
156 enableCores);
157 }
158 return generateCDOBinariesSeparately(ctl, workDirPath, targetOp, aieSim,
159 enableCores);
160 }();
161 return result;
162}
163
165 ModuleOp m, llvm::StringRef workDirPath, bool bigEndian, bool emitUnified,
166 bool cdoDebug, bool aieSim, bool xaieDebug, bool enableCores) {
167 byte_ordering endianness =
168 bigEndian ? byte_ordering::Big_Endian : byte_ordering::Little_Endian;
169 return translateToCDODirect(m, workDirPath, endianness, emitUnified, cdoDebug,
170 aieSim, xaieDebug, enableCores);
171}
bool hasProperty(ModelProperty Prop) const
Include the generated interface declarations.
mlir::LogicalResult AIETranslateToCDODirect(mlir::ModuleOp m, llvm::StringRef workDirPath, bool bigEndian=false, bool emitUnified=false, bool cdoDebug=false, bool aieSim=false, bool xaieDebug=false, bool enableCores=true)
mlir::LogicalResult addAieElfs(DeviceOp &targetOp, const mlir::StringRef workDirPath, bool aieSim)
Definition AIERT.cpp:685
mlir::LogicalResult setIOBackend(bool aieSim, bool xaieDebug)
Definition AIERT.cpp:109
mlir::LogicalResult addCoreEnable(DeviceOp &targetOp)
Definition AIERT.cpp:655
mlir::LogicalResult addInitConfig(DeviceOp &targetOp)
Definition AIERT.cpp:582