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 1/6] 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 From a2d32d19a3e39eac0cdbcf975bf19e236dd20bf7 Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Thu, 28 Feb 2019 16:43:49 -0800 Subject: [PATCH 2/6] Run make format. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- CONTRIBUTING.md | 3 +- fuzzers/030-iob/check_results.py | 20 ++-- fuzzers/030-iob/generate.py | 38 ++++-- fuzzers/030-iob/process_rdb.py | 34 +++--- fuzzers/030-iob/top.py | 48 +++++--- fuzzers/035-iob-ilogic/generate.py | 99 +++++++++------- fuzzers/035-iob-ilogic/top.py | 184 ++++++++++++++++------------- 7 files changed, 251 insertions(+), 175 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4b7acc0a..9acd526e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,7 +10,8 @@ All contributions should be sent as ### License -All code in the Project X-Ray repository is licensed under the very permissive +All software (code, associated documentation, support files, etc) in the +Project X-Ray repository are licensed under the very permissive [ISC Licence](COPYING). A copy can be found in the [`COPYING`](COPYING) file. All new contributions must also be released under this license. diff --git a/fuzzers/030-iob/check_results.py b/fuzzers/030-iob/check_results.py index 2369e628..affe8942 100644 --- a/fuzzers/030-iob/check_results.py +++ b/fuzzers/030-iob/check_results.py @@ -19,6 +19,7 @@ from prjxray import verilog import json import generate + def process_parts(parts): if parts[0] == 'INOUT': yield 'type', 'IOBUF_INTERMDISABLE' @@ -39,6 +40,7 @@ def process_parts(parts): yield 'IOSTANDARDS', parts[0].split('_') yield 'DRIVES', parts[2].split('_') + def create_sites_from_fasm(root): sites = {} @@ -52,9 +54,9 @@ def create_sites_from_fasm(root): site = parts[1] if (tile, site) not in sites: sites[(tile, site)] = { - 'tile': tile, - 'site_key': site, - } + 'tile': tile, + 'site_key': site, + } for key, value in process_parts(parts[2:]): sites[(tile, site)][key] = value @@ -80,7 +82,7 @@ def process_specimen(root): for p in params: tile = p['tile'] site = p['site'] - site_y = int(site[site.find('Y')+1:]) % 2 + site_y = int(site[site.find('Y') + 1:]) % 2 if generate.skip_broken_tiles(p): continue @@ -94,20 +96,21 @@ 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, site_from_fasm) if p['type'] is None: continue assert p['PULLTYPE'] == site_from_fasm['PULLTYPE'], ( - tile, site_key, p, site_from_fasm) + tile, site_key, p, site_from_fasm) - assert verilog.unquote(p['IOSTANDARD']) in site_from_fasm['IOSTANDARDS'], ( + 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) + tile, site_key, p, site_from_fasm) assert 'I{}'.format(p['DRIVE']) in site_from_fasm['DRIVES'], ( tile, site_key, p, site_from_fasm) @@ -121,5 +124,6 @@ def main(): print('No errors found!') + if __name__ == "__main__": main() diff --git a/fuzzers/030-iob/generate.py b/fuzzers/030-iob/generate.py index 0fe9e9ca..7ad44b2c 100644 --- a/fuzzers/030-iob/generate.py +++ b/fuzzers/030-iob/generate.py @@ -13,6 +13,7 @@ def bitfilter(frame, word): return True + def mk_drive_opt(iostandard, drive): return '{}.DRIVE.I{}'.format(iostandard, drive) @@ -28,6 +29,7 @@ def skip_broken_tiles(d): return False + def drives_for_iostandard(iostandard): if iostandard in ['LVTTL', 'LVCMOS18']: drives = [4, 8, 12, 16, 24] @@ -38,6 +40,7 @@ def drives_for_iostandard(iostandard): return drives + def main(): print("Loading tags") segmk = Segmaker("design.bits") @@ -63,14 +66,18 @@ def main(): 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, '{}.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) + 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) @@ -78,9 +85,13 @@ def main(): 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) + 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) + 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) @@ -88,14 +99,16 @@ def main(): if d['type'] is not None: segmaker.add_site_group_zero( - segmk, site, "PULLTYPE.", ("NONE", "KEEPER", "PULLDOWN", "PULLUP"), - "PULLDOWN", verilog.unquote(d['PULLTYPE'])) + 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 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 @@ -106,23 +119,24 @@ def main(): drive_opts.add(mk_drive_opt(opt, drive_opt)) segmaker.add_site_group_zero( - segmk, site, '', drive_opts, - mk_drive_opt('LVCMOS25', '12'), + 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') + 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.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/process_rdb.py b/fuzzers/030-iob/process_rdb.py index 1ae5c2cc..3712e34b 100644 --- a/fuzzers/030-iob/process_rdb.py +++ b/fuzzers/030-iob/process_rdb.py @@ -9,13 +9,16 @@ There are couple cases that need to be handled here: """ 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': @@ -23,8 +26,11 @@ def parse_bits(l): else: return frozenset(parts[1:]) + def main(): - parser = argparse.ArgumentParser(description="Convert IOB rdb into good rdb.""") + parser = argparse.ArgumentParser( + description="Convert IOB rdb into good rdb." + "") parser.add_argument('input_rdb') args = parser.parse_args() @@ -38,9 +44,9 @@ def main(): print(l.strip()) common_in_bits = { - 'IOB_Y0': set(), - 'IOB_Y1': set(), - } + '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) @@ -53,7 +59,6 @@ def main(): drives = {} in_use = {} - for l in iostandard_lines: name = get_name(l) site = get_site(l) @@ -76,7 +81,8 @@ def main(): iostandard_in[in_bits].append((site, iostandard)) if name.endswith('.OUT'): - outs[(site, iostandard)] = parse_bits(l) | in_use[(site, iostandard)] + 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] @@ -96,8 +102,8 @@ def main(): assert len(site) == 1, site site = site.pop() - print('IOB33.{}.{}.IN'.format(site, '_'.join(standards)), - ' '.join(bits)) + print( + 'IOB33.{}.{}.IN'.format(site, '_'.join(standards)), ' '.join(bits)) iodrives = {} @@ -105,14 +111,14 @@ def main(): for site, iostandard in drives: for drive in drives[(site, iostandard)]: - combined_bits = drives[(site, iostandard)][drive] | outs[(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] = [] @@ -128,10 +134,10 @@ def main(): 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)) + print( + 'IOB33.{}.{}.DRIVE.{}'.format( + site, '_'.join(sorted(set(standards))), '_'.join( + sorted(set(drives)))), ' '.join(bits | neg_bits)) if __name__ == "__main__": diff --git a/fuzzers/030-iob/top.py b/fuzzers/030-iob/top.py index 9f3cc311..e89456d6 100644 --- a/fuzzers/030-iob/top.py +++ b/fuzzers/030-iob/top.py @@ -26,6 +26,7 @@ def gen_sites(): 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: @@ -35,13 +36,17 @@ def write_params(params): def run(): - tile_types = ['IBUF', 'OBUF', 'IOBUF_INTERMDISABLE', None, None, None, None, None] + tile_types = [ + 'IBUF', 'OBUF', 'IOBUF_INTERMDISABLE', None, None, None, None, None + ] i_idx = 0 o_idx = 0 io_idx = 0 - iostandards = ['LVCMOS12', 'LVCMOS15', 'LVCMOS18', 'LVCMOS25', 'LVCMOS33', 'LVTTL'] + iostandards = [ + 'LVCMOS12', 'LVCMOS15', 'LVCMOS18', 'LVCMOS25', 'LVCMOS33', 'LVTTL' + ] iostandard = random.choice(iostandards) if iostandard in ['LVTTL', 'LVCMOS18']: @@ -96,18 +101,22 @@ def run(): 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())) + 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']))) + 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) @@ -120,10 +129,7 @@ def run(): 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)) + '''.format(n_di=i_idx, n_do=o_idx, n_dio=io_idx)) # Always output a LUT6 to make placer happy. print(''' @@ -145,13 +151,16 @@ module top(input wire [`N_DI-1:0] di, output wire [`N_DO-1:0] do, inout wire [`N ) ibuf_{site} ( .I({pad_wire}), .O({owire}) - );'''.format(**p), file=connects) + );'''.format(**p), + file=connects) if p['IDELAY_ONLY']: - print(""" + print( + """ (* KEEP, DONT_TOUCH *) IDELAYE2 idelay_site_{site} ( .IDATAIN(idelay_{site}) - );""".format(**p), file=connects) + );""".format(**p), + file=connects) elif p['type'] == 'OBUF': print( @@ -164,7 +173,8 @@ module top(input wire [`N_DI-1:0] di, output wire [`N_DO-1:0] do, inout wire [`N ) ibuf_{site} ( .O({pad_wire}), .I({iwire}) - );'''.format(**p), file=connects) + );'''.format(**p), + file=connects) elif p['type'] == 'IOBUF_INTERMDISABLE': print( ''' @@ -180,7 +190,8 @@ module top(input wire [`N_DI-1:0] di, output wire [`N_DO-1:0] do, inout wire [`N .T({tristate_wire}), .IBUFDISABLE({ibufdisable_wire}), .INTERMDISABLE({intermdisable_wire}) - );'''.format(**p), file=connects) + );'''.format(**p), + file=connects) for l in luts.create_wires_and_luts(): print(l) @@ -195,4 +206,3 @@ module top(input wire [`N_DI-1:0] di, output wire [`N_DO-1:0] do, inout wire [`N if __name__ == '__main__': run() - diff --git a/fuzzers/035-iob-ilogic/generate.py b/fuzzers/035-iob-ilogic/generate.py index cb9424a2..54610837 100644 --- a/fuzzers/035-iob-ilogic/generate.py +++ b/fuzzers/035-iob-ilogic/generate.py @@ -4,6 +4,7 @@ from prjxray.segmaker import Segmaker from prjxray import verilog import json + def handle_data_width(segmk, d): if 'DATA_WIDTH' not in d: return @@ -11,17 +12,21 @@ def handle_data_width(segmk, d): 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) + 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) + segmk.add_site_tag( + d['site'], 'ISERDES.DATA_RATE.{}'.format(opt), + verilog.unquote(d['DATA_RATE']) == opt) + def main(): print("Loading tags") @@ -43,9 +48,10 @@ def main(): 'MEMORY_QDR', 'NETWORKING', 'OVERSAMPLE', - ): - segmk.add_site_tag(site, 'ISERDES.INTERFACE_TYPE.{}'.format(opt), - opt == verilog.unquote(d['INTERFACE_TYPE'])) + ): + 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']) @@ -54,52 +60,65 @@ def main(): 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']) + 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', 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_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'])) + 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']) + 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_C', not d['IS_C_INVERTED']) - segmk.add_site_tag(site, 'IFF.ZINV_D', - not d['IS_D_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) + 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) + 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']: @@ -163,9 +182,9 @@ def main(): else: assert False, d['mux_config'] - segmk.compile() segmk.write(allow_empty=True) + if __name__ == "__main__": main() diff --git a/fuzzers/035-iob-ilogic/top.py b/fuzzers/035-iob-ilogic/top.py index 97c224fe..4404bdd9 100644 --- a/fuzzers/035-iob-ilogic/top.py +++ b/fuzzers/035-iob-ilogic/top.py @@ -26,6 +26,7 @@ def gen_sites(): 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: @@ -33,13 +34,14 @@ def write_params(params): 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) @@ -57,17 +59,19 @@ def use_iserdese2(p, luts, connects): 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['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: @@ -96,7 +100,8 @@ def use_iserdese2(p, luts, connects): p['DYN_CLK_INV_EN'] = verilog.quote(random.choice(('TRUE', 'FALSE'))) if use_delay: - print(""" + print( + """ wire idelay_{site}; (* KEEP, DONT_TOUCH, LOC = "{idelay_loc}" *) @@ -104,8 +109,8 @@ def use_iserdese2(p, luts, connects): ) idelay_site_{site} ( .IDATAIN({iwire}), .DATAOUT(idelay_{site}) - );""".format( - **p), file=connects) + );""".format(**p), + file=connects) p['ddly_connection'] = '.DDLY(idelay_{site}),'.format(**p) else: @@ -115,7 +120,7 @@ def use_iserdese2(p, luts, connects): 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: @@ -129,8 +134,8 @@ def use_iserdese2(p, luts, connects): else: p['TRISTATE_WIDTH'] = 4 - - print(""" + print( + """ wire tfb_{site}; wire ofb_{site}; @@ -149,8 +154,8 @@ def use_iserdese2(p, luts, connects): .OQ({owire}), .TQ({twire}), .OFB(ofb_{site}) - );""".format( - **p), file=connects) + );""".format(**p), + file=connects) p['ofb_connections'] = """ .OFB(ofb_{site}), @@ -158,8 +163,8 @@ def use_iserdese2(p, luts, connects): else: p['ofb_connections'] = '' - - print(''' + print( + ''' (* KEEP, DONT_TOUCH, LOC = "{ilogic_loc}" *) ISERDESE2 #( .SERDES_MODE({SERDES_MODE}), @@ -193,14 +198,15 @@ def use_iserdese2(p, luts, connects): .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) + 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): @@ -208,13 +214,13 @@ def use_direct_and_iddr(p, luts, connects): '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) @@ -222,13 +228,16 @@ def use_direct_and_iddr(p, luts, connects): 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', - ))) + p['DDR_CLK_EDGE'] = verilog.quote( + random.choice( + ( + 'OPPOSITE_EDGE', + 'SAME_EDGE', + 'SAME_EDGE_PIPELINED', + ))) - print(''' + print( + ''' (* KEEP, DONT_TOUCH, LOC = "{ilogic_loc}" *) IDDR #( .IS_D_INVERTED({IS_D_INVERTED}), @@ -244,13 +253,16 @@ def use_direct_and_iddr(p, luts, connects): .Q2({q2}) ); '''.format( - cnet=luts.get_next_output_net(), - q1=luts.get_next_input_net(), - q2=luts.get_next_input_net(), - **p), file=connects) + 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(""" + 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}" *) @@ -258,56 +270,66 @@ def use_direct_and_iddr(p, luts, connects): ) idelay_site_{site} ( .IDATAIN({iwire}), .DATAOUT(idelay_{site}) - );""".format( - **p), file=connects) + );""".format(**p), + file=connects) - print(""" + print( + """ assign {owire} = {onet}; assign {twire} = {tnet}; """.format( onet=luts.get_next_output_net(), tnet=luts.get_next_output_net(), - **p), file=connects) + **p), + file=connects) if p['iddr_mux_config'] == 'direct': - print(''' - assign iddr_d_{site} = {iwire};'''.format( - **p, - ), file=connects) + 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) + print( + ''' + assign iddr_d_{site} = idelay_{site};'''.format(**p, ), + file=connects) elif p['iddr_mux_config'] == 'tristate_feedback': - print(''' + print( + ''' assign iddr_d_{site} = tfb_{site} ? ofb_{site} : idelay_{site};'''.format( - **p, - ), file=connects) + **p, ), + file=connects) elif p['iddr_mux_config'] == 'none': pass else: assert False, p['mux_config'] if p['mux_config'] == 'direct': - print(''' + print( + ''' assign {net} = {iwire};'''.format( - net=luts.get_next_input_net(), - **p, - ), file=connects) + net=luts.get_next_input_net(), + **p, + ), + file=connects) elif p['mux_config'] == 'idelay': - print(''' + print( + ''' assign {net} = idelay_{site};'''.format( - net=luts.get_next_input_net(), - **p, - ), file=connects) + 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'] + iostandards = [ + 'LVCMOS12', 'LVCMOS15', 'LVCMOS18', 'LVCMOS25', 'LVCMOS33', 'LVTTL' + ] iostandard = random.choice(iostandards) if iostandard in ['LVTTL', 'LVCMOS18']: @@ -330,7 +352,6 @@ def run(): if idx == 0: continue - p = {} p['tile'] = tile p['site'] = site @@ -342,16 +363,17 @@ def run(): 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) + 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']))) + 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) @@ -363,11 +385,11 @@ 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)) + '''.format(n_di=idx)) # Always output a LUT6 to make placer happy. - print(''' + print( + ''' (* KEEP, DONT_TOUCH *) LUT6 dummy_lut(); ''') @@ -375,7 +397,8 @@ module top(input clk, inout wire [`N_DI-1:0] dio); any_idelay = False for p in params: - print(''' + print( + ''' wire iddr_d_{site}; (* KEEP, DONT_TOUCH, LOC = "{site}" *) @@ -387,8 +410,8 @@ module top(input clk, inout wire [`N_DI-1:0] dio); .O({iwire}), .T({twire}) ); - '''.format( - **p), file=connects) + '''.format(**p), + file=connects) p['use_iserdese2'] = random.randint(0, 1) if p['use_iserdese2']: @@ -417,4 +440,3 @@ module top(input clk, inout wire [`N_DI-1:0] dio); if __name__ == '__main__': run() - From ac4accbd57d49b8dd7def681bbae13dc0b429d19 Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Thu, 28 Feb 2019 17:11:10 -0800 Subject: [PATCH 3/6] Add bit for standards that are stepdown. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- fuzzers/030-iob/generate.py | 7 +++++++ fuzzers/030-iob/process_rdb.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/fuzzers/030-iob/generate.py b/fuzzers/030-iob/generate.py index 7ad44b2c..ceb562dc 100644 --- a/fuzzers/030-iob/generate.py +++ b/fuzzers/030-iob/generate.py @@ -41,6 +41,9 @@ def drives_for_iostandard(iostandard): return drives +STEPDOWN_IOSTANDARDS = ['LVCMOS12', 'LVCMOS15', 'LVCMOS18'] + + def main(): print("Loading tags") segmk = Segmaker("design.bits") @@ -60,6 +63,10 @@ def main(): iostandard = verilog.unquote(d['IOSTANDARD']) + stepdown = iostandard in STEPDOWN_IOSTANDARDS + segmk.add_tile_tag( + d['tile'], '_'.join(STEPDOWN_IOSTANDARDS), stepdown) + if d['type'] is None: segmk.add_site_tag(site, 'INOUT', 0) segmk.add_site_tag(site, '{}.IN_USE'.format(iostandard), 0) diff --git a/fuzzers/030-iob/process_rdb.py b/fuzzers/030-iob/process_rdb.py index 3712e34b..786302c8 100644 --- a/fuzzers/030-iob/process_rdb.py +++ b/fuzzers/030-iob/process_rdb.py @@ -38,7 +38,7 @@ def main(): iostandard_lines = [] with open(args.input_rdb) as f: for l in f: - if '.LVCMOS' in l or '.LVTTL' in l: + if ('.LVCMOS' in l or '.LVTTL' in l) and 'IOB_' in l: iostandard_lines.append(l) else: print(l.strip()) From 9dccf2a59eb8e5f9d2938480f322763d6a8c8563 Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Thu, 28 Feb 2019 18:08:19 -0800 Subject: [PATCH 4/6] ZINV_D applies to both IFF and direct data path. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- fuzzers/035-iob-ilogic/generate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fuzzers/035-iob-ilogic/generate.py b/fuzzers/035-iob-ilogic/generate.py index 54610837..f907b938 100644 --- a/fuzzers/035-iob-ilogic/generate.py +++ b/fuzzers/035-iob-ilogic/generate.py @@ -105,7 +105,7 @@ def main(): 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']) + segmk.add_site_tag(site, 'ZINV_D', not d['IS_D_INVERTED']) if 'SRTYPE' in d: for opt in ['ASYNC', 'SYNC']: From 8d1866518248cbb4391c9b8419931a07a943a5ea Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Fri, 1 Mar 2019 08:21:36 -0800 Subject: [PATCH 5/6] Fix bugs found during review. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- fuzzers/030-iob/top.py | 9 +++++++-- fuzzers/035-iob-ilogic/top.py | 6 +++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/fuzzers/030-iob/top.py b/fuzzers/030-iob/top.py index e89456d6..3a0700b1 100644 --- a/fuzzers/030-iob/top.py +++ b/fuzzers/030-iob/top.py @@ -65,6 +65,7 @@ def run(): tile_params = [] params = [] + any_idelay = False for tile, site in gen_sites(): p = {} p['tile'] = tile @@ -81,6 +82,7 @@ def run(): 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 @@ -127,10 +129,13 @@ def run(): `define N_DIO {n_dio} 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)) + if any_idelay: + print(''' + (* KEEP, DONT_TOUCH *) + IDELAYCTRL();''') + # Always output a LUT6 to make placer happy. print(''' (* KEEP, DONT_TOUCH *) diff --git a/fuzzers/035-iob-ilogic/top.py b/fuzzers/035-iob-ilogic/top.py index 4404bdd9..7dc7320e 100644 --- a/fuzzers/035-iob-ilogic/top.py +++ b/fuzzers/035-iob-ilogic/top.py @@ -129,10 +129,10 @@ def use_iserdese2(p, luts, connects): 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: + if p['ODATA_WIDTH'] == 4 and verilog.unquote(p['ODATA_RATE']) == 'DDR': p['TRISTATE_WIDTH'] = 4 + else: + p['TRISTATE_WIDTH'] = 1 print( """ From 8f5fa39914316e45b2b75e2a74dd26c3991554b6 Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Fri, 1 Mar 2019 10:56:18 -0800 Subject: [PATCH 6/6] Rework stepdown bits to isolate top and bottom IOBs. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- fuzzers/030-iob/generate.py | 3 +- fuzzers/030-iob/process_rdb.py | 63 ++++++++++++++++++++++++++++++---- 2 files changed, 57 insertions(+), 9 deletions(-) diff --git a/fuzzers/030-iob/generate.py b/fuzzers/030-iob/generate.py index ceb562dc..64e9ff17 100644 --- a/fuzzers/030-iob/generate.py +++ b/fuzzers/030-iob/generate.py @@ -64,8 +64,7 @@ def main(): iostandard = verilog.unquote(d['IOSTANDARD']) stepdown = iostandard in STEPDOWN_IOSTANDARDS - segmk.add_tile_tag( - d['tile'], '_'.join(STEPDOWN_IOSTANDARDS), stepdown) + segmk.add_site_tag(site, '_'.join(STEPDOWN_IOSTANDARDS), stepdown) if d['type'] is None: segmk.add_site_tag(site, 'INOUT', 0) diff --git a/fuzzers/030-iob/process_rdb.py b/fuzzers/030-iob/process_rdb.py index 786302c8..abdd7ecc 100644 --- a/fuzzers/030-iob/process_rdb.py +++ b/fuzzers/030-iob/process_rdb.py @@ -27,6 +27,34 @@ def parse_bits(l): return frozenset(parts[1:]) +def filter_bits(site, bits): + """ Seperate top and bottom bits. + + Some IOSTANDARD bits are tile wide, but really only apply to a half. + It is hard to write a fuzzer for this, but it is easy to filter by site, + and all bits appear to have a nice hard halve seperatation in the bitidx. + """ + if site == 'IOB_Y0': + min_bitidx = 64 + max_bitidx = 127 + elif site == 'IOB_Y1': + min_bitidx = 0 + max_bitidx = 63 + else: + assert False, site + + def inner(): + for bit in bits: + bitidx = int(bit.split('_')[1]) + + if bitidx < min_bitidx or bitidx > max_bitidx: + continue + + yield bit + + return frozenset(inner()) + + def main(): parser = argparse.ArgumentParser( description="Convert IOB rdb into good rdb." @@ -43,16 +71,18 @@ def main(): else: print(l.strip()) - common_in_bits = { + common_in_only_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) + common_in_only_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])) + for site in sorted(common_in_only_bits): + print( + 'IOB33.{}.IN_ONLY'.format(site), ' '.join( + common_in_only_bits[site])) iostandard_in = {} outs = {} @@ -92,7 +122,13 @@ def main(): if drive not in drives[(site, iostandard)]: drives[(site, iostandard)][drive] = {} - drives[(site, iostandard)][drive] = parse_bits(l) + 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]) @@ -102,8 +138,21 @@ def main(): 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)) + 'IOB33.{}.{}.IN'.format(site, '_'.join(standards)), + ' '.join(bits | neg_bits)) iodrives = {} @@ -115,7 +164,7 @@ def main(): site, iostandard)] if site not in common_bits: - common_bits[site] = set(common_in_bits[site]) + common_bits[site] = set(common_in_only_bits[site]) common_bits[site] |= combined_bits