MLIR-AIE 1.4.5.dev
AIETargetSimulationFiles.cpp
Go to the documentation of this file.
1//===- AIETargetSimulationFiles.cpp -----------------------------*- C++ -*-===//
2//
3// Copyright (C) 2022 Advanced Micro Devices, Inc.
4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5//
6//===----------------------------------------------------------------------===//
7
10
11#include "mlir/IR/Attributes.h"
12#include "mlir/Target/LLVMIR/Import.h"
13#include "mlir/Tools/mlir-translate/MlirTranslateMain.h"
14
15#include "llvm/IR/Module.h"
16
17using namespace xilinx;
18using namespace AIE;
19
20mlir::LogicalResult AIE::AIETranslateSCSimConfig(mlir::ModuleOp module,
21 llvm::raw_ostream &output,
22 llvm::StringRef deviceName) {
23 DeviceOp targetOp =
24 AIE::DeviceOp::getForSymbolInModuleOrError(module, deviceName);
25 if (!targetOp) {
26 return mlir::failure();
27 }
28 AIEArch arch = targetOp.getTargetModel().getTargetArch();
29
30 if (arch == AIEArch::AIE2p) {
31 output << "{\n"
32 << " \"SimulationConfig\": {\n"
33 << " \"device_json\": {\n"
34 << " \"directory\": \"data/aie2p/devices\",\n"
35 << " \"file\": \"aie2p_8x4_device.json\"\n"
36 << " },\n"
37 << " \"phy_device_file\": \"aie2p_8x4_device\",\n"
38 << " \"aiearch\": \"aie2p\",\n"
39 << " \"aie_freq\": 1000000000.0,\n"
40 << " \"use_real_noc\": 1,\n"
41 << " \"evaluate_fifo_depth\": 0,\n"
42 << " \"noc_ip_block\": {\n"
43 << " \"lib_path\": \"./sim/noc/liblnoc_tlm.so\",\n"
44 << " \"traffic_file\": \"./sim/noc/noc_traffic.nts\",\n"
45 << " \"config_file\": \"./sim/noc/noc_soln.ncr\"\n"
46 << " },\n"
47 << " \"pl_ip_block\": [\n"
48 << " {\n"
49 << " \"name\": \"ps_ps_main\",\n"
50 << " \"ip\": \"ps\",\n"
51 << " \"lib_path\": \"ps/ps.so\",\n"
52 << " \"pl_freq\": 362500000.0,\n"
53 << " \"axi_mm\": [\n"
54 << " {\n"
55 << " \"port_name\": \"ps_axi\",\n"
56 << " \"direction\": \"ps_to_gm\",\n"
57 << " \"noc_endpoint\": \"NOC_NMU128_X0Y5\",\n"
58 << " \"bus_width\": 0\n"
59 << " }\n"
60 << " ],\n"
61 << " \"event_bus\": []\n"
62 << " }\n"
63 << " ]\n"
64 << " }\n"
65 << "}\n";
66 } else if (arch == AIEArch::AIE2) {
67 output
68 << "{\n"
69 << " \"SimulationConfig\": {\n"
70 << " \"device_json\": {\n"
71 << " \"directory\": \"data/aie_ml/devices\",\n"
72 << " \"file\": \"VC2802.json\"\n"
73 << " },\n"
74 << " \"phy_device_file\": \"xcve2802-vsvh1760-2LP-e-S-es1\",\n"
75 << " \"aiearch\": \"aie2\",\n"
76 << " \"aie_freq\": 1050000000.0,\n"
77 << " \"use_real_noc\": 1,\n"
78 << " \"evaluate_fifo_depth\": 0,\n"
79 << " \"noc_ip_block\": {\n"
80 << " \"lib_path\": \"./sim/noc/liblnoc_tlm.so\",\n"
81 << " \"traffic_file\": \"./sim/noc/noc_traffic.nts\",\n"
82 << " \"config_file\": \"./sim/noc/noc_soln.ncr\"\n"
83 << " },\n"
84 << " \"pl_ip_block\": [\n"
85 << " {\n"
86 << " \"name\": \"ps_ps_main\",\n"
87 << " \"ip\": \"ps\",\n"
88 << " \"lib_path\": \"ps/ps.so\",\n"
89 << " \"pl_freq\": 362500000.0,\n"
90 << " \"axi_mm\": [\n"
91 << " {\n"
92 << " \"port_name\": \"ps_axi\",\n"
93 << " \"direction\": \"ps_to_gm\",\n"
94 << " \"noc_endpoint\": \"NOC_NMU128_X0Y5\",\n"
95 << " \"bus_width\": 0\n"
96 << " }\n"
97 << " ],\n"
98 << " \"event_bus\": []\n"
99 << " }\n"
100 << " ]\n"
101 << " }\n"
102 << "}\n";
103 } else if (arch == AIEArch::AIE1) { // AIEArch::AIE1
104 output << "{\n"
105 << " \"SimulationConfig\": {\n"
106 << " \"device_json\": {\n"
107 << " \"directory\": \"data/devices\",\n"
108 << " \"file\": \"VC1902.json\"\n"
109 << " },\n"
110 << " \"phy_device_file\": \"xcvc1902-vsva2197-2MP-e-S\",\n"
111 << " \"aiearch\": \"aie\",\n"
112 << " \"aie_freq\": 1250000000.0,\n"
113 << " \"use_real_noc\": 1,\n"
114 << " \"evaluate_fifo_depth\": 0,\n"
115 << " \"noc_ip_block\": {\n"
116 << " \"lib_path\": \"./Work/noc/liblnoc_tlm.so\",\n"
117 << " \"traffic_file\": \"./Work/noc/noc_traffic.nts\",\n"
118 << " \"config_file\": \"./Work/noc/noc_soln.ncr\"\n"
119 << " },\n"
120 << " \"pl_ip_block\": [\n"
121 << " {\n"
122 << " \"name\": \"ps_ps_main\",\n"
123 << " \"ip\": \"ps\",\n"
124 << " \"lib_path\": \"ps/ps.so\",\n"
125 << " \"pl_freq\": 312500000.0,\n"
126 << " \"axi_mm\": [\n"
127 << " {\n"
128 << " \"port_name\": \"ps_axi\",\n"
129 << " \"direction\": \"ps_to_gm\",\n"
130 << " \"noc_endpoint\": \"NOC_NMU128_X0Y5\",\n"
131 << " \"bus_width\": 0\n"
132 << " }\n"
133 << " ],\n"
134 << " \"event_bus\": []\n"
135 << " }\n"
136 << " ]\n"
137 << " }\n"
138 << "}\n";
139 }
140 return mlir::success();
141}
142
143/* Generates a aieshim_solution.aiesol file which is necessary to run aiesim.
144Sample invocation:
145aie-translate --aie-mlir-to-shim-solution ./aie.mlir >
146./Work/arch/aieshim_solution.aiesol
147
148NOTE: to correctly enable all tiles used for routing, the aie-opt routing pass
149must be called first. So, a more practical invocation: aie-opt
150--aie-create-pathfinder-flows ./aie.mlir | aie-translate --aie-mlir-to-shim >
151./Work/arch/aieshim_solution.aiesol
152*/
153mlir::LogicalResult AIE::AIETranslateShimSolution(mlir::ModuleOp module,
154 llvm::raw_ostream &output,
155 llvm::StringRef deviceName) {
156 DeviceOp targetOp =
157 AIE::DeviceOp::getForSymbolInModuleOrError(module, deviceName);
158 if (!targetOp) {
159 return mlir::failure();
160 }
161 if (failed(verifyDMAChannelsResolved(targetOp)))
162 return mlir::failure();
163
164 // Generate boilerplate header
165 output << "{\n";
166 output << " \"Placement\": [\n";
167
168 int shim_MM2S_count = 0;
169
170 // For each DMAStartOp in shims, generate a "LogicalInstance" section
171 auto all_shim_ops = targetOp.getOps<ShimDMAOp>();
172 for (ShimDMAOp shimOp : all_shim_ops) {
173 for (DMAStartOp startOp : shimOp.getOps<DMAStartOp>()) {
174 // For aiesimulator to run, PortName must start at 00 and increase
175 if (startOp.getChannelDir() == DMAChannelDir::MM2S) {
176 if (shim_MM2S_count > 0)
177 output << ",\n";
178
179 std::string port_name = "";
180 port_name.append("M");
181 port_name.append(shim_MM2S_count < 10 ? "0" : ""); // padding zero
182 port_name.append(std::to_string(shim_MM2S_count++));
183 port_name.append("_AXI");
184 // TODO: How to tell if PortName should be AXI or AXIS?
185
186 // Generate a Logical Instance line
187 output << " {\n"
188 << R"( "LogicalInstance" : { "InstanceName" : )"
189 << R"("aie_engine_0", "PortName" : ")" << port_name << "\"},\n";
190
191 std::string col = std::to_string(shimOp.colIndex());
192 int ch = startOp.getChannelIndex();
193 std::string channel = std::to_string(ch);
194 // "name" field appears to be arbitrary, but we try to be descriptive
195 std::string physical_name = "";
196 physical_name.append("AIE_NOC_X").append(col).append("Y0_AIE_NOC_");
197 physical_name.append("M_AXI_ch").append(channel);
198
199 // Generate a Physical Instance line
200 output << R"( "PhysicalInstance" : [{ "name" : ")" << physical_name
201 << R"(", "column" : )" << col << ", \"channel\" : " << channel
202 << " }],\n"
203 << " \"IsSoft\" : true\n }";
204 }
205 }
206 }
207
208 output << "\n ]\n";
209 output << "}\n";
210
211 return mlir::success();
212}
213
214mlir::LogicalResult AIE::AIETranslateGraphXPE(mlir::ModuleOp module,
215 llvm::raw_ostream &output,
216 llvm::StringRef deviceName) {
217 /* Generates a .xpe file which is necessary to run aiesim.
218 .xpe is a power report file, but has information on which AIE tiles are used.
219 Sample invocation:
220 aie-translate --aie-mlir-to-xpe ./aie.mlir > ./Work/reports/graph.xpe
221
222 NOTE: to correctly enable all tiles used for routing, the aie-opt routing pass
223 must be called first. So, a more practical invocation: aie-opt
224 --aie-create-pathfinder-flows ./aie.mlir | aie-translate --aie-mlir-to-xpe >
225 ./Work/reports/graph.xpe
226 */
227
228 DeviceOp targetOp =
229 AIE::DeviceOp::getForSymbolInModuleOrError(module, deviceName);
230 if (!targetOp) {
231 return mlir::failure();
232 }
233 AIEArch arch = targetOp.getTargetModel().getTargetArch();
234
235 // Generate boilerplate header
236 // TODO: date and version should probably not be hardcoded
237 output << "<?xml version=\"1.0\"?>"
238 << "\n";
239 output << "<POWERDATA data=\"AI-Engine Compiler\" dataVersion=\"2022.2\" "
240 "design=\"graph\" date=\"2023\">\n";
241 if ((arch == AIEArch::AIE2) || (arch == AIEArch::AIE2p)) {
242 output
243 // AIE2 xcve2802
244 << " <DEVICE part=\"xcve2802\" grade=\"extended\" package=\"vsvh1760\" "
245 "speed=\"-2LP\" process=\"typical\" vid=\"No\"></DEVICE>\n";
246 // AIE2 - xcve2302
247 // << " <DEVICE part=\"xcve2302\" grade=\"extended\" package=\"sfva784\" "
248 // "speed=\"-1MP\" process=\"typical\" vid=\"No\"></DEVICE>\n";
249 } else { // AIEArch::AIE1
250 output
251 << " <DEVICE part=\"xcvc1902\" grade=\"extended\" package=\"vsva2197\" "
252 "speed=\"-2MP\" process=\"typical\" vid=\"No\"></DEVICE>\n";
253 }
254 output << " <AIE status=\"COMPILER_OUTPUT\">\n";
255
256 // Generate design specific info on tiles within the mlir module
257 auto module_tile_ops = targetOp.getOps<TileOp>();
258 int num_tiles = std::distance(module_tile_ops.begin(), module_tile_ops.end());
259 // TODO: clk_freq only 1150 for AIE2
260 if ((arch == AIEArch::AIE2) || (arch == AIEArch::AIE2p)) {
261 output << R"( <AIE_MODULE name="graph" num_tiles=")"
262 << std::to_string(num_tiles) << "\" clk_freq=\"1150\">\n";
263 } else {
264 output << R"( <AIE_MODULE name="graph" num_tiles=")"
265 << std::to_string(num_tiles) << "\" clk_freq=\"1250\">\n";
266 }
267
268 // Get all CoreOps into a convenient map which can then be referenced by
269 // coordinates
270 std::map<std::pair<int, int>, std::vector<CoreOp>> coreMap;
271 for (CoreOp coreOp : targetOp.getOps<CoreOp>())
272 coreMap[std::make_pair(coreOp.colIndex(), coreOp.rowIndex())].push_back(
273 coreOp);
274
275 // For each TileOp in the module, generate a <TILE> section
276 int kernel_count = 0;
277 for (TileOp tileOp : module_tile_ops) {
278 int col = tileOp.colIndex();
279 int row = tileOp.rowIndex();
280
281 // NOTE: row == 0 assumes shim always row 0
282 if (tileOp.isShimNOCorPLTile() || tileOp.isMemTile())
283 continue; // Skip shim and mem tiles (handled below)
284
285 if ((arch == AIEArch::AIE2) || (arch == AIEArch::AIE2p)) {
286
287 output << " <TILE name=\"CR(" <<
288 // CR coordinates ignores shim, and 2 mem rows hence row-3
289 // AIE2 - xcve2802
290 std::to_string(col) << ","
291 << std::to_string(
292 row - targetOp.getTargetModel().getNumMemTileRows() - 1)
293 << ")\" "
294 // CR coordinates ignores shim and 1 mem row, hence row-2
295 // AIE2 - xcve2302
296 // std::to_string(col) << "," << std::to_string(row - 2) << ")\" "
297 << R"(type="int16" int_core_load="1.0" fp_core_load="0" )"
298 << "mem_banks=\"0\" mem_rw_rate=\"0.2\" stream_util=\"0.0\" "
299 "coordinates=\""
300 <<
301 // TODO: where does number of mem_banks come from?? Hardcoded to 0 for
302 // now
303 // TODO: does stream_util matter for sim?
304 std::to_string(col) << ","
305 << std::to_string(row -
306 targetOp.getTargetModel().getNumMemTileRows())
307 << "\">\n";
308
309 } else {
310 output << " <TILE name=\"CR(" <<
311 // CR coordinates ignores shim, hence row-1
312 std::to_string(col) << "," << std::to_string(row - 1) << ")\" "
313 << R"(type="int16" int_core_load="1.0" fp_core_load="0" )"
314 << "mem_banks=\"0\" mem_rw_rate=\"0.2\" stream_util=\"0.0\" "
315 "coordinates=\""
316 <<
317 // TODO: where does number of mem_banks come from?? Hardcoded to 0 for
318 // now
319 // TODO: does stream_util matter for sim?
320 std::to_string(col) << "," << std::to_string(row) << "\">\n";
321 }
322
323 // If the TileOp has associated Kernels, generate <KERNEL> sections
324 auto coreOps_in_tile =
325 coreMap[std::make_pair(tileOp.colIndex(), tileOp.rowIndex())];
326 for (auto coreOp : coreOps_in_tile) {
327 (void)(coreOp); // get around unused variable warning for coreOp
328 output << " <KERNEL name=\"i" << std::to_string(kernel_count++)
329 << "\" "
330 << "int_core_load=\"" << std::to_string(1 / coreOps_in_tile.size())
331 << "\" fp_core_load=\"0\"></KERNEL>\n";
332 }
333 output << " </TILE>\n";
334 }
335
336 // For each ShimOp in the module, generate a <SHIM> section
337 for (ShimDMAOp shimOp : targetOp.getOps<ShimDMAOp>()) {
338 if ((arch == AIEArch::AIE2) || (arch == AIEArch::AIE2p)) {
339 const auto *noc_label = (targetOp.getTargetModel().isShimNOCTile(
340 shimOp.colIndex(), shimOp.rowIndex()))
341 ? "AIE_PL_NOC_SIM"
342 : "AIE_PL_SHIM";
343 output << " <SHIM name=\"SHIM(" << std::to_string(shimOp.colIndex())
344 << ", " << std::to_string(shimOp.rowIndex())
345 << ")\" "
346 // TODO: stream_util can be 0 for aiesim purposes?
347 "type=\""
348 << noc_label << R"(" stream_util="0" num_pl_streams="0" )" <<
349 // TODO: how to get num_aximm_connections from mlir?
350 R"(num_aximm_connections="1" coordinates=")"
351 << std::to_string(shimOp.colIndex()) << ","
352 << std::to_string(shimOp.rowIndex()) << "\" "
353 << "></SHIM>\n";
354 } else {
355 output << " <SHIM name=\"SHIM(" << std::to_string(shimOp.colIndex())
356 << ", " << std::to_string(shimOp.rowIndex()) << ")\" " <<
357 // TODO: stream_util can be 0 for aiesim purposes?
358 R"(type="AIE_PL_NOC_SHIM" stream_util="0" num_pl_streams="0"
359 )" <<
360 // TODO: how to get num_aximm_connections from mlir?
361 R"(num_aximm_connections="1" coordinates=")"
362 << std::to_string(shimOp.colIndex()) << ","
363 << std::to_string(shimOp.rowIndex()) << "\" "
364 << "></SHIM>\n";
365 }
366 }
367
368 // For each memTile
369 if ((arch == AIEArch::AIE2) || (arch == AIEArch::AIE2p)) {
370 for (TileOp tileOp : module_tile_ops) {
371 int col = tileOp.colIndex();
372 int row = tileOp.rowIndex();
373
374 // NOTE: row == 0 assumes shim always row 0
375 if (row == 0 ||
376 row > static_cast<int>(targetOp.getTargetModel().getNumMemTileRows()))
377 continue; // Skip regular tiles (handled above)
378
379 output << " <MEM name=\"MEM(" << std::to_string(col) << ", "
380 << std::to_string(row - 1)
381 << ")\" "
382 // TODO: stream_util can be 0 for aiesim purposes?
383 "type=\"AIE_MEM\" mem_banks=\"0\" mme_rw_rate=\"0.1\" "
384 << R"(stream_util="0.1" coordinates=")" << std::to_string(col)
385 << "," << std::to_string(row - 1) << "\" "
386 << "></MEM>\n";
387 }
388 }
389
390 output << " </AIE_MODULE>\n";
391 output << " </AIE>\n";
392 output << "</POWERDATA>\n";
393
394 return mlir::success();
395}
mlir::LogicalResult AIETranslateSCSimConfig(mlir::ModuleOp module, llvm::raw_ostream &output, llvm::StringRef deviceName="")
mlir::LogicalResult AIETranslateShimSolution(mlir::ModuleOp module, llvm::raw_ostream &, llvm::StringRef deviceName="")
mlir::LogicalResult AIETranslateGraphXPE(mlir::ModuleOp module, llvm::raw_ostream &, llvm::StringRef)
mlir::LogicalResult verifyDMAChannelsResolved(DeviceOp device)
AIEArch
Definition Passes.h:19