From 816bf4415613baa3cf1ca69c9622a39fba2decdb Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Thu, 28 Feb 2019 16:36:02 -0800 Subject: [PATCH] Rework IOB fuzzers. - Add most single ended IOSTANDARD's. - Add bits for input, output and input/output buffers for single ended IOBs. - Add initial ILOGIC fuzzer. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- fuzzers/030-iob/Makefile | 33 +- fuzzers/030-iob/bits.dbf | 16 +- fuzzers/030-iob/check_results.py | 125 ++++++ fuzzers/030-iob/generate.py | 159 +++++-- fuzzers/030-iob/generate.sh | 5 - fuzzers/030-iob/generate.tcl | 54 +-- fuzzers/030-iob/process_rdb.py | 138 ++++++ fuzzers/030-iob/top.py | 244 ++++++---- fuzzers/034-iob-stag/Makefile | 20 - fuzzers/034-iob-stag/generate.py | 18 - fuzzers/034-iob-stag/generate.sh | 5 - fuzzers/034-iob-stag/groups.grp | 1 - fuzzers/034-iob-stag/top.py | 152 ------- fuzzers/035-iob-ilogic/Makefile | 20 + fuzzers/035-iob-ilogic/bits.dbf | 0 fuzzers/035-iob-ilogic/generate.py | 171 +++++++ .../generate.tcl | 51 ++- fuzzers/035-iob-ilogic/top.py | 420 ++++++++++++++++++ fuzzers/Makefile | 2 + prjxray/segmaker.py | 4 + utils/mergedb.sh | 5 +- 21 files changed, 1219 insertions(+), 424 deletions(-) create mode 100644 fuzzers/030-iob/check_results.py delete mode 100644 fuzzers/030-iob/generate.sh create mode 100644 fuzzers/030-iob/process_rdb.py delete mode 100644 fuzzers/034-iob-stag/Makefile delete mode 100644 fuzzers/034-iob-stag/generate.py delete mode 100644 fuzzers/034-iob-stag/generate.sh delete mode 100644 fuzzers/034-iob-stag/groups.grp delete mode 100644 fuzzers/034-iob-stag/top.py create mode 100644 fuzzers/035-iob-ilogic/Makefile create mode 100644 fuzzers/035-iob-ilogic/bits.dbf create mode 100644 fuzzers/035-iob-ilogic/generate.py rename fuzzers/{034-iob-stag => 035-iob-ilogic}/generate.tcl (67%) create mode 100644 fuzzers/035-iob-ilogic/top.py diff --git a/fuzzers/030-iob/Makefile b/fuzzers/030-iob/Makefile index c36191bd..f7559d28 100644 --- a/fuzzers/030-iob/Makefile +++ b/fuzzers/030-iob/Makefile @@ -1,30 +1,21 @@ -N := 1 +N := 50 include ../fuzzer.mk -SEGDATAS_L=$(addsuffix /segdata_liob33.txt,$(SPECIMENS)) -SEGDATAS_R=$(addsuffix /segdata_riob33.txt,$(SPECIMENS)) +database: build/segbits_xiob33.db -database: build/segbits_liob33.db build/segbits_riob33.db +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) -build/segbits_liob33.rdb: $(SPECIMENS_OK) - ${XRAY_SEGMATCH} -o build/segbits_liob33.rdb $(SEGDATAS_L) - -build/segbits_liob33.db: build/segbits_liob33.rdb - ${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf --seg-fn-in $^ --seg-fn-out $@ - ${XRAY_MASKMERGE} build/mask_liob33.db $(SEGDATAS_L) - -build/segbits_riob33.rdb: $(SPECIMENS_OK) - ${XRAY_SEGMATCH} -o build/segbits_riob33.rdb $(SEGDATAS_R) - -build/segbits_riob33.db: build/segbits_riob33.rdb - ${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf --seg-fn-in $^ --seg-fn-out $@ - ${XRAY_MASKMERGE} build/mask_riob33.db $(SEGDATAS_R) +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 + ${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf --seg-fn-in build/segbits_xiob33_processed.rdb --seg-fn-out $@ + ${XRAY_MASKMERGE} build/mask_xiob33.db $$(find -name segdata_liob33.txt) $$(find -name segdata_riob33.txt) pushdb: - ${XRAY_MERGEDB} liob33 build/segbits_liob33.db - ${XRAY_MERGEDB} riob33 build/segbits_riob33.db - ${XRAY_MERGEDB} mask_liob33 build/mask_liob33.db - ${XRAY_MERGEDB} mask_riob33 build/mask_riob33.db + ${XRAY_MERGEDB} liob33 build/segbits_xiob33.db + ${XRAY_MERGEDB} riob33 build/segbits_xiob33.db + ${XRAY_MERGEDB} mask_liob33 build/mask_xiob33.db + ${XRAY_MERGEDB} mask_riob33 build/mask_xiob33.db .PHONY: database pushdb diff --git a/fuzzers/030-iob/bits.dbf b/fuzzers/030-iob/bits.dbf index a2219bfd..c0eca9c9 100644 --- a/fuzzers/030-iob/bits.dbf +++ b/fuzzers/030-iob/bits.dbf @@ -1,12 +1,4 @@ -38_92 39_93 38_94,LIOB33.IOB_Y0.PULLTYPE.PULLDOWN -38_118 38_126 39_117 39_119 39_125 39_127,LIOB33.IOB_Y0.LVCMOS25.DRIVE.12 -38_106 38_110 39_105 39_109,LIOB33.IOB_Y0.SLEW.FAST -39_33 38_34 39_35,LIOB33.IOB_Y1.PULLTYPE.PULLDOWN -38_00 38_02 38_08 38_10 39_01 39_09,LIOB33.IOB_Y1.LVCMOS25.DRIVE.12 -38_18 38_22 39_17 39_21,LIOB33.IOB_Y1.SLEW.FAST -38_92 39_93 38_94,RIOB33.IOB_Y0.PULLTYPE.PULLDOWN -38_118 38_126 39_117 39_119 39_125 39_127,RIOB33.IOB_Y0.LVCMOS25.DRIVE.12 -38_106 38_110 39_105 39_109,RIOB33.IOB_Y0.SLEW.FAST -39_33 38_34 39_35,RIOB33.IOB_Y1.PULLTYPE.PULLDOWN -38_00 38_02 38_08 38_10 39_01 39_09,RIOB33.IOB_Y1.LVCMOS25.DRIVE.12 -38_18 38_22 39_17 39_21,RIOB33.IOB_Y1.SLEW.FAST +38_92 39_93 38_94,IOB33.IOB_Y0.PULLTYPE.PULLDOWN +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 diff --git a/fuzzers/030-iob/check_results.py b/fuzzers/030-iob/check_results.py new file mode 100644 index 00000000..2369e628 --- /dev/null +++ b/fuzzers/030-iob/check_results.py @@ -0,0 +1,125 @@ +""" Sanity checks FASM output from IOB fuzzer. + +The IOB fuzzer is fairly complicated, and it's output is hard to verify by +inspected. For this reason, check_results.py was written to compare the +specimen's generated and their FASM output. The FASM output does pose a +chicken and egg issue. The test procedure is a follows: + +1. Build the database (e.g. make -j run) +2. Build the database again (e.g. make -j run) +3. Run check_results.py + +The second time that the database is run, the FASM files in the specimen's +will have the bits documented by fuzzer. + +""" +import os +import os.path +from prjxray import verilog +import json +import generate + +def process_parts(parts): + if parts[0] == 'INOUT': + yield 'type', 'IOBUF_INTERMDISABLE' + + if parts[0] == 'IN_ONLY': + yield 'type', 'IBUF' + + if parts[0] == 'SLEW': + yield 'SLEW', verilog.quote(parts[1]) + + if parts[0] == 'PULLTYPE': + yield 'PULLTYPE', verilog.quote(parts[1]) + + if len(parts) > 1 and parts[1] == 'IN': + yield 'IOSTANDARDS', parts[0].split('_') + + if len(parts) > 1 and parts[1] == 'DRIVE': + yield 'IOSTANDARDS', parts[0].split('_') + yield 'DRIVES', parts[2].split('_') + +def create_sites_from_fasm(root): + sites = {} + + with open(os.path.join(root, 'design.fasm')) as f: + for l in f: + if 'IOB33' not in l: + continue + + parts = l.strip().split('.') + tile = parts[0] + site = parts[1] + if (tile, site) not in sites: + sites[(tile, site)] = { + 'tile': tile, + 'site_key': site, + } + + 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 + else: + assert 'IOSTANDARDS' in sites[key], sites[key] + assert 'DRIVES' in sites[key] + sites[key]['type'] = "OBUF" + + return sites + + +def process_specimen(root): + sites = create_sites_from_fasm(root) + + with open(os.path.join(root, 'params.jl')) as f: + params = json.load(f) + + for p in params: + tile = p['tile'] + site = p['site'] + site_y = int(site[site.find('Y')+1:]) % 2 + + if generate.skip_broken_tiles(p): + continue + + site_key = 'IOB_Y{}'.format(site_y) + + if (tile, site_key) not in sites: + assert p['type'] is None, p + continue + + site_from_fasm = sites[(tile, site_key)] + + assert p['type'] == site_from_fasm['type'], ( + tile, site_key, p, site_from_fasm) + + if p['type'] is None: + continue + + assert p['PULLTYPE'] == site_from_fasm['PULLTYPE'], ( + tile, site_key, p, site_from_fasm) + + assert verilog.unquote(p['IOSTANDARD']) in site_from_fasm['IOSTANDARDS'], ( + tile, site_key, p, site_from_fasm) + + 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) + + +def main(): + for root, dirs, files in os.walk('build'): + if os.path.basename(root).startswith('specimen_'): + print('Processing', os.path.basename(root)) + process_specimen(root) + + print('No errors found!') + +if __name__ == "__main__": + main() diff --git a/fuzzers/030-iob/generate.py b/fuzzers/030-iob/generate.py index bfda6d32..0fe9e9ca 100644 --- a/fuzzers/030-iob/generate.py +++ b/fuzzers/030-iob/generate.py @@ -2,48 +2,127 @@ from prjxray.segmaker import Segmaker from prjxray import segmaker +from prjxray import verilog +import os +import json -segmk = Segmaker("design.bits") -print("Loading tags") -''' -port,site,tile,pin,slew,drive,pulltype -di[0],IOB_X0Y107,LIOB33_X0Y107,A21,PULLDOWN -di[10],IOB_X0Y147,LIOB33_X0Y147,F14,PULLUP -''' -f = open('design.csv', 'r') -f.readline() -for l in f: - l = l.strip() - port, site, tile, pin, iostandard, slew, drive, pulltype = l.split(',') +def bitfilter(frame, word): + if frame < 26: + return False + + return True + +def mk_drive_opt(iostandard, drive): + return '{}.DRIVE.I{}'.format(iostandard, drive) + + +def skip_broken_tiles(d): + """ Skip tiles that appear to have bits always set. + + This is likely caused by a defect? + + """ + if os.getenv('XRAY_DATABASE') == 'artix7' and d['tile'] == 'LIOB33_X0Y43': + return True + + return False + +def drives_for_iostandard(iostandard): + if iostandard in ['LVTTL', 'LVCMOS18']: + drives = [4, 8, 12, 16, 24] + elif iostandard == 'LVCMOS12': + drives = [4, 8, 12] + else: + drives = [4, 8, 12, 16] + + return drives + +def main(): + print("Loading tags") + segmk = Segmaker("design.bits") ''' - LVCMOS25 - SLEW 38_82 38_86 39_81 39_85 - SLOW X X X X - FAST - - DRIVE 38_64 38_66 38_72 38_74 39_65 39_73 - 4 X X X - 8 X - 12 - 16 X X X - - PULLTYPE 28 29 30 - NONE X - KEEPER X X - PULLDOWN - PULLUP X X + port,site,tile,pin,slew,drive,pulltype + di[0],IOB_X0Y107,LIOB33_X0Y107,A21,PULLDOWN + di[10],IOB_X0Y147,LIOB33_X0Y147,F14,PULLUP ''' - if pulltype == "": - pulltype = "NONE" - segmaker.add_site_group_zero( - segmk, site, "PULLTYPE.", ("NONE", "KEEPER", "PULLDOWN", "PULLUP"), - "PULLDOWN", pulltype) + with open('params.jl', 'r') as f: + design = json.load(f) - segmaker.add_site_group_zero( - segmk, site, iostandard + ".DRIVE.", ("4", "8", "12", "16"), "12", - drive) - segmaker.add_site_group_zero( - segmk, site, "SLEW.", ("SLOW", "FAST"), "FAST", slew) -segmk.compile() -segmk.write() + for d in design: + site = d['site'] + + if skip_broken_tiles(d): + continue + + iostandard = verilog.unquote(d['IOSTANDARD']) + + 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) + 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) + 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, '{}.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'] == 'IBUF' or d['type'] is None: + 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)) + + 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'])) + + 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') + + segmk.compile(bitfilter=bitfilter) + segmk.write(allow_empty=True) + +if __name__ == "__main__": + main() diff --git a/fuzzers/030-iob/generate.sh b/fuzzers/030-iob/generate.sh deleted file mode 100644 index f42f840c..00000000 --- a/fuzzers/030-iob/generate.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -set -ex -source ${XRAY_DIR}/utils/top_generate.sh - diff --git a/fuzzers/030-iob/generate.tcl b/fuzzers/030-iob/generate.tcl index 262d98f0..8cae847b 100644 --- a/fuzzers/030-iob/generate.tcl +++ b/fuzzers/030-iob/generate.tcl @@ -19,6 +19,8 @@ proc load_pin_lines {} { # IOB_X0Y129 do[0] output set fp [open "params.csv" r] + gets $fp line + set pin_lines {} for {gets $fp line} {$line != ""} {gets $fp line} { lappend pin_lines [split $line ","] @@ -31,51 +33,46 @@ proc loc_pins {} { set pin_lines [load_pin_lines] set io_pin_sites [make_io_pin_sites] - set fp [open "design.csv" w] - puts $fp "port,site,tile,pin,iostandard,slew,drive,pulltype" - puts "Looping" for {set idx 0} {$idx < [llength $pin_lines]} {incr idx} { set line [lindex $pin_lines $idx] puts "$line" - set site_str [lindex $line 0] - set pin_str [lindex $line 1] - set io [lindex $line 2] - set cell_str [lindex $line 3] + set site_str [lindex $line 1] + set pin_str [lindex $line 2] + set iostandard [lindex $line 3] + set drive [lindex $line 4] + set slew [lindex $line 5] + set pulltype [lindex $line 6] # Have: site # Want: pin for site + set site [get_sites $site_str] set pad_bel [get_bels -of_objects $site -filter {TYPE =~ PAD && NAME =~ IOB_*}] # set port [get_ports -of_objects $site] set port [get_ports $pin_str] set tile [get_tiles -of_objects $site] + set pin [dict get $io_pin_sites $site] - set iostandard_val "LVCMOS25" - set_property -dict "PACKAGE_PIN $pin IOSTANDARD $iostandard_val" $port + set props {} + lappend props PACKAGE_PIN $pin + lappend props IOSTANDARD $iostandard + lappend props PULLTYPE $pulltype - set pulltype "NONE PULLUP PULLDOWN KEEPER" - set pulltype_val [randsample_list 1 $pulltype] - if { $pulltype_val == "NONE" } { - set pulltype_val "" + if {$drive != "None"} { + lappend props DRIVE $drive } - set_property PULLTYPE $pulltype_val $port - if {$io == "input"} continue + if {$slew != "None"} { + lappend props SLEW $slew + } - set drive "4 8 12 16" - set drive_val [lindex $drive [expr {$idx % 4}]] - set_property DRIVE $drive_val $port + puts $props - set slew "SLOW FAST" - set slew_val [lindex $slew [expr {($idx + ($idx / 4)) % 2}]] - set_property SLEW $slew_val $port - - puts $fp "$port,$site,$tile,$pin,$iostandard_val,$slew_val,$drive_val,$pulltype_val" + set_property -dict "$props" $port } - close $fp } proc run {} { @@ -83,17 +80,14 @@ proc run {} { read_verilog top.v synth_design -top top - # Mostly doesn't matter since IOB are special, but add anyway - create_pblock roi - add_cells_to_pblock [get_pblocks roi] [get_cells roi] - resize_pblock [get_pblocks roi] -add "$::env(XRAY_ROI)" - loc_pins set_property CFGBVS VCCO [current_design] set_property CONFIG_VOLTAGE 3.3 [current_design] set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design] - set_param tcl.collectionResultDisplayLimit 0 + set_property IS_ENABLED 0 [get_drc_checks {REQP-79}] + + write_checkpoint -force design_pre_place.dcp place_design route_design diff --git a/fuzzers/030-iob/process_rdb.py b/fuzzers/030-iob/process_rdb.py new file mode 100644 index 00000000..1ae5c2cc --- /dev/null +++ b/fuzzers/030-iob/process_rdb.py @@ -0,0 +1,138 @@ +""" IOB bits are more complicated than can be easily expressed to segmaker. + +There are couple cases that need to be handled here: + +- There are some bits that are always set for IN-only ports, but are cleared + selectively for OUT and INOUT ports. +- There are bits per each IOSTANDARD, in addition to drive patterns. These + can be merged to provide unique "(IOSTANDARD, DRIVE)" bit sets. +""" +import argparse + +def get_name(l): + parts = l.strip().split(' ') + return parts[0] + +def get_site(l): + return get_name(l).split('.')[1] + +def parse_bits(l): + parts = l.strip().split(' ') + if parts[1] == '<0': + return frozenset() + else: + return frozenset(parts[1:]) + +def main(): + parser = argparse.ArgumentParser(description="Convert IOB rdb into good rdb.""") + parser.add_argument('input_rdb') + + args = parser.parse_args() + + iostandard_lines = [] + with open(args.input_rdb) as f: + for l in f: + if '.LVCMOS' in l or '.LVTTL' in l: + iostandard_lines.append(l) + else: + print(l.strip()) + + common_in_bits = { + 'IOB_Y0': set(), + 'IOB_Y1': set(), + } + for l in iostandard_lines: + if 'IN_OUT_COMMON' in l: + common_in_bits[get_site(l)] |= parse_bits(l) + + for site in sorted(common_in_bits): + print('IOB33.{}.IN_ONLY'.format(site), ' '.join(common_in_bits[site])) + + iostandard_in = {} + outs = {} + drives = {} + in_use = {} + + + for l in iostandard_lines: + name = get_name(l) + site = get_site(l) + iostandard = name.split('.')[2] + + if name.endswith('.IN_USE'): + in_use[(site, iostandard)] = parse_bits(l) + + for l in iostandard_lines: + name = get_name(l) + site = get_site(l) + iostandard = name.split('.')[2] + + if name.endswith('.IN'): + in_bits = parse_bits(l) | in_use[(site, iostandard)] + + if in_bits not in iostandard_in: + iostandard_in[in_bits] = [] + + iostandard_in[in_bits].append((site, iostandard)) + + 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] = parse_bits(l) + + for bits in sorted(iostandard_in.keys()): + sites, standards = zip(*iostandard_in[bits]) + + site = set(sites) + + assert len(site) == 1, site + site = site.pop() + + print('IOB33.{}.{}.IN'.format(site, '_'.join(standards)), + ' '.join(bits)) + + iodrives = {} + + common_bits = {} + + for site, iostandard in drives: + for drive in drives[(site, iostandard)]: + combined_bits = drives[(site, iostandard)][drive] | outs[(site, iostandard)] + + if site not in common_bits: + common_bits[site] = set(common_in_bits[site]) + + common_bits[site] |= combined_bits + + + if combined_bits not in iodrives: + iodrives[combined_bits] = [] + + iodrives[combined_bits].append((site, iostandard, drive)) + + for bits in iodrives: + sites, standards, drives = zip(*iodrives[bits]) + + site = set(sites) + + assert len(site) == 1, site + site = site.pop() + + neg_bits = set('!' + bit for bit in (common_bits[site] - bits)) + + print('IOB33.{}.{}.DRIVE.{}'.format( + site, + '_'.join(sorted(set(standards))), + '_'.join(sorted(set(drives)))), ' '.join(bits | neg_bits)) + + +if __name__ == "__main__": + main() diff --git a/fuzzers/030-iob/top.py b/fuzzers/030-iob/top.py index cf95c3e8..9f3cc311 100644 --- a/fuzzers/030-iob/top.py +++ b/fuzzers/030-iob/top.py @@ -1,17 +1,15 @@ -''' -Generate a primitive to place at every I/O -Unlike CLB tests, the LFSR for this is inside the ROI, not driving it -''' - +import json +import io import os import random random.seed(int(os.getenv("SEED"), 16)) from prjxray import util +from prjxray import lut_maker from prjxray import verilog from prjxray.db import Database -def gen_iobs(): +def gen_sites(): ''' IOB33S: main IOB of a diff pair IOB33M: secondary IOB of a diff pair @@ -26,125 +24,175 @@ def gen_iobs(): for site_name, site_type in gridinfo.sites.items(): if site_type in ['IOB33S', 'IOB33M']: - yield site_name, site_type + yield tile_name, site_name +def write_params(params): + pinstr = 'tile,site,pin,iostandard,drive,slew\n' + for vals in params: + pinstr += ','.join(map(str, vals)) + '\n' -def write_pins(ports): - pinstr = '' - for site, (name, dir_, cell) in sorted(ports.items(), key=lambda x: x[1]): - # pinstr += 'set_property -dict "PACKAGE_PIN %s IOSTANDARD LVCMOS33" [get_ports %s]' % (packpin, port) - pinstr += '%s,%s,%s,%s\n' % (site, name, dir_, cell) open('params.csv', 'w').write(pinstr) def run(): - # All possible values - iosites = {} - for site_name, site_type in gen_iobs(): - iosites[site_name] = site_type + tile_types = ['IBUF', 'OBUF', 'IOBUF_INTERMDISABLE', None, None, None, None, None] - # Assigned in this design - ports = {} - DIN_N = 0 - DOUT_N = 0 + i_idx = 0 + o_idx = 0 + io_idx = 0 - def remain_sites(): - return set(iosites.keys()) - set(ports.keys()) + iostandards = ['LVCMOS12', 'LVCMOS15', 'LVCMOS18', 'LVCMOS25', 'LVCMOS33', 'LVTTL'] + iostandard = random.choice(iostandards) - def rand_site(): - '''Get a random, unused site''' - return random.choice(list(remain_sites())) + if iostandard in ['LVTTL', 'LVCMOS18']: + drives = [4, 8, 12, 16, 24] + elif iostandard == 'LVCMOS12': + drives = [4, 8, 12] + else: + drives = [4, 8, 12, 16] - def assign_i(site, name): - nonlocal DIN_N + slews = ['FAST', 'SLOW'] + pulls = ["NONE", "KEEPER", "PULLDOWN", "PULLUP"] - assert site not in ports - cell = "di_bufs[%u].ibuf" % DIN_N - DIN_N += 1 - ports[site] = (name, 'input', cell) + luts = lut_maker.LutMaker() - def assign_o(site, name): - nonlocal DOUT_N + connects = io.StringIO() - assert site not in ports - cell = "do_bufs[%u].obuf" % DOUT_N - DOUT_N += 1 - ports[site] = (name, 'output', cell) + tile_params = [] + params = [] + 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)) - # Assign at least one di and one do - assign_i(rand_site(), 'di[0]') - assign_o(rand_site(), 'do[0]') - # Now assign the rest randomly - while len(remain_sites()): - assign_o(rand_site(), 'do[%u]' % DOUT_N) + 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: + p['owire'] = 'idelay_{site}'.format(**p) - write_pins(ports) + p['DRIVE'] = None + p['SLEW'] = None + p['IBUF_LOW_PWR'] = random.randint(0, 1) + + i_idx += 1 + elif p['type'] == 'OBUF': + p['pad_wire'] = 'do[{}]'.format(o_idx) + p['iwire'] = luts.get_next_output_net() + p['DRIVE'] = random.choice(drives) + 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() + p['DRIVE'] = random.choice(drives) + 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 + + params.append(p) + + 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']))) + + write_params(tile_params) print( ''' -`define N_DI %u -`define N_DO %u +`define N_DI {n_di} +`define N_DO {n_do} +`define N_DIO {n_dio} -module top(input wire [`N_DI-1:0] di, output wire [`N_DO-1:0] do); - genvar i; +module top(input wire [`N_DI-1:0] di, output wire [`N_DO-1:0] do, inout wire [`N_DIO-1:0] dio); + (* KEEP, DONT_TOUCH *) + IDELAYCTRL(); + '''.format( + n_di=i_idx, + n_do=o_idx, + n_dio=io_idx)) - //Instantiate BUFs so we can LOC them + # Always output a LUT6 to make placer happy. + print(''' + (* KEEP, DONT_TOUCH *) + LUT6 dummy_lut();''') - wire [`N_DI-1:0] di_buf; - generate - for (i = 0; i < `N_DI; i = i+1) begin:di_bufs - IBUF ibuf(.I(di[i]), .O(di_buf[i])); - end - endgenerate + for p in params: + if p['type'] is None: + continue + elif p['type'] == 'IBUF': + print( + ''' + wire idelay_{site}; - wire [`N_DO-1:0] do_unbuf; - generate - for (i = 0; i < `N_DO; i = i+1) begin:do_bufs - OBUF obuf(.I(do_unbuf[i]), .O(do[i])); - end - endgenerate + (* KEEP, DONT_TOUCH *) + IBUF #( + .IBUF_LOW_PWR({IBUF_LOW_PWR}), + .IOSTANDARD({IOSTANDARD}) + ) ibuf_{site} ( + .I({pad_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) - roi roi(.di(di_buf), .do(do_unbuf)); -endmodule + elif p['type'] == 'OBUF': + print( + ''' + (* KEEP, DONT_TOUCH *) + OBUF #( + .IOSTANDARD({IOSTANDARD}), + .DRIVE({DRIVE}), + .SLEW({SLEW}) + ) ibuf_{site} ( + .O({pad_wire}), + .I({iwire}) + );'''.format(**p), file=connects) + elif p['type'] == 'IOBUF_INTERMDISABLE': + print( + ''' + (* KEEP, DONT_TOUCH *) + IOBUF_INTERMDISABLE #( + .IOSTANDARD({IOSTANDARD}), + .DRIVE({DRIVE}), + .SLEW({SLEW}) + ) ibuf_{site} ( + .IO({pad_wire}), + .I({iwire}), + .O({owire}), + .T({tristate_wire}), + .IBUFDISABLE({ibufdisable_wire}), + .INTERMDISABLE({intermdisable_wire}) + );'''.format(**p), file=connects) -//Arbitrary terminate into LUTs -module roi(input wire [`N_DI-1:0] di, output wire [`N_DO-1:0] do); - genvar i; + for l in luts.create_wires_and_luts(): + print(l) - generate - for (i = 0; i < `N_DI; i = i+1) begin:dis - (* KEEP, DONT_TOUCH *) - LUT6 #( - .INIT(64'h8000_0000_0000_0001) - ) lut ( - .I0(di[i]), - .I1(di[i]), - .I2(di[i]), - .I3(di[i]), - .I4(di[i]), - .I5(di[i]), - .O()); - end - endgenerate + print(connects.getvalue()) - generate - for (i = 0; i < `N_DO; i = i+1) begin:dos - (* KEEP, DONT_TOUCH *) - LUT6 #( - .INIT(64'h8000_0000_0000_0001) - ) lut ( - .I0(), - .I1(), - .I2(), - .I3(), - .I4(), - .I5(), - .O(do[i])); - end - endgenerate -endmodule - ''' % (DIN_N, DOUT_N)) + print("endmodule") + + with open('params.jl', 'w') as f: + json.dump(params, f, indent=2) if __name__ == '__main__': run() + diff --git a/fuzzers/034-iob-stag/Makefile b/fuzzers/034-iob-stag/Makefile deleted file mode 100644 index 4e3685f8..00000000 --- a/fuzzers/034-iob-stag/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -N := 1 -include ../fuzzer.mk - -SEGDATAS=$(addsuffix /segdata_liob33.txt,$(SPECIMENS)) - -database: build/segbits_liob33.db - -build/segbits_liob33.rdb: $(SPECIMENS_OK) - ${XRAY_SEGMATCH} -c -1 -o build/segbits_liob33.rdb $(SEGDATAS) - -build/segbits_liob33.db: build/segbits_liob33.rdb - python3 ${XRAY_DIR}/utils/groupmask.py $^ $@ - ${XRAY_MASKMERGE} build/mask_liob33.db $(SEGDATAS) - -pushdb: - ${XRAY_MERGEDB} liob33 build/segbits_liob33.db - ${XRAY_MERGEDB} mask_liob33 build/mask_liob33.db - -.PHONY: database pushdb - diff --git a/fuzzers/034-iob-stag/generate.py b/fuzzers/034-iob-stag/generate.py deleted file mode 100644 index 3667d5a7..00000000 --- a/fuzzers/034-iob-stag/generate.py +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env python3 - -from prjxray.segmaker import Segmaker -from prjxray import segmaker - -segmk = Segmaker("design.bits") - -print("Loading params") -f = open('params.csv', 'r') -f.readline() -for l in f: - l = l.strip() - site, name, dir_, cell = l.split(',') - segmaker.add_site_group_zero( - segmk, site, "MACRO.", ("INPUT", "OUTPUT"), "", dir_.upper()) - -segmk.compile() -segmk.write() diff --git a/fuzzers/034-iob-stag/generate.sh b/fuzzers/034-iob-stag/generate.sh deleted file mode 100644 index f42f840c..00000000 --- a/fuzzers/034-iob-stag/generate.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -set -ex -source ${XRAY_DIR}/utils/top_generate.sh - diff --git a/fuzzers/034-iob-stag/groups.grp b/fuzzers/034-iob-stag/groups.grp deleted file mode 100644 index f9cca48f..00000000 --- a/fuzzers/034-iob-stag/groups.grp +++ /dev/null @@ -1 +0,0 @@ -LIOB33.IOB_Y1.MACRO diff --git a/fuzzers/034-iob-stag/top.py b/fuzzers/034-iob-stag/top.py deleted file mode 100644 index 8c2001f7..00000000 --- a/fuzzers/034-iob-stag/top.py +++ /dev/null @@ -1,152 +0,0 @@ -''' -Generate a primitive to place at every I/O -Unlike CLB tests, the LFSR for this is inside the ROI, not driving it -''' - -import os -import random -random.seed(int(os.getenv("SEED"), 16)) -from prjxray import util -from prjxray import verilog - - -def gen_iobs(): - ''' - IOB33S: main IOB of a diff pair - IOB33M: secondary IOB of a diff pair - IOB33: not a diff pair. Relatively rare (at least in ROI...2 of them?) - Focus on IOB33S to start - ''' - for _tile_name, site_name, site_type in util.get_roi().gen_sites( - #['IOB33', 'IOB33S', 'IOB33M']): - ['IOB33S']): - yield site_name, site_type - - -def write_pins(ports): - pinstr = 'site,name,dir,cell\n' - for site, (name, dir_, cell) in sorted(ports.items(), key=lambda x: x[1]): - # pinstr += 'set_property -dict "PACKAGE_PIN %s IOSTANDARD LVCMOS33" [get_ports %s]' % (packpin, port) - pinstr += '%s,%s,%s,%s\n' % (site, name, dir_, cell) - open('params.csv', 'w').write(pinstr) - - -def run(): - # All possible values - iosites = {} - for site_name, site_type in gen_iobs(): - iosites[site_name] = site_type - - # Assigned in this design - ports = {} - DIN_N = 0 - DOUT_N = 0 - - def remain_sites(): - return set(iosites.keys()) - set(ports.keys()) - - def rand_site(): - '''Get a random, unused site''' - return random.choice(list(remain_sites())) - - def assign_i(site, name): - nonlocal DIN_N - - assert site not in ports - cell = "di_bufs[%u].ibuf" % DIN_N - DIN_N += 1 - ports[site] = (name, 'input', cell) - - def assign_o(site, name): - nonlocal DOUT_N - - assert site not in ports - cell = "do_bufs[%u].obuf" % DOUT_N - DOUT_N += 1 - ports[site] = (name, 'output', cell) - - # Assign at least one di and one do - assign_i(rand_site(), 'di[0]') - assign_o(rand_site(), 'do[0]') - # Now assign the rest randomly - while len(remain_sites()): - site = rand_site() - choice = random.randint(0, 2) - if choice == 0: - assign_i(site, 'di[%u]' % DIN_N) - elif choice == 1: - assign_o(site, 'do[%u]' % DOUT_N) - # Empty to provide a reference for no instance - else: - ports[site] = ("", "", "") - - write_pins(ports) - - print( - ''' -`define N_DI %u -`define N_DO %u - -module top(input wire [`N_DI-1:0] di, output wire [`N_DO-1:0] do); - genvar i; - - //Instantiate BUFs so we can LOC them - - wire [`N_DI-1:0] di_buf; - generate - for (i = 0; i < `N_DI; i = i+1) begin:di_bufs - IBUF ibuf(.I(di[i]), .O(di_buf[i])); - end - endgenerate - - wire [`N_DO-1:0] do_unbuf; - generate - for (i = 0; i < `N_DO; i = i+1) begin:do_bufs - OBUF obuf(.I(do_unbuf[i]), .O(do[i])); - end - endgenerate - - roi roi(.di(di_buf), .do(do_unbuf)); -endmodule - -//Arbitrary terminate into LUTs -module roi(input wire [`N_DI-1:0] di, output wire [`N_DO-1:0] do); - genvar i; - - generate - for (i = 0; i < `N_DI; i = i+1) begin:dis - (* KEEP, DONT_TOUCH *) - LUT6 #( - .INIT(64'h8000_0000_0000_0001) - ) lut ( - .I0(di[i]), - .I1(di[i]), - .I2(di[i]), - .I3(di[i]), - .I4(di[i]), - .I5(di[i]), - .O()); - end - endgenerate - - generate - for (i = 0; i < `N_DO; i = i+1) begin:dos - (* KEEP, DONT_TOUCH *) - LUT6 #( - .INIT(64'h8000_0000_0000_0001) - ) lut ( - .I0(), - .I1(), - .I2(), - .I3(), - .I4(), - .I5(), - .O(do[i])); - end - endgenerate -endmodule - ''' % (DIN_N, DOUT_N)) - - -if __name__ == '__main__': - run() diff --git a/fuzzers/035-iob-ilogic/Makefile b/fuzzers/035-iob-ilogic/Makefile new file mode 100644 index 00000000..a8780e89 --- /dev/null +++ b/fuzzers/035-iob-ilogic/Makefile @@ -0,0 +1,20 @@ +N := 30 +include ../fuzzer.mk + +database: build/segbits_xiob33.db + +build/segbits_xiob33.rdb: $(SPECIMENS_OK) + ${XRAY_SEGMATCH} -c 6 -o build/segbits_xiob33.rdb $$(find -name segdata_liob33.txt) $$(find -name segdata_riob33.txt) + +build/segbits_xiob33.db: build/segbits_xiob33.rdb + ${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf --seg-fn-in $^ --seg-fn-out $@ + ${XRAY_MASKMERGE} build/mask_xiob33.db $$(find -name segdata_liob33.txt) $$(find -name segdata_riob33.txt) + +pushdb: + ${XRAY_MERGEDB} liob33 build/segbits_xiob33.db + ${XRAY_MERGEDB} riob33 build/segbits_xiob33.db + ${XRAY_MERGEDB} mask_liob33 build/mask_xiob33.db + ${XRAY_MERGEDB} mask_riob33 build/mask_xiob33.db + +.PHONY: database pushdb + diff --git a/fuzzers/035-iob-ilogic/bits.dbf b/fuzzers/035-iob-ilogic/bits.dbf new file mode 100644 index 00000000..e69de29b diff --git a/fuzzers/035-iob-ilogic/generate.py b/fuzzers/035-iob-ilogic/generate.py new file mode 100644 index 00000000..cb9424a2 --- /dev/null +++ b/fuzzers/035-iob-ilogic/generate.py @@ -0,0 +1,171 @@ +#!/usr/bin/env python3 + +from prjxray.segmaker import Segmaker +from prjxray import verilog +import json + +def handle_data_width(segmk, d): + if 'DATA_WIDTH' not in d: + return + + if d['DATA_RATE'] == 'DDR': + return + + for opt in [2, 3, 4,5, 6, 7, 8, 10, 14]: + segmk.add_site_tag(d['site'], 'ISERDES.DATA_WIDTH.{}'.format(opt), + d['DATA_WIDTH'] == opt) + +def handle_data_rate(segmk, d): + if 'DATA_WIDTH' not in d: + return + + for opt in ['SDR', 'DDR']: + segmk.add_site_tag(d['site'], 'ISERDES.DATA_RATE.{}'.format(opt), + verilog.unquote(d['DATA_RATE']) == opt) + +def main(): + print("Loading tags") + segmk = Segmaker("design.bits") + + with open('params.jl', 'r') as f: + design = json.load(f) + + for d in design: + site = d['site'] + + handle_data_width(segmk, d) + handle_data_rate(segmk, d) + + if 'INTERFACE_TYPE' in d: + for opt in ( + 'MEMORY', + 'MEMORY_DDR3', + 'MEMORY_QDR', + 'NETWORKING', + 'OVERSAMPLE', + ): + segmk.add_site_tag(site, 'ISERDES.INTERFACE_TYPE.{}'.format(opt), + opt == verilog.unquote(d['INTERFACE_TYPE'])) + + if d['iddr_mux_config'] != 'none': + segmk.add_site_tag(site, 'IFF.ZINIT_Q1', not d['INIT_Q1']) + segmk.add_site_tag(site, 'IFF.ZINIT_Q2', not d['INIT_Q2']) + + if 'INIT_Q3' in d: + segmk.add_site_tag(site, 'IFF.ZINIT_Q3', not d['INIT_Q3']) + segmk.add_site_tag(site, 'IFF.ZINIT_Q4', not d['INIT_Q4']) + segmk.add_site_tag(site, 'IFF.ZSRVAL_Q1', not d['SRVAL_Q1']) + segmk.add_site_tag(site, 'IFF.ZSRVAL_Q2', not d['SRVAL_Q2']) + segmk.add_site_tag(site, 'IFF.ZSRVAL_Q3', not d['SRVAL_Q3']) + segmk.add_site_tag(site, 'IFF.ZSRVAL_Q4', not d['SRVAL_Q4']) + + if 'IS_CLK_INVERTED' in d: + if verilog.unquote(d['INTERFACE_TYPE']) == 'MEMORY_DDR3': + segmk.add_site_tag(site, 'IFF.ZINV_CLK', + not d['IS_CLK_INVERTED']) + segmk.add_site_tag(site, 'IFF.ZINV_CLKB', + not d['IS_CLKB_INVERTED']) + + segmk.add_site_tag(site, 'IFF.ZINV_CLK_XOR', + d['IS_CLK_INVERTED'] ^ d['IS_CLKB_INVERTED']) + segmk.add_site_tag(site, 'IFF.ZINV_CLK_NXOR', + not (d['IS_CLK_INVERTED'] ^ d['IS_CLKB_INVERTED'])) + + segmk.add_site_tag(site, 'IFF.ZINV_CLK_OR', + d['IS_CLK_INVERTED'] or d['IS_CLKB_INVERTED']) + segmk.add_site_tag(site, 'IFF.ZINV_CLK_NOR', + not (d['IS_CLK_INVERTED'] or d['IS_CLKB_INVERTED'])) + segmk.add_site_tag(site, 'IFF.ZINV_CLK_AND', + d['IS_CLK_INVERTED'] and d['IS_CLKB_INVERTED']) + segmk.add_site_tag(site, 'IFF.ZINV_CLK_NAND', + not (d['IS_CLK_INVERTED'] and d['IS_CLKB_INVERTED'])) + + if 'IS_OCLK_INVERTED' in d: + segmk.add_site_tag(site, 'IFF.ZINV_OCLK', + not d['IS_OCLK_INVERTED']) + + if 'IS_C_INVERTED' in d: + segmk.add_site_tag(site, 'IFF.ZINV_C', + not d['IS_C_INVERTED']) + + segmk.add_site_tag(site, 'IFF.ZINV_D', + not d['IS_D_INVERTED']) + + if 'SRTYPE' in d: + for opt in ['ASYNC', 'SYNC']: + segmk.add_site_tag(site, 'IFF.SRTYPE.{}'.format(opt), + verilog.unquote(d['SRTYPE']) == opt) + + if 'DDR_CLK_EDGE' in d: + for opt in ['OPPOSITE_EDGE', 'SAME_EDGE', 'SAME_EDGE_PIPELINED']: + segmk.add_site_tag(site, 'IFF.DDR_CLK_EDGE.{}'.format(opt), + verilog.unquote(d['DDR_CLK_EDGE']) == opt) + + ofb_used = False + if 'OFB_USED' in d and d['OFB_USED']: + ofb_used = True + + if d['iddr_mux_config'] == 'direct': + segmk.add_site_tag(site, 'IFFDELMUXE3.0', 0) + segmk.add_site_tag(site, 'IFFDELMUXE3.1', 1) + segmk.add_site_tag(site, 'IFFDELMUXE3.2', 0) + + if ofb_used: + segmk.add_site_tag(site, 'IFFMUX.1', 1) + segmk.add_site_tag(site, 'IFFMUX.0', 0) + else: + segmk.add_site_tag(site, 'IFFMUX.1', 0) + segmk.add_site_tag(site, 'IFFMUX.0', 1) + elif d['iddr_mux_config'] == 'idelay': + segmk.add_site_tag(site, 'IFFDELMUXE3.0', 1) + segmk.add_site_tag(site, 'IFFDELMUXE3.1', 0) + segmk.add_site_tag(site, 'IFFDELMUXE3.2', 0) + + if ofb_used: + segmk.add_site_tag(site, 'IFFMUX.1', 1) + segmk.add_site_tag(site, 'IFFMUX.0', 0) + else: + segmk.add_site_tag(site, 'IFFMUX.1', 0) + segmk.add_site_tag(site, 'IFFMUX.0', 1) + elif d['iddr_mux_config'] == 'none': + segmk.add_site_tag(site, 'IFFDELMUXE3.0', 0) + segmk.add_site_tag(site, 'IFFDELMUXE3.1', 0) + segmk.add_site_tag(site, 'IFFDELMUXE3.2', 0) + else: + assert False, d['mux_config'] + + if d['mux_config'] == 'direct': + segmk.add_site_tag(site, 'IDELMUXE3.0', 0) + segmk.add_site_tag(site, 'IDELMUXE3.1', 1) + segmk.add_site_tag(site, 'IDELMUXE3.2', 0) + + if ofb_used: + segmk.add_site_tag(site, 'IMUX.1', 1) + segmk.add_site_tag(site, 'IMUX.0', 0) + else: + segmk.add_site_tag(site, 'IMUX.1', 0) + segmk.add_site_tag(site, 'IMUX.0', 1) + elif d['mux_config'] == 'idelay': + segmk.add_site_tag(site, 'IDELMUXE3.0', 1) + segmk.add_site_tag(site, 'IDELMUXE3.1', 0) + segmk.add_site_tag(site, 'IDELMUXE3.2', 0) + + if ofb_used: + segmk.add_site_tag(site, 'IMUX.1', 1) + segmk.add_site_tag(site, 'IMUX.0', 0) + else: + segmk.add_site_tag(site, 'IMUX.1', 0) + segmk.add_site_tag(site, 'IMUX.0', 1) + elif d['mux_config'] == 'none': + segmk.add_site_tag(site, 'IDELMUXE3.0', 0) + segmk.add_site_tag(site, 'IDELMUXE3.1', 0) + segmk.add_site_tag(site, 'IDELMUXE3.2', 0) + else: + assert False, d['mux_config'] + + + segmk.compile() + segmk.write(allow_empty=True) + +if __name__ == "__main__": + main() diff --git a/fuzzers/034-iob-stag/generate.tcl b/fuzzers/035-iob-ilogic/generate.tcl similarity index 67% rename from fuzzers/034-iob-stag/generate.tcl rename to fuzzers/035-iob-ilogic/generate.tcl index 556d5814..85caab36 100644 --- a/fuzzers/034-iob-stag/generate.tcl +++ b/fuzzers/035-iob-ilogic/generate.tcl @@ -19,6 +19,8 @@ proc load_pin_lines {} { # IOB_X0Y129 do[0] output set fp [open "params.csv" r] + gets $fp line + set pin_lines {} for {gets $fp line} {$line != ""} {gets $fp line} { lappend pin_lines [split $line ","] @@ -31,36 +33,46 @@ proc loc_pins {} { set pin_lines [load_pin_lines] set io_pin_sites [make_io_pin_sites] - set fp [open "design.csv" w] - puts $fp "port,site,tile,pin,val" - puts "Looping" - for {set idx 1} {$idx < [llength $pin_lines]} {incr idx} { + for {set idx 0} {$idx < [llength $pin_lines]} {incr idx} { set line [lindex $pin_lines $idx] puts "$line" - set site_str [lindex $line 0] - set pin_str [lindex $line 1] - set io [lindex $line 2] - set cell_str [lindex $line 3] - # Skip unused site - if {"$pin_str" == ""} { - continue - } + set site_str [lindex $line 1] + set pin_str [lindex $line 2] + set iostandard [lindex $line 3] + set drive [lindex $line 4] + set slew [lindex $line 5] + set pulltype [lindex $line 6] # Have: site # Want: pin for site + set site [get_sites $site_str] set pad_bel [get_bels -of_objects $site -filter {TYPE =~ PAD && NAME =~ IOB_*}] + # set port [get_ports -of_objects $site] set port [get_ports $pin_str] set tile [get_tiles -of_objects $site] + set pin [dict get $io_pin_sites $site] - set_property -dict "PACKAGE_PIN $pin IOSTANDARD LVCMOS33" $port + set props {} + #lappend props PACKAGE_PIN $pin + lappend props IOSTANDARD $iostandard + lappend props PULLTYPE $pulltype - puts $fp "$port,$site,$tile,$pin" + if {$drive != "None"} { + lappend props DRIVE $drive + } + + if {$slew != "None"} { + lappend props SLEW $slew + } + + puts $props + + set_property -dict "$props" $port } - close $fp } proc run {} { @@ -68,17 +80,14 @@ proc run {} { read_verilog top.v synth_design -top top - # Mostly doesn't matter since IOB are special, but add anyway - create_pblock roi - add_cells_to_pblock [get_pblocks roi] [get_cells roi] - resize_pblock [get_pblocks roi] -add "$::env(XRAY_ROI)" - loc_pins set_property CFGBVS VCCO [current_design] set_property CONFIG_VOLTAGE 3.3 [current_design] set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design] - set_param tcl.collectionResultDisplayLimit 0 + set_property IS_ENABLED 0 [get_drc_checks {REQP-79}] + + write_checkpoint -force design_pre_place.dcp place_design route_design diff --git a/fuzzers/035-iob-ilogic/top.py b/fuzzers/035-iob-ilogic/top.py new file mode 100644 index 00000000..97c224fe --- /dev/null +++ b/fuzzers/035-iob-ilogic/top.py @@ -0,0 +1,420 @@ +import json +import io +import os +import random +random.seed(int(os.getenv("SEED"), 16)) +from prjxray import util +from prjxray import lut_maker +from prjxray import verilog +from prjxray.db import Database + + +def gen_sites(): + ''' + IOB33S: main IOB of a diff pair + IOB33M: secondary IOB of a diff pair + IOB33: not a diff pair. Relatively rare (at least in ROI...2 of them?) + Focus on IOB33S to start + ''' + db = Database(util.get_db_root()) + grid = db.grid() + for tile_name in sorted(grid.tiles()): + loc = grid.loc_of_tilename(tile_name) + gridinfo = grid.gridinfo_at_loc(loc) + + for site_name, site_type in gridinfo.sites.items(): + if site_type in ['IOB33S', 'IOB33M']: + yield tile_name, site_name + +def write_params(params): + pinstr = 'tile,site,pin,iostandard,drive,slew\n' + for vals in params: + pinstr += ','.join(map(str, vals)) + '\n' + + open('params.csv', 'w').write(pinstr) + +def use_iserdese2(p, luts, connects): + iobdelay = random.choice(( + 'NONE', + 'BOTH', + 'IBUF', + 'IFD', + )) + + p['IOBDELAY'] = verilog.quote(iobdelay) + p['INIT_Q1'] = random.randint(0, 1) + p['INIT_Q2'] = random.randint(0, 1) + p['INIT_Q3'] = random.randint(0, 1) + p['INIT_Q4'] = random.randint(0, 1) + + p['SRVAL_Q1'] = random.randint(0, 1) + p['SRVAL_Q2'] = random.randint(0, 1) + p['SRVAL_Q3'] = random.randint(0, 1) + p['SRVAL_Q4'] = random.randint(0, 1) + p['NUM_CE'] = random.randint(1, 2) + + p['IS_CLK_INVERTED'] = random.randint(0, 1) + p['IS_CLKB_INVERTED'] = random.randint(0, 1) + p['IS_OCLK_INVERTED'] = random.randint(0, 1) + p['IS_D_INVERTED'] = random.randint(0, 1) + p['INTERFACE_TYPE'] = verilog.quote(random.choice(( + 'MEMORY', + 'MEMORY_DDR3', + 'MEMORY_QDR', + 'NETWORKING', + 'OVERSAMPLE', + ))) + p['DATA_RATE'] = verilog.quote(random.choice(( + 'SDR', + 'DDR', + ))) + if verilog.unquote(p['DATA_RATE']) == 'SDR': + data_widths = [2, 3, 4, 5, 6, 7, 8] + else: + data_widths = [4, 6, 8] + + p['DATA_WIDTH'] = random.choice(data_widths) + p['SERDES_MODE'] = verilog.quote(random.choice(('MASTER', 'SLAVE'))) + + use_delay = iobdelay != 'NONE' + + if iobdelay == 'NONE': + p['mux_config'] = 'direct' + p['iddr_mux_config'] = 'direct' + elif iobdelay == 'BOTH': + p['mux_config'] = 'idelay' + p['iddr_mux_config'] = 'idelay' + elif iobdelay == 'IBUF': + p['mux_config'] = 'idelay' + p['iddr_mux_config'] = 'direct' + elif iobdelay == 'IFD': + p['mux_config'] = 'direct' + p['iddr_mux_config'] = 'idelay' + + p['OFB_USED'] = verilog.quote(random.choice(('TRUE', 'FALSE'))) + p['DYN_CLKDIV_INV_EN'] = verilog.quote(random.choice(('TRUE', 'FALSE'))) + p['DYN_CLK_INV_EN'] = verilog.quote(random.choice(('TRUE', 'FALSE'))) + + if use_delay: + print(""" + wire idelay_{site}; + + (* KEEP, DONT_TOUCH, LOC = "{idelay_loc}" *) + IDELAYE2 #( + ) idelay_site_{site} ( + .IDATAIN({iwire}), + .DATAOUT(idelay_{site}) + );""".format( + **p), file=connects) + + p['ddly_connection'] = '.DDLY(idelay_{site}),'.format(**p) + else: + p['ddly_connection'] = '' + + if verilog.unquote(p['OFB_USED']) == 'TRUE': + p['ODATA_RATE'] = verilog.quote(random.choice(( + 'SDR', + 'DDR', + ))) + if verilog.unquote(p['ODATA_RATE']) == 'SDR': + data_widths = [2, 3, 4, 5, 6, 7, 8] + else: + data_widths = [4, 6, 8] + + p['ODATA_WIDTH'] = random.choice(data_widths) + p['OSERDES_MODE'] = verilog.quote(random.choice(('MASTER', 'SLAVE'))) + + if p['ODATA_WIDTH'] > 4 or verilog.unquote(p['ODATA_RATE']) == 'SDR': + p['TRISTATE_WIDTH'] = 1 + else: + p['TRISTATE_WIDTH'] = 4 + + + print(""" + wire tfb_{site}; + wire ofb_{site}; + + (* KEEP, DONT_TOUCH, LOC = "{ologic_loc}" *) + OSERDESE2 #( + .SERDES_MODE({OSERDES_MODE}), + .DATA_RATE_TQ({ODATA_RATE}), + .DATA_RATE_OQ({ODATA_RATE}), + .DATA_WIDTH({ODATA_WIDTH}), + .TRISTATE_WIDTH({TRISTATE_WIDTH}) + ) oserdese2_{site} ( + .CLK(0), + .CLKDIV(0), + .D1(0), + .TFB(tfb_{site}), + .OQ({owire}), + .TQ({twire}), + .OFB(ofb_{site}) + );""".format( + **p), file=connects) + + p['ofb_connections'] = """ + .OFB(ofb_{site}), + """.format(**p) + else: + p['ofb_connections'] = '' + + + print(''' + (* KEEP, DONT_TOUCH, LOC = "{ilogic_loc}" *) + ISERDESE2 #( + .SERDES_MODE({SERDES_MODE}), + .INIT_Q1({INIT_Q1}), + .INIT_Q2({INIT_Q2}), + .INIT_Q3({INIT_Q3}), + .INIT_Q4({INIT_Q4}), + .SRVAL_Q1({SRVAL_Q1}), + .SRVAL_Q2({SRVAL_Q2}), + .SRVAL_Q3({SRVAL_Q3}), + .SRVAL_Q4({SRVAL_Q4}), + .DYN_CLKDIV_INV_EN({DYN_CLKDIV_INV_EN}), + .DYN_CLK_INV_EN({DYN_CLK_INV_EN}), + .INTERFACE_TYPE({INTERFACE_TYPE}), + .IS_CLK_INVERTED({IS_CLK_INVERTED}), + .IS_CLKB_INVERTED({IS_CLKB_INVERTED}), + .IS_OCLK_INVERTED({IS_OCLK_INVERTED}), + .IS_D_INVERTED({IS_D_INVERTED}), + .OFB_USED({OFB_USED}), + .NUM_CE({NUM_CE}), + .DATA_RATE({DATA_RATE}), + .IOBDELAY({IOBDELAY}) + ) iserdese2_{site} ( + {ddly_connection} + {ofb_connections} + .D({iwire}), + .CLK({clknet}), + .CLKB({clkbnet}), + .OCLK({oclknet}), + .O({onet}), + .Q1({q1net}), + .CLKDIV(0) + );'''.format( + clknet=luts.get_next_output_net(), + clkbnet=luts.get_next_output_net(), + oclknet=luts.get_next_output_net(), + onet=luts.get_next_input_net(), + q1net=luts.get_next_input_net(), + shiftout1net=luts.get_next_input_net(), + shiftout2net=luts.get_next_input_net(), + **p), file=connects) + + +def use_direct_and_iddr(p, luts, connects): + p['mux_config'] = random.choice(( + 'direct', + 'idelay', + 'none', + )) + + p['iddr_mux_config'] = random.choice(( + 'direct', + 'idelay', + 'none', + )) + + if p['iddr_mux_config'] != 'none': + p['INIT_Q1'] = random.randint(0, 1) + p['INIT_Q2'] = random.randint(0, 1) + p['IS_C_INVERTED'] = random.randint(0, 1) + p['IS_D_INVERTED'] = random.randint(0, 1) + p['SRTYPE'] = verilog.quote(random.choice(('SYNC', 'ASYNC'))) + p['DDR_CLK_EDGE'] = verilog.quote(random.choice(( + 'OPPOSITE_EDGE', + 'SAME_EDGE', + 'SAME_EDGE_PIPELINED', + ))) + + print(''' + (* KEEP, DONT_TOUCH, LOC = "{ilogic_loc}" *) + IDDR #( + .IS_D_INVERTED({IS_D_INVERTED}), + .IS_C_INVERTED({IS_C_INVERTED}), + .INIT_Q1({INIT_Q1}), + .INIT_Q2({INIT_Q2}), + .SRTYPE({SRTYPE}), + .DDR_CLK_EDGE({DDR_CLK_EDGE}) + ) iddr_{site} ( + .C({cnet}), + .D(iddr_d_{site}), + .Q1({q1}), + .Q2({q2}) + ); + '''.format( + cnet=luts.get_next_output_net(), + q1=luts.get_next_input_net(), + q2=luts.get_next_input_net(), + **p), file=connects) + + if p['iddr_mux_config'] == 'idelay' or p['mux_config'] == 'idelay' or p['iddr_mux_config'] == 'tristate_feedback': + print(""" + wire idelay_{site}; + + (* KEEP, DONT_TOUCH, LOC = "{idelay_loc}" *) + IDELAYE2 #( + ) idelay_site_{site} ( + .IDATAIN({iwire}), + .DATAOUT(idelay_{site}) + );""".format( + **p), file=connects) + + print(""" + assign {owire} = {onet}; + assign {twire} = {tnet}; + """.format( + onet=luts.get_next_output_net(), + tnet=luts.get_next_output_net(), + **p), file=connects) + + if p['iddr_mux_config'] == 'direct': + print(''' + assign iddr_d_{site} = {iwire};'''.format( + **p, + ), file=connects) + elif p['iddr_mux_config'] == 'idelay': + print(''' + assign iddr_d_{site} = idelay_{site};'''.format( + **p, + ), file=connects) + elif p['iddr_mux_config'] == 'tristate_feedback': + print(''' + assign iddr_d_{site} = tfb_{site} ? ofb_{site} : idelay_{site};'''.format( + **p, + ), file=connects) + elif p['iddr_mux_config'] == 'none': + pass + else: + assert False, p['mux_config'] + + if p['mux_config'] == 'direct': + print(''' + assign {net} = {iwire};'''.format( + net=luts.get_next_input_net(), + **p, + ), file=connects) + elif p['mux_config'] == 'idelay': + print(''' + assign {net} = idelay_{site};'''.format( + net=luts.get_next_input_net(), + **p, + ), file=connects) + elif p['mux_config'] == 'none': + pass + else: + assert False, p['mux_config'] + +def run(): + iostandards = ['LVCMOS12', 'LVCMOS15', 'LVCMOS18', 'LVCMOS25', 'LVCMOS33', 'LVTTL'] + iostandard = random.choice(iostandards) + + if iostandard in ['LVTTL', 'LVCMOS18']: + drives = [4, 8, 12, 16, 24] + elif iostandard == 'LVCMOS12': + drives = [4, 8, 12] + else: + drives = [4, 8, 12, 16] + + slews = ['FAST', 'SLOW'] + pulls = ["NONE", "KEEPER", "PULLDOWN", "PULLUP"] + + luts = lut_maker.LutMaker() + + connects = io.StringIO() + + tile_params = [] + params = [] + for idx, (tile, site) in enumerate(gen_sites()): + if idx == 0: + continue + + + p = {} + p['tile'] = tile + p['site'] = site + p['ilogic_loc'] = site.replace('IOB', 'ILOGIC') + p['ologic_loc'] = site.replace('IOB', 'OLOGIC') + p['idelay_loc'] = site.replace('IOB', 'IDELAY') + p['IOSTANDARD'] = verilog.quote(iostandard) + p['PULLTYPE'] = verilog.quote(random.choice(pulls)) + p['DRIVE'] = random.choice(drives) + p['SLEW'] = verilog.quote(random.choice(slews)) + + p['pad_wire'] = 'dio[{}]'.format(idx-1) + p['owire'] = 'do_buf[{}]'.format(idx-1) + p['iwire'] = 'di_buf[{}]'.format(idx-1) + p['twire'] = 't[{}]'.format(idx-1) + + params.append(p) + tile_params.append((tile, site, p['pad_wire'], iostandard, + p['DRIVE'], + verilog.unquote(p['SLEW']) if p['SLEW'] else None, + verilog.unquote(p['PULLTYPE']))) + + write_params(tile_params) + + print( + ''' +`define N_DI {n_di} + +module top(input clk, inout wire [`N_DI-1:0] dio); + wire [`N_DI-1:0] di_buf; + wire [`N_DI-1:0] do_buf; + wire [`N_DI-1:0] t; + '''.format( + n_di=idx)) + + # Always output a LUT6 to make placer happy. + print(''' + (* KEEP, DONT_TOUCH *) + LUT6 dummy_lut(); + ''') + + any_idelay = False + + for p in params: + print(''' + wire iddr_d_{site}; + + (* KEEP, DONT_TOUCH, LOC = "{site}" *) + IOBUF #( + .IOSTANDARD({IOSTANDARD}) + ) ibuf_{site} ( + .IO({pad_wire}), + .I({owire}), + .O({iwire}), + .T({twire}) + ); + '''.format( + **p), file=connects) + + p['use_iserdese2'] = random.randint(0, 1) + if p['use_iserdese2']: + use_iserdese2(p, luts, connects) + else: + use_direct_and_iddr(p, luts, connects) + + if p['iddr_mux_config'] == 'idelay' or p['mux_config'] == 'idelay': + any_idelay = True + + if any_idelay: + print(""" + (* KEEP, DONT_TOUCH *) + IDELAYCTRL();""") + + for l in luts.create_wires_and_luts(): + print(l) + + print(connects.getvalue()) + + print("endmodule") + + with open('params.jl', 'w') as f: + json.dump(params, f, indent=2) + + +if __name__ == '__main__': + run() + diff --git a/fuzzers/Makefile b/fuzzers/Makefile index b14bc645..9bf0aee3 100644 --- a/fuzzers/Makefile +++ b/fuzzers/Makefile @@ -73,6 +73,8 @@ $(eval $(call fuzzer,026-bram-data,005-tilegrid)) $(eval $(call fuzzer,027-bram36-config,005-tilegrid)) $(eval $(call fuzzer,028-fifo-config,005-tilegrid)) $(eval $(call fuzzer,029-bram-fifo-config,005-tilegrid)) +$(eval $(call fuzzer,030-iob,005-tilegrid)) +$(eval $(call fuzzer,035-iob-ilogic,005-tilegrid)) $(eval $(call fuzzer,040-clk-hrow-config,005-tilegrid)) $(eval $(call fuzzer,041-clk-hrow-pips,005-tilegrid)) # 042 fuzzer is unstable, issue #657 diff --git a/prjxray/segmaker.py b/prjxray/segmaker.py index 559556a1..9dcb6e07 100644 --- a/prjxray/segmaker.py +++ b/prjxray/segmaker.py @@ -336,9 +336,13 @@ class Segmaker: -CLBLM_L => CLB -CENTER_INTER_R => CENTER_INTER -CLK_HROW_TOP_R => CLK_HROW + -LIOB33 => IOB33 ''' tile_type_norm = re.sub("(_TOP|_BOT|LL|LM)?_[LR]$", "", tile_type) + if tile_type_norm in ['LIOB33', 'RIOB33']: + tile_type_norm = 'IOB33' + # ignore dummy tiles (ex: VBRK) if len(tiledata['bits']) == 0: if self.verbose: diff --git a/utils/mergedb.sh b/utils/mergedb.sh index 62164dc4..da1cbbea 100755 --- a/utils/mergedb.sh +++ b/utils/mergedb.sh @@ -87,7 +87,10 @@ case "$1" in cp "$2" "$tmp1" ;; liob33) - cp "$2" "$tmp1" ;; + sed < "$2" > "$tmp1" -e 's/^IOB33\./LIOB33./' ;; + + riob33) + sed < "$2" > "$tmp1" -e 's/^IOB33\./RIOB33./' ;; mask_*) db=$XRAY_DATABASE_DIR/$XRAY_DATABASE/$1.db