Merge pull request #638 from litghost/add_clk_hrow_bits

Add CLK HROW bits
This commit is contained in:
litghost 2019-02-12 15:15:03 -08:00 committed by GitHub
commit c39b67007a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 1049 additions and 28 deletions

View File

@ -13,6 +13,7 @@ TILEGRID_TDB_DEPENDENCIES += dsp/build/segbits_tilegrid.tdb
TILEGRID_TDB_DEPENDENCIES += fifo_int/build/segbits_tilegrid.tdb
TILEGRID_TDB_DEPENDENCIES += cfg_int/build/segbits_tilegrid.tdb
TILEGRID_TDB_DEPENDENCIES += monitor_int/build/segbits_tilegrid.tdb
TILEGRID_TDB_DEPENDENCIES += clk_hrow/build/segbits_tilegrid.tdb
GENERATE_FULL_ARGS=
ifeq (${XRAY_DATABASE}, zynq7)
@ -96,6 +97,9 @@ cfg_int/build/segbits_tilegrid.tdb: build/basicdb/tilegrid.json
orphan_int_column/build/segbits_tilegrid.tdb: build/basicdb/tilegrid.json
cd orphan_int_column && $(MAKE)
clk_hrow/build/segbits_tilegrid.tdb: build/basicdb/tilegrid.json
cd clk_hrow && $(MAKE)
build/tilegrid_tdb.json: add_tdb.py $(TILEGRID_TDB_DEPENDENCIES)
python3 add_tdb.py \
--fn-in build/basicdb/tilegrid.json \
@ -129,6 +133,7 @@ clean:
cd monitor_int && $(MAKE) clean
cd cfg_int && $(MAKE) clean
cd orphan_int_column && $(MAKE) clean
cd clk_hrow && $(MAKE) clean
.PHONY: database pushdb clean run

View File

@ -84,6 +84,7 @@ def run(fn_in, fn_out, verbose=False):
("bram_block/build/segbits_tilegrid.tdb", 128, 10),
("clb/build/segbits_tilegrid.tdb", 36, 2),
("dsp/build/segbits_tilegrid.tdb", 28, 10),
("clk_hrow/build/segbits_tilegrid.tdb", 30, 7),
("clb_int/build/segbits_tilegrid.tdb", int_frames, int_words),
("iob_int/build/segbits_tilegrid.tdb", int_frames, int_words),
("bram_int/build/segbits_tilegrid.tdb", int_frames, int_words),

View File

@ -0,0 +1,4 @@
N ?= 5
GENERATE_ARGS?="--oneval 1 --design params.csv --dword 1 --dframe 1A"
include ../fuzzaddr/common.mk

View File

@ -0,0 +1,21 @@
source "$::env(XRAY_DIR)/utils/utils.tcl"
proc run {} {
create_project -force -part $::env(XRAY_PART) design design
read_verilog top.v
synth_design -top top
#set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_00) IOSTANDARD LVCMOS33" [get_ports clk]
set_property CFGBVS VCCO [current_design]
set_property CONFIG_VOLTAGE 3.3 [current_design]
set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design]
place_design
route_design
write_checkpoint -force design.dcp
write_bitstream -force design.bit
}
run

View File

@ -0,0 +1,59 @@
import os
import random
random.seed(int(os.getenv("SEED"), 16))
from prjxray import util
from prjxray.db import Database
def gen_sites():
db = Database(util.get_db_root())
grid = db.grid()
for tile_name in grid.tiles():
loc = grid.loc_of_tilename(tile_name)
gridinfo = grid.gridinfo_at_loc(loc)
sites = []
for site, site_type in gridinfo.sites.items():
if site_type == 'BUFHCE':
sites.append(site)
if sites:
yield tile_name, sorted(sites)
def write_params(params):
pinstr = 'tile,val,site\n'
for tile, (site, val) in sorted(params.items()):
pinstr += '%s,%s,%s\n' % (tile, val, site)
open('params.csv', 'w').write(pinstr)
def run():
print('''
module top();
''')
params = {}
sites = list(gen_sites())
for (tile_name, sites), isone in zip(sites,
util.gen_fuzz_states(len(sites))):
site_name = sites[0]
params[tile_name] = (site_name, isone)
print(
'''
(* KEEP, DONT_TOUCH, LOC = "{site}" *)
BUFHCE #(
.INIT_OUT({isone})
) buf_{site} ();
'''.format(
site=site_name,
isone=isone,
))
print("endmodule")
write_params(params)
if __name__ == '__main__':
run()

View File

@ -0,0 +1,26 @@
N ?= 15
include ../fuzzer.mk
database: build/segbits_clk_hrow.db
build/segbits_clk_hrow.rdb: $(SPECIMENS_OK)
${XRAY_SEGMATCH} -o build/segbits_clk_hrow.rdb \
$(addsuffix /segdata_clk_hrow_top_r.txt,$(SPECIMENS)) \
$(addsuffix /segdata_clk_hrow_bot_r.txt,$(SPECIMENS))
build/segbits_clk_hrow.db: build/segbits_clk_hrow.rdb
${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf \
--seg-fn-in build/segbits_clk_hrow.rdb \
--seg-fn-out build/segbits_clk_hrow.db
${XRAY_MASKMERGE} build/mask_clk_hrow.db \
$(addsuffix /segdata_clk_hrow_top_r.txt,$(SPECIMENS)) \
$(addsuffix /segdata_clk_hrow_bot_r.txt,$(SPECIMENS))
pushdb: database
${XRAY_MERGEDB} clk_hrow_bot_r build/segbits_clk_hrow.db
${XRAY_MERGEDB} clk_hrow_top_r build/segbits_clk_hrow.db
${XRAY_MERGEDB} mask_clk_hrow_bot_r build/mask_clk_hrow.db
${XRAY_MERGEDB} mask_clk_hrow_top_r build/mask_clk_hrow.db
.PHONY: database pushdb

View File

View File

@ -0,0 +1,42 @@
#!/usr/bin/env python3
import json
from prjxray.segmaker import Segmaker
from prjxray import verilog
def main():
segmk = Segmaker("design.bits")
print("Loading tags")
with open('params.json') as f:
params = json.load(f)
for row in params:
base_name = 'BUFHCE_X{}Y{}'.format(row['x'], row['y'])
segmk.add_site_tag(
row['site'], '{}.IN_USE'.format(base_name), row['IN_USE'])
if not row['IN_USE']:
continue
segmk.add_site_tag(
row['site'], '{}.INIT_OUT'.format(base_name), row['INIT_OUT'])
segmk.add_site_tag(
row['site'], '{}.ZINV_CE'.format(base_name),
1 ^ row['IS_CE_INVERTED'])
# SYNC is a zero pattern
for opt in ['ASYNC']:
segmk.add_site_tag(
row['site'], '{}.CE_TYPE.'.format(base_name) + opt,
verilog.unquote(row['CE_TYPE']) == opt)
segmk.compile()
segmk.write()
if __name__ == '__main__':
main()

View File

@ -0,0 +1,17 @@
proc run {} {
create_project -force -part $::env(XRAY_PART) design design
read_verilog top.v
synth_design -top top
set_property CFGBVS VCCO [current_design]
set_property CONFIG_VOLTAGE 3.3 [current_design]
set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design]
place_design
route_design
write_checkpoint -force design.dcp
write_bitstream -force design.bit
}
run

View File

@ -0,0 +1,73 @@
import json
import os
import random
random.seed(int(os.getenv("SEED"), 16))
from prjxray import util
from prjxray import verilog
from prjxray.db import Database
def gen_sites():
get_xy = util.create_xy_fun('BUFHCE_')
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)
sites = []
xs = []
ys = []
for site, site_type in gridinfo.sites.items():
if site_type == 'BUFHCE':
x, y = get_xy(site)
xs.append(x)
ys.append(y)
sites.append((site, x, y))
if sites:
yield tile_name, min(xs), min(ys), sorted(sites)
def main():
print('''
module top();
''')
params_list = []
for tile_name, x_min, y_min, sites in gen_sites():
for site, x, y in sites:
params = {}
params['tile'] = tile_name
params['site'] = site
params['x'] = x - x_min
params['y'] = y - y_min
params['IN_USE'] = random.randint(0, 1)
if params['IN_USE']:
params['INIT_OUT'] = random.randint(0, 1)
params['CE_TYPE'] = verilog.quote(
random.choice(('SYNC', 'ASYNC')))
params['IS_CE_INVERTED'] = random.randint(0, 1)
print(
'''
(* KEEP, DONT_TOUCH, LOC = "{site}" *)
BUFHCE #(
.INIT_OUT({INIT_OUT}),
.CE_TYPE({CE_TYPE}),
.IS_CE_INVERTED({IS_CE_INVERTED})
) buf_{site} ();
'''.format(**params))
params_list.append(params)
print("endmodule")
with open('params.json', 'w') as f:
json.dump(params_list, f, indent=2)
if __name__ == '__main__':
main()

View File

@ -0,0 +1,56 @@
export FUZDIR=$(shell pwd)
PIP_TYPE?=clk_hrow
PIPLIST_TCL=$(FUZDIR)/clk_hrow_pip_list.tcl
MAKETODO_FLAGS=--no-l --pip-type clk_hrow_bot --seg-type clk_hrow_bot --re "[^\.]+\.CLK_HROW_CK_MUX_OUT_"
N = 50
# These PIPs all appear to be either a 0 or 2 bit solution.
SEGMATCH_FLAGS=-m 20 -M 45 -c 2
SPECIMENS_DEPS=build/cmt_regions.csv
A_PIPLIST=clk_hrow_bot_r.txt
include ../pip_loop.mk
database: build/segbits_clk_hrow.db
build/cmt_regions.csv: output_cmt.tcl
mkdir -p build
cd build/ && ${XRAY_VIVADO} -mode batch -source ${FUZDIR}/output_cmt.tcl
build/segbits_clk_hrow.rdb: $(SPECIMENS_OK)
${XRAY_SEGMATCH} -o build/segbits_clk_hrow.rdb \
$(addsuffix /segdata_clk_hrow_top_r.txt,$(SPECIMENS)) \
$(addsuffix /segdata_clk_hrow_bot_r.txt,$(SPECIMENS))
build/segbits_clk_hrow.db: build/segbits_clk_hrow.rdb $(XRAY_FUZZERS_DIR)/piplist/build/clk_hrow_bot_r.txt
${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf \
--seg-fn-in build/segbits_clk_hrow.rdb \
--seg-fn-out build/segbits_clk_hrow_rc.db
# Convert row/column into PIP definition.
python3 merge_clk_entries.py \
build/segbits_clk_hrow_rc.db \
$(XRAY_FUZZERS_DIR)/piplist/build/clk_hrow_bot_r.txt \
build/segbits_clk_hrow.db
# Keep a copy to track iter progress
cp build/segbits_clk_hrow.rdb build/$(ITER)/segbits_clk_hrow.rdb
cp build/segbits_clk_hrow_rc.db build/$(ITER)/segbits_clk_hrow_rc.db
${XRAY_MASKMERGE} build/mask_clk_hrow.db \
$(addsuffix /segdata_clk_hrow_top_r.txt,$(SPECIMENS)) \
$(addsuffix /segdata_clk_hrow_bot_r.txt,$(SPECIMENS))
# Clobber existing .db to eliminate potential conflicts
cp ${XRAY_DATABASE_DIR}/${XRAY_DATABASE}/segbits*.db build/database/${XRAY_DATABASE}
XRAY_DATABASE_DIR=${FUZDIR}/build/database ${XRAY_MERGEDB} clk_hrow_bot_r build/segbits_clk_hrow.db
XRAY_DATABASE_DIR=${FUZDIR}/build/database ${XRAY_MERGEDB} clk_hrow_top_r build/segbits_clk_hrow.db
pushdb: database
${XRAY_MERGEDB} clk_hrow_bot_r build/segbits_clk_hrow.db
${XRAY_MERGEDB} clk_hrow_top_r build/segbits_clk_hrow.db
${XRAY_MERGEDB} mask_clk_hrow_bot_r build/mask_clk_hrow.db
${XRAY_MERGEDB} mask_clk_hrow_top_r build/mask_clk_hrow.db
.PHONY: database pushdb

View File

View File

@ -0,0 +1,20 @@
proc print_tile_pips {tile_type filename} {
set tile [lindex [get_tiles -filter "TYPE == $tile_type"] 0]
puts "Dumping PIPs for tile $tile ($tile_type) to $filename."
set fp [open $filename w]
foreach pip [lsort [get_pips -of_objects [get_tiles $tile]]] {
set src [get_wires -uphill -of_objects $pip]
set dst [get_wires -downhill -of_objects $pip]
if {[llength [get_nodes -uphill -of_objects [get_nodes -of_objects $dst]]] != 1} {
puts $fp "$tile_type.[regsub {.*/} $dst ""].[regsub {.*/} $src ""]"
}
}
close $fp
}
create_project -force -part $::env(XRAY_PART) design design
set_property design_mode PinPlanning [current_fileset]
open_io_design -name io_1
print_tile_pips CLK_HROW_TOP_R clk_hrow_top_r.txt
print_tile_pips CLK_HROW_BOT_R clk_hrow_bot_r.txt

View File

@ -0,0 +1,34 @@
HCLKS = 24
GCLKS = 32
SIDE_CLK_INPUTS = 14
CLK_TABLE_NUM_ROWS = 8
CLK_TABLE_NUM_COLS = 8
def get_clk_table():
clk_table = {}
for gclk in range(GCLKS):
gclk_name = 'CLK_HROW_R_CK_GCLK{}'.format(gclk)
row = gclk % CLK_TABLE_NUM_ROWS
column = int(gclk / CLK_TABLE_NUM_ROWS)
clk_table[gclk_name] = (row, column)
for row in range(8):
clk_table['CLK_HROW_CK_IN_L{}'.format(row)] = (row, 4)
for row in range(6):
clk_table['CLK_HROW_CK_IN_L{}'.format(row + 8)] = (row, 5)
for row in range(8):
clk_table['CLK_HROW_CK_IN_R{}'.format(row)] = (row, 6)
for row in range(6):
clk_table['CLK_HROW_CK_IN_R{}'.format(row + 8)] = (row, 7)
# HROW_CK_INT_<X>_<Y>, Y == Y share the same bits, and only X = 0 or X = 1
# are present on a particular HROW.
for y in range(2):
for x in range(2):
int_clk_name = 'CLK_HROW_CK_INT_{}_{}'.format(x, y)
clk_table[int_clk_name] = (y + 6, 7)
return clk_table

View File

@ -0,0 +1,52 @@
#!/usr/bin/env python3
from prjxray.segmaker import Segmaker
import clk_table
def main():
segmk = Segmaker("design.bits")
table = clk_table.get_clk_table()
print("Loading tags from design.txt.")
with open("design.txt", "r") as f:
for line in f:
tile, pip, src, dst, pnum, pdir = line.split()
if not tile.startswith('CLK_HROW'):
continue
pip_prefix, pip = pip.split(".")
tile_from_pip, tile_type = pip_prefix.split('/')
assert tile == tile_from_pip
_, src = src.split("/")
_, dst = dst.split("/")
rows = set(range(clk_table.CLK_TABLE_NUM_ROWS))
columns = set(range(clk_table.CLK_TABLE_NUM_COLS))
if src in table:
row, column = table[src]
segmk.add_tile_tag(
tile, '{}.HCLK_ENABLE_ROW{}'.format(dst, row), 1)
segmk.add_tile_tag(
tile, '{}.HCLK_ENABLE_COLUMN{}'.format(dst, column), 1)
rows.remove(row)
columns.remove(column)
for row in rows:
segmk.add_tile_tag(
tile, '{}.HCLK_ENABLE_ROW{}'.format(dst, row), 0)
for column in columns:
segmk.add_tile_tag(
tile, '{}.HCLK_ENABLE_COLUMN{}'.format(dst, column), 0)
segmk.compile()
segmk.write()
if __name__ == '__main__':
main()

View File

@ -0,0 +1,167 @@
source "$::env(XRAY_DIR)/utils/utils.tcl"
proc write_pip_txtdata {filename} {
puts "FUZ([pwd]): Writing $filename."
set fp [open $filename w]
set nets [get_nets -hierarchical]
set nnets [llength $nets]
set neti 0
foreach net $nets {
incr neti
if {($neti % 100) == 0 } {
puts "FUZ([pwd]): Dumping pips from net $net ($neti / $nnets)"
}
foreach pip [get_pips -of_objects $net] {
set tile [get_tiles -of_objects $pip]
set src_wire [get_wires -uphill -of_objects $pip]
set dst_wire [get_wires -downhill -of_objects $pip]
set num_pips [llength [get_nodes -uphill -of_objects [get_nodes -of_objects $dst_wire]]]
set dir_prop [get_property IS_DIRECTIONAL $pip]
puts $fp "$tile $pip $src_wire $dst_wire $num_pips $dir_prop"
}
}
close $fp
}
proc load_todo {} {
set fp [open "../../todo.txt" r]
set todo_lines {}
for {gets $fp line} {$line != ""} {gets $fp line} {
lappend todo_lines [split $line .]
}
close $fp
return $todo_lines
}
proc route_todo {} {
puts "Checking TODO's"
set todo_lines [load_todo]
set srcs {}
foreach todo $todo_lines {
set src [lindex $todo 2]
if [string match "*CLK_HROW_CK_IN_*" $src] {
lappend srcs $src
}
}
set srcs [lsort -unique $srcs]
set nets [get_nets -hierarchical "*clock*"]
set found_wires {}
set remaining_nets {}
foreach net $nets {
set wires [get_wires -of_objects $net]
foreach wire $wires {
if [regexp "CLK_HROW_CK_IN_\[LR\]\[0-9\]+" $wire] {
# Route already going where we want it, continue
puts "Checking wire $wire."
set wire [lindex [split $wire "/"] 1]
if {[lsearch -regexp $srcs "$wire$"] != -1} {
puts "Found in TODO list, removing from list."
lappend found_wires $wire
# Fix route that is using target net.
set_property is_route_fixed 1 $net
} else {
puts "Wire not in TODO list, adding to reroute list."
lappend remaining_nets $net
}
break
}
}
}
set found_wires [lsort -unique $found_wires]
foreach wire $found_wires {
puts "Removing $wire"
set srcs [lsearch -regexp -all -inline -not $srcs "$wire$"]
}
puts "Remaining TODOs:"
foreach src $srcs {
puts $src
}
set remaining_nets [lsort -unique $remaining_nets]
set completed_todos {}
foreach net $remaining_nets {
set wires [get_wires -of_objects $net]
set clk_in_wire ""
foreach wire $wires {
if [regexp "CLK_HROW_CK_IN_(\[LR\])\[0-9\]+" $wire match lr] {
set clk_in_wire $wire
break
}
}
if {$clk_in_wire == ""} {
error "$net does not appear to be correct net for rerouting?"
}
puts ""
puts "Rerouting net $net at $clk_in_wire ($lr)"
# Find an input in the todo list that this can can drive.
foreach src $srcs {
if {[lsearch -exact $completed_todos $src] != -1} {
continue
}
if [regexp "CLK_HROW_CK_IN_$lr\[0-9\]+" $src] {
puts "Found target pip $src for net $net."
set tile [get_tiles -of_objects $clk_in_wire]
set target_wire [get_wires "$tile/$src"]
set target_node [get_nodes -of_objects $target_wire]
if {[llength $target_node] == 0} {
error "Failed to find node for $tile/$src."
}
set origin_node [get_nodes -of_objects [get_site_pins -filter {DIRECTION == OUT} -of_objects $net]]
set destination_nodes [get_nodes -of_objects [get_site_pins -filter {DIRECTION == IN} -of_objects $net]]
route_design -unroute -nets $net
set new_route [find_routing_path -to $target_node -from $origin_node]
puts "Origin node: $origin_node"
puts "Target wire: $target_wire"
puts "Target node: $target_node"
puts "Destination nodes: $destination_nodes"
# Only need to set route to one of the destinations.
# Router will handle the rest.
set_property FIXED_ROUTE [concat $new_route [lindex $destination_nodes 0]] $net
# Remove wire, as we've found a clock to set
lappend completed_todos $src
break
}
}
}
}
proc run {} {
create_project -force -part $::env(XRAY_PART) design design
read_verilog top.v
synth_design -top top
set_property CFGBVS VCCO [current_design]
set_property CONFIG_VOLTAGE 3.3 [current_design]
set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design]
set_property IS_ENABLED 0 [get_drc_checks {REQP-161}]
set_property IS_ENABLED 0 [get_drc_checks {REQP-123}]
set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets]
place_design
route_design
route_todo
route_design
write_checkpoint -force design.dcp
write_bitstream -force design.bit
write_pip_txtdata design.txt
}
run

View File

@ -0,0 +1,80 @@
import argparse
import clk_table
def main():
parser = argparse.ArgumentParser(
description="Convert HCLK ROW/COLUMN definitions into HCLK pips.")
parser.add_argument('in_segbit')
parser.add_argument('piplist')
parser.add_argument('out_segbit')
args = parser.parse_args()
hrow_outs = {}
tile = None
with open(args.in_segbit) as f:
for l in f:
parts = l.strip().split(' ')
feature = parts[0]
bits = ' '.join(parts[1:])
tile1, dst, src = feature.split('.')
if tile is None:
tile = tile1
else:
assert tile == tile1
n = int(src[-1])
if dst not in hrow_outs:
hrow_outs[dst] = {
'rows': {},
'columns': {},
}
if src[-4:-1] == 'ROW':
hrow_outs[dst]['rows'][n] = bits
else:
assert src[-7:-1] == 'COLUMN', src
hrow_outs[dst]['columns'][n] = bits
piplists = {}
with open(args.piplist) as f:
for l in f:
tile, dst, src = l.strip().split('.')
assert tile == 'CLK_HROW_BOT_R', tile
if dst not in piplists:
piplists[dst] = []
piplists[dst].append(src)
table = clk_table.get_clk_table()
with open(args.out_segbit, 'w') as f:
for dst in sorted(hrow_outs):
for src in sorted(piplists[dst]):
if src not in table:
continue
row, column = table[src]
if row not in hrow_outs[dst]['rows']:
continue
if column not in hrow_outs[dst]['columns']:
continue
print(
'CLK_HROW.{dst}.{inclk} {row_bits} {column_bits}'.format(
dst=dst,
inclk=src,
row_bits=hrow_outs[dst]['rows'][row],
column_bits=hrow_outs[dst]['columns'][column],
),
file=f)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,11 @@
create_project -force -part $::env(XRAY_PART) design design
set_property design_mode PinPlanning [current_fileset]
open_io_design -name io_1
set fp [open "cmt_regions.csv" "w"]
foreach site_type {MMCME2_ADV PLLE2_ADV BUFHCE} {
foreach site [get_sites -filter "SITE_TYPE == $site_type"] {
puts $fp "$site,[get_property CLOCK_REGION $site]"
}
}
close $fp

View File

@ -0,0 +1,298 @@
""" Emits top.v's for various BUFHCE routing inputs. """
import os
import random
random.seed(int(os.getenv("SEED"), 16))
from prjxray import util
from prjxray.db import Database
CMT_XY_FUN = util.create_xy_fun(prefix='')
def gen_sites(desired_site_type):
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, site_type in gridinfo.sites.items():
if site_type == desired_site_type:
yield site
def gen_bufhce_sites():
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)
sites = []
for site, site_type in gridinfo.sites.items():
if site_type == 'BUFHCE':
sites.append(site)
if sites:
yield tile_name, sorted(sites)
def read_site_to_cmt():
""" Yields clock sources and which CMT they route within. """
with open(os.path.join(os.getenv('FUZDIR'), 'build',
'cmt_regions.csv')) as f:
for l in f:
site, cmt = l.strip().split(',')
yield (site, cmt)
class ClockSources(object):
""" Class for tracking clock sources.
Some clock sources can be routed to any CMT, for these, cmt='ANY'.
For clock sources that belong to a CMT, cmt should be set to the CMT of
the source.
"""
def __init__(self):
self.sources = {}
self.merged_sources = {}
self.source_to_cmt = {}
self.used_sources_from_cmt = {}
def add_clock_source(self, source, cmt):
""" Adds a source from a specific CMT.
cmt='ANY' indicates that this source can be routed to any CMT.
"""
if cmt not in self.sources:
self.sources[cmt] = []
self.sources[cmt].append(source)
assert source not in self.source_to_cmt or self.source_to_cmt[
source] == cmt, source
self.source_to_cmt[source] = cmt
def get_random_source(self, cmt):
""" Get a random source that is routable to the specific CMT.
get_random_source will return a source that is either cmt='ANY',
cmt equal to the input CMT, or the adjecent CMT.
"""
if cmt not in self.merged_sources:
choices = []
if 'ANY' in self.sources:
choices.extend(self.sources['ANY'])
if cmt in self.sources:
choices.extend(self.sources[cmt])
x, y = CMT_XY_FUN(cmt)
if x % 2 == 0:
x += 1
else:
x -= 1
paired_cmt = 'X{}Y{}'.format(x, y)
if paired_cmt in self.sources:
choices.extend(self.sources[paired_cmt])
self.merged_sources[cmt] = choices
if self.merged_sources[cmt]:
source = random.choice(self.merged_sources[cmt])
source_cmt = self.source_to_cmt[source]
if source_cmt not in self.used_sources_from_cmt:
self.used_sources_from_cmt[source_cmt] = set()
self.used_sources_from_cmt[source_cmt].add(source)
if source_cmt != 'ANY' and len(
self.used_sources_from_cmt[source_cmt]) > 14:
print('//', self.used_sources_from_cmt)
self.used_sources_from_cmt[source_cmt].remove(source)
return None
else:
return source
def check_allowed(mmcm_pll_dir, cmt):
""" Check whether the CMT specified is in the allowed direction.
This function is designed to bias sources to either the left or right
input lines.
"""
if mmcm_pll_dir == 'BOTH':
return True
elif mmcm_pll_dir == 'ODD':
x, y = CMT_XY_FUN(cmt)
return (x & 1) == 1
elif mmcm_pll_dir == 'EVEN':
x, y = CMT_XY_FUN(cmt)
return (x & 1) == 0
else:
assert False, mmcm_pll_dir
def main():
"""
BUFHCE's can be driven from:
MMCME2_ADV
PLLE2_ADV
BUFGCTRL
Local INT connect
"""
print('''
module top();
''')
site_to_cmt = dict(read_site_to_cmt())
clock_sources = ClockSources()
# To ensure that all left or right sources are used, sometimes only MMCM/PLL
# sources are allowed. The force of ODD/EVEN/BOTH further biases the
# clock sources to the left or right column inputs.
mmcm_pll_only = random.randint(0, 1)
mmcm_pll_dir = random.choice(('ODD', 'EVEN', 'BOTH'))
if not mmcm_pll_only:
for _ in range(2):
clock_sources.add_clock_source('one', 'ANY')
clock_sources.add_clock_source('zero', 'ANY')
print("""
wire zero = 0;
wire one = 1;""")
for site in gen_sites('MMCME2_ADV'):
mmcm_clocks = [
'mmcm_clock_{site}_{idx}'.format(site=site, idx=idx)
for idx in range(13)
]
if not check_allowed(mmcm_pll_dir, site_to_cmt[site]):
continue
for clk in mmcm_clocks:
clock_sources.add_clock_source(clk, site_to_cmt[site])
print(
"""
wire {c0}, {c1}, {c2}, {c3}, {c4}, {c5};
(* KEEP, DONT_TOUCH, LOC = "{site}" *)
MMCME2_ADV pll_{site} (
.CLKOUT0({c0}),
.CLKOUT0B({c1}),
.CLKOUT1({c2}),
.CLKOUT1B({c3}),
.CLKOUT2({c4}),
.CLKOUT2B({c5}),
.CLKOUT3({c6}),
.CLKOUT3B({c7}),
.CLKOUT4({c8}),
.CLKOUT5({c9}),
.CLKOUT6({c10}),
.CLKFBOUT({c11}),
.CLKFBOUTB({c12})
);
""".format(
site=site,
c0=mmcm_clocks[0],
c1=mmcm_clocks[1],
c2=mmcm_clocks[2],
c3=mmcm_clocks[3],
c4=mmcm_clocks[4],
c5=mmcm_clocks[5],
c6=mmcm_clocks[6],
c7=mmcm_clocks[7],
c8=mmcm_clocks[8],
c9=mmcm_clocks[9],
c10=mmcm_clocks[10],
c11=mmcm_clocks[11],
c12=mmcm_clocks[12],
))
for site in gen_sites('PLLE2_ADV'):
pll_clocks = [
'pll_clock_{site}_{idx}'.format(site=site, idx=idx)
for idx in range(6)
]
if not check_allowed(mmcm_pll_dir, site_to_cmt[site]):
continue
for clk in pll_clocks:
clock_sources.add_clock_source(clk, site_to_cmt[site])
print(
"""
wire {c0}, {c1}, {c2}, {c3}, {c4}, {c5};
(* KEEP, DONT_TOUCH, LOC = "{site}" *)
PLLE2_ADV pll_{site} (
.CLKOUT0({c0}),
.CLKOUT1({c1}),
.CLKOUT2({c2}),
.CLKOUT3({c3}),
.CLKOUT4({c4}),
.CLKOUT5({c5})
);
""".format(
site=site,
c0=pll_clocks[0],
c1=pll_clocks[1],
c2=pll_clocks[2],
c3=pll_clocks[3],
c4=pll_clocks[4],
c5=pll_clocks[5],
))
for site in sorted(gen_sites("BUFGCTRL"),
key=util.create_xy_fun('BUFGCTRL_')):
wire_name = 'clk_{}'.format(site)
if not mmcm_pll_only:
clock_sources.add_clock_source(wire_name, 'ANY')
print(
"""
wire {wire_name};
(* KEEP, DONT_TOUCH, LOC = "{site}" *)
BUFG bufg_{site} (
.O({wire_name})
);
""".format(
site=site,
wire_name=wire_name,
))
for tile_name, sites in gen_bufhce_sites():
for site in sites:
wire_name = clock_sources.get_random_source(site_to_cmt[site])
if wire_name is None:
continue
print(
"""
(* KEEP, DONT_TOUCH, LOC = "{site}" *)
BUFHCE buf_{site} (
.I({wire_name})
);
""".format(
site=site,
wire_name=wire_name,
))
print("endmodule")
if __name__ == '__main__':
main()

View File

@ -1,4 +1,4 @@
MAKETODO_FLAGS=--re ".*"
MAKETODO_FLAGS=--pip-type bipips_int --re ".*"
export FUZDIR=$(shell pwd)
PIPLIST_TCL=$(FUZDIR)/bipiplist.tcl
PIP_TYPE?=bipips_int

View File

@ -84,8 +84,7 @@ for {set idx 0} {$idx < [llength $todo_lines]} {incr idx} {
# sometimes it gets stuck in specific src -> dst locations
if {$tries >= 3} {
puts "WARNING: failed to route net after $tries tries"
error
error "WARNING: failed to route net after $tries tries"
}
}

View File

@ -1,11 +1,12 @@
MAKETODO_FLAGS=--re "BRAM_.\.BRAM_(?!LOGIC_OUTS).*"
export FUZDIR=$(shell pwd)
PIPLIST_TCL=$(FUZDIR)/bram_pip_list.tcl
PIP_TYPE?=bram_pips_int
SEG_TYPE?=bram
PIPLIST_TCL=$(FUZDIR)/bram_pip_list.tcl
MAKETODO_FLAGS=--pip-type ${PIP_TYPE} --seg-type bram --re "BRAM_.\.BRAM_(?!LOGIC_OUTS).*"
N = 50
# These PIPs all appear to be either a 0 or 2 bit solution.
SEGMATCH_FLAGS=-m 20 -M 45 -c 2
include ../pip_loop.mk
#
# Specimens from current run must complete, but previous iterations may exist

View File

@ -70,6 +70,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,040-clk-hrow-config,005-tilegrid))
$(eval $(call fuzzer,041-clk-hrow-pips,005-tilegrid))
$(eval $(call fuzzer,050-pip-seed,005-tilegrid))
$(eval $(call fuzzer,051-pip-imuxlout-bypalts,050-pip-seed))
$(eval $(call fuzzer,052-pip-clkin,050-pip-seed))

View File

@ -2,13 +2,14 @@ N ?= 1
SPECIMENS := $(addprefix build/specimen_,$(shell seq -f '%03.0f' $(N)))
SPECIMENS_OK := $(addsuffix /OK,$(SPECIMENS))
ENV_VAR ?=
SPECIMENS_DEPS ?=
FUZDIR ?= ${PWD}
all: database
# generate.sh / top_generate.sh call make, hence the command must
# have a + before it.
$(SPECIMENS_OK):
$(SPECIMENS_OK): $(SPECIMENS_DEPS)
mkdir -p build
+if [ -f $(FUZDIR)/generate.sh ]; then \
export $(ENV_VAR); \

View File

@ -1,7 +1,6 @@
#!/usr/bin/env python3
import os, re
import sys
from prjxray import util
@ -90,6 +89,8 @@ def run(
db_dir,
pip_dir,
intre,
l,
r,
pip_type,
seg_type,
not_endswith=None,
@ -102,18 +103,22 @@ def run(
pip_dir = "%s/piplist/build" % (os.getenv("XRAY_FUZZERS_DIR"))
assert intre, "RE is required"
maketodo(
"%s/%s_l.txt" % (pip_dir, pip_type),
"%s/segbits_%s_l.db" % (db_dir, seg_type),
intre,
not_endswith,
verbose=verbose)
maketodo(
"%s/%s_r.txt" % (pip_dir, pip_type),
"%s/segbits_%s_r.db" % (db_dir, seg_type),
intre,
not_endswith,
verbose=verbose)
if l:
maketodo(
"%s/%s_l.txt" % (pip_dir, pip_type),
"%s/segbits_%s_l.db" % (db_dir, seg_type),
intre,
not_endswith,
verbose=verbose)
if r:
maketodo(
"%s/%s_r.txt" % (pip_dir, pip_type),
"%s/segbits_%s_r.db" % (db_dir, seg_type),
intre,
not_endswith,
verbose=verbose)
def main():
@ -129,6 +134,8 @@ def main():
parser.add_argument('--re', required=True, help='')
parser.add_argument('--pip-type', default="pips_int", help='')
parser.add_argument('--seg-type', default="int", help='')
util.add_bool_arg(parser, '--l', default=True, help='')
util.add_bool_arg(parser, '--r', default=True, help='')
parser.add_argument(
'--not-endswith', help='Drop lines if they end with this')
args = parser.parse_args()
@ -138,6 +145,8 @@ def main():
db_dir=args.db_dir,
pip_dir=args.pip_dir,
intre=args.re,
l=args.l,
r=args.r,
pip_type=args.pip_type,
seg_type=args.seg_type,
not_endswith=args.not_endswith,

View File

@ -12,10 +12,11 @@ endif
# Iteration number (each containing N specimens)
# Driven by int_loop.sh
ITER ?= 1
MAKETODO_FLAGS ?=
PIP_TYPE?=pips_int
SEG_TYPE?=int
MAKETODO_FLAGS ?=--pip-type pips_int --seg-type int
A_PIPLIST?=$(PIP_TYPE)_l.txt
PIPLIST_TCL?=$(XRAY_FUZZERS_DIR)/piplist/piplist.tcl
SPECIMENS_DEPS ?=
# See int_loop_check.py
# rempips took 35 iters once, so set 50 as a good start point
@ -27,18 +28,20 @@ export FUZDIR=$(shell pwd)
all: database
$(SPECIMENS_OK): build/todo.txt
$(SPECIMENS_OK): build/todo.txt $(SPECIMENS_DEPS)
mkdir -p build/$(ITER)
bash ${XRAY_DIR}/utils/top_generate.sh $(subst /OK,,$@)
touch $@
$(XRAY_FUZZERS_DIR)/piplist/build/$(PIP_TYPE)_l.txt: $(PIPLIST_TCL)
$(XRAY_FUZZERS_DIR)/piplist/build/$(A_PIPLIST): $(PIPLIST_TCL)
mkdir -p $(XRAY_FUZZERS_DIR)/piplist/build
cd $(XRAY_FUZZERS_DIR)/piplist/build && ${XRAY_VIVADO} -mode batch -source $(PIPLIST_TCL)
# Used 1) to see if we are done 2) pips to try in generate.tcl
build/todo.txt: $(XRAY_FUZZERS_DIR)/piplist/build/$(PIP_TYPE)_l.txt $(XRAY_DIR)/fuzzers/int_maketodo.py build/database/seeded
XRAY_DATABASE_DIR=${FUZDIR}/build/database python3 $(XRAY_DIR)/fuzzers/int_maketodo.py --pip-type $(PIP_TYPE) --seg-type $(SEG_TYPE) $(MAKETODO_FLAGS) |sort >build/todo_all.txt
build/todo.txt: $(XRAY_FUZZERS_DIR)/piplist/build/$(A_PIPLIST) $(XRAY_DIR)/fuzzers/int_maketodo.py build/database/seeded
XRAY_DATABASE_DIR=${FUZDIR}/build/database \
python3 $(XRAY_DIR)/fuzzers/int_maketodo.py \
$(MAKETODO_FLAGS) |sort >build/todo_all.txt
cat build/todo_all.txt | sort -R | head -n$(TODO_N) > build/todo.txt.tmp
mv build/todo.txt.tmp build/todo.txt
# Per iter files

View File

@ -335,8 +335,9 @@ class Segmaker:
Simplify names by simplifying like:
-CLBLM_L => CLB
-CENTER_INTER_R => CENTER_INTER
-CLK_HROW_TOP_R => CLK_HROW
'''
tile_type_norm = re.sub("(LL|LM)?_[LR]$", "", tile_type)
tile_type_norm = re.sub("(_TOP|_BOT|LL|LM)?_[LR]$", "", tile_type)
# ignore dummy tiles (ex: VBRK)
if len(tiledata['bits']) == 0:

View File

@ -22,6 +22,41 @@ def roi_xy():
return (x1, x2), (y1, y2)
def create_xy_fun(prefix):
""" Create function that extracts X and Y coordinate from a prefixed string
>>> fun = create_xy_fun(prefix='')
>>> fun('X5Y23')
(5, 23)
>>> fun('X0Y0')
(0, 0)
>>> fun('X50Y100')
(50, 100)
>>> fun = create_xy_fun(prefix='SITE_')
>>> fun('SITE_X5Y23')
(5, 23)
>>> fun('SITE_X0Y0')
(0, 0)
>>> fun('SITE_X50Y100')
(50, 100)
"""
compiled_re = re.compile(
'^{prefix}X([0-9]+)Y([0-9]+)$'.format(prefix=prefix))
def get_xy(s):
m = compiled_re.match(s)
assert m, (prefix, s)
x = int(m.group(1))
y = int(m.group(2))
return x, y
return get_xy
def slice_xy():
'''Return (X1, X2), (Y1, Y2) from XRAY_ROI, exclusive end (for xrange)'''
# SLICE_X12Y100:SLICE_X27Y149

View File

@ -1,6 +1,5 @@
#!/usr/bin/env python3
import sys, re
import os
from prjxray import util

View File

@ -73,6 +73,11 @@ case "$1" in
hclk_r)
sed < "$2" > "$tmp1" -e 's/^HCLK\./HCLK_R./' ;;
clk_hrow_bot_r)
sed < "$2" > "$tmp1" -e 's/^CLK_HROW\./CLK_HROW_BOT_R./' ;;
clk_hrow_top_r)
sed < "$2" > "$tmp1" -e 's/^CLK_HROW\./CLK_HROW_TOP_R./' ;;
liob33)
cp "$2" "$tmp1" ;;