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