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>
This commit is contained in:
Keith Rothman 2019-02-28 16:36:02 -08:00
parent 6bc8d8ad02
commit 816bf44156
21 changed files with 1219 additions and 424 deletions

View File

@ -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

View File

@ -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

View File

@ -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<N> run)
2. Build the database again (e.g. make -j<N> 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()

View File

@ -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()

View File

@ -1,5 +0,0 @@
#!/bin/bash
set -ex
source ${XRAY_DIR}/utils/top_generate.sh

View File

@ -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

View File

@ -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()

View File

@ -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()

View File

@ -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

View File

@ -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()

View File

@ -1,5 +0,0 @@
#!/bin/bash
set -ex
source ${XRAY_DIR}/utils/top_generate.sh

View File

@ -1 +0,0 @@
LIOB33.IOB_Y1.MACRO

View File

@ -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()

View File

@ -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

View File

View File

@ -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()

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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:

View File

@ -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