| #!/usr/bin/env python3 |
| # -*- coding: utf-8 -*- |
| # |
| # Copyright (C) 2017-2022 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 |
| |
| from iostandards import * |
| |
| def bitfilter(frame, word): |
| return 38 <= frame |
| |
| 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 ['LVCMOS18', 'LVCMOS15']: |
| drives = [2, 4, 6, 8, 12, 16] |
| elif iostandard == 'LVCMOS12': |
| drives = [2, 4, 6, 8] |
| elif iostandard in SSTL + DIFF_SSTL: |
| return ['_FIXED'] |
| else: |
| assert False, "this line should be unreachable" |
| |
| return drives |
| |
| STEPDOWN_IOSTANDARDS = LVCMOS + SSTL |
| IBUF_LOW_PWR_SUPPORTED = LVDS + SSTL |
| ONLY_DIFF_IOSTANDARDS = LVDS |
| |
| |
| 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_X1Y107,RIOB18_X1Y107,AF4,PULLDOWN |
| di[10],IOB_X1Y147,RIOB18_X1Y147,U5,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) |
| |
| 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(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': |
| psite = d['pair_site'] |
| 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(psite, '{}.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(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(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(tile, 'OUT_DIFF', 1 and not only_diff_io) |
| segmk.add_tile_tag(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(tile, 'OUT_DIFF', 1 and not only_diff_io) |
| segmk.add_tile_tag(tile, 'OUT_TDIFF', 1 and not only_diff_io) |
| |
| elif d['type'] == 'IOBUF_DCIEN': |
| 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 LVCMOS: |
| for drive_opt in ("2", "4", "6", "8", "12", "16"): |
| if drive_opt in ["12", "16"] and opt == "LVCMOS12": |
| continue |
| |
| drive_opts.add(mk_drive_opt(opt, drive_opt)) |
| |
| for sstl in SSTL: |
| drive_opts.add(mk_drive_opt(sstl, None)) |
| |
| drive_opts.add(mk_drive_opt("LVDS", 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 'dcitermdisable_wire' in d: |
| segmk.add_site_tag( |
| site, 'DCITERMDISABLE.I', d['dcitermdisable_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_IOI tiles, and |
| # there is only on HCLK_IOI 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] |
| 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() |