|  | #!/usr/bin/env python3 | 
|  | # -*- coding: utf-8 -*- | 
|  | # | 
|  | # Copyright (C) 2017-2020  The Project X-Ray Authors. | 
|  | # | 
|  | # Use of this source code is governed by a ISC-style | 
|  | # license that can be found in the LICENSE file or at | 
|  | # https://opensource.org/licenses/ISC | 
|  | # | 
|  | # SPDX-License-Identifier: ISC | 
|  |  | 
|  | import json | 
|  | import argparse | 
|  |  | 
|  | from prjxray.util import OpenSafeFile | 
|  |  | 
|  | def get_elems_count(timings, slice, site, bel_type): | 
|  | combinational = 0 | 
|  | sequential = 0 | 
|  | for delay in timings[slice][site][bel_type]: | 
|  | if 'sequential' in timings[slice][site][bel_type][delay]: | 
|  | sequential += 1 | 
|  | else: | 
|  | combinational += 1 | 
|  | return combinational, sequential | 
|  |  | 
|  |  | 
|  | def produce_sdf(timings, outdir): | 
|  |  | 
|  | for slice in timings: | 
|  | sdf = \ | 
|  | """ | 
|  | (DELAYFILE | 
|  | (SDFVERSION \"3.0\") | 
|  | (TIMESCALE 1ns) | 
|  | """ | 
|  | for site in sorted(timings[slice]): | 
|  | for bel_type in sorted(timings[slice][site]): | 
|  | combinational, sequential = get_elems_count( | 
|  | timings, slice, site, bel_type) | 
|  | #define CELL | 
|  | cell= \ | 
|  | """ | 
|  | (CELL | 
|  | (CELLTYPE \"{name}\") | 
|  | (INSTANCE {location})""".format(name=bel_type.upper(), location=site) | 
|  | sdf += cell | 
|  |  | 
|  | #define delay header (if needed) | 
|  | if combinational > 0: | 
|  | delay_hdr = \ | 
|  | """ | 
|  | (DELAY | 
|  | (ABSOLUTE""" | 
|  | sdf += delay_hdr | 
|  | # add all delays definitions | 
|  | for delay in sorted(timings[slice][site][bel_type]): | 
|  | if 'sequential' in timings[slice][site][bel_type][ | 
|  | delay]: | 
|  | continue | 
|  | dly = \ | 
|  | """ | 
|  | (IOPATH {input} {output} ({FAST_MIN}::{FAST_MAX})({SLOW_MIN}::{SLOW_MAX}))""".format(**timings[slice][site][bel_type][delay]) | 
|  | if 'extra_ports' in timings[slice][site][bel_type][ | 
|  | delay] is not None: | 
|  | dly += \ | 
|  | """ #extra ports {}""".format(timings[slice][site][bel_type][delay]['extra_ports']) | 
|  |  | 
|  | sdf += dly | 
|  |  | 
|  | # close DELAY definition | 
|  | enddelay = \ | 
|  | """ | 
|  | ) | 
|  | )""" | 
|  | sdf += enddelay | 
|  |  | 
|  | # define TIMINGCHECK header (if needed) | 
|  | if sequential > 0: | 
|  | timingcheck_hdr = \ | 
|  | """ | 
|  | (TIMINGCHECK""" | 
|  | sdf += timingcheck_hdr | 
|  |  | 
|  | for delay in sorted(timings[slice][site][bel_type]): | 
|  | if 'sequential' not in timings[slice][site][bel_type][ | 
|  | delay]: | 
|  | continue | 
|  | timingcheck = \ | 
|  | """ | 
|  | ({prop} {input} (posedge {clock}) ({SLOW_MIN}::{SLOW_MAX}))""".format( | 
|  | prop=timings[slice][site][bel_type][delay]['sequential'].upper(), | 
|  | **timings[slice][site][bel_type][delay]) | 
|  |  | 
|  | if 'extra_ports' in timings[slice][site][bel_type][ | 
|  | delay] is not None: | 
|  | timingcheck += \ | 
|  | """ #extra ports {}""".format(timings[slice][site][bel_type][delay]['extra_ports']) | 
|  |  | 
|  | sdf += timingcheck | 
|  |  | 
|  | # close TIMINGCHECK definition | 
|  | endtimingcheck = \ | 
|  | """ | 
|  | )""" | 
|  | sdf += endtimingcheck | 
|  |  | 
|  | endcell = \ | 
|  | """ | 
|  | )""" | 
|  | sdf += endcell | 
|  | # end of SDF | 
|  | sdf += \ | 
|  | """ | 
|  | )""" | 
|  |  | 
|  | with OpenSafeFile(outdir + '/' + slice + '.sdf', "w") as fp: | 
|  | fp.write(sdf) | 
|  |  | 
|  |  | 
|  | def main(): | 
|  |  | 
|  | parser = argparse.ArgumentParser() | 
|  | parser.add_argument('--json', type=str, help="Input JSON file") | 
|  | parser.add_argument('--sdf', type=str, help="SDF files output directory") | 
|  |  | 
|  | args = parser.parse_args() | 
|  |  | 
|  | with OpenSafeFile(args.json, 'r') as fp: | 
|  | timings = json.load(fp) | 
|  |  | 
|  | produce_sdf(timings, args.sdf) | 
|  |  | 
|  |  | 
|  | if __name__ == '__main__': | 
|  | main() |