diff --git a/.github/eos-s3_test.json b/.github/eos-s3_test.json index 9960475..aa858c7 100644 --- a/.github/eos-s3_test.json +++ b/.github/eos-s3_test.json @@ -8,7 +8,8 @@ "eos-s3/btn_counter/btn_counter.v" ], "synth_log": "synth.log", - "pack_log": "pack.log" + "pack_log": "pack.log", + "analysis_log": "analysis.log" }, "EOS3FF512-PDN64": { "default_target": "bitstream", @@ -18,8 +19,7 @@ "sdc-in": "eos-s3/btn_counter/dummy.sdc" }, "values": { - "part": "ql-eos-s3", - "package": "PD64" + "part": "ql-eos-s3" } } } diff --git a/f4pga/common.py b/f4pga/common.py index 8da06cf..4225a96 100644 --- a/f4pga/common.py +++ b/f4pga/common.py @@ -174,6 +174,8 @@ def vpr(mode: str, vprargs: VprArgs, cwd=None): modeargs = ['--place'] elif mode == 'route': modeargs = ['--route'] + elif mode == 'analysis': + modeargs = ['--analysis'] return sub(*([ 'vpr', diff --git a/f4pga/common_modules/analysis.py b/f4pga/common_modules/analysis.py new file mode 100644 index 0000000..1a324a7 --- /dev/null +++ b/f4pga/common_modules/analysis.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Copyright (C) 2022 F4PGA Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +from pathlib import Path +from shutil import move as sh_mv + +from f4pga.common import * +from f4pga.module import Module, ModuleContext + + +def analysis_merged_post_implementation_file(ctx: ModuleContext): + return str(Path(ctx.takes.eblif).with_suffix('')) + '_merged_post_implementation.v' + + +def analysis_post_implementation_file(ctx: ModuleContext): + return str(Path(ctx.takes.eblif).with_suffix('')) + '_post_synthesis.v' + + +class analysisModule(Module): + def map_io(self, ctx: ModuleContext): + return { + 'merged_post_implementation_v': analysis_merged_post_implementation_file(ctx), + 'post_implementation_v': analysis_post_implementation_file(ctx) + } + + def execute(self, ctx: ModuleContext): + build_dir = str(Path(ctx.takes.eblif).parent) + + vpr_options = [] + if ctx.values.vpr_options: + vpr_options = options_dict_to_list(ctx.values.vpr_options) + + yield 'Analysis with VPR...' + vpr( + 'analysis', + VprArgs( + ctx.share, + ctx.takes.eblif, + ctx.values, + sdc_file=ctx.takes.sdc + ), + cwd=build_dir + ) + + if ctx.is_output_explicit('merged_post_implementation_v'): + sh_mv(analysis_merged_post_implementation_file(ctx), ctx.outputs.merged_post_implementation_v) + + if ctx.is_output_explicit('post_implementation_v'): + sh_mv(analysis_post_implementation_file(ctx), ctx.outputs.post_implementation_v) + + yield 'Saving log...' + save_vpr_log('analysis.log', build_dir=build_dir) + + def __init__(self, _): + self.name = 'analysis' + self.no_of_phases = 2 + self.takes = [ + 'eblif', + 'route', + 'sdc?' + ] + self.produces = [ + 'merged_post_implementation_v', + 'post_implementation_v', + 'analysis_log' + ] + self.values = [ + 'device', + 'vpr_options?' + ] + vpr_specific_values() + +ModuleClass = analysisModule diff --git a/f4pga/platforms/ql-eos-s3.json b/f4pga/platforms/ql-eos-s3.json index c1d130d..e63c276 100644 --- a/f4pga/platforms/ql-eos-s3.json +++ b/f4pga/platforms/ql-eos-s3.json @@ -11,6 +11,7 @@ "iomux_binary": "common:generic_script_wrapper", "place": "common:place", "route": "common:route", + "analysis": "common:analysis", "fasm": "common:fasm", "bitstream": "common:generic_script_wrapper" }, @@ -270,6 +271,45 @@ } } }, + "analysis": { + "values": { + "device": "ql-eos-s3", + "device_alt": "ql-eos-s3_wlcsp", + "pinmap": "${shareDir}/arch/ql-eos-s3_wlcsp/pinmap_PD64.csv", + "arch_def": "${shareDir}/arch/ql-eos-s3_wlcsp/arch.timing.xml", + "rr_graph_lookahead_bin": "${shareDir}/arch/ql-eos-s3_wlcsp/rr_graph_ql-eos-s3_wlcsp.lookahead.bin", + "rr_graph_real_bin": "${shareDir}/arch/ql-eos-s3_wlcsp/rr_graph_ql-eos-s3_wlcsp.rr_graph.real.bin", + "vpr_place_delay": "${shareDir}/arch/ql-eos-s3_wlcsp/rr_graph_ql-eos-s3_wlcsp.place_delay.bin", + "vpr_grid_layout_name": "ql-eos-s3", + "vpr_options": { + "gen_post_synthesis_netlist": "on", + "gen_post_implementation_merged_netlist": "on", + "post_synth_netlist_unconn_inputs": "nets", + "post_synth_netlist_unconn_outputs": "nets", + "verify_file_digests": "off", + "max_router_iterations": 500, + "routing_failure_predictor": "off", + "router_high_fanout_threshold": -1, + "constant_net_method": "route", + "route_chan_width": 100, + "clock_modeling": "route", + "place_delay_model": "delta_override", + "router_lookahead": "extended_map", + "check_route": "quick", + "strict_checks": "off", + "allow_dangling_combinational_nodes": "on", + "disable_errors": "check_unbuffered_edges:check_route", + "congested_routing_iteration_threshold": "0.8", + "incremental_reroute_delay_ripup": "off", + "base_cost_type": "delay_normalized_length_bounded", + "bb_factor": "10", + "initial_pres_fac": "4.0", + "check_rr_graph": "off", + "pack_high_fanout_threshold": "PB-lOGIC:18", + "suppress_warnings": "${noisyWarnings},sum_pin_class:check_unbuffered_edges:load_rr_indexed_data_T_values:check_rr_node:trans_per_R:check_route:set_rr_graph_tool_comment " + } + } + }, "bitstream": { "params": { "stage_name": "bitstream",