mirror of https://github.com/openXC7/prjxray.git
303 lines
11 KiB
Python
303 lines
11 KiB
Python
#!/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
|
|
|
|
from iostandards import *
|
|
|
|
def bitfilter(frame, word):
|
|
# the fuzzers seem to find bits in frame 24 which seems
|
|
# to be used by other tile types
|
|
if frame < 30:
|
|
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 ['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 + DIFF_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()
|