Merge pull request #983 from litghost/iob_diff

Add initial DIFF_ support to IOB fuzzer.
This commit is contained in:
litghost 2019-07-29 17:53:35 -07:00 committed by GitHub
commit 11b5f39a78
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 325 additions and 72 deletions

View File

@ -22,8 +22,11 @@ import generate
def process_parts(parts):
if len(parts) == 0:
return
if parts[-1] == 'IN_ONLY':
yield 'type', ['IBUF']
yield 'type', ['IBUF', 'IBUFDS']
if len(parts) > 2 and parts[-2] == 'SLEW':
yield 'SLEW', verilog.quote(parts[-1])
@ -35,6 +38,10 @@ def process_parts(parts):
yield 'IOSTANDARDS', parts[0].split('_')
yield 'IN', True
if len(parts) > 1 and parts[1] == 'IN_DIFF':
yield 'IOSTANDARDS', parts[0].split('_')
yield 'IN_DIFF', True
if len(parts) > 1 and parts[1] == 'DRIVE':
yield 'IOSTANDARDS', parts[0].split('_')
@ -47,6 +54,8 @@ def process_parts(parts):
def create_sites_from_fasm(fasm_file):
sites = {}
diff_tiles = set()
with open(fasm_file) as f:
for l in f:
if 'IOB33' not in l:
@ -55,19 +64,27 @@ def create_sites_from_fasm(fasm_file):
parts = l.strip().split('.')
tile = parts[0]
site = parts[1]
if 'OUT_DIFF' == site:
diff_tiles.add(tile)
continue
if (tile, site) not in sites:
sites[(tile, site)] = {
'tile': tile,
'site_key': site,
}
if len(parts) > 3 and 'IN_DIFF' == parts[3]:
diff_tiles.add(tile)
for key, value in process_parts(parts[2:]):
sites[(tile, site)][key] = value
for key in sites:
if 'type' not in sites[key]:
if 'IOSTANDARDS' not in sites[key]:
sites[key]['type'] = None
sites[key]['type'] = [None]
else:
assert 'IOSTANDARDS' in sites[key], sites[key]
assert 'DRIVES' in sites[key], sites[key]
@ -77,15 +94,17 @@ def create_sites_from_fasm(fasm_file):
else:
sites[key]['type'] = [
"OBUF",
"OBUFDS",
"OBUFTDS",
"OBUFDS_DUAL_BUF",
"OBUFTDS_DUAL_BUF",
]
return sites
return sites, diff_tiles
def process_specimen(fasm_file, params_json):
sites = create_sites_from_fasm(fasm_file)
sites, diff_tiles = create_sites_from_fasm(fasm_file)
with open(params_json) as f:
params = json.load(f)
@ -107,8 +126,12 @@ def process_specimen(fasm_file, params_json):
site_from_fasm = sites[(tile, site_key)]
assert p['type'] in site_from_fasm['type'], (
tile, site_key, p['type'], site_from_fasm['type'])
if site_y == 0 or tile not in diff_tiles:
assert p['type'] in site_from_fasm['type'], (
tile, site_key, p['type'], site_from_fasm['type'])
else:
# Y1 on DIFF tiles is always none.
assert p['type'] is None, p
if p['type'] is None:
continue
@ -136,7 +159,7 @@ def process_specimen(fasm_file, params_json):
site_from_fasm['IOSTANDARDS'],
)
if p['type'] != 'IBUF':
if p['type'] not in ['IBUF', 'IBUFDS']:
if verilog.unquote(p['SLEW']) == '':
# Default is None.
slew = verilog.quote('SLOW')

View File

@ -48,6 +48,7 @@ def drives_for_iostandard(iostandard):
STEPDOWN_IOSTANDARDS = ['LVCMOS12', 'LVCMOS15', 'LVCMOS18', 'SSTL135']
IBUF_LOW_PWR_SUPPORTED = ['SSTL135']
def main():
@ -61,18 +62,36 @@ def main():
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']
if skip_broken_tiles(d):
continue
if site in diff_pairs:
continue
iostandard = verilog.unquote(d['IOSTANDARD'])
if iostandard.startswith('DIFF_'):
iostandard = iostandard[5:]
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'])
if d['type'] is None:
segmk.add_site_tag(site, 'INOUT', 0)
segmk.add_site_tag(site, '{}.IN_USE'.format(iostandard), 0)
@ -83,13 +102,43 @@ def main():
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(site, '{}.OUT'.format(iostandard), 0)
segmk.add_site_tag(site, '{}.IN_ONLY'.format(iostandard), 1)
segmk.add_tile_tag(d['tile'], 'IN_DIFF', 1)
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)
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)
segmk.add_tile_tag(d['tile'], 'OUT_TDIFF', 1)
elif d['type'] == 'IOBUF_INTERMDISABLE':
segmk.add_site_tag(site, 'INOUT', 1)
segmk.add_site_tag(site, '{}.IN_USE'.format(iostandard), 1)
@ -102,7 +151,7 @@ def main():
("NONE", "KEEPER", "PULLDOWN", "PULLUP"), "PULLDOWN",
verilog.unquote(d['PULLTYPE']))
if d['type'] == 'IBUF' or d['type'] is None:
if d['type'] in [None, 'IBUF', 'IBUFDS']:
continue
drive_opts = set()

View File

@ -44,6 +44,7 @@ proc loc_pins {} {
set drive [lindex $line 4]
set slew [lindex $line 5]
set pulltype [lindex $line 6]
set in_term [lindex $line 7]
# Have: site
# Want: pin for site
@ -69,6 +70,10 @@ proc loc_pins {} {
lappend props SLEW $slew
}
if {$in_term != "None"} {
lappend props IN_TERM $in_term
}
puts $props
set_property -dict "$props" $port

View File

@ -21,7 +21,7 @@ def get_site(l):
def parse_bits(l):
parts = l.strip().split(' ')
if parts[1] == '<0':
if parts[1] in ['<0', '<const0>']:
return frozenset()
else:
return frozenset(parts[1:])
@ -93,7 +93,8 @@ def main():
if group in ['DRIVE', 'SLEW']:
enum = feature_parts[4]
sites[site][group][(iostandard, enum)] = bits
elif group in ['IN', 'IN_ONLY', 'IN_USE', 'OUT', 'STEPDOWN']:
elif group in ['IN', 'IN_DIFF', 'IN_ONLY', 'IN_USE', 'OUT',
'STEPDOWN']:
sites[site][group][(iostandard, None)] = bits
else:
assert False, group
@ -124,6 +125,9 @@ def main():
common_bits[(site, 'IN_ONLY')] |= common_bits[(site, 'DRIVE')]
common_bits[(site, 'IN_ONLY')] -= common_bits[(site, 'STEPDOWN')]
common_bits[(site, 'IN')] |= common_bits[(site, 'IN_DIFF')]
common_bits[(site, 'IN_DIFF')] |= common_bits[(site, 'IN')]
for iostandard, enum in sites[site]['DRIVE']:
slew_in_drive = common_bits[
(site, 'SLEW')] & sites[site]['DRIVE'][(iostandard, enum)]
@ -142,10 +146,22 @@ def main():
sites[site]['SLEW'][(iostandard,
enum)] |= slew_in_drives[(site, iostandard)]
for site in sites:
for iostandard, enum in sites[site]['DRIVE']:
sites[site]['DRIVE'][(iostandard, enum)] |= sites[site]['IN_USE'][(
iostandard, None)]
for iostandard, enum in sites[site]['IN']:
if sites[site]['IN_DIFF'][(iostandard, enum)]:
sites[site]['IN_DIFF'][(iostandard, enum)] |= \
sites[site]['IN'][(iostandard, enum)]
for site in sites:
del sites[site]['OUT']
del sites[site]['IN_USE']
allow_zero = ['SLEW']
for site in sites:
for group in sites[site]:
common_groups = {}
@ -184,6 +200,9 @@ def main():
group=group,
)
if not bits and group not in allow_zero:
continue
neg_bits = frozenset(
'!{}'.format(b)
for b in (common_bits[(site, group)] - bits))

View File

@ -22,9 +22,13 @@ def gen_sites():
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']:
yield tile_name, site_name
sites[site_type] = site_name
if sites:
yield tile_name, sites
def write_params(params):
@ -53,6 +57,24 @@ def run():
'LVTTL',
'SSTL135',
]
diff_map = {
"SSTL135": ["DIFF_SSTL135"],
}
IN_TERM_ALLOWED = [
'SSTL15',
'SSTL15_R',
'SSTL18',
'SSTL18_R',
'SSTL135',
'SSTL135_R',
'HSTL_I'
'HSTL_I_18'
'HSTL_II',
'HSTL_II_18',
]
iostandard = random.choice(iostandards)
if iostandard in ['LVTTL', 'LVCMOS18']:
@ -93,70 +115,151 @@ def run():
))
any_idelay = False
for tile, site in gen_sites():
p = {}
p['tile'] = tile
p['site'] = site
p['type'] = random.choice(tile_types)
p['IOSTANDARD'] = verilog.quote(iostandard)
p['PULLTYPE'] = verilog.quote(random.choice(pulls))
for tile, sites in gen_sites():
site_bels = {}
for site_type in sites:
if site_type.endswith('M'):
if iostandard in diff_map:
site_bels[site_type] = random.choice(
tile_types + ['IBUFDS', 'OBUFDS', 'OBUFTDS'])
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 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']:
if is_m_diff:
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'):
iostandard_site = random.choice(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()
else:
any_idelay = True
p['owire'] = 'idelay_{site}'.format(**p)
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
p['DRIVE'] = None
p['SLEW'] = None
p['IBUF_LOW_PWR'] = random.randint(0, 1)
if 'DRIVE' in p:
if p['DRIVE'] is not None:
p['DRIVE_STR'] = '.DRIVE({}),'.format(p['DRIVE'])
else:
p['DRIVE_STR'] = ''
i_idx += 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'] == '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 p['type'] is not None:
tile_params.append(
(
tile, site, p['pad_wire'], iostandard, p['DRIVE'],
verilog.unquote(p['SLEW']) if p['SLEW'] else None,
verilog.unquote(p['PULLTYPE'])))
params['tiles'].append(p)
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)
@ -209,6 +312,31 @@ module top(input wire [`N_DI-1:0] di, output wire [`N_DO-1:0] do, inout wire [`N
);""".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(
'''
@ -217,11 +345,40 @@ module top(input wire [`N_DI-1:0] di, output wire [`N_DO-1:0] do, inout wire [`N
.IOSTANDARD({IOSTANDARD}),
{DRIVE_STR}
.SLEW({SLEW})
) ibuf_{site} (
) obuf_{site} (
.O({pad_wire}),
.I({iwire})
);'''.format(**p),
file=connects)
elif p['type'] == 'OBUFDS':
print(
'''
(* KEEP, DONT_TOUCH *)
OBUFDS #(
.IOSTANDARD({IOSTANDARD}),
{DRIVE_STR}
.SLEW({SLEW})
) obufds_{site} (
.O({pad_wire}),
.OB({bpad_wire}),
.I({iwire})
);'''.format(**p),
file=connects)
elif p['type'] == 'OBUFTDS':
print(
'''
(* KEEP, DONT_TOUCH *)
OBUFTDS #(
.IOSTANDARD({IOSTANDARD}),
{DRIVE_STR}
.SLEW({SLEW})
) obufds_{site} (
.O({pad_wire}),
.OB({bpad_wire}),
.T({tristate_wire}),
.I({iwire})
);'''.format(**p),
file=connects)
elif p['type'] == 'IOBUF_INTERMDISABLE':
print(
'''