#!/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 from prjxray.segmaker import Segmaker from prjxray import segmaker from prjxray import verilog import os import json import csv def bitfilter(frame, word): if frame < 38: return False return True def mk_drive_opt(iostandard, drive): if drive is None: drive = '_FIXED' return '{}.DRIVE.I{}'.format(iostandard, drive) def drives_for_iostandard(iostandard): if iostandard in ['LVTTL', 'LVCMOS18']: drives = [4, 8, 12, 16, 24] elif iostandard == 'LVCMOS12': drives = [4, 8, 12] elif iostandard in ['SSTL135', 'SSTL15']: return ['_FIXED'] else: drives = [4, 8, 12, 16] return drives STEPDOWN_IOSTANDARDS = [ 'LVCMOS12', 'LVCMOS15', 'LVCMOS18', 'SSTL135', 'SSTL15' ] IBUF_LOW_PWR_SUPPORTED = ['SSTL135', 'SSTL15', 'LVDS_25', 'TMDS_33'] ONLY_DIFF_IOSTANDARDS = ['LVDS_25', 'TMDS_33'] def main(): # Create map of iobank -> sites iobanks = {} site_to_iobank = {} iobank_iostandards = {} with open(os.path.join(os.getenv('FUZDIR'), 'build', 'iobanks.txt')) as f: for l in f: iob_site, iobank = l.strip().split(',') iobank = int(iobank) if iobank not in iobanks: iobanks[iobank] = set() iobanks[iobank].add(iob_site) assert iob_site not in site_to_iobank site_to_iobank[iob_site] = iobank for iobank in iobanks: iobank_iostandards[iobank] = set() # Load a list of PUDC_B pin function tiles. They are configured differently # by the vendor tools so need to be skipped pudc_tiles = set() with open(os.path.join(os.getenv('FUZDIR'), 'build', 'pudc_sites.csv')) as f: for l in csv.DictReader(f): pudc_tiles.add(l["tile"]) print("Loading tags") segmk = Segmaker("design.bits") ''' port,site,tile,pin,slew,drive,pulltype di[0],IOB_X0Y107,LIOB33_X0Y107,A21,PULLDOWN di[10],IOB_X0Y147,LIOB33_X0Y147,F14,PULLUP ''' with open('params.json', 'r') as f: design = json.load(f) diff_pairs = set() for d in design['tiles']: iostandard = verilog.unquote(d['IOSTANDARD']) if iostandard.startswith('DIFF_'): diff_pairs.add(d['pair_site']) for d in design['tiles']: site = d['site'] tile = d['tile'] if tile in pudc_tiles: continue if site in diff_pairs: continue iostandard = verilog.unquote(d['IOSTANDARD']) if iostandard.startswith('DIFF_'): iostandard = iostandard[5:] iobank_iostandards[site_to_iobank[site]].add(iostandard) segmk.add_site_tag( site, '_'.join(STEPDOWN_IOSTANDARDS) + '.STEPDOWN', iostandard in STEPDOWN_IOSTANDARDS) if 'IN_TERM' in d: segmaker.add_site_group_zero( segmk, site, 'IN_TERM.', [ 'NONE', 'UNTUNED_SPLIT_40', 'UNTUNED_SPLIT_50', 'UNTUNED_SPLIT_60' ], 'NONE', d['IN_TERM']) only_diff_io = iostandard in ONLY_DIFF_IOSTANDARDS if d['type'] is None: segmk.add_site_tag(site, 'INOUT', 0) segmk.add_site_tag(site, '{}.IN_USE'.format(iostandard), 0) segmk.add_site_tag(site, '{}.IN'.format(iostandard), 0) segmk.add_site_tag(site, '{}.OUT'.format(iostandard), 0) segmk.add_site_tag(site, '{}.IN_ONLY'.format(iostandard), 0) elif d['type'] == 'IBUF': segmk.add_site_tag(site, 'INOUT', 0) segmk.add_site_tag(site, '{}.IN_USE'.format(iostandard), 1) segmk.add_site_tag(site, '{}.IN'.format(iostandard), 1) segmk.add_site_tag(site, '{}.IN_DIFF'.format(iostandard), 0) segmk.add_site_tag(site, '{}.OUT'.format(iostandard), 0) segmk.add_site_tag(site, '{}.IN_ONLY'.format(iostandard), 1) segmk.add_tile_tag(d['tile'], 'IN_DIFF', 0) if iostandard in IBUF_LOW_PWR_SUPPORTED: segmk.add_site_tag(site, 'IBUF_LOW_PWR', d['IBUF_LOW_PWR']) segmk.add_site_tag( site, 'ZIBUF_LOW_PWR', 1 ^ d['IBUF_LOW_PWR']) elif d['type'] == 'IBUFDS': segmk.add_site_tag(site, 'INOUT', 0) segmk.add_site_tag(site, '{}.IN_USE'.format(iostandard), 1) segmk.add_site_tag(site, '{}.IN'.format(iostandard), 1) segmk.add_site_tag(site, '{}.IN_DIFF'.format(iostandard), 1) segmk.add_site_tag( d['pair_site'], '{}.IN_DIFF'.format(iostandard), 1) segmk.add_site_tag(site, '{}.OUT'.format(iostandard), 0) segmk.add_site_tag(site, '{}.IN_ONLY'.format(iostandard), 1) segmk.add_tile_tag(d['tile'], 'IN_DIFF', 1) if iostandard in IBUF_LOW_PWR_SUPPORTED: segmk.add_tile_tag( tile, 'DIFF.IBUF_LOW_PWR', d['IBUF_LOW_PWR']) segmk.add_tile_tag( tile, 'DIFF.ZIBUF_LOW_PWR', 1 ^ d['IBUF_LOW_PWR']) elif d['type'] == 'OBUF': segmk.add_site_tag(site, 'INOUT', 0) segmk.add_site_tag(site, '{}.IN_USE'.format(iostandard), 1) segmk.add_site_tag(site, '{}.IN'.format(iostandard), 0) segmk.add_site_tag(site, '{}.OUT'.format(iostandard), 1) segmk.add_tile_tag(d['tile'], 'OUT_DIFF', 0) elif d['type'] == 'OBUFDS': segmk.add_site_tag(site, 'INOUT', 0) segmk.add_site_tag(site, '{}.IN_USE'.format(iostandard), 1) segmk.add_site_tag(site, '{}.IN'.format(iostandard), 0) segmk.add_site_tag(site, '{}.OUT'.format(iostandard), 1) segmk.add_tile_tag( d['tile'], 'OUT_DIFF', 1 and not only_diff_io) segmk.add_tile_tag(d['tile'], 'OUT_TDIFF', 0) elif d['type'] == 'OBUFTDS': segmk.add_site_tag(site, 'INOUT', 0) segmk.add_site_tag(site, '{}.IN_USE'.format(iostandard), 1) segmk.add_site_tag(site, '{}.IN'.format(iostandard), 0) segmk.add_site_tag(site, '{}.OUT'.format(iostandard), 1) segmk.add_tile_tag( d['tile'], 'OUT_DIFF', 1 and not only_diff_io) segmk.add_tile_tag( d['tile'], 'OUT_TDIFF', 1 and not only_diff_io) elif d['type'] == 'IOBUF_INTERMDISABLE': segmk.add_site_tag(site, 'INOUT', 1) segmk.add_site_tag(site, '{}.IN_USE'.format(iostandard), 1) segmk.add_site_tag(site, '{}.IN'.format(iostandard), 1) segmk.add_site_tag(site, '{}.OUT'.format(iostandard), 1) if d['type'] is not None: segmaker.add_site_group_zero( segmk, site, "PULLTYPE.", ("NONE", "KEEPER", "PULLDOWN", "PULLUP"), "PULLDOWN", verilog.unquote(d['PULLTYPE'])) if d['type'] in [None, 'IBUF', 'IBUFDS']: continue drive_opts = set() for opt in ("LVCMOS25", "LVCMOS33", "LVCMOS18", "LVCMOS15", "LVCMOS12", 'LVTTL'): for drive_opt in ("4", "8", "12", "16", "24"): if drive_opt == "16" and opt == "LVCMOS12": continue if drive_opt == "24" and opt not in ["LVCMOS18", 'LVTTL']: continue drive_opts.add(mk_drive_opt(opt, drive_opt)) drive_opts.add(mk_drive_opt("SSTL135", None)) drive_opts.add(mk_drive_opt("SSTL15", None)) drive_opts.add(mk_drive_opt("LVDS_25", None)) drive_opts.add(mk_drive_opt("TMDS_33", None)) segmaker.add_site_group_zero( segmk, site, '', drive_opts, mk_drive_opt('LVCMOS25', '12'), mk_drive_opt(iostandard, d['DRIVE'])) if d['SLEW']: for opt in ["SLOW", "FAST"]: segmk.add_site_tag( site, iostandard + ".SLEW." + opt, opt == verilog.unquote(d['SLEW'])) if 'ibufdisable_wire' in d: segmk.add_site_tag( site, 'IBUFDISABLE.I', d['ibufdisable_wire'] != '0') if 'intermdisable_wire' in d: segmk.add_site_tag( site, 'INTERMDISABLE.I', d['intermdisable_wire'] != '0') site_to_cmt = {} site_to_tile = {} tile_to_cmt = {} cmt_to_idelay = {} with open(os.path.join(os.getenv('FUZDIR'), 'build', 'cmt_regions.csv')) as f: for l in f: site, tile, cmt = l.strip().split(',') site_to_tile[site] = tile site_to_cmt[site] = cmt tile_to_cmt[tile] = cmt # Given IDELAYCTRL's are only located in HCLK_IOI3 tiles, and # there is only on HCLK_IOI3 tile per CMT, update # CMT -> IDELAYCTRL / tile map. if 'IDELAYCTRL' in site: assert cmt not in cmt_to_idelay cmt_to_idelay[cmt] = site, tile # For each IOBANK with an active VREF set the feature cmt_vref_active = set() with open('iobank_vref.csv') as f: for l in f: iobank, vref = l.strip().split(',') iobank = int(iobank) cmt = None for cmt_site in iobanks[iobank]: if cmt_site in site_to_cmt: cmt = site_to_cmt[cmt_site] break if cmt is None: continue cmt_vref_active.add(cmt) _, hclk_cmt_tile = cmt_to_idelay[cmt] opt = 'VREF.V_{:d}_MV'.format(int(float(vref) * 1000)) segmk.add_tile_tag(hclk_cmt_tile, opt, 1) for iobank in iobank_iostandards: if len(iobank_iostandards[iobank]) == 0: continue for cmt_site in iobanks[iobank]: if cmt_site in site_to_cmt: cmt = site_to_cmt[cmt_site] break if cmt is None: continue _, hclk_cmt_tile = cmt_to_idelay[cmt] assert len(iobank_iostandards[iobank]) == 1, iobank_iostandards[iobank] iostandard = list(iobank_iostandards[iobank])[0] segmk.add_tile_tag( hclk_cmt_tile, 'STEPDOWN', iostandard in STEPDOWN_IOSTANDARDS) for only_diff_io in ONLY_DIFF_IOSTANDARDS: segmk.add_tile_tag( hclk_cmt_tile, '{}_IN_USE'.format(only_diff_io), iostandard == only_diff_io) segmk.add_tile_tag( hclk_cmt_tile, 'ONLY_DIFF_IN_USE', iostandard in ONLY_DIFF_IOSTANDARDS) # For IOBANK's with no active VREF, clear all VREF options. for cmt, (_, hclk_cmt_tile) in cmt_to_idelay.items(): if cmt in cmt_vref_active: continue for vref in ( .600, .675, .75, .90, ): opt = 'VREF.V_{:d}_MV'.format(int(vref * 1000)) segmk.add_tile_tag(hclk_cmt_tile, opt, 0) segmk.compile(bitfilter=bitfilter) segmk.write(allow_empty=True) if __name__ == "__main__": main()