| #!/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() |