Merge pull request #683 from litghost/iob_rework

Rework IOB fuzzers.
This commit is contained in:
litghost 2019-03-01 16:46:17 -08:00 committed by GitHub
commit ca45656e5f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 1354 additions and 424 deletions

View File

@ -1,30 +1,21 @@
N := 1 N := 50
include ../fuzzer.mk include ../fuzzer.mk
SEGDATAS_L=$(addsuffix /segdata_liob33.txt,$(SPECIMENS)) database: build/segbits_xiob33.db
SEGDATAS_R=$(addsuffix /segdata_riob33.txt,$(SPECIMENS))
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) build/segbits_xiob33.db: build/segbits_xiob33.rdb process_rdb.py bits.dbf
${XRAY_SEGMATCH} -o build/segbits_liob33.rdb $(SEGDATAS_L) 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 $@
build/segbits_liob33.db: build/segbits_liob33.rdb ${XRAY_MASKMERGE} build/mask_xiob33.db $$(find -name segdata_liob33.txt) $$(find -name segdata_riob33.txt)
${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)
pushdb: pushdb:
${XRAY_MERGEDB} liob33 build/segbits_liob33.db ${XRAY_MERGEDB} liob33 build/segbits_xiob33.db
${XRAY_MERGEDB} riob33 build/segbits_riob33.db ${XRAY_MERGEDB} riob33 build/segbits_xiob33.db
${XRAY_MERGEDB} mask_liob33 build/mask_liob33.db ${XRAY_MERGEDB} mask_liob33 build/mask_xiob33.db
${XRAY_MERGEDB} mask_riob33 build/mask_riob33.db ${XRAY_MERGEDB} mask_riob33 build/mask_xiob33.db
.PHONY: database pushdb .PHONY: database pushdb

View File

@ -1,12 +1,4 @@
38_92 39_93 38_94,LIOB33.IOB_Y0.PULLTYPE.PULLDOWN 38_92 39_93 38_94,IOB33.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,IOB33.IOB_Y0.SLEW.FAST
38_106 38_110 39_105 39_109,LIOB33.IOB_Y0.SLEW.FAST 39_33 38_34 39_35,IOB33.IOB_Y1.PULLTYPE.PULLDOWN
39_33 38_34 39_35,LIOB33.IOB_Y1.PULLTYPE.PULLDOWN 38_18 38_22 39_17 39_21,IOB33.IOB_Y1.SLEW.FAST
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

View File

@ -0,0 +1,129 @@
""" 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,147 @@
from prjxray.segmaker import Segmaker from prjxray.segmaker import Segmaker
from prjxray import segmaker from prjxray import segmaker
from prjxray import verilog
import os
import json
segmk = Segmaker("design.bits")
print("Loading tags") def bitfilter(frame, word):
''' if frame < 26:
port,site,tile,pin,slew,drive,pulltype return False
di[0],IOB_X0Y107,LIOB33_X0Y107,A21,PULLDOWN
di[10],IOB_X0Y147,LIOB33_X0Y147,F14,PULLUP return True
'''
f = open('design.csv', 'r')
f.readline() def mk_drive_opt(iostandard, drive):
for l in f: return '{}.DRIVE.I{}'.format(iostandard, drive)
l = l.strip()
port, site, tile, pin, iostandard, slew, drive, pulltype = l.split(',')
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
STEPDOWN_IOSTANDARDS = ['LVCMOS12', 'LVCMOS15', 'LVCMOS18']
def main():
print("Loading tags")
segmk = Segmaker("design.bits")
''' '''
LVCMOS25 port,site,tile,pin,slew,drive,pulltype
SLEW 38_82 38_86 39_81 39_85 di[0],IOB_X0Y107,LIOB33_X0Y107,A21,PULLDOWN
SLOW X X X X di[10],IOB_X0Y147,LIOB33_X0Y147,F14,PULLUP
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
''' '''
if pulltype == "": with open('params.jl', 'r') as f:
pulltype = "NONE" design = json.load(f)
segmaker.add_site_group_zero(
segmk, site, "PULLTYPE.", ("NONE", "KEEPER", "PULLDOWN", "PULLUP"),
"PULLDOWN", pulltype)
segmaker.add_site_group_zero( for d in design:
segmk, site, iostandard + ".DRIVE.", ("4", "8", "12", "16"), "12", site = d['site']
drive)
segmaker.add_site_group_zero( if skip_broken_tiles(d):
segmk, site, "SLEW.", ("SLOW", "FAST"), "FAST", slew) continue
segmk.compile()
segmk.write() iostandard = verilog.unquote(d['IOSTANDARD'])
stepdown = iostandard in STEPDOWN_IOSTANDARDS
segmk.add_site_tag(site, '_'.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)
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 # IOB_X0Y129 do[0] output
set fp [open "params.csv" r] set fp [open "params.csv" r]
gets $fp line
set pin_lines {} set pin_lines {}
for {gets $fp line} {$line != ""} {gets $fp line} { for {gets $fp line} {$line != ""} {gets $fp line} {
lappend pin_lines [split $line ","] lappend pin_lines [split $line ","]
@ -31,51 +33,46 @@ proc loc_pins {} {
set pin_lines [load_pin_lines] set pin_lines [load_pin_lines]
set io_pin_sites [make_io_pin_sites] 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" puts "Looping"
for {set idx 0} {$idx < [llength $pin_lines]} {incr idx} { for {set idx 0} {$idx < [llength $pin_lines]} {incr idx} {
set line [lindex $pin_lines $idx] set line [lindex $pin_lines $idx]
puts "$line" puts "$line"
set site_str [lindex $line 0] set site_str [lindex $line 1]
set pin_str [lindex $line 1] set pin_str [lindex $line 2]
set io [lindex $line 2] set iostandard [lindex $line 3]
set cell_str [lindex $line 3] set drive [lindex $line 4]
set slew [lindex $line 5]
set pulltype [lindex $line 6]
# Have: site # Have: site
# Want: pin for site # Want: pin for site
set site [get_sites $site_str] set site [get_sites $site_str]
set pad_bel [get_bels -of_objects $site -filter {TYPE =~ PAD && NAME =~ IOB_*}] set pad_bel [get_bels -of_objects $site -filter {TYPE =~ PAD && NAME =~ IOB_*}]
# set port [get_ports -of_objects $site] # set port [get_ports -of_objects $site]
set port [get_ports $pin_str] set port [get_ports $pin_str]
set tile [get_tiles -of_objects $site] set tile [get_tiles -of_objects $site]
set pin [dict get $io_pin_sites $site] set pin [dict get $io_pin_sites $site]
set iostandard_val "LVCMOS25" set props {}
set_property -dict "PACKAGE_PIN $pin IOSTANDARD $iostandard_val" $port lappend props PACKAGE_PIN $pin
lappend props IOSTANDARD $iostandard
lappend props PULLTYPE $pulltype
set pulltype "NONE PULLUP PULLDOWN KEEPER" if {$drive != "None"} {
set pulltype_val [randsample_list 1 $pulltype] lappend props DRIVE $drive
if { $pulltype_val == "NONE" } {
set pulltype_val ""
} }
set_property PULLTYPE $pulltype_val $port
if {$io == "input"} continue if {$slew != "None"} {
lappend props SLEW $slew
}
set drive "4 8 12 16" puts $props
set drive_val [lindex $drive [expr {$idx % 4}]]
set_property DRIVE $drive_val $port
set slew "SLOW FAST" set_property -dict "$props" $port
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"
} }
close $fp
} }
proc run {} { proc run {} {
@ -83,17 +80,14 @@ proc run {} {
read_verilog top.v read_verilog top.v
synth_design -top top 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 loc_pins
set_property CFGBVS VCCO [current_design] set_property CFGBVS VCCO [current_design]
set_property CONFIG_VOLTAGE 3.3 [current_design] set_property CONFIG_VOLTAGE 3.3 [current_design]
set_property BITSTREAM.GENERAL.PERFRAMECRC YES [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 place_design
route_design route_design

View File

@ -0,0 +1,193 @@
""" 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 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."
"")
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) and 'IOB_' in l:
iostandard_lines.append(l)
else:
print(l.strip())
common_in_only_bits = {
'IOB_Y0': set(),
'IOB_Y1': set(),
}
for l in iostandard_lines:
if 'IN_OUT_COMMON' in l:
common_in_only_bits[get_site(l)] |= parse_bits(l)
for site in sorted(common_in_only_bits):
print(
'IOB33.{}.IN_ONLY'.format(site), ' '.join(
common_in_only_bits[site]))
iostandard_in = {}
outs = {}
drives = {}
in_use = {}
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] = filter_bits(
site, parse_bits(l))
common_in_bits = {
'IOB_Y0': set(),
'IOB_Y1': set(),
}
for bits in sorted(iostandard_in.keys()):
sites, standards = zip(*iostandard_in[bits])
site = set(sites)
assert len(site) == 1, site
site = site.pop()
common_in_bits[site] |= bits
for bits in sorted(iostandard_in.keys()):
sites, standards = zip(*iostandard_in[bits])
site = set(sites)
assert len(site) == 1, site
site = site.pop()
neg_bits = set('!' + bit for bit in (common_in_bits[site] - bits))
print(
'IOB33.{}.{}.IN'.format(site, '_'.join(standards)),
' '.join(bits | neg_bits))
iodrives = {}
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_only_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 @@
''' import json
Generate a primitive to place at every I/O import io
Unlike CLB tests, the LFSR for this is inside the ROI, not driving it
'''
import os import os
import random import random
random.seed(int(os.getenv("SEED"), 16)) random.seed(int(os.getenv("SEED"), 16))
from prjxray import util from prjxray import util
from prjxray import lut_maker
from prjxray import verilog from prjxray import verilog
from prjxray.db import Database from prjxray.db import Database
def gen_iobs(): def gen_sites():
''' '''
IOB33S: main IOB of a diff pair IOB33S: main IOB of a diff pair
IOB33M: secondary IOB of a diff pair IOB33M: secondary IOB of a diff pair
@ -26,124 +24,189 @@ def gen_iobs():
for site_name, site_type in gridinfo.sites.items(): for site_name, site_type in gridinfo.sites.items():
if site_type in ['IOB33S', 'IOB33M']: if site_type in ['IOB33S', 'IOB33M']:
yield site_name, site_type yield tile_name, site_name
def write_pins(ports): def write_params(params):
pinstr = '' pinstr = 'tile,site,pin,iostandard,drive,slew\n'
for site, (name, dir_, cell) in sorted(ports.items(), key=lambda x: x[1]): for vals in params:
# pinstr += 'set_property -dict "PACKAGE_PIN %s IOSTANDARD LVCMOS33" [get_ports %s]' % (packpin, port) pinstr += ','.join(map(str, vals)) + '\n'
pinstr += '%s,%s,%s,%s\n' % (site, name, dir_, cell)
open('params.csv', 'w').write(pinstr) open('params.csv', 'w').write(pinstr)
def run(): def run():
# All possible values tile_types = [
iosites = {} 'IBUF', 'OBUF', 'IOBUF_INTERMDISABLE', None, None, None, None, None
for site_name, site_type in gen_iobs(): ]
iosites[site_name] = site_type
# Assigned in this design i_idx = 0
ports = {} o_idx = 0
DIN_N = 0 io_idx = 0
DOUT_N = 0
def remain_sites(): iostandards = [
return set(iosites.keys()) - set(ports.keys()) 'LVCMOS12', 'LVCMOS15', 'LVCMOS18', 'LVCMOS25', 'LVCMOS33', 'LVTTL'
]
iostandard = random.choice(iostandards)
def rand_site(): if iostandard in ['LVTTL', 'LVCMOS18']:
'''Get a random, unused site''' drives = [4, 8, 12, 16, 24]
return random.choice(list(remain_sites())) elif iostandard == 'LVCMOS12':
drives = [4, 8, 12]
else:
drives = [4, 8, 12, 16]
def assign_i(site, name): slews = ['FAST', 'SLOW']
nonlocal DIN_N pulls = ["NONE", "KEEPER", "PULLDOWN", "PULLUP"]
assert site not in ports luts = lut_maker.LutMaker()
cell = "di_bufs[%u].ibuf" % DIN_N
DIN_N += 1
ports[site] = (name, 'input', cell)
def assign_o(site, name): connects = io.StringIO()
nonlocal DOUT_N
assert site not in ports tile_params = []
cell = "do_bufs[%u].obuf" % DOUT_N params = []
DOUT_N += 1 any_idelay = False
ports[site] = (name, 'output', cell) 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 if p['type'] is None:
assign_i(rand_site(), 'di[0]') p['pad_wire'] = None
assign_o(rand_site(), 'do[0]') elif p['type'] == 'IBUF':
# Now assign the rest randomly p['pad_wire'] = 'di[{}]'.format(i_idx)
while len(remain_sites()): p['IDELAY_ONLY'] = random.randint(0, 1)
assign_o(rand_site(), 'do[%u]' % DOUT_N) if not p['IDELAY_ONLY']:
p['owire'] = luts.get_next_input_net()
else:
any_idelay = True
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( print(
''' '''
`define N_DI %u `define N_DI {n_di}
`define N_DO %u `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); module top(input wire [`N_DI-1:0] di, output wire [`N_DO-1:0] do, inout wire [`N_DIO-1:0] dio);
genvar i; '''.format(n_di=i_idx, n_do=o_idx, n_dio=io_idx))
//Instantiate BUFs so we can LOC them if any_idelay:
print('''
(* KEEP, DONT_TOUCH *)
IDELAYCTRL();''')
wire [`N_DI-1:0] di_buf; # Always output a LUT6 to make placer happy.
generate print('''
for (i = 0; i < `N_DI; i = i+1) begin:di_bufs (* KEEP, DONT_TOUCH *)
IBUF ibuf(.I(di[i]), .O(di_buf[i])); LUT6 dummy_lut();''')
end
endgenerate
wire [`N_DO-1:0] do_unbuf; for p in params:
generate if p['type'] is None:
for (i = 0; i < `N_DO; i = i+1) begin:do_bufs continue
OBUF obuf(.I(do_unbuf[i]), .O(do[i])); elif p['type'] == 'IBUF':
end print(
endgenerate '''
wire idelay_{site};
roi roi(.di(di_buf), .do(do_unbuf)); (* KEEP, DONT_TOUCH *)
endmodule 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)
//Arbitrary terminate into LUTs elif p['type'] == 'OBUF':
module roi(input wire [`N_DI-1:0] di, output wire [`N_DO-1:0] do); print(
genvar i; '''
(* 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)
generate for l in luts.create_wires_and_luts():
for (i = 0; i < `N_DI; i = i+1) begin:dis print(l)
(* 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 print(connects.getvalue())
for (i = 0; i < `N_DO; i = i+1) begin:dos
(* KEEP, DONT_TOUCH *) print("endmodule")
LUT6 #(
.INIT(64'h8000_0000_0000_0001) with open('params.jl', 'w') as f:
) lut ( json.dump(params, f, indent=2)
.I0(),
.I1(),
.I2(),
.I3(),
.I4(),
.I5(),
.O(do[i]));
end
endgenerate
endmodule
''' % (DIN_N, DOUT_N))
if __name__ == '__main__': if __name__ == '__main__':

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,190 @@
#!/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, '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 # IOB_X0Y129 do[0] output
set fp [open "params.csv" r] set fp [open "params.csv" r]
gets $fp line
set pin_lines {} set pin_lines {}
for {gets $fp line} {$line != ""} {gets $fp line} { for {gets $fp line} {$line != ""} {gets $fp line} {
lappend pin_lines [split $line ","] lappend pin_lines [split $line ","]
@ -31,36 +33,46 @@ proc loc_pins {} {
set pin_lines [load_pin_lines] set pin_lines [load_pin_lines]
set io_pin_sites [make_io_pin_sites] set io_pin_sites [make_io_pin_sites]
set fp [open "design.csv" w]
puts $fp "port,site,tile,pin,val"
puts "Looping" 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] set line [lindex $pin_lines $idx]
puts "$line" puts "$line"
set site_str [lindex $line 0] set site_str [lindex $line 1]
set pin_str [lindex $line 1] set pin_str [lindex $line 2]
set io [lindex $line 2] set iostandard [lindex $line 3]
set cell_str [lindex $line 3] set drive [lindex $line 4]
# Skip unused site set slew [lindex $line 5]
if {"$pin_str" == ""} { set pulltype [lindex $line 6]
continue
}
# Have: site # Have: site
# Want: pin for site # Want: pin for site
set site [get_sites $site_str] set site [get_sites $site_str]
set pad_bel [get_bels -of_objects $site -filter {TYPE =~ PAD && NAME =~ IOB_*}] 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 port [get_ports $pin_str]
set tile [get_tiles -of_objects $site] set tile [get_tiles -of_objects $site]
set pin [dict get $io_pin_sites $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 {} { proc run {} {
@ -68,17 +80,14 @@ proc run {} {
read_verilog top.v read_verilog top.v
synth_design -top top 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 loc_pins
set_property CFGBVS VCCO [current_design] set_property CFGBVS VCCO [current_design]
set_property CONFIG_VOLTAGE 3.3 [current_design] set_property CONFIG_VOLTAGE 3.3 [current_design]
set_property BITSTREAM.GENERAL.PERFRAMECRC YES [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 place_design
route_design route_design

View File

@ -0,0 +1,442 @@
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 and verilog.unquote(p['ODATA_RATE']) == 'DDR':
p['TRISTATE_WIDTH'] = 4
else:
p['TRISTATE_WIDTH'] = 1
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,027-bram36-config,005-tilegrid))
$(eval $(call fuzzer,028-fifo-config,005-tilegrid)) $(eval $(call fuzzer,028-fifo-config,005-tilegrid))
$(eval $(call fuzzer,029-bram-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,040-clk-hrow-config,005-tilegrid))
$(eval $(call fuzzer,041-clk-hrow-pips,005-tilegrid)) $(eval $(call fuzzer,041-clk-hrow-pips,005-tilegrid))
# 042 fuzzer is unstable, issue #657 # 042 fuzzer is unstable, issue #657

View File

@ -336,9 +336,13 @@ class Segmaker:
-CLBLM_L => CLB -CLBLM_L => CLB
-CENTER_INTER_R => CENTER_INTER -CENTER_INTER_R => CENTER_INTER
-CLK_HROW_TOP_R => CLK_HROW -CLK_HROW_TOP_R => CLK_HROW
-LIOB33 => IOB33
''' '''
tile_type_norm = re.sub("(_TOP|_BOT|LL|LM)?_[LR]$", "", tile_type) 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) # ignore dummy tiles (ex: VBRK)
if len(tiledata['bits']) == 0: if len(tiledata['bits']) == 0:
if self.verbose: if self.verbose:

View File

@ -87,7 +87,10 @@ case "$1" in
cp "$2" "$tmp1" ;; cp "$2" "$tmp1" ;;
liob33) liob33)
cp "$2" "$tmp1" ;; sed < "$2" > "$tmp1" -e 's/^IOB33\./LIOB33./' ;;
riob33)
sed < "$2" > "$tmp1" -e 's/^IOB33\./RIOB33./' ;;
mask_*) mask_*)
db=$XRAY_DATABASE_DIR/$XRAY_DATABASE/$1.db db=$XRAY_DATABASE_DIR/$XRAY_DATABASE/$1.db