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