| #!/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 io | 
 | import os | 
 | import random | 
 | random.seed(int(os.getenv("SEED"), 16)) | 
 | from prjxray import util | 
 | from prjxray import lut_maker | 
 | from prjxray import verilog | 
 | from prjxray.db import Database | 
 |  | 
 |  | 
 | def gen_sites(): | 
 |     ''' | 
 |     IOB33S: main IOB of a diff pair | 
 |     IOB33M: secondary IOB of a diff pair | 
 |     IOB33: not a diff pair. Relatively rare (at least in ROI...2 of them?) | 
 |     Focus on IOB33S to start | 
 |     ''' | 
 |     db = Database(util.get_db_root(), util.get_part()) | 
 |     grid = db.grid() | 
 |     for tile_name in sorted(grid.tiles()): | 
 |         loc = grid.loc_of_tilename(tile_name) | 
 |         gridinfo = grid.gridinfo_at_loc(loc) | 
 |  | 
 |         sites = {} | 
 |         for site_name, site_type in gridinfo.sites.items(): | 
 |             if site_type in ['IOB33S', 'IOB33M']: | 
 |                 sites[site_type] = site_name | 
 |  | 
 |         if sites: | 
 |             yield tile_name, sites | 
 |  | 
 |  | 
 | def write_params(params): | 
 |     pinstr = 'tile,site,pin,iostandard,drive,slew\n' | 
 |     for vals in params: | 
 |         pinstr += ','.join(map(str, vals)) + '\n' | 
 |  | 
 |     open('params.csv', 'w').write(pinstr) | 
 |  | 
 |  | 
 | def run(): | 
 |     tile_types = ['IBUF', 'OBUF', 'IOBUF_INTERMDISABLE', None, None] | 
 |  | 
 |     i_idx = 0 | 
 |     o_idx = 0 | 
 |     io_idx = 0 | 
 |  | 
 |     iostandards = [ | 
 |         'LVCMOS12', | 
 |         'LVCMOS15', | 
 |         'LVCMOS18', | 
 |         'LVCMOS25', | 
 |         'LVCMOS33', | 
 |         'LVTTL', | 
 |         'SSTL135', | 
 |         'SSTL15', | 
 |         'LVDS_25', | 
 |         'TMDS_33', | 
 |     ] | 
 |  | 
 |     diff_map = { | 
 |         "SSTL135": ["DIFF_SSTL135"], | 
 |         "SSTL15": ["DIFF_SSTL15"], | 
 |     } | 
 |  | 
 |     only_diff_map = { | 
 |         "LVDS_25": ["LVDS_25"], | 
 |         "TMDS_33": ["TMDS_33"], | 
 |     } | 
 |  | 
 |     IN_TERM_ALLOWED = [ | 
 |         'SSTL15', | 
 |         'SSTL15_R', | 
 |         'SSTL18', | 
 |         'SSTL18_R', | 
 |         'SSTL135', | 
 |         'SSTL135_R', | 
 |         'HSTL_I' | 
 |         'HSTL_I_18' | 
 |         'HSTL_II', | 
 |         'HSTL_II_18', | 
 |     ] | 
 |  | 
 |     slews = ['FAST', 'SLOW'] | 
 |     pulls = ["NONE", "KEEPER", "PULLDOWN", "PULLUP"] | 
 |  | 
 |     luts = lut_maker.LutMaker() | 
 |  | 
 |     connects = io.StringIO() | 
 |  | 
 |     tile_params = [] | 
 |     params = { | 
 |         "tiles": [], | 
 |         'INTERNAL_VREF': {}, | 
 |     } | 
 |  | 
 |     with open(os.path.join(os.getenv('FUZDIR'), 'build', 'iobanks.txt')) as f: | 
 |         iobanks = set() | 
 |         iob_sites = dict() | 
 |         for l in f: | 
 |             fields = l.split(',') | 
 |             iob_site = fields[0] | 
 |             iobank = fields[1].rstrip() | 
 |  | 
 |             iobanks.add(iobank) | 
 |             iob_sites[iob_site] = iobank | 
 |  | 
 |     params['iobanks'] = iobanks | 
 |  | 
 |     iostandard_map = dict() | 
 |     for iobank in iobanks: | 
 |         iostandard = random.choice(iostandards) | 
 |         if iostandard in ['SSTL135', 'SSTL15']: | 
 |             params['INTERNAL_VREF'][iobank] = random.choice( | 
 |                 ( | 
 |                     .600, | 
 |                     .675, | 
 |                     .75, | 
 |                     .90, | 
 |                 )) | 
 |  | 
 |         iostandard_map[iobank] = iostandard | 
 |  | 
 |     params['iobanks'] = list(iobanks) | 
 |  | 
 |     any_idelay = False | 
 |     for tile, sites in gen_sites(): | 
 |         iostandard = None | 
 |  | 
 |         site_bels = {} | 
 |         for site_type, site_name in sites.items(): | 
 |             iobank = iob_sites[site_name] | 
 |             iostandard = iostandard_map[iobank] | 
 |  | 
 |             if iostandard in ['LVTTL', 'LVCMOS18']: | 
 |                 drives = [4, 8, 12, 16, 24] | 
 |             elif iostandard in ['LVCMOS12']: | 
 |                 drives = [4, 8, 12] | 
 |             elif iostandard in ['SSTL135', 'SSTL15', 'LVDS_25', 'TMDS_33']: | 
 |                 drives = None | 
 |             else: | 
 |                 drives = [4, 8, 12, 16] | 
 |  | 
 |             if site_type.endswith('M'): | 
 |                 if iostandard in diff_map: | 
 |                     site_bels[site_type] = random.choice( | 
 |                         tile_types + ['IBUFDS', 'OBUFDS', 'OBUFTDS']) | 
 |                 elif iostandard in only_diff_map: | 
 |                     site_bels[site_type] = random.choice( | 
 |                         ['IBUFDS', 'OBUFDS', 'OBUFTDS', None, None]) | 
 |                 else: | 
 |                     site_bels[site_type] = random.choice(tile_types) | 
 |                 is_m_diff = site_bels[site_type] is not None and site_bels[ | 
 |                     site_type].endswith('DS') | 
 |             else: | 
 |                 site_bels[site_type] = random.choice(tile_types) | 
 |  | 
 |         if is_m_diff or iostandard in only_diff_map: | 
 |             site_bels['IOB33S'] = None | 
 |  | 
 |         for site_type, site in sites.items(): | 
 |             p = {} | 
 |             p['tile'] = tile | 
 |             p['site'] = site | 
 |             p['type'] = site_bels[site_type] | 
 |  | 
 |             if p['type'] is not None and p['type'].endswith('DS'): | 
 |                 if iostandard in diff_map: | 
 |                     iostandard_site = random.choice(diff_map[iostandard]) | 
 |                 elif iostandard in only_diff_map: | 
 |                     iostandard_site = random.choice(only_diff_map[iostandard]) | 
 |                 p['pair_site'] = sites['IOB33S'] | 
 |             else: | 
 |                 iostandard_site = iostandard | 
 |  | 
 |             p['IOSTANDARD'] = verilog.quote(iostandard_site) | 
 |             p['PULLTYPE'] = verilog.quote(random.choice(pulls)) | 
 |  | 
 |             if p['type'] is None: | 
 |                 p['pad_wire'] = None | 
 |             elif p['type'] == 'IBUF': | 
 |                 p['pad_wire'] = 'di[{}]'.format(i_idx) | 
 |                 p['IDELAY_ONLY'] = random.randint(0, 1) | 
 |                 if not p['IDELAY_ONLY']: | 
 |                     p['owire'] = luts.get_next_input_net() | 
 |                 else: | 
 |                     any_idelay = True | 
 |                     p['owire'] = 'idelay_{site}'.format(**p) | 
 |  | 
 |                 p['DRIVE'] = None | 
 |                 p['SLEW'] = None | 
 |                 p['IBUF_LOW_PWR'] = random.randint(0, 1) | 
 |  | 
 |                 if iostandard in IN_TERM_ALLOWED: | 
 |                     p['IN_TERM'] = random.choice( | 
 |                         ( | 
 |                             'NONE', | 
 |                             'UNTUNED_SPLIT_40', | 
 |                             'UNTUNED_SPLIT_50', | 
 |                             'UNTUNED_SPLIT_60', | 
 |                         )) | 
 |  | 
 |                 i_idx += 1 | 
 |             elif p['type'] == 'IBUFDS': | 
 |                 p['pad_wire'] = 'di[{}]'.format(i_idx) | 
 |                 i_idx += 1 | 
 |                 p['bpad_wire'] = 'di[{}]'.format(i_idx) | 
 |                 i_idx += 1 | 
 |  | 
 |                 p['IDELAY_ONLY'] = random.randint(0, 1) | 
 |                 p['DIFF_TERM'] = random.randint(0, 1) | 
 |                 if not p['IDELAY_ONLY']: | 
 |                     p['owire'] = luts.get_next_input_net() | 
 |                 else: | 
 |                     any_idelay = True | 
 |                     p['owire'] = 'idelay_{site}'.format(**p) | 
 |  | 
 |                 p['DRIVE'] = None | 
 |                 p['SLEW'] = None | 
 |                 p['IBUF_LOW_PWR'] = random.randint(0, 1) | 
 |  | 
 |             elif p['type'] == 'OBUF': | 
 |                 p['pad_wire'] = 'do[{}]'.format(o_idx) | 
 |                 p['iwire'] = luts.get_next_output_net() | 
 |                 if drives is not None: | 
 |                     p['DRIVE'] = random.choice(drives) | 
 |                 else: | 
 |                     p['DRIVE'] = None | 
 |                 p['SLEW'] = verilog.quote(random.choice(slews)) | 
 |  | 
 |                 o_idx += 1 | 
 |             elif p['type'] == 'OBUFDS': | 
 |                 p['pad_wire'] = 'do[{}]'.format(o_idx) | 
 |                 o_idx += 1 | 
 |                 p['bpad_wire'] = 'do[{}]'.format(o_idx) | 
 |                 o_idx += 1 | 
 |                 p['iwire'] = luts.get_next_output_net() | 
 |                 if drives is not None: | 
 |                     p['DRIVE'] = random.choice(drives) | 
 |                 else: | 
 |                     p['DRIVE'] = None | 
 |                 p['SLEW'] = verilog.quote(random.choice(slews)) | 
 |             elif p['type'] == 'OBUFTDS': | 
 |                 p['pad_wire'] = 'do[{}]'.format(o_idx) | 
 |                 o_idx += 1 | 
 |                 p['bpad_wire'] = 'do[{}]'.format(o_idx) | 
 |                 o_idx += 1 | 
 |                 p['tristate_wire'] = random.choice( | 
 |                     ('0', luts.get_next_output_net())) | 
 |                 p['iwire'] = luts.get_next_output_net() | 
 |                 if drives is not None: | 
 |                     p['DRIVE'] = random.choice(drives) | 
 |                 else: | 
 |                     p['DRIVE'] = None | 
 |                 p['SLEW'] = verilog.quote(random.choice(slews)) | 
 |             elif p['type'] == 'IOBUF_INTERMDISABLE': | 
 |                 p['pad_wire'] = 'dio[{}]'.format(io_idx) | 
 |                 p['iwire'] = luts.get_next_output_net() | 
 |                 p['owire'] = luts.get_next_input_net() | 
 |                 if drives is not None: | 
 |                     p['DRIVE'] = random.choice(drives) | 
 |                 else: | 
 |                     p['DRIVE'] = None | 
 |                 p['SLEW'] = verilog.quote(random.choice(slews)) | 
 |                 p['tristate_wire'] = random.choice( | 
 |                     ('0', luts.get_next_output_net())) | 
 |                 p['ibufdisable_wire'] = random.choice( | 
 |                     ('0', luts.get_next_output_net())) | 
 |                 p['intermdisable_wire'] = random.choice( | 
 |                     ('0', luts.get_next_output_net())) | 
 |                 io_idx += 1 | 
 |  | 
 |             if 'DRIVE' in p: | 
 |                 if p['DRIVE'] is not None: | 
 |                     p['DRIVE_STR'] = '.DRIVE({}),'.format(p['DRIVE']) | 
 |                 else: | 
 |                     p['DRIVE_STR'] = '' | 
 |  | 
 |             if 'SLEW' in p: | 
 |                 p['SLEW_STR'] = '' | 
 |                 if iostandard in only_diff_map: | 
 |                     p['SLEW'] = None | 
 |                 elif p['DRIVE'] is not None: | 
 |                     p['SLEW_STR'] = '.SLEW({}),'.format(p['SLEW']) | 
 |  | 
 |             if p['type'] is not None: | 
 |                 tile_params.append( | 
 |                     ( | 
 |                         tile, | 
 |                         site, | 
 |                         p['pad_wire'], | 
 |                         iostandard_site, | 
 |                         p['DRIVE'], | 
 |                         verilog.unquote(p['SLEW']) if p['SLEW'] else None, | 
 |                         verilog.unquote(p['PULLTYPE']), | 
 |                         p['IN_TERM'] if 'IN_TERM' in p else None, | 
 |                     )) | 
 |             params['tiles'].append(p) | 
 |  | 
 |     write_params(tile_params) | 
 |  | 
 |     with open('iobank_vref.csv', 'w') as f: | 
 |         for iobank, vref in params['INTERNAL_VREF'].items(): | 
 |             f.write('{},{}\n'.format(iobank, vref)) | 
 |  | 
 |     print( | 
 |         ''' | 
 | `define N_DI {n_di} | 
 | `define N_DO {n_do} | 
 | `define N_DIO {n_dio} | 
 |  | 
 | module top(input wire [`N_DI-1:0] di, output wire [`N_DO-1:0] do, inout wire [`N_DIO-1:0] dio); | 
 |     '''.format(n_di=i_idx, n_do=o_idx, n_dio=io_idx)) | 
 |  | 
 |     if any_idelay: | 
 |         print(''' | 
 |         (* KEEP, DONT_TOUCH *) | 
 |         IDELAYCTRL();''') | 
 |  | 
 |     # Always output a LUT6 to make placer happy. | 
 |     print(''' | 
 |         (* KEEP, DONT_TOUCH *) | 
 |         LUT6 dummy_lut();''') | 
 |  | 
 |     for p in params['tiles']: | 
 |         if p['type'] is None: | 
 |             continue | 
 |         elif p['type'] == 'IBUF': | 
 |             print( | 
 |                 ''' | 
 |         wire idelay_{site}; | 
 |  | 
 |         (* KEEP, DONT_TOUCH *) | 
 |         IBUF #( | 
 |             .IBUF_LOW_PWR({IBUF_LOW_PWR}), | 
 |             .IOSTANDARD({IOSTANDARD}) | 
 |         ) ibuf_{site} ( | 
 |             .I({pad_wire}), | 
 |             .O({owire}) | 
 |             );'''.format(**p), | 
 |                 file=connects) | 
 |             if p['IDELAY_ONLY']: | 
 |                 print( | 
 |                     """ | 
 |         (* KEEP, DONT_TOUCH *) | 
 |         IDELAYE2 idelay_site_{site} ( | 
 |             .IDATAIN(idelay_{site}) | 
 |             );""".format(**p), | 
 |                     file=connects) | 
 |  | 
 |         elif p['type'] == 'IBUFDS': | 
 |             print( | 
 |                 ''' | 
 |         wire idelay_{site}; | 
 |  | 
 |         (* KEEP, DONT_TOUCH *) | 
 |         IBUFDS #( | 
 |             .IBUF_LOW_PWR({IBUF_LOW_PWR}), | 
 |             .DIFF_TERM({DIFF_TERM}), | 
 |             .IOSTANDARD({IOSTANDARD}) | 
 |         ) ibuf_{site} ( | 
 |             .I({pad_wire}), | 
 |             .IB({bpad_wire}), | 
 |             .O({owire}) | 
 |             );'''.format(**p), | 
 |                 file=connects) | 
 |             if p['IDELAY_ONLY']: | 
 |                 print( | 
 |                     """ | 
 |         (* KEEP, DONT_TOUCH *) | 
 |         IDELAYE2 idelay_site_{site} ( | 
 |             .IDATAIN(idelay_{site}) | 
 |             );""".format(**p), | 
 |                     file=connects) | 
 |  | 
 |         elif p['type'] == 'OBUF': | 
 |             print( | 
 |                 ''' | 
 |         (* KEEP, DONT_TOUCH *) | 
 |         OBUF #( | 
 |             {DRIVE_STR} | 
 |             {SLEW_STR} | 
 |             .IOSTANDARD({IOSTANDARD}) | 
 |         ) obuf_{site} ( | 
 |             .O({pad_wire}), | 
 |             .I({iwire}) | 
 |             );'''.format(**p), | 
 |                 file=connects) | 
 |         elif p['type'] == 'OBUFDS': | 
 |             print( | 
 |                 ''' | 
 |         (* KEEP, DONT_TOUCH *) | 
 |         OBUFDS #( | 
 |             {DRIVE_STR} | 
 |             {SLEW_STR} | 
 |             .IOSTANDARD({IOSTANDARD}) | 
 |         ) obufds_{site} ( | 
 |             .O({pad_wire}), | 
 |             .OB({bpad_wire}), | 
 |             .I({iwire}) | 
 |             );'''.format(**p), | 
 |                 file=connects) | 
 |         elif p['type'] == 'OBUFTDS': | 
 |             print( | 
 |                 ''' | 
 |         (* KEEP, DONT_TOUCH *) | 
 |         OBUFTDS #( | 
 |             {DRIVE_STR} | 
 |             {SLEW_STR} | 
 |             .IOSTANDARD({IOSTANDARD}) | 
 |         ) obufds_{site} ( | 
 |             .O({pad_wire}), | 
 |             .OB({bpad_wire}), | 
 |             .T({tristate_wire}), | 
 |             .I({iwire}) | 
 |             );'''.format(**p), | 
 |                 file=connects) | 
 |         elif p['type'] == 'IOBUF_INTERMDISABLE': | 
 |             print( | 
 |                 ''' | 
 |         (* KEEP, DONT_TOUCH *) | 
 |         IOBUF_INTERMDISABLE #( | 
 |             {DRIVE_STR} | 
 |             {SLEW_STR} | 
 |             .IOSTANDARD({IOSTANDARD}) | 
 |         ) ibuf_{site} ( | 
 |             .IO({pad_wire}), | 
 |             .I({iwire}), | 
 |             .O({owire}), | 
 |             .T({tristate_wire}), | 
 |             .IBUFDISABLE({ibufdisable_wire}), | 
 |             .INTERMDISABLE({intermdisable_wire}) | 
 |             );'''.format(**p), | 
 |                 file=connects) | 
 |  | 
 |     for l in luts.create_wires_and_luts(): | 
 |         print(l) | 
 |  | 
 |     print(connects.getvalue()) | 
 |  | 
 |     print("endmodule") | 
 |  | 
 |     with open('params.json', 'w') as f: | 
 |         json.dump(params, f, indent=2) | 
 |  | 
 |  | 
 | if __name__ == '__main__': | 
 |     run() |