|
119 | 119 | from finn.transformation.fpgadataflow.set_folding import SetFolding |
120 | 120 | from finn.transformation.fpgadataflow.set_loop_boundary import SetLoopBoundary |
121 | 121 | from finn.transformation.fpgadataflow.specialize_layers import SpecializeLayers |
122 | | -from finn.transformation.fpgadataflow.synth_ooc import SynthOutOfContext |
123 | 122 | from finn.transformation.fpgadataflow.transpose_decomposition import ( |
124 | 123 | InferInnerOuterShuffles, |
125 | 124 | ShuffleDecomposition, |
|
141 | 140 | from finn.util.fpgadataflow import warn_hls_rtl_dsp_conflict |
142 | 141 | from finn.util.mlo_sim import is_mlo, mlo_prehook_func_factory |
143 | 142 | from finn.util.test import execute_parent |
| 143 | +from finn.util.vivado import parse_ooc_synth_results |
144 | 144 |
|
145 | 145 |
|
146 | 146 | def verify_step( |
@@ -272,7 +272,6 @@ def prepare_for_stitched_ip_rtlsim(verify_model, cfg): |
272 | 272 | CreateStitchedIP( |
273 | 273 | cfg._resolve_fpga_part(), |
274 | 274 | cfg.synth_clk_period_ns, |
275 | | - vitis=False, |
276 | 275 | ) |
277 | 276 | ) |
278 | 277 | else: |
@@ -332,7 +331,6 @@ def prepare_loop_ops_ipgen(node, cfg): |
332 | 331 | CreateStitchedIP( |
333 | 332 | cfg._resolve_fpga_part(), |
334 | 333 | cfg.synth_clk_period_ns, |
335 | | - vitis=False, |
336 | 334 | ) |
337 | 335 | ) |
338 | 336 | node_inst.set_nodeattr("body", loop_model.graph) |
@@ -1061,14 +1059,35 @@ def step_create_stitched_ip(model: ModelWrapper, cfg: DataflowBuildConfig): |
1061 | 1059 |
|
1062 | 1060 | if DataflowOutputType.STITCHED_IP in cfg.generate_outputs: |
1063 | 1061 | stitched_ip_dir = cfg.output_dir + "/stitched_ip" |
| 1062 | + # If OOC_SYNTH is also requested, run P&R to extract metrics |
| 1063 | + run_pnr = DataflowOutputType.OOC_SYNTH in cfg.generate_outputs |
1064 | 1064 | model = model.transform( |
1065 | 1065 | CreateStitchedIP( |
1066 | 1066 | cfg._resolve_fpga_part(), |
1067 | 1067 | cfg.synth_clk_period_ns, |
1068 | | - vitis=cfg.stitched_ip_gen_dcp, |
| 1068 | + run_synth=cfg.stitched_ip_gen_dcp or run_pnr, |
| 1069 | + run_pnr=run_pnr, |
1069 | 1070 | signature=cfg.signature, |
1070 | 1071 | ) |
1071 | 1072 | ) |
| 1073 | + # If P&R was run, parse the OOC results and store in model metadata + write report |
| 1074 | + if run_pnr: |
| 1075 | + vivado_stitch_proj = model.get_metadata_prop("vivado_stitch_proj") |
| 1076 | + ooc_res_dict = parse_ooc_synth_results(vivado_stitch_proj) |
| 1077 | + if ooc_res_dict is not None: |
| 1078 | + # Calculate estimated throughput from fmax and cycle analysis |
| 1079 | + estimate_network_performance = model.analysis(dataflow_performance) |
| 1080 | + n_clock_cycles_per_sec = float(ooc_res_dict["fmax_mhz"]) * (10**6) |
| 1081 | + est_fps = n_clock_cycles_per_sec / estimate_network_performance["max_cycles"] |
| 1082 | + ooc_res_dict["estimated_throughput_fps"] = est_fps |
| 1083 | + |
| 1084 | + model.set_metadata_prop("res_total_ooc_synth", str(ooc_res_dict)) |
| 1085 | + # Write results to report directory |
| 1086 | + report_dir = cfg.output_dir + "/report" |
| 1087 | + os.makedirs(report_dir, exist_ok=True) |
| 1088 | + with open(report_dir + "/ooc_synth_and_timing.json", "w") as f: |
| 1089 | + json.dump(ooc_res_dict, f, indent=2) |
| 1090 | + |
1072 | 1091 | # TODO copy all ip sources into output dir? as zip? |
1073 | 1092 | shutil.copytree( |
1074 | 1093 | model.get_metadata_prop("vivado_stitch_proj"), stitched_ip_dir, dirs_exist_ok=True |
@@ -1212,35 +1231,6 @@ def step_make_driver(model: ModelWrapper, cfg: DataflowBuildConfig): |
1212 | 1231 | return model |
1213 | 1232 |
|
1214 | 1233 |
|
1215 | | -def step_out_of_context_synthesis(model: ModelWrapper, cfg: DataflowBuildConfig): |
1216 | | - """Run out-of-context synthesis and generate reports. |
1217 | | - Depends on the DataflowOutputType.STITCHED_IP output product.""" |
1218 | | - if DataflowOutputType.OOC_SYNTH in cfg.generate_outputs: |
1219 | | - assert DataflowOutputType.STITCHED_IP in cfg.generate_outputs, "OOC needs stitched IP" |
1220 | | - model = model.transform( |
1221 | | - SynthOutOfContext(part=cfg._resolve_fpga_part(), clk_period_ns=cfg.synth_clk_period_ns) |
1222 | | - ) |
1223 | | - report_dir = cfg.output_dir + "/report" |
1224 | | - os.makedirs(report_dir, exist_ok=True) |
1225 | | - ooc_res_dict = model.get_metadata_prop("res_total_ooc_synth") |
1226 | | - ooc_res_dict = eval(ooc_res_dict) |
1227 | | - |
1228 | | - estimate_network_performance = model.analysis(dataflow_performance) |
1229 | | - # add some more metrics to estimated performance |
1230 | | - n_clock_cycles_per_sec = float(ooc_res_dict["fmax_mhz"]) * (10**6) |
1231 | | - est_fps = n_clock_cycles_per_sec / estimate_network_performance["max_cycles"] |
1232 | | - ooc_res_dict["estimated_throughput_fps"] = est_fps |
1233 | | - with open(report_dir + "/ooc_synth_and_timing.json", "w") as f: |
1234 | | - json.dump(ooc_res_dict, f, indent=2) |
1235 | | - |
1236 | | - else: |
1237 | | - print( |
1238 | | - """DataflowOutputType.OOC_SYNTH not in requested outputs, |
1239 | | - skipping step_out_of_context_synthesis.""" |
1240 | | - ) |
1241 | | - return model |
1242 | | - |
1243 | | - |
1244 | 1234 | def step_synthesize_bitfile(model: ModelWrapper, cfg: DataflowBuildConfig): |
1245 | 1235 | """Synthesize a bitfile for the using the specified shell flow, using either |
1246 | 1236 | Vivado or Vitis, to target the specified board.""" |
@@ -1399,7 +1389,6 @@ def step_loop_rolling(model, cfg): |
1399 | 1389 | "step_create_stitched_ip": step_create_stitched_ip, |
1400 | 1390 | "step_measure_rtlsim_performance": step_measure_rtlsim_performance, |
1401 | 1391 | "step_make_driver": step_make_driver, |
1402 | | - "step_out_of_context_synthesis": step_out_of_context_synthesis, |
1403 | 1392 | "step_synthesize_bitfile": step_synthesize_bitfile, |
1404 | 1393 | "step_deployment_package": step_deployment_package, |
1405 | 1394 | "step_loop_rolling": step_loop_rolling, |
|
0 commit comments