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
20namespace xilinx {
21namespace AIE {
22
23mlir::LogicalResult AIETranslateSCSimConfig(mlir::ModuleOp module,
24 llvm::raw_ostream &output) {
25 DeviceOp targetOp;
26 AIEArch arch = AIEArch::AIE1;
27 for (auto tOp : module.getOps<DeviceOp>()) {
28 targetOp = tOp;
29 arch = targetOp.getTargetModel().getTargetArch();
30 break; // Should only have 1 object in iterator
31 }
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 AIETranslateShimSolution(mlir::ModuleOp module,
157 llvm::raw_ostream &output) {
158 DeviceOp targetOp;
159 for (auto tOp : module.getOps<DeviceOp>()) {
160 targetOp = tOp;
161 break; // Should only have 1 object in iterator
162 }
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 << " \"LogicalInstance\" : { \"InstanceName\" : "
189 << "\"aie_engine_0\", \"PortName\" : \"" << port_name
190 << "\"},\n";
191
192 std::string col = std::to_string(shimOp.colIndex());
193 int ch = startOp.getChannelIndex();
194 std::string channel = std::to_string(ch);
195 // "name" field appears to be arbitrary, but we try to be descriptive
196 std::string physical_name = "";
197 physical_name.append("AIE_NOC_X").append(col).append("Y0_AIE_NOC_");
198 physical_name.append("M_AXI_ch").append(channel);
199
200 // Generate a Physical Instance line
201 output << " \"PhysicalInstance\" : [{ \"name\" : \""
202 << physical_name << "\", \"column\" : " << col
203 << ", \"channel\" : " << channel << " }],\n"
204 << " \"IsSoft\" : true\n }";
205 }
206 }
207 }
208
209 output << "\n ]\n";
210 output << "}\n";
211
212 return mlir::success();
213}
214
215mlir::LogicalResult AIETranslateGraphXPE(mlir::ModuleOp module,
216 llvm::raw_ostream &output) {
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 for (auto tOp : module.getOps<DeviceOp>()) {
230 targetOp = tOp;
231 break; // Should only have 1 object in iterator
232 }
233 AIEArch arch = AIEArch::AIE1;
234 if (targetOp) {
235 arch = targetOp.getTargetModel().getTargetArch();
236 }
237
238 // Generate boilerplate header
239 // TODO: date and version should probably not be hardcoded
240 output << "<?xml version=\"1.0\"?>"
241 << "\n";
242 output << "<POWERDATA data=\"AI-Engine Compiler\" dataVersion=\"2022.2\" "
243 "design=\"graph\" date=\"2023\">\n";
244 if ((arch == AIEArch::AIE2) || (arch == AIEArch::AIE2p)) {
245 output
246 // AIE2 xcve2802
247 << " <DEVICE part=\"xcve2802\" grade=\"extended\" package=\"vsvh1760\" "
248 "speed=\"-2LP\" process=\"typical\" vid=\"No\"></DEVICE>\n";
249 // AIE2 - xcve2302
250 // << " <DEVICE part=\"xcve2302\" grade=\"extended\" package=\"sfva784\" "
251 // "speed=\"-1MP\" process=\"typical\" vid=\"No\"></DEVICE>\n";
252 } else { // AIEArch::AIE1
253 output
254 << " <DEVICE part=\"xcvc1902\" grade=\"extended\" package=\"vsva2197\" "
255 "speed=\"-2MP\" process=\"typical\" vid=\"No\"></DEVICE>\n";
256 }
257 output << " <AIE status=\"COMPILER_OUTPUT\">\n";
258
259 // Generate design specific info on tiles within the mlir module
260 auto module_tile_ops = targetOp.getOps<TileOp>();
261 int num_tiles = std::distance(module_tile_ops.begin(), module_tile_ops.end());
262 // TODO: clk_freq only 1150 for AIE2
263 if ((arch == AIEArch::AIE2) || (arch == AIEArch::AIE2p)) {
264 output << " <AIE_MODULE name=\"graph\" num_tiles=\""
265 << std::to_string(num_tiles) << "\" clk_freq=\"1150\">\n";
266 } else {
267 output << " <AIE_MODULE name=\"graph\" num_tiles=\""
268 << std::to_string(num_tiles) << "\" clk_freq=\"1250\">\n";
269 }
270
271 // Get all CoreOps into a convenient map which can then be referenced by
272 // coordinates
273 std::map<std::pair<int, int>, std::vector<CoreOp>> coreMap;
274 for (CoreOp coreOp : targetOp.getOps<CoreOp>())
275 coreMap[std::make_pair(coreOp.colIndex(), coreOp.rowIndex())].push_back(
276 coreOp);
277
278 // For each TileOp in the module, generate a <TILE> section
279 int kernel_count = 0;
280 for (TileOp tileOp : module_tile_ops) {
281 int col = tileOp.colIndex();
282 int row = tileOp.rowIndex();
283
284 // NOTE: row == 0 assumes shim always row 0
285 if (tileOp.isShimNOCorPLTile() || tileOp.isMemTile())
286 continue; // Skip shim and mem tiles (handled below)
287
288 if ((arch == AIEArch::AIE2) || (arch == AIEArch::AIE2p)) {
289
290 output << " <TILE name=\"CR(" <<
291 // CR coordinates ignores shim, and 2 mem rows hence row-3
292 // AIE2 - xcve2802
293 std::to_string(col) << ","
294 << std::to_string(
295 row - targetOp.getTargetModel().getNumMemTileRows() - 1)
296 << ")\" "
297 // CR coordinates ignores shim and 1 mem row, hence row-2
298 // AIE2 - xcve2302
299 // std::to_string(col) << "," << std::to_string(row - 2) << ")\" "
300 << "type=\"int16\" int_core_load=\"1.0\" fp_core_load=\"0\" "
301 << "mem_banks=\"0\" mem_rw_rate=\"0.2\" stream_util=\"0.0\" "
302 "coordinates=\""
303 <<
304 // TODO: where does number of mem_banks come from?? Hardcoded to 0 for
305 // now
306 // TODO: does stream_util matter for sim?
307 std::to_string(col) << ","
308 << std::to_string(row -
309 targetOp.getTargetModel().getNumMemTileRows())
310 << "\">\n";
311
312 } else {
313 output << " <TILE name=\"CR(" <<
314 // CR coordinates ignores shim, hence row-1
315 std::to_string(col) << "," << std::to_string(row - 1) << ")\" "
316 << "type=\"int16\" int_core_load=\"1.0\" fp_core_load=\"0\" "
317 << "mem_banks=\"0\" mem_rw_rate=\"0.2\" stream_util=\"0.0\" "
318 "coordinates=\""
319 <<
320 // TODO: where does number of mem_banks come from?? Hardcoded to 0 for
321 // now
322 // TODO: does stream_util matter for sim?
323 std::to_string(col) << "," << std::to_string(row) << "\">\n";
324 }
325
326 // If the TileOp has associated Kernels, generate <KERNEL> sections
327 auto coreOps_in_tile =
328 coreMap[std::make_pair(tileOp.colIndex(), tileOp.rowIndex())];
329 for (auto coreOp : coreOps_in_tile) {
330 (void)(coreOp); // get around unused variable warning for coreOp
331 output << " <KERNEL name=\"i" << std::to_string(kernel_count++)
332 << "\" "
333 << "int_core_load=\"" << std::to_string(1 / coreOps_in_tile.size())
334 << "\" fp_core_load=\"0\"></KERNEL>\n";
335 }
336 output << " </TILE>\n";
337 }
338
339 // For each ShimOp in the module, generate a <SHIM> section
340 for (ShimDMAOp shimOp : targetOp.getOps<ShimDMAOp>()) {
341 if ((arch == AIEArch::AIE2) || (arch == AIEArch::AIE2p)) {
342 auto noc_label = (targetOp.getTargetModel().isShimNOCTile(
343 shimOp.colIndex(), shimOp.rowIndex()))
344 ? "AIE_PL_NOC_SIM"
345 : "AIE_PL_SHIM";
346 output << " <SHIM name=\"SHIM(" << std::to_string(shimOp.colIndex())
347 << ", " << std::to_string(shimOp.rowIndex())
348 << ")\" "
349 // TODO: stream_util can be 0 for aiesim purposes?
350 "type=\""
351 << noc_label << "\" stream_util=\"0\" num_pl_streams=\"0\" " <<
352 // TODO: how to get num_aximm_connections from mlir?
353 "num_aximm_connections=\"1\" coordinates=\""
354 << std::to_string(shimOp.colIndex()) << ","
355 << std::to_string(shimOp.rowIndex()) << "\" "
356 << "></SHIM>\n";
357 } else {
358 output << " <SHIM name=\"SHIM(" << std::to_string(shimOp.colIndex())
359 << ", " << std::to_string(shimOp.rowIndex()) << ")\" " <<
360 // TODO: stream_util can be 0 for aiesim purposes?
361 "type=\"AIE_PL_NOC_SHIM\" stream_util=\"0\" num_pl_streams=\"0\" " <<
362 // TODO: how to get num_aximm_connections from mlir?
363 "num_aximm_connections=\"1\" coordinates=\""
364 << std::to_string(shimOp.colIndex()) << ","
365 << std::to_string(shimOp.rowIndex()) << "\" "
366 << "></SHIM>\n";
367 }
368 }
369
370 // For each memTile
371 if ((arch == AIEArch::AIE2) || (arch == AIEArch::AIE2p)) {
372 for (TileOp tileOp : module_tile_ops) {
373 int col = tileOp.colIndex();
374 int row = tileOp.rowIndex();
375
376 // NOTE: row == 0 assumes shim always row 0
377 if (row == 0 ||
378 row > static_cast<int>(targetOp.getTargetModel().getNumMemTileRows()))
379 continue; // Skip regular tiles (handled above)
380
381 output << " <MEM name=\"MEM(" << std::to_string(col) << ", "
382 << std::to_string(row - 1)
383 << ")\" "
384 // TODO: stream_util can be 0 for aiesim purposes?
385 "type=\"AIE_MEM\" mem_banks=\"0\" mme_rw_rate=\"0.1\" "
386 << "stream_util=\"0.1\" coordinates=\"" << std::to_string(col)
387 << "," << std::to_string(row - 1) << "\" "
388 << "></MEM>\n";
389 }
390 }
391
392 output << " </AIE_MODULE>\n";
393 output << " </AIE>\n";
394 output << "</POWERDATA>\n";
395
396 return mlir::success();
397}
398
399} // namespace AIE
400} // namespace xilinx
mlir::LogicalResult AIETranslateShimSolution(mlir::ModuleOp module, llvm::raw_ostream &)
mlir::LogicalResult AIETranslateSCSimConfig(mlir::ModuleOp module, llvm::raw_ostream &output)
mlir::LogicalResult AIETranslateGraphXPE(mlir::ModuleOp module, llvm::raw_ostream &)
AIEArch
Definition Passes.h:21