Refactor IOB fuzzer.

- Add SSTL135
 - Refactor process_rdb to handle varying SLEW by IOSTANDARD.

Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com>
This commit is contained in:
Keith Rothman 2019-07-23 08:35:00 -07:00
parent ae526981a2
commit aa331131f2
7 changed files with 217 additions and 145 deletions

View File

@ -1,10 +1,15 @@
N := 50
SPECIMENS_DEPS := build/iobanks.txt
include ../fuzzer.mk
database: build/segbits_xiob33.db
build/iobanks.txt: write_io_banks.tcl
mkdir -p build
cd build/ && ${XRAY_VIVADO} -mode batch -source ${FUZDIR}/write_io_banks.tcl
build/segbits_xiob33.rdb: $(SPECIMENS_OK)
${XRAY_SEGMATCH} -c 7 -o build/segbits_xiob33.rdb $$(find -name segdata_liob33.txt) $$(find -name segdata_riob33.txt)
${XRAY_SEGMATCH} -c 12 -o build/segbits_xiob33.rdb $$(find -name segdata_liob33.txt) $$(find -name segdata_riob33.txt)
build/segbits_xiob33.db: build/segbits_xiob33.rdb process_rdb.py bits.dbf
python3 process_rdb.py build/segbits_xiob33.rdb > build/segbits_xiob33_processed.rdb

View File

@ -1,4 +1,4 @@
38_92 39_93 38_94,IOB33.IOB_Y0.PULLTYPE.PULLDOWN
38_106 38_110 39_105 39_109,IOB33.IOB_Y0.SLEW.FAST
38_106 39_107 39_111 38_106 38_110 39_105 39_109,IOB33.IOB_Y0.SLEW.FAST
39_33 38_34 39_35,IOB33.IOB_Y1.PULLTYPE.PULLDOWN
38_18 38_22 39_17 39_21,IOB33.IOB_Y1.SLEW.FAST
39_21 38_16 38_20 38_18 38_22 39_17,IOB33.IOB_Y1.SLEW.FAST

View File

@ -24,11 +24,11 @@ def process_parts(parts):
if parts[0] == 'INOUT':
yield 'type', 'IOBUF_INTERMDISABLE'
if parts[0] == 'IN_ONLY':
if parts[-1] == 'IN_ONLY':
yield 'type', 'IBUF'
if parts[0] == 'SLEW':
yield 'SLEW', verilog.quote(parts[1])
if len(parts) > 2 and parts[-2] == 'SLEW':
yield 'SLEW', verilog.quote(parts[-1])
if parts[0] == 'PULLTYPE':
yield 'PULLTYPE', verilog.quote(parts[1])
@ -38,7 +38,11 @@ def process_parts(parts):
if len(parts) > 1 and parts[1] == 'DRIVE':
yield 'IOSTANDARDS', parts[0].split('_')
yield 'DRIVES', parts[2].split('_')
if parts[2] == 'I_FIXED':
yield 'DRIVES', [None]
else:
yield 'DRIVES', parts[2].split('_')
def create_sites_from_fasm(root):
@ -67,7 +71,7 @@ def create_sites_from_fasm(root):
sites[key]['type'] = None
else:
assert 'IOSTANDARDS' in sites[key], sites[key]
assert 'DRIVES' in sites[key]
assert 'DRIVES' in sites[key], sites[key]
sites[key]['type'] = "OBUF"
return sites
@ -76,10 +80,10 @@ def create_sites_from_fasm(root):
def process_specimen(root):
sites = create_sites_from_fasm(root)
with open(os.path.join(root, 'params.jl')) as f:
with open(os.path.join(root, 'params.json')) as f:
params = json.load(f)
for p in params:
for p in params['tiles']:
tile = p['tile']
site = p['site']
site_y = int(site[site.find('Y') + 1:]) % 2
@ -96,7 +100,7 @@ def process_specimen(root):
site_from_fasm = sites[(tile, site_key)]
assert p['type'] == site_from_fasm['type'], (
tile, site_key, p, site_from_fasm)
tile, site_key, p['type'], site_from_fasm['type'])
if p['type'] is None:
continue
@ -104,16 +108,28 @@ def process_specimen(root):
assert p['PULLTYPE'] == site_from_fasm['PULLTYPE'], (
tile, site_key, p, site_from_fasm)
assert 'IOSTANDARDS' in site_from_fasm, (root, tile, site)
assert verilog.unquote(
p['IOSTANDARD']) in site_from_fasm['IOSTANDARDS'], (
tile, site_key, p, site_from_fasm)
p['IOSTANDARD'],
site_from_fasm['IOSTANDARDS'],
)
if p['type'] != 'IBUF':
assert p['SLEW'] == site_from_fasm['SLEW'], (
tile, site_key, p, site_from_fasm)
assert 'I{}'.format(p['DRIVE']) in site_from_fasm['DRIVES'], (
tile, site_key, p, site_from_fasm)
assert 'DRIVES' not in p, p
assert 'DRIVES' in site_from_fasm, (
tile, site, p['type'], site_from_fasm)
if p['DRIVE'] is None:
assert None in site_from_fasm['DRIVES'], (
tile, site_key, p['DRIVE'], site_from_fasm['DRIVES'])
else:
assert 'I{}'.format(p['DRIVE']) in site_from_fasm['DRIVES'], (
tile, site_key, p['DRIVE'], site_from_fasm['DRIVES'])
def main():

View File

@ -15,6 +15,8 @@ def bitfilter(frame, word):
def mk_drive_opt(iostandard, drive):
if drive is None:
drive = '_FIXED'
return '{}.DRIVE.I{}'.format(iostandard, drive)
@ -37,13 +39,15 @@ def drives_for_iostandard(iostandard):
drives = [4, 8, 12, 16, 24]
elif iostandard == 'LVCMOS12':
drives = [4, 8, 12]
elif iostandard == 'SSTL135':
return ['_FIXED']
else:
drives = [4, 8, 12, 16]
return drives
STEPDOWN_IOSTANDARDS = ['LVCMOS12', 'LVCMOS15', 'LVCMOS18']
STEPDOWN_IOSTANDARDS = ['LVCMOS12', 'LVCMOS15', 'LVCMOS18', 'SSTL135']
def main():
@ -54,10 +58,10 @@ def main():
di[0],IOB_X0Y107,LIOB33_X0Y107,A21,PULLDOWN
di[10],IOB_X0Y147,LIOB33_X0Y147,F14,PULLUP
'''
with open('params.jl', 'r') as f:
with open('params.json', 'r') as f:
design = json.load(f)
for d in design:
for d in design['tiles']:
site = d['site']
if skip_broken_tiles(d):
@ -65,44 +69,31 @@ def main():
iostandard = verilog.unquote(d['IOSTANDARD'])
stepdown = iostandard in STEPDOWN_IOSTANDARDS
segmk.add_site_tag(site, '_'.join(STEPDOWN_IOSTANDARDS), stepdown)
segmk.add_site_tag(
site, '_'.join(STEPDOWN_IOSTANDARDS) + '.STEPDOWN',
iostandard in STEPDOWN_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)
for drive in drives_for_iostandard(iostandard):
segmk.add_site_tag(
site, '{}.DRIVE.I{}.IN_OUT_COMMON'.format(
iostandard, drive), 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, '{}.OUT'.format(iostandard), 0)
for drive in drives_for_iostandard(iostandard):
segmk.add_site_tag(
site, '{}.DRIVE.I{}.IN_OUT_COMMON'.format(
iostandard, drive), 1)
segmk.add_site_tag(site, '{}.IN_ONLY'.format(iostandard), 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)
for drive in drives_for_iostandard(iostandard):
if drive == d['DRIVE']:
segmk.add_site_tag(
site, '{}.DRIVE.I{}.IN_OUT_COMMON'.format(
iostandard, drive), 1)
else:
segmk.add_site_tag(
site, '{}.DRIVE.I{}.IN_OUT_COMMON'.format(
iostandard, drive), 0)
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:
@ -126,13 +117,16 @@ def main():
drive_opts.add(mk_drive_opt(opt, drive_opt))
drive_opts.add(mk_drive_opt("SSTL135", None))
segmaker.add_site_group_zero(
segmk, site, '', drive_opts, mk_drive_opt('LVCMOS25', '12'),
mk_drive_opt(iostandard, d['DRIVE']))
segmaker.add_site_group_zero(
segmk, site, "SLEW.", ("SLOW", "FAST"), "FAST",
verilog.unquote(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(

View File

@ -75,12 +75,25 @@ proc loc_pins {} {
}
}
proc set_vref {} {
set fp [open "iobank_vref.csv" r]
for {gets $fp line} {$line != ""} {gets $fp line} {
set parts [split $line ","]
set iobank [lindex $parts 0]
set vref [lindex $parts 1]
puts "setting $iobank ([get_iobanks $iobank]) to INTERNAL_VREF $vref"
set_property INTERNAL_VREF $vref [get_iobanks $iobank]
}
}
proc run {} {
create_project -force -part $::env(XRAY_PART) design design
read_verilog top.v
synth_design -top top
loc_pins
set_vref
set_property CFGBVS VCCO [current_design]
set_property CONFIG_VOLTAGE 3.3 [current_design]

View File

@ -66,127 +66,129 @@ def main():
iostandard_lines = []
with open(args.input_rdb) as f:
for l in f:
if ('.LVCMOS' in l or '.LVTTL' in l) and 'IOB_' in l:
if ('.SSTL135' in l or '.LVCMOS' in l
or '.LVTTL' in l) and 'IOB_' in l:
iostandard_lines.append(l)
else:
print(l.strip())
common_in_only_bits = {
'IOB_Y0': set(),
'IOB_Y1': set(),
}
for l in iostandard_lines:
if 'IN_OUT_COMMON' in l:
common_in_only_bits[get_site(l)] |= parse_bits(l)
for site in sorted(common_in_only_bits):
print(
'IOB33.{}.IN_ONLY'.format(site), ' '.join(
common_in_only_bits[site]))
iostandard_in = {}
outs = {}
drives = {}
in_use = {}
sites = {}
for l in iostandard_lines:
name = get_name(l)
feature = get_name(l)
feature_parts = feature.split('.')
site = get_site(l)
iostandard = name.split('.')[2]
iostandard = feature_parts[2]
if name.endswith('.IN_USE'):
in_use[(site, iostandard)] = parse_bits(l)
bits = parse_bits(l)
bits = filter_bits(site, bits)
for l in iostandard_lines:
name = get_name(l)
site = get_site(l)
iostandard = name.split('.')[2]
if site not in sites:
sites[site] = {}
if name.endswith('.IN'):
in_bits = parse_bits(l) | in_use[(site, iostandard)]
group = feature_parts[3]
if group not in sites[site]:
sites[site][group] = {}
if in_bits not in iostandard_in:
iostandard_in[in_bits] = []
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']:
sites[site][group][(iostandard, None)] = bits
else:
assert False, group
iostandard_in[in_bits].append((site, iostandard))
for site in sites:
for iostandard, enum in sites[site]['DRIVE']:
sites[site]['DRIVE'][(iostandard, enum)] |= sites[site]['OUT'][(
iostandard, None)]
if name.endswith('.OUT'):
outs[(site,
iostandard)] = parse_bits(l) | in_use[(site, iostandard)]
if '.DRIVE.' in name and '.IN_OUT_COMMON' not in name:
drive = name.split('.')[-1]
if (site, iostandard) not in drives:
drives[(site, iostandard)] = {}
if drive not in drives[(site, iostandard)]:
drives[(site, iostandard)][drive] = {}
drives[(site, iostandard)][drive] = filter_bits(
site, parse_bits(l))
common_in_bits = {
'IOB_Y0': set(),
'IOB_Y1': set(),
}
for bits in sorted(iostandard_in.keys()):
sites, standards = zip(*iostandard_in[bits])
site = set(sites)
assert len(site) == 1, site
site = site.pop()
common_in_bits[site] |= bits
for bits in sorted(iostandard_in.keys()):
sites, standards = zip(*iostandard_in[bits])
site = set(sites)
assert len(site) == 1, site
site = site.pop()
neg_bits = set('!' + bit for bit in (common_in_bits[site] - bits))
print(
'IOB33.{}.{}.IN'.format(site, '_'.join(standards)),
' '.join(bits | neg_bits))
iodrives = {}
for iostandard, enum in sites[site]['IN']:
sites[site]['IN_ONLY'][(iostandard, enum)] -= sites[site]['IN'][(
iostandard, enum)]
common_bits = {}
for site in sites:
for group in sites[site]:
if (site, group) not in common_bits:
common_bits[(site, group)] = set()
for site, iostandard in drives:
for drive in drives[(site, iostandard)]:
combined_bits = drives[(site, iostandard)][drive] | outs[(
site, iostandard)]
for bits in sites[site][group].values():
common_bits[(site, group)] |= bits
if site not in common_bits:
common_bits[site] = set(common_in_only_bits[site])
slew_in_drives = {}
common_bits[site] |= combined_bits
for site in sites:
common_bits[(site, 'DRIVE')] -= common_bits[(site, 'SLEW')]
common_bits[(site, 'DRIVE')] -= common_bits[(site, 'STEPDOWN')]
common_bits[(site, 'IN_ONLY')] |= common_bits[(site, 'DRIVE')]
common_bits[(site, 'IN_ONLY')] -= common_bits[(site, 'STEPDOWN')]
if combined_bits not in iodrives:
iodrives[combined_bits] = []
for iostandard, enum in sites[site]['DRIVE']:
slew_in_drive = common_bits[
(site, 'SLEW')] & sites[site]['DRIVE'][(iostandard, enum)]
if slew_in_drive:
if (site, iostandard) not in slew_in_drives:
slew_in_drives[(site, iostandard)] = set()
iodrives[combined_bits].append((site, iostandard, drive))
slew_in_drives[(site, iostandard)] |= slew_in_drive
sites[site]['DRIVE'][(iostandard, enum)] -= slew_in_drive
for bits in iodrives:
sites, standards, drives = zip(*iodrives[bits])
sites[site]['DRIVE'][(iostandard,
enum)] -= common_bits[(site, 'STEPDOWN')]
site = set(sites)
for site, iostandard in slew_in_drives:
for _, enum in sites[site]['SLEW']:
sites[site]['SLEW'][(iostandard,
enum)] |= slew_in_drives[(site, iostandard)]
assert len(site) == 1, site
site = site.pop()
for site in sites:
del sites[site]['OUT']
del sites[site]['IN_USE']
neg_bits = set('!' + bit for bit in (common_bits[site] - bits))
for site in sites:
for group in sites[site]:
common_groups = {}
print(
'IOB33.{}.{}.DRIVE.{}'.format(
site, '_'.join(sorted(set(standards))), '_'.join(
sorted(set(drives)))), ' '.join(bits | neg_bits))
# Merge features that are identical.
#
# For example:
#
# IOB33.IOB_Y1.LVCMOS15.IN 38_42 39_41
# IOB33.IOB_Y1.LVCMOS18.IN 38_42 39_41
#
# Must be grouped.
for (iostandard, enum), bits in sites[site][group].items():
if bits not in common_groups:
common_groups[bits] = {
'IOSTANDARDS': set(),
'enums': set(),
}
common_groups[bits]['IOSTANDARDS'].add(iostandard)
if enum is not None:
common_groups[bits]['enums'].add(enum)
for bits, v in common_groups.items():
if v['enums']:
feature = 'IOB33.{site}.{iostandards}.{group}.{enums}'.format(
site=site,
iostandards='_'.join(sorted(v['IOSTANDARDS'])),
group=group,
enums='_'.join(sorted(v['enums'])),
)
else:
feature = 'IOB33.{site}.{iostandards}.{group}'.format(
site=site,
iostandards='_'.join(sorted(v['IOSTANDARDS'])),
group=group,
)
neg_bits = frozenset(
'!{}'.format(b)
for b in (common_bits[(site, group)] - bits))
print(
'{} {}'.format(feature, ' '.join(sorted(bits | neg_bits))))
if __name__ == "__main__":

View File

@ -45,14 +45,22 @@ def run():
io_idx = 0
iostandards = [
'LVCMOS12', 'LVCMOS15', 'LVCMOS18', 'LVCMOS25', 'LVCMOS33', 'LVTTL'
'LVCMOS12',
'LVCMOS15',
'LVCMOS18',
'LVCMOS25',
'LVCMOS33',
'LVTTL',
'SSTL135',
]
iostandard = random.choice(iostandards)
if iostandard in ['LVTTL', 'LVCMOS18']:
drives = [4, 8, 12, 16, 24]
elif iostandard == 'LVCMOS12':
elif iostandard in ['LVCMOS12']:
drives = [4, 8, 12]
elif iostandard == 'SSTL135':
drives = None
else:
drives = [4, 8, 12, 16]
@ -64,7 +72,26 @@ def run():
connects = io.StringIO()
tile_params = []
params = []
params = {
"tiles": [],
'INTERNAL_VREF': {},
}
with open(os.path.join(os.getenv('FUZDIR'), 'build', 'iobanks.txt')) as f:
iobanks = [int(l.strip()) for l in f]
params['iobanks'] = iobanks
if iostandard in ['SSTL135']:
for iobank in iobanks:
params['INTERNAL_VREF'][iobank] = random.choice(
(
.600,
.675,
.75,
.90,
))
any_idelay = False
for tile, site in gen_sites():
p = {}
@ -93,7 +120,10 @@ def run():
elif p['type'] == 'OBUF':
p['pad_wire'] = 'do[{}]'.format(o_idx)
p['iwire'] = luts.get_next_output_net()
p['DRIVE'] = random.choice(drives)
if drives is not None:
p['DRIVE'] = random.choice(drives)
else:
p['DRIVE'] = None
p['SLEW'] = verilog.quote(random.choice(slews))
o_idx += 1
@ -101,7 +131,10 @@ def run():
p['pad_wire'] = 'dio[{}]'.format(io_idx)
p['iwire'] = luts.get_next_output_net()
p['owire'] = luts.get_next_input_net()
p['DRIVE'] = random.choice(drives)
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()))
@ -111,7 +144,11 @@ def run():
('0', luts.get_next_output_net()))
io_idx += 1
params.append(p)
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(
@ -119,9 +156,14 @@ def run():
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)
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}
@ -141,7 +183,7 @@ module top(input wire [`N_DI-1:0] di, output wire [`N_DO-1:0] do, inout wire [`N
(* KEEP, DONT_TOUCH *)
LUT6 dummy_lut();''')
for p in params:
for p in params['tiles']:
if p['type'] is None:
continue
elif p['type'] == 'IBUF':
@ -173,7 +215,7 @@ module top(input wire [`N_DI-1:0] di, output wire [`N_DO-1:0] do, inout wire [`N
(* KEEP, DONT_TOUCH *)
OBUF #(
.IOSTANDARD({IOSTANDARD}),
.DRIVE({DRIVE}),
{DRIVE_STR}
.SLEW({SLEW})
) ibuf_{site} (
.O({pad_wire}),
@ -186,7 +228,7 @@ module top(input wire [`N_DI-1:0] di, output wire [`N_DO-1:0] do, inout wire [`N
(* KEEP, DONT_TOUCH *)
IOBUF_INTERMDISABLE #(
.IOSTANDARD({IOSTANDARD}),
.DRIVE({DRIVE}),
{DRIVE_STR}
.SLEW({SLEW})
) ibuf_{site} (
.IO({pad_wire}),
@ -205,7 +247,7 @@ module top(input wire [`N_DI-1:0] di, output wire [`N_DO-1:0] do, inout wire [`N
print("endmodule")
with open('params.jl', 'w') as f:
with open('params.json', 'w') as f:
json.dump(params, f, indent=2)