Merge pull request #727 from litghost/bufmrce

Solve remaining bits in the ROI
This commit is contained in:
litghost 2019-03-22 07:58:00 -07:00 committed by GitHub
commit 5e9211d57c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 2344 additions and 358 deletions

View File

@ -15,6 +15,7 @@ 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
TILEGRID_TDB_DEPENDENCIES += clk_bufg/build/segbits_tilegrid.tdb
TILEGRID_TDB_DEPENDENCIES += hclk_cmt/build/segbits_tilegrid.tdb
GENERATE_FULL_ARGS=
ifeq (${XRAY_DATABASE}, zynq7)
@ -104,6 +105,9 @@ clk_hrow/build/segbits_tilegrid.tdb: build/basicdb/tilegrid.json
clk_bufg/build/segbits_tilegrid.tdb: build/basicdb/tilegrid.json
cd clk_bufg && $(MAKE)
hclk_cmt/build/segbits_tilegrid.tdb: build/basicdb/tilegrid.json
cd hclk_cmt && $(MAKE)
build/tilegrid_tdb.json: add_tdb.py $(TILEGRID_TDB_DEPENDENCIES)
python3 add_tdb.py \
--fn-in build/basicdb/tilegrid.json \
@ -139,6 +143,7 @@ clean:
cd orphan_int_column && $(MAKE) clean
cd clk_hrow && $(MAKE) clean
cd clk_bufg && $(MAKE) clean
cd hclk_cmt && $(MAKE) clean
.PHONY: database pushdb clean run

View File

@ -84,8 +84,9 @@ 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),
("clk_hrow/build/segbits_tilegrid.tdb", 30, 18),
("clk_bufg/build/segbits_tilegrid.tdb", 30, 8),
("hclk_cmt/build/segbits_tilegrid.tdb", 30, 10),
("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

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

View File

@ -233,7 +233,7 @@ def propagate_rebuf(database, tiles_by_grid):
rebuf_below]['type']
assert database[tile_name]['bits']['CLB_IO_CLK'][
'offset'] == 47, database[tile_name]['bits']['CLB_IO_CLK']
'offset'] == 42, database[tile_name]['bits']['CLB_IO_CLK']
database[rebuf_below]['bits'] = copy.deepcopy(
database[tile_name]['bits'])
database[rebuf_below]['bits']['CLB_IO_CLK']['offset'] = 73

View File

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

View File

@ -0,0 +1,3 @@
source "$::env(XRAY_DIR)/utils/utils.tcl"
generate_top

View File

@ -0,0 +1,66 @@
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 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 == 'BUFMRCE':
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(
'''
wire clk_{site};
(* KEEP, DONT_TOUCH, LOC = "{site}" *)
BUFMRCE #(
.INIT_OUT({isone})
) buf_{site} (
.O(clk_{site})
);
BUFR bufr_{site} (
.I(clk_{site})
);
'''.format(
site=site_name,
isone=isone,
))
print("endmodule")
write_params(params)
if __name__ == '__main__':
run()

View File

@ -1,65 +1,62 @@
export FUZDIR=$(shell pwd)
PIP_TYPE?=clk_hrow_bot
PIP_TYPE?=clk_hrow
PIPLIST_TCL=$(FUZDIR)/clk_hrow_pip_list.tcl
ifeq (${XRAY_PART}, xc7z010clg400-1)
# xc7z010clg400-1 is missing some side clock connections, so these bits cannot
# be documented.
TODO_RE="[^\.]+\.CLK_HROW_CK_MUX_OUT_[LR][0-9]+\.CLK_HROW_.*[KR_][0-9]+"
else
TODO_RE="[^\.]+\.CLK_HROW_CK_MUX_OUT_"
endif
TODO_RE=".*"
MAKETODO_FLAGS=--no-l --pip-type ${PIP_TYPE} --seg-type clk_hrow_bot --re $(TODO_RE)
MAKETODO_FLAGS=--sides "bot_r,top_r" --pip-type ${PIP_TYPE} --seg-type clk_hrow --re $(TODO_RE)
N = 50
# These PIPs all appear to be either a 1 bit solutions.
SEGMATCH_FLAGS=-c 1
# These PIPs all appear to be either a 2 bit solutions.
SEGMATCH_FLAGS=-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
database: build/segbits_clk_hrow_bot_r.rdb build/segbits_clk_hrow_top_r.rdb
${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf \
--seg-fn-in build/segbits_clk_hrow_top_r.rdb \
--seg-fn-out build/segbits_clk_hrow_top_r.db
${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf \
--seg-fn-in build/segbits_clk_hrow_bot_r.rdb \
--seg-fn-out build/segbits_clk_hrow_bot_r.db
# Keep a copy to track iter progress
cp build/segbits_clk_hrow_top_r.rdb build/$(ITER)/segbits_clk_hrow_top_r.rdb
cp build/segbits_clk_hrow_bot_r.rdb build/$(ITER)/segbits_clk_hrow_bot_r.rdb
${XRAY_MASKMERGE} build/mask_clk_hrow_top_r.db \
$(shell find build -name segdata_clk_hrow_top_r.txt)
${XRAY_MASKMERGE} build/mask_clk_hrow_bot_r.db \
$(shell find build -name segdata_clk_hrow_bot_r.txt)
# Clobber existing .db to eliminate potential conflicts
rm -f build/database/${XRAY_DATABASE}/*
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_bot_r.db
XRAY_DATABASE_DIR=${FUZDIR}/build/database ${XRAY_MERGEDB} clk_hrow_top_r build/segbits_clk_hrow_top_r.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} ${SEGMATCH_FLAGS} -o build/segbits_clk_hrow.rdb \
$(shell find build -name segdata_clk_hrow_top_r.txt) \
generate: $(SPECIMENS_OK)
build/segbits_clk_hrow_top_r.rdb: $(SPECIMENS_OK)
${XRAY_SEGMATCH} ${SEGMATCH_FLAGS} -o build/segbits_clk_hrow_top_r.rdb \
$(shell find build -name segdata_clk_hrow_top_r.txt)
build/segbits_clk_hrow_bot_r.rdb: $(SPECIMENS_OK)
${XRAY_SEGMATCH} ${SEGMATCH_FLAGS} -o build/segbits_clk_hrow_bot_r.rdb \
$(shell find build -name segdata_clk_hrow_bot_r.txt)
build/segbits_clk_hrow.db: build/segbits_clk_hrow.rdb piplist
${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/${PIP_TYPE}/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 \
$(shell find build -name segdata_clk_hrow_top_r.txt) \
$(shell find build -name segdata_clk_hrow_bot_r.txt)
# 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
build/segbits_clk_hrow.db: build/segbits_clk_hrow_top_.rdb
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
${XRAY_MERGEDB} clk_hrow_bot_r build/segbits_clk_hrow_bot_r.db
${XRAY_MERGEDB} clk_hrow_top_r build/segbits_clk_hrow_top_r.db
${XRAY_MERGEDB} mask_clk_hrow_bot_r build/mask_clk_hrow_bot_r.db
${XRAY_MERGEDB} mask_clk_hrow_top_r build/mask_clk_hrow_top_r.db
.PHONY: database pushdb
.PHONY: database pushdb generate

View File

@ -1,12 +1,45 @@
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 ""]"
set pips [dict create]
foreach tile [get_tiles -filter "TYPE == $tile_type"] {
puts "Dumping PIPs for tile $tile ($tile_type) to $filename."
foreach pip [lsort [get_pips -of_objects $tile]] {
set src [get_wires -uphill -of_objects $pip]
set dst [get_wires -downhill -of_objects $pip]
# Skip pips with disconnected nodes
set src_node [get_nodes -of_objects $src]
if { $src_node == {} } {
continue
}
set dst_node [get_nodes -of_objects $src]
if { $dst_node == {} } {
continue
}
# TODO: Support CLK sources from GTX hardblocks.
if [string match *GTX* $src_node] {
continue
}
# Some ports appear to be just test signals, ignore these.
if [string match *TESTPLL* $src_node] {
continue
}
# TODO: Support CLK sources from PS7 hardblock
if [string match *PSS_HCLK* $src_node] {
continue
}
if {[llength [get_nodes -uphill -of_objects [get_nodes -of_objects $dst]]] != 1} {
set pip_string "$tile_type.[regsub {.*/} $dst ""].[regsub {.*/} $src ""]"
if ![dict exists $pips $pip_string] {
puts $fp $pip_string
dict set pips $pip_string 1
}
}
}
}
close $fp

View File

@ -1,34 +0,0 @@
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

@ -1,17 +1,54 @@
#!/usr/bin/env python3
import os
import os.path
from prjxray.segmaker import Segmaker
import clk_table
def main():
segmk = Segmaker("design.bits")
table = clk_table.get_clk_table()
tiledata = {}
pipdata = {}
clk_list = {}
casco_list = {}
ignpip = set()
with open(os.path.join(os.getenv('FUZDIR'), '..', 'piplist', 'build',
'clk_hrow', 'clk_hrow_bot_r.txt')) as f:
for l in f:
tile_type, dst, src = l.strip().split('.')
if tile_type not in pipdata:
pipdata[tile_type] = []
clk_list[tile_type] = set()
casco_list[tile_type] = set()
pipdata[tile_type].append((src, dst))
if 'CASCO' in dst:
casco_list[tile_type].add(dst)
if dst.startswith('CLK_HROW_CK_MUX_OUT_'):
clk_list[tile_type].add(src)
with open(os.path.join(os.getenv('FUZDIR'), '..', 'piplist', 'build',
'clk_hrow', 'clk_hrow_top_r.txt')) as f:
for l in f:
tile_type, dst, src = l.strip().split('.')
if tile_type not in pipdata:
pipdata[tile_type] = []
clk_list[tile_type] = set()
casco_list[tile_type] = set()
pipdata[tile_type].append((src, dst))
if 'CASCO' in dst:
casco_list[tile_type].add(dst)
if dst.startswith('CLK_HROW_CK_MUX_OUT_'):
clk_list[tile_type].add(src)
print("Loading tags from design.txt.")
active_gclks = {}
active_clks = {}
with open("design.txt", "r") as f:
for line in f:
tile, pip, src, dst, pnum, pdir = line.split()
@ -19,57 +56,71 @@ def main():
if not tile.startswith('CLK_HROW'):
continue
pip_prefix, pip = pip.split(".")
pip_prefix, _ = pip.split(".")
tile_from_pip, tile_type = pip_prefix.split('/')
assert tile == tile_from_pip
_, src = src.split("/")
_, dst = dst.split("/")
pnum = int(pnum)
pdir = int(pdir)
rows = set(range(clk_table.CLK_TABLE_NUM_ROWS))
columns = set(range(clk_table.CLK_TABLE_NUM_COLS))
if tile not in tiledata:
tiledata[tile] = {
"type": tile_type,
"pips": set(),
"srcs": set(),
"dsts": set()
}
if src in table:
row, column = table[src]
tiledata[tile]["pips"].add((src, dst))
tiledata[tile]["srcs"].add(src)
tiledata[tile]["dsts"].add(dst)
segmk.add_tile_tag(
tile, '{}.HCLK_ENABLE_ROW{}'.format(dst, row), 1)
segmk.add_tile_tag(
tile, '{}.HCLK_ENABLE_COLUMN{}'.format(dst, column), 1)
if pdir == 0:
tiledata[tile]["srcs"].add(dst)
tiledata[tile]["dsts"].add(src)
rows.remove(row)
columns.remove(column)
if pnum == 1 or pdir == 0:
ignpip.add((src, dst))
for row in rows:
segmk.add_tile_tag(
tile, '{}.HCLK_ENABLE_ROW{}'.format(dst, row), 0)
active_gclks = {}
active_clks = {}
for column in columns:
segmk.add_tile_tag(
tile, '{}.HCLK_ENABLE_COLUMN{}'.format(dst, column), 0)
for tile, pips_srcs_dsts in tiledata.items():
tile_type = pips_srcs_dsts["type"]
pips = pips_srcs_dsts["pips"]
if tile not in active_clks:
active_clks[tile] = set()
if tile not in active_clks:
active_clks[tile] = set()
active_clks[tile].add(src)
for src, dst in pips_srcs_dsts["pips"]:
active_clks[tile].add(src)
if 'GCLK' in src:
if src not in active_gclks:
active_gclks[src] = set()
active_gclks[src].add(tile)
tiles = sorted(active_clks.keys())
for tile in active_clks:
for src in table:
if 'GCLK' not in src:
active = src in active_clks[tile]
segmk.add_tile_tag(tile, '{}_ACTIVE'.format(src), active)
else:
if 'GCLK' in src:
if src not in active_gclks:
segmk.add_tile_tag(tile, '{}_ACTIVE'.format(src), 0)
elif tile in active_gclks[src]:
segmk.add_tile_tag(tile, '{}_ACTIVE'.format(src), 1)
active_gclks[src] = set()
active_gclks[src].add(tile)
for src, dst in pipdata[tile_type]:
if (src, dst) in ignpip:
pass
elif (src, dst) in pips:
segmk.add_tile_tag(tile, "%s.%s" % (dst, src), 1)
elif dst not in tiledata[tile]["dsts"]:
segmk.add_tile_tag(tile, "%s.%s" % (dst, src), 0)
for tile_type, srcs in clk_list.items():
for tile, pips_srcs_dsts in tiledata.items():
for src in srcs:
if 'GCLK' not in src:
active = src in active_clks[tile]
segmk.add_tile_tag(tile, '{}_ACTIVE'.format(src), active)
else:
if src not in active_gclks:
segmk.add_tile_tag(tile, '{}_ACTIVE'.format(src), 0)
elif tile in active_gclks[src]:
segmk.add_tile_tag(tile, '{}_ACTIVE'.format(src), 1)
segmk.compile()
segmk.write()

View File

@ -24,119 +24,209 @@ proc write_pip_txtdata {filename} {
}
proc load_todo {} {
set fp [open "../../todo.txt" r]
set todo_lines {}
set fp [open "../../todo_all.txt" r]
# Create map of pip destinations to remaining sources for that pip
set todo_map [dict create]
for {gets $fp line} {$line != ""} {gets $fp line} {
lappend todo_lines [split $line .]
set parts [split $line .]
if ![string match "*CLK_HROW_CK_IN_*" [lindex $parts 2]] {
continue
}
dict lappend todo_map [lindex $parts 1] [list [lindex $parts 0] [lindex $parts 2]]
}
close $fp
return $todo_lines
return $todo_map
}
proc route_todo {} {
puts "Checking TODO's"
set todo_lines [load_todo]
set srcs {}
foreach todo $todo_lines {
set src [lindex $todo 2]
set todo_map [load_todo]
if [string match "*CLK_HROW_CK_IN_*" $src] {
lappend srcs $src
}
}
set nets [get_nets]
set srcs [lsort -unique $srcs]
set todo_nets [dict create]
set used_destinations [dict create]
set nets [get_nets -hierarchical "*clock*"]
set found_wires {}
set remaining_nets {}
foreach net $nets {
set wires [get_wires -of_objects $net]
# Check to see if this net is one we are interested in
set wires [get_wires -of_objects $net -filter {TILE_NAME =~ *CLK_HROW*}]
set is_gclk_net 0
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
puts "Check wire $wire in $net"
if [string match "*CLK_HROW_CK_IN_*" $wire] {
set gclk_tile [lindex [split $wire /] 0]
set gclk_wire [lindex [split $wire /] 1]
set is_gclk_net 1
break
}
}
if {$clk_in_wire == ""} {
error "$net does not appear to be correct net for rerouting?"
if {$is_gclk_net == 0} {
puts "$net not going to a HCLK port, skipping."
continue
}
puts ""
puts "Rerouting net $net at $clk_in_wire ($lr)"
puts "Net $net wires:"
foreach wire [get_wires -of_objects $net] {
puts " - $wire"
}
# Find an input in the todo list that this can can drive.
foreach src $srcs {
if {[lsearch -exact $completed_todos $src] != -1} {
foreach wire $wires {
set tile [lindex [split $wire /] 0]
set wire [lindex [split $wire /] 1]
if { $tile != $gclk_tile } {
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 tile_type [get_property TILE_TYPE [get_tiles $tile]]
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."
if { ![dict exists $todo_map $wire] } {
continue
}
set srcs [dict get $todo_map $wire]
# This net is interesting, see if it is already going somewhere we
# want.
set found_target 0
foreach other_wire $wires {
if { $found_target == 1 } {
break
}
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"
set other_wire [lindex [split $other_wire /] 1]
# 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
if { $wire == $other_wire } {
continue
}
# Remove wire, as we've found a clock to set
lappend completed_todos $src
break
foreach src $srcs {
set src_tile_type [lindex $src 0]
if {$src_tile_type != $tile_type} {
continue
}
set src_wire [lindex $src 1]
if { $other_wire == $src_wire } {
set found_target 1
puts "Interesting net $net already going from $wire to $other_wire."
set_property IS_ROUTE_FIXED 1 $net
dict set used_destinations "$tile/$src_wire" 1
break
}
}
}
if { $found_target == 1 } {
# Net has an interesting
continue
}
dict set todo_nets $net [list $tile $wire $gclk_wire]
puts "Interesting net $net (including $wire and $gclk_wire) is being rerouted."
}
}
set routed_sources [dict create]
dict for {net tile_wire} $todo_nets {
if { [get_property IS_ROUTE_FIXED $net] == 1 } {
puts "Net $net is already routed, skipping."
continue
}
set tile [lindex $tile_wire 0]
set wire [lindex $tile_wire 1]
set gclk_wire [lindex $tile_wire 2]
set srcs [dict get $todo_map $wire]
puts ""
puts "Rerouting net $net at $tile / $gclk_wire (type $tile_type)"
set tile_type [get_property TILE_TYPE [get_tiles $tile]]
regexp "CLK_HROW_CK_IN_(\[LR\])\[0-9\]+" $gclk_wire match lr
set todos {}
foreach src $srcs {
set src_tile_type [lindex $src 0]
if {$src_tile_type != $tile_type} {
continue
}
set src_wire [lindex $src 1]
if [regexp "CLK_HROW_CK_IN_$lr\[0-9\]+" $src_wire] {
lappend todos $src_wire
}
}
if {[llength $todos] == 0} {
puts "No inputs for net $net."
dict set used_destinations "$tile/$gclk_wire" 1
continue
}
puts "All todos for $tile_type / $wire"
foreach src_wire $todos {
puts " - $src_wire"
}
# Find an input in the todo list that this can can drive.
set set_new_route 0
foreach src_wire $todos {
if { [dict exists $used_destinations "$tile/$src_wire"] } {
puts "Not routing to $tile / $src_wire, in use."
continue
}
puts "Attempting to route to $src_wire for net $net."
set target_wire [get_wires "$tile/$src_wire"]
set target_node [get_nodes -of_objects $target_wire]
if {[llength $target_node] == 0} {
continue
}
set origin_node [get_nodes -of_objects [get_site_pins -filter {DIRECTION == OUT} -of_objects $net]]
if [dict exists $routed_sources $origin_node] {
puts "Skip net $net, already routed."
continue
}
route_design -unroute -nets $net
set old_nets [get_nets -of_objects $target_node]
if { $old_nets != {} } {
puts "Unrouting $old_nets"
route_design -unroute -nets $old_nets
}
set old_nets [get_nets -of_objects $origin_node]
if { $old_nets != {} } {
puts "Unrouting $old_nets"
route_design -unroute -nets $old_nets
}
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"
# Only need to set route to one of the destinations.
# Router will handle the rest.
set_property FIXED_ROUTE $new_route $net
dict set used_destinations "$tile/$src_wire" 1
dict set routed_sources "$origin_node" 1
set set_new_route 1
break
}
}
}
@ -151,6 +241,7 @@ proc run {} {
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 IS_ENABLED 0 [get_drc_checks {REQP-13}]
set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets]

View File

@ -1,89 +0,0 @@
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()
output_features = []
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:])
# No post-processing on _ACTIVE bits.
if feature.endswith('_ACTIVE'):
output_features.append(l.strip())
continue
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 l in output_features:
print(l, file=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

@ -3,7 +3,7 @@ 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_type {MMCME2_ADV PLLE2_ADV BUFHCE BUFR} {
foreach site [get_sites -filter "SITE_TYPE == $site_type"] {
puts $fp "$site,[get_property CLOCK_REGION $site]"
}

View File

@ -1,11 +1,17 @@
""" Emits top.v's for various BUFHCE routing inputs. """
import os
import random
import re
random.seed(int(os.getenv("SEED"), 16))
from prjxray import util
from prjxray import verilog
from prjxray.db import Database
from prjxray.lut_maker import LutMaker
from io import StringIO
CMT_XY_FUN = util.create_xy_fun(prefix='')
BUFGCTRL_XY_FUN = util.create_xy_fun('BUFGCTRL_')
BUFHCE_XY_FUN = util.create_xy_fun('BUFHCE_')
def gen_sites(desired_site_type):
@ -17,7 +23,7 @@ def gen_sites(desired_site_type):
gridinfo = grid.gridinfo_at_loc(loc)
for site, site_type in gridinfo.sites.items():
if site_type == desired_site_type:
yield site
yield loc, gridinfo.tile_type, site
def gen_bufhce_sites():
@ -59,8 +65,10 @@ class ClockSources(object):
self.merged_sources = {}
self.source_to_cmt = {}
self.used_sources_from_cmt = {}
self.sources_by_loc = {}
self.active_cmt_ports = {}
def add_clock_source(self, source, cmt):
def add_clock_source(self, source, cmt, loc=None):
""" Adds a source from a specific CMT.
cmt='ANY' indicates that this source can be routed to any CMT.
@ -73,6 +81,14 @@ class ClockSources(object):
source] == cmt, source
self.source_to_cmt[source] = cmt
self.add_bufg_clock_source(source, cmt, loc)
def add_bufg_clock_source(self, source, cmt, loc):
if loc not in self.sources_by_loc:
self.sources_by_loc[loc] = []
self.sources_by_loc[loc].append((cmt, source))
def get_random_source(self, cmt):
""" Get a random source that is routable to the specific CMT.
@ -113,12 +129,88 @@ class ClockSources(object):
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 get_bufg_source(self, loc, tile_type, site, todos, i_wire, used_only):
bufg_sources = []
top = '_TOP_' in tile_type
bottom = '_BOT_' in tile_type
assert top ^ bottom, tile_type
if top:
for src_loc, cmt_sources in self.sources_by_loc.items():
if src_loc is None:
continue
if src_loc.grid_y <= loc.grid_y:
bufg_sources.extend(cmt_sources)
elif bottom:
for src_loc, cmt_sources in self.sources_by_loc.items():
if src_loc is None:
continue
if src_loc.grid_y > loc.grid_y:
bufg_sources.extend(cmt_sources)
# CLK_HROW_TOP_R_CK_BUFG_CASCO0 -> CLK_BUFG_BUFGCTRL0_I0
# CLK_HROW_TOP_R_CK_BUFG_CASCO22 -> CLK_BUFG_BUFGCTRL11_I0
# CLK_HROW_TOP_R_CK_BUFG_CASCO23 -> CLK_BUFG_BUFGCTRL11_I1
# CLK_HROW_BOT_R_CK_BUFG_CASCO27 -> CLK_BUFG_BUFGCTRL13_I1
x, y = BUFGCTRL_XY_FUN(site)
assert x == 0
y = y % 16
assert i_wire in [0, 1], i_wire
casco_wire = '{tile_type}_CK_BUFG_CASCO{casco_idx}'.format(
tile_type=tile_type.replace('BUFG', 'HROW'),
casco_idx=(y * 2 + i_wire))
if casco_wire not in todos:
return None
target_wires = []
need_bufr = False
for src_wire in todos[casco_wire]:
if 'BUFRCLK' in src_wire:
need_bufr = True
break
for cmt, wire in bufg_sources:
if 'BUFR' in wire:
if need_bufr:
target_wires.append((cmt, wire))
else:
target_wires.append((cmt, wire))
random.shuffle(target_wires)
for cmt, source in target_wires:
if cmt == 'ANY':
return source
else:
# Make sure to not try to import move than 14 sources from
# the CMT, there is limited routing.
if cmt not in self.used_sources_from_cmt:
self.used_sources_from_cmt[cmt] = set()
if source in self.used_sources_from_cmt[cmt]:
return source
elif used_only:
continue
if len(self.used_sources_from_cmt[cmt]) < 14:
self.used_sources_from_cmt[cmt].add(source)
return source
else:
continue
return None
def check_allowed(mmcm_pll_dir, cmt):
""" Check whether the CMT specified is in the allowed direction.
@ -135,10 +227,76 @@ def check_allowed(mmcm_pll_dir, cmt):
elif mmcm_pll_dir == 'EVEN':
x, y = CMT_XY_FUN(cmt)
return (x & 1) == 0
elif mmcm_pll_dir == 'NONE':
return False
else:
assert False, mmcm_pll_dir
def read_todo():
dsts = {}
with open(os.path.join('..', 'todo_all.txt')) as f:
for l in f:
tile_type, dst, src = l.strip().split('.')
if dst not in dsts:
dsts[dst] = set()
dsts[dst].add(src)
return dsts
def need_int_connections(todos):
for srcs in todos.values():
for src in srcs:
if re.search('INT_._.', src):
return True
return False
def bufhce_in_todo(todos, site):
if 'BUFHCE' in site:
# CLK_HROW_CK_MUX_OUT_R9 -> X1Y9
# CLK_HROW_CK_MUX_OUT_L11 -> X0Y35
x, y = BUFHCE_XY_FUN(site)
y = y % 12
if x == 0:
lr = 'L'
elif x == 1:
lr = 'R'
else:
assert False, x
return 'CLK_HROW_CK_MUX_OUT_{lr}{y}'.format(lr=lr, y=y) in todos
else:
return True
def need_gclk_connection(todos, site):
x, y = BUFGCTRL_XY_FUN(site)
assert x == 0
src_wire = 'CLK_HROW_R_CK_GCLK{}'.format(y)
for srcs in todos.values():
if src_wire in srcs:
return True
return False
def only_gclk_left(todos):
for srcs in todos.values():
for src in srcs:
if 'GCLK' not in src:
return False
return True
def main():
"""
BUFHCE's can be driven from:
@ -162,28 +320,32 @@ module top();
# 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'))
mmcm_pll_dir = random.choice(('ODD', 'EVEN', 'BOTH', 'NONE'))
todos = read_todo()
if only_gclk_left(todos):
mmcm_pll_dir = 'NONE'
if not mmcm_pll_only:
for _ in range(2):
clock_sources.add_clock_source('one', 'ANY')
clock_sources.add_clock_source('zero', 'ANY')
if need_int_connections(todos):
for _ in range(10):
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'):
for loc, _, 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])
if check_allowed(mmcm_pll_dir, site_to_cmt[site]):
for clk in mmcm_clocks:
clock_sources.add_clock_source(clk, site_to_cmt[site], loc)
print(
"""
@ -221,17 +383,15 @@ module top();
c12=mmcm_clocks[12],
))
for site in gen_sites('PLLE2_ADV'):
for loc, _, 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])
if check_allowed(mmcm_pll_dir, site_to_cmt[site]):
for clk in pll_clocks:
clock_sources.add_clock_source(clk, site_to_cmt[site], loc)
print(
"""
@ -255,45 +415,97 @@ module top();
c5=pll_clocks[5],
))
gclks = []
for site in sorted(gen_sites("BUFGCTRL"),
key=util.create_xy_fun('BUFGCTRL_')):
wire_name = 'clk_{}'.format(site)
gclks.append(wire_name)
if not mmcm_pll_only:
clock_sources.add_clock_source(wire_name, 'ANY')
for loc, _, site in gen_sites('BUFR'):
clock_sources.add_bufg_clock_source(
'O_{site}'.format(site=site), site_to_cmt[site], loc)
print(
"""
wire {wire_name};
wire O_{site};
(* KEEP, DONT_TOUCH, LOC = "{site}" *)
BUFG bufg_{site} (
.O({wire_name})
BUFR bufr_{site} (
.O(O_{site})
);""".format(site=site))
luts = LutMaker()
bufhs = StringIO()
bufgs = StringIO()
gclks = []
for _, _, site in sorted(gen_sites("BUFGCTRL"),
key=lambda x: BUFGCTRL_XY_FUN(x[2])):
wire_name = 'gclk_{}'.format(site)
gclks.append(wire_name)
include_source = True
if mmcm_pll_only:
include_source = False
elif only_gclk_left(todos):
include_source = need_gclk_connection(todos, site)
if include_source:
clock_sources.add_clock_source(wire_name, 'ANY')
print("""
wire {wire_name};
""".format(wire_name=wire_name))
print(
"""
wire I1_{site};
wire I0_{site};
(* KEEP, DONT_TOUCH, LOC = "{site}" *)
BUFGCTRL bufg_{site} (
.O({wire_name}),
.S1({s1net}),
.S0({s0net}),
.IGNORE1({ignore1net}),
.IGNORE0({ignore0net}),
.I1(I1_{site}),
.I0(I0_{site}),
.CE1({ce1net}),
.CE0({ce0net})
);
""".format(
site=site,
wire_name=wire_name,
))
s1net=luts.get_next_output_net(),
s0net=luts.get_next_output_net(),
ignore1net=luts.get_next_output_net(),
ignore0net=luts.get_next_output_net(),
ce1net=luts.get_next_output_net(),
ce0net=luts.get_next_output_net(),
),
file=bufgs)
any_bufhce = False
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:
if not bufhce_in_todo(todos, site):
continue
any_bufhce = True
print(
"""
wire I_{site};
(* KEEP, DONT_TOUCH, LOC = "{site}" *)
BUFHCE buf_{site} (
.I({wire_name})
.I(I_{site})
);
""".format(
site=site,
wire_name=wire_name,
))
""".format(site=site, ),
file=bufhs)
if random.random() > .05:
wire_name = clock_sources.get_random_source(site_to_cmt[site])
if wire_name is None:
continue
print(
"""
assign I_{site} = {wire_name};""".format(
site=site,
wire_name=wire_name,
),
file=bufhs)
if not any_bufhce:
for tile_name, sites in gen_bufhce_sites():
@ -301,16 +513,56 @@ module top();
print(
"""
(* KEEP, DONT_TOUCH, LOC = "{site}" *)
BUFHCE buf_{site} (
BUFHCE #(
.INIT_OUT({INIT_OUT}),
.CE_TYPE({CE_TYPE}),
.IS_CE_INVERTED({IS_CE_INVERTED})
) buf_{site} (
.I({wire_name})
);
""".format(
INIT_OUT=random.randint(0, 1),
CE_TYPE=verilog.quote(
random.choice(('SYNC', 'ASYNC'))),
IS_CE_INVERTED=random.randint(0, 1),
site=site,
wire_name=gclks[0],
))
break
break
for l in luts.create_wires_and_luts():
print(l)
print(bufhs.getvalue())
print(bufgs.getvalue())
used_only = random.random() < .25
for loc, tile_type, site in sorted(gen_sites("BUFGCTRL"),
key=lambda x: BUFGCTRL_XY_FUN(x[2])):
if random.randint(0, 1):
wire_name = clock_sources.get_bufg_source(
loc, tile_type, site, todos, 1, used_only)
if wire_name is not None:
print(
"""
assign I1_{site} = {wire_name};""".format(
site=site,
wire_name=wire_name,
))
if random.randint(0, 1):
wire_name = clock_sources.get_bufg_source(
loc, tile_type, site, todos, 0, used_only)
if wire_name is not None:
print(
"""
assign I0_{site} = {wire_name};""".format(
site=site,
wire_name=wire_name,
))
print("endmodule")

View File

@ -0,0 +1,61 @@
export FUZDIR=$(shell pwd)
PIP_TYPE?=clk_bufg
PIPLIST_TCL=$(FUZDIR)/clk_bufg_pip_list.tcl
TODO_RE=".*"
MAKETODO_FLAGS=--sides "bot_r,top_r" --pip-type ${PIP_TYPE} --seg-type clk_bufg --re $(TODO_RE)
N = 50
# These PIPs all appear to be either a 1 bit solutions.
SEGMATCH_FLAGS=-c 2
SPECIMENS_DEPS=build/cmt_regions.csv
A_PIPLIST=clk_bufg_bot_r.txt
include ../pip_loop.mk
build/segbits_clk_bufg_top_r.rdb: $(SPECIMENS_OK)
${XRAY_SEGMATCH} ${SEGMATCH_FLAGS} -o build/segbits_clk_bufg_top_r.rdb \
$(shell find build -name segdata_clk_bufg_top_r.txt)
build/segbits_clk_bufg_bot_r.rdb: $(SPECIMENS_OK)
${XRAY_SEGMATCH} ${SEGMATCH_FLAGS} -o build/segbits_clk_bufg_bot_r.rdb \
$(shell find build -name segdata_clk_bufg_bot_r.txt)
database: build/segbits_clk_bufg_top_r.rdb build/segbits_clk_bufg_bot_r.rdb
${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf \
--seg-fn-in build/segbits_clk_bufg_bot_r.rdb \
--seg-fn-out build/segbits_clk_bufg_bot_r.db
${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf \
--seg-fn-in build/segbits_clk_bufg_top_r.rdb \
--seg-fn-out build/segbits_clk_bufg_top_r.db
# Keep a copy to track iter progress
cp build/segbits_clk_bufg_top_r.rdb build/$(ITER)/segbits_clk_bufg_top_r.rdb
cp build/segbits_clk_bufg_top_r.db build/$(ITER)/segbits_clk_bufg_top_r.db
cp build/segbits_clk_bufg_bot_r.rdb build/$(ITER)/segbits_clk_bufg_bot_r.rdb
cp build/segbits_clk_bufg_bot_r.db build/$(ITER)/segbits_clk_bufg_bot_r.db
${XRAY_MASKMERGE} build/mask_clk_bufg_top_r.db \
$(shell find build -name segdata_clk_bufg_top_r.txt)
${XRAY_MASKMERGE} build/mask_clk_bufg_bot_r.db \
$(shell find build -name segdata_clk_bufg_bot_r.txt)
# 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_bufg_top_r build/segbits_clk_bufg_top_r.db
XRAY_DATABASE_DIR=${FUZDIR}/build/database ${XRAY_MERGEDB} clk_bufg_bot_r build/segbits_clk_bufg_bot_r.db
build/cmt_regions.csv: output_cmt.tcl
mkdir -p build
cd build/ && ${XRAY_VIVADO} -mode batch -source ${FUZDIR}/output_cmt.tcl
pushdb: database
${XRAY_MERGEDB} clk_bufg_bot_r build/segbits_clk_bufg_bot_r.db
${XRAY_MERGEDB} clk_bufg_top_r build/segbits_clk_bufg_top_r.db
${XRAY_MERGEDB} mask_clk_bufg_bot_r build/mask_clk_bufg_bot_r.db
${XRAY_MERGEDB} mask_clk_bufg_top_r build/mask_clk_bufg_top_r.db
.PHONY: database pushdb

View File

@ -0,0 +1,4 @@
BUFG interconnect fuzzer
========================
Solves pips located within the BUFG switch box.

View File

@ -0,0 +1,33 @@
# Generated from build_zdb.py
26_07 26_08 27_06,CLK_BUFG.CLK_BUFG_BUFGCTRL0_I0.CLK_BUFG_IMUX28_0
26_04 26_05 27_05,CLK_BUFG.CLK_BUFG_BUFGCTRL0_I1.CLK_BUFG_IMUX28_0
26_167 26_168 27_166,CLK_BUFG.CLK_BUFG_BUFGCTRL10_I0.CLK_BUFG_IMUX30_2
26_164 26_165 27_165,CLK_BUFG.CLK_BUFG_BUFGCTRL10_I1.CLK_BUFG_IMUX30_2
26_183 26_184 27_182,CLK_BUFG.CLK_BUFG_BUFGCTRL11_I0.CLK_BUFG_IMUX31_2
26_180 26_181 27_181,CLK_BUFG.CLK_BUFG_BUFGCTRL11_I1.CLK_BUFG_IMUX31_2
26_199 26_200 27_198,CLK_BUFG.CLK_BUFG_BUFGCTRL12_I0.CLK_BUFG_IMUX28_3
26_196 26_197 27_197,CLK_BUFG.CLK_BUFG_BUFGCTRL12_I1.CLK_BUFG_IMUX28_3
26_215 26_216 27_214,CLK_BUFG.CLK_BUFG_BUFGCTRL13_I0.CLK_BUFG_IMUX29_3
26_212 26_213 27_213,CLK_BUFG.CLK_BUFG_BUFGCTRL13_I1.CLK_BUFG_IMUX29_3
26_231 26_232 27_230,CLK_BUFG.CLK_BUFG_BUFGCTRL14_I0.CLK_BUFG_IMUX30_3
26_228 26_229 27_229,CLK_BUFG.CLK_BUFG_BUFGCTRL14_I1.CLK_BUFG_IMUX30_3
26_247 26_248 27_246,CLK_BUFG.CLK_BUFG_BUFGCTRL15_I0.CLK_BUFG_IMUX31_3
26_244 26_245 27_245,CLK_BUFG.CLK_BUFG_BUFGCTRL15_I1.CLK_BUFG_IMUX31_3
26_23 26_24 27_22,CLK_BUFG.CLK_BUFG_BUFGCTRL1_I0.CLK_BUFG_IMUX29_0
26_20 26_21 27_21,CLK_BUFG.CLK_BUFG_BUFGCTRL1_I1.CLK_BUFG_IMUX29_0
26_39 26_40 27_38,CLK_BUFG.CLK_BUFG_BUFGCTRL2_I0.CLK_BUFG_IMUX30_0
26_36 26_37 27_37,CLK_BUFG.CLK_BUFG_BUFGCTRL2_I1.CLK_BUFG_IMUX30_0
26_55 26_56 27_54,CLK_BUFG.CLK_BUFG_BUFGCTRL3_I0.CLK_BUFG_IMUX31_0
26_52 26_53 27_53,CLK_BUFG.CLK_BUFG_BUFGCTRL3_I1.CLK_BUFG_IMUX31_0
26_71 26_72 27_70,CLK_BUFG.CLK_BUFG_BUFGCTRL4_I0.CLK_BUFG_IMUX28_1
26_68 26_69 27_69,CLK_BUFG.CLK_BUFG_BUFGCTRL4_I1.CLK_BUFG_IMUX28_1
26_87 26_88 27_86,CLK_BUFG.CLK_BUFG_BUFGCTRL5_I0.CLK_BUFG_IMUX29_1
26_84 26_85 27_85,CLK_BUFG.CLK_BUFG_BUFGCTRL5_I1.CLK_BUFG_IMUX29_1
26_103 26_104 27_102,CLK_BUFG.CLK_BUFG_BUFGCTRL6_I0.CLK_BUFG_IMUX30_1
26_100 26_101 27_101,CLK_BUFG.CLK_BUFG_BUFGCTRL6_I1.CLK_BUFG_IMUX30_1
26_119 26_120 27_118,CLK_BUFG.CLK_BUFG_BUFGCTRL7_I0.CLK_BUFG_IMUX31_1
26_116 26_117 27_117,CLK_BUFG.CLK_BUFG_BUFGCTRL7_I1.CLK_BUFG_IMUX31_1
26_135 26_136 27_134,CLK_BUFG.CLK_BUFG_BUFGCTRL8_I0.CLK_BUFG_IMUX28_2
26_132 26_133 27_133,CLK_BUFG.CLK_BUFG_BUFGCTRL8_I1.CLK_BUFG_IMUX28_2
26_151 26_152 27_150,CLK_BUFG.CLK_BUFG_BUFGCTRL9_I0.CLK_BUFG_IMUX29_2
26_148 26_149 27_149,CLK_BUFG.CLK_BUFG_BUFGCTRL9_I1.CLK_BUFG_IMUX29_2

View File

@ -0,0 +1,71 @@
""" Tool for building zero db file for BUFG pips.
This requires that the rdb files be good enough to identify all the 0 candidate
features, which may take multiple manual iterations. Manual iterations can
be running like:
make ITER=<N> -j<J> database
And then invoking:
python3 build_zdb.py build/segbits_clk_bufg_bot_r.rdb build/segbits_clk_bufg_top_r.rdb > bits.dbf
will successed if and only if the rdb is complete enough.
bits.dbf is committed, so this utility should only be needed to document the
process.
"""
import argparse
def main():
parser = argparse.ArgumentParser("Form ZDB groups for BUFG.")
parser.add_argument('bot_r')
parser.add_argument('top_r')
args = parser.parse_args()
groups = {}
with open(args.bot_r) as f:
for l in f:
parts = l.strip().split(' ')
feature = parts[0]
bits = parts[1:]
tile_type, dst, src = feature.split('.')
assert tile_type == "CLK_BUFG"
if dst not in groups:
groups[dst] = {}
groups[dst][src] = bits
print('# Generated from build_zdb.py')
for dst in groups:
if len(groups[dst]) == 1:
continue
bits = set()
zero_feature = None
for src in groups[dst]:
if groups[dst][src][0] == '<0':
assert zero_feature is None
zero_feature = src
else:
bits |= set(groups[dst][src])
assert zero_feature is not None, dst
print(
'{bits},{type}.{dst}.{src}'.format(
bits=' '.join(sorted(bits)),
type='CLK_BUFG',
dst=dst,
src=zero_feature))
if __name__ == "__main__":
main()

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_BUFG_TOP_R clk_bufg_top_r.txt
print_tile_pips CLK_BUFG_BOT_R clk_bufg_bot_r.txt

View File

@ -0,0 +1,95 @@
#!/usr/bin/env python3
from prjxray.segmaker import Segmaker
import os
import os.path
def bitfilter(frame, word):
if frame < 26:
return False
return True
def main():
segmk = Segmaker("design.bits")
tiledata = {}
pipdata = {}
ignpip = set()
with open(os.path.join(os.getenv('FUZDIR'), '..', 'piplist', 'build',
'clk_bufg', 'clk_bufg_bot_r.txt')) as f:
for l in f:
tile_type, dst, src = l.strip().split('.')
if tile_type not in pipdata:
pipdata[tile_type] = []
pipdata[tile_type].append((src, dst))
with open(os.path.join(os.getenv('FUZDIR'), '..', 'piplist', 'build',
'clk_bufg', 'clk_bufg_top_r.txt')) as f:
for l in f:
tile_type, dst, src = l.strip().split('.')
if tile_type not in pipdata:
pipdata[tile_type] = []
pipdata[tile_type].append((src, dst))
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_BUFG'):
continue
if tile.startswith('CLK_BUFG_REBUF'):
continue
pip_prefix, _ = pip.split(".")
tile_from_pip, tile_type = pip_prefix.split('/')
assert tile == tile_from_pip
_, src = src.split("/")
_, dst = dst.split("/")
pnum = int(pnum)
pdir = int(pdir)
if tile not in tiledata:
tiledata[tile] = {
"type": tile_type,
"pips": set(),
"srcs": set(),
"dsts": set()
}
tiledata[tile]["pips"].add((src, dst))
tiledata[tile]["srcs"].add(src)
tiledata[tile]["dsts"].add(dst)
if pdir == 0:
tiledata[tile]["srcs"].add(dst)
tiledata[tile]["dsts"].add(src)
if pnum == 1 or pdir == 0:
ignpip.add((src, dst))
for tile, pips_srcs_dsts in tiledata.items():
tile_type = pips_srcs_dsts["type"]
pips = pips_srcs_dsts["pips"]
for src, dst in pipdata[tile_type]:
if (src, dst) in ignpip:
pass
elif (src, dst) in pips:
segmk.add_tile_tag(tile, "%s.%s" % (dst, src), 1)
elif dst not in tiledata[tile]["dsts"]:
segmk.add_tile_tag(tile, "%s.%s" % (dst, src), 0)
segmk.compile(bitfilter=bitfilter)
segmk.write()
if __name__ == "__main__":
main()

View File

@ -0,0 +1,46 @@
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 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-123}]
set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets]
place_design
route_design
write_checkpoint -force design.dcp
write_bitstream -force design.bit
write_pip_txtdata design.txt
}
run

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 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,337 @@
""" 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.lut_maker import LutMaker
from prjxray.db import Database
from io import StringIO
CMT_XY_FUN = util.create_xy_fun(prefix='')
BUFGCTRL_XY_FUN = util.create_xy_fun('BUFGCTRL_')
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 main():
"""
BUFG's can be driven from:
Interconnect
HROW cascade
"""
print(
'''
module top();
(* KEEP, DONT_TOUCH *)
LUT6 dummy();
''')
site_to_cmt = dict(read_site_to_cmt())
luts = LutMaker()
wires = StringIO()
bufgs = StringIO()
clock_sources = ClockSources()
db = Database(util.get_db_root())
grid = db.grid()
def gen_sites(desired_site_type):
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 tile_name, site
for _, site in gen_sites('MMCME2_ADV'):
mmcm_clocks = [
'mmcm_clock_{site}_{idx}'.format(site=site, idx=idx)
for idx in range(13)
]
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 sorted(gen_sites("BUFGCTRL"),
key=lambda x: BUFGCTRL_XY_FUN(x[1])):
print(
"""
wire O_{site};
wire S1_{site};
wire S0_{site};
wire IGNORE1_{site};
wire IGNORE0_{site};
wire I1_{site};
wire I0_{site};
wire CE1_{site};
wire CE0_{site};
""".format(site=site),
file=wires)
print(
"""
(* KEEP, DONT_TOUCH, LOC = "{site}" *)
BUFGCTRL bufg_{site} (
.O(O_{site}),
.S1(S1_{site}),
.S0(S0_{site}),
.IGNORE1(IGNORE1_{site}),
.IGNORE0(IGNORE0_{site}),
.I1(I1_{site}),
.I0(I0_{site}),
.CE1(CE1_{site}),
.CE0(CE0_{site})
);
""".format(site=site),
file=bufgs)
""" BUFG clock sources:
2 from interconnect
Output of BUFG +/- 1
Cascade in (e.g. PLL, MMCM)
"""
CLOCK_CHOICES = (
'LUT',
'BUFG_+1',
'BUFG_-1',
'CASCADE',
)
def find_bufg_cmt(tile):
if '_BOT_' in tile:
inc = 1
else:
inc = -1
loc = grid.loc_of_tilename(tile)
offset = 1
while True:
gridinfo = grid.gridinfo_at_loc(
(loc.grid_x, loc.grid_y + offset * inc))
if gridinfo.tile_type.startswith('CLK_HROW_'):
return site_to_cmt[list(gridinfo.sites.keys())[0]]
offset += 1
def get_clock_net(tile, site, source_type):
if source_type == 'LUT':
return luts.get_next_output_net()
elif source_type == 'BUFG_+1':
x, y = BUFGCTRL_XY_FUN(site)
target_y = y + 1
max_y = ((y // 16) + 1) * 16
if target_y >= max_y:
target_y -= 16
return 'O_BUFGCTRL_X{x}Y{y}'.format(x=x, y=target_y)
elif source_type == 'BUFG_-1':
x, y = BUFGCTRL_XY_FUN(site)
target_y = y - 1
min_y = (y // 16) * 16
if target_y < min_y:
target_y += 16
return 'O_BUFGCTRL_X{x}Y{y}'.format(x=x, y=target_y)
elif source_type == 'CASCADE':
cmt = find_bufg_cmt(tile)
return clock_sources.get_random_source(cmt)
else:
assert False, source_type
for tile, site in sorted(gen_sites("BUFGCTRL"),
key=lambda x: BUFGCTRL_XY_FUN(x[1])):
if random.randint(0, 1):
print(
"""
assign I0_{site} = {i0_net};""".format(
site=site,
i0_net=get_clock_net(
tile, site, random.choice(CLOCK_CHOICES))),
file=bufgs)
if random.randint(0, 1):
print(
"""
assign I1_{site} = {i1_net};""".format(
site=site,
i1_net=get_clock_net(
tile, site, random.choice(CLOCK_CHOICES))),
file=bufgs)
print(
"""
assign S0_{site} = {s0_net};
assign S1_{site} = {s1_net};
assign IGNORE0_{site} = {ignore0_net};
assign IGNORE1_{site} = {ignore1_net};
assign CE0_{site} = {ce0_net};
assign CE1_{site} = {ce1_net};
""".format(
site=site,
s0_net=luts.get_next_output_net(),
s1_net=luts.get_next_output_net(),
ignore0_net=luts.get_next_output_net(),
ignore1_net=luts.get_next_output_net(),
ce0_net=luts.get_next_output_net(),
ce1_net=luts.get_next_output_net(),
),
file=bufgs)
for l in luts.create_wires_and_luts():
print(l)
print(wires.getvalue())
print(bufgs.getvalue())
itr = iter(gen_sites('BUFHCE'))
for tile, site in sorted(gen_sites("BUFGCTRL"),
key=lambda x: BUFGCTRL_XY_FUN(x[1])):
if random.randint(0, 1):
_, bufhce_site = next(itr)
print(
"""
(* KEEP, DONT_TOUCH, LOC = "{bufhce_site}" *)
BUFHCE bufhce_{bufhce_site} (
.I(O_{site})
);""".format(
site=site,
bufhce_site=bufhce_site,
))
print("endmodule")
if __name__ == '__main__':
main()

View File

@ -0,0 +1,64 @@
export FUZDIR=$(shell pwd)
PIP_TYPE?=hclk_cmt
PIPLIST_TCL=$(FUZDIR)/hclk_cmt_pip_list.tcl
TODO_RE=".*"
# Skipped pips:
# - FREQ_REF is only used by interconnect clocks, so low likelyhood of usage.
# A BUFR can be used to clock divide if needed
# - PHSR PIPs are connected to PHASER sites, which are undocumented, so avoid
# for now.
EXCLUDE_RE="(^.*LEAF)|(^.*BUFMR)|(^.*FREQ_REF)|(^.*PHSR)|(^.*CLK_PLL7)|(^.*CLK_MMCM13)"
MAKETODO_FLAGS=--sides ",l" --pip-type ${PIP_TYPE} --seg-type ${PIP_TYPE} --re $(TODO_RE) --exclude-re $(EXCLUDE_RE)
N = 50
# These PIPs all appear to be either a 1 bit solutions.
SEGMATCH_FLAGS=-c 2
SPECIMENS_DEPS=build/cmt_regions.csv
A_PIPLIST=hclk_cmt.txt
include ../pip_loop.mk
build/segbits_hclk_cmt.rdb: $(SPECIMENS_OK)
${XRAY_SEGMATCH} ${SEGMATCH_FLAGS} -o build/segbits_hclk_cmt.rdb \
$(shell find build -name segdata_hclk_cmt.txt)
build/segbits_hclk_cmt_l.rdb: $(SPECIMENS_OK)
${XRAY_SEGMATCH} ${SEGMATCH_FLAGS} -o build/segbits_hclk_cmt_l.rdb \
$(shell find build -name segdata_hclk_cmt_l.txt)
database: build/segbits_hclk_cmt.rdb build/segbits_hclk_cmt_l.rdb
${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf \
--seg-fn-in build/segbits_hclk_cmt.rdb \
--seg-fn-out build/segbits_hclk_cmt.db
${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf \
--seg-fn-in build/segbits_hclk_cmt_l.rdb \
--seg-fn-out build/segbits_hclk_cmt_l.db
# Keep a copy to track iter progress
cp build/segbits_hclk_cmt.rdb build/$(ITER)/segbits_hclk_cmt.rdb
cp build/segbits_hclk_cmt_l.rdb build/$(ITER)/segbits_hclk_cmt_l.rdb
${XRAY_MASKMERGE} build/mask_hclk_cmt.db \
$(shell find build -name segdata_hclk_cmt.txt)
${XRAY_MASKMERGE} build/mask_hclk_cmt_l.db \
$(shell find build -name segdata_hclk_cmt_l.txt)
# 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} hclk_cmt build/segbits_hclk_cmt.db
XRAY_DATABASE_DIR=${FUZDIR}/build/database ${XRAY_MERGEDB} hclk_cmt_l build/segbits_hclk_cmt_l.db
build/cmt_regions.csv: output_cmt.tcl
mkdir -p build
cd build/ && ${XRAY_VIVADO} -mode batch -source ${FUZDIR}/output_cmt.tcl
pushdb: database
${XRAY_MERGEDB} hclk_cmt build/segbits_hclk_cmt.db
${XRAY_MERGEDB} hclk_cmt_l build/segbits_hclk_cmt_l.db
${XRAY_MERGEDB} mask_hclk_cmt build/mask_hclk_cmt.db
${XRAY_MERGEDB} mask_hclk_cmt_l build/mask_hclk_cmt_l.db
.PHONY: database pushdb

View File

@ -0,0 +1,4 @@
HCLK\_CMT interconnect fuzzer
=============================
Solves pips located within the HCLK\_CMT switch box.

View File

View File

@ -0,0 +1,105 @@
#!/usr/bin/env python3
from prjxray.segmaker import Segmaker
import os
import os.path
def bitfilter(frame, word):
if frame < 26:
return False
return True
def main():
segmk = Segmaker("design.bits")
tiledata = {}
pipdata = {}
ignpip = set()
tile_ports = {}
with open(os.path.join(os.getenv('FUZDIR'), '..', 'piplist', 'build',
'hclk_cmt', 'hclk_cmt.txt')) as f:
for l in f:
tile_type, dst, src = l.strip().split('.')
if tile_type not in pipdata:
pipdata[tile_type] = []
tile_ports[tile_type] = set()
pipdata[tile_type].append((src, dst))
tile_ports[tile_type].add(src)
tile_ports[tile_type].add(dst)
with open(os.path.join(os.getenv('FUZDIR'), '..', 'piplist', 'build',
'hclk_cmt', 'hclk_cmt_l.txt')) as f:
for l in f:
tile_type, dst, src = l.strip().split('.')
if tile_type not in pipdata:
pipdata[tile_type] = []
tile_ports[tile_type] = set()
pipdata[tile_type].append((src, dst))
tile_ports[tile_type].add(src)
tile_ports[tile_type].add(dst)
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('HCLK_CMT'):
continue
pip_prefix, _ = pip.split(".")
tile_from_pip, tile_type = pip_prefix.split('/')
assert tile == tile_from_pip
_, src = src.split("/")
_, dst = dst.split("/")
pnum = int(pnum)
pdir = int(pdir)
if tile not in tiledata:
tiledata[tile] = {
"type": tile_type,
"pips": set(),
"srcs": set(),
"dsts": set()
}
tiledata[tile]["pips"].add((src, dst))
tiledata[tile]["srcs"].add(src)
tiledata[tile]["dsts"].add(dst)
if pdir == 0:
tiledata[tile]["srcs"].add(dst)
tiledata[tile]["dsts"].add(src)
if pnum == 1 or pdir == 0:
ignpip.add((src, dst))
for tile, pips_srcs_dsts in tiledata.items():
tile_type = pips_srcs_dsts["type"]
pips = pips_srcs_dsts["pips"]
for src, dst in pipdata[tile_type]:
if (src, dst) in ignpip:
pass
elif (src, dst) in pips:
segmk.add_tile_tag(tile, "%s.%s" % (dst, src), 1)
elif dst not in tiledata[tile]["dsts"]:
segmk.add_tile_tag(tile, "%s.%s" % (dst, src), 0)
for port in tile_ports[tile_type]:
if port in tiledata[tile]["dsts"] or port in tiledata[tile]["srcs"]:
segmk.add_tile_tag(tile, "{}_ACTIVE".format(port), 1)
else:
segmk.add_tile_tag(tile, "{}_ACTIVE".format(port), 0)
segmk.compile(bitfilter=bitfilter)
segmk.write()
if __name__ == "__main__":
main()

View File

@ -0,0 +1,233 @@
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_all.txt" r]
# Create map of pip source to remaining destinations for that pip
set todo_map [dict create]
for {gets $fp line} {$line != ""} {gets $fp line} {
set parts [split $line .]
dict lappend todo_map [lindex $parts 2] [list [lindex $parts 0] [lindex $parts 1]]
}
close $fp
return $todo_map
}
proc route_todo {} {
puts "Checking TODO's"
set todo_map [load_todo]
set nets [get_nets]
set todo_nets [dict create]
set used_destinations [dict create]
foreach net $nets {
# Check to see if this net is one we are interested in
set wires [get_wires -of_objects $net -filter {TILE_NAME =~ *HCLK_CMT*}]
set is_gclk_net 0
foreach wire $wires {
if [regexp "HCLK_CMT_MUX_CLK_\[0-9\]+" $wire] {
set is_gclk_net 1
break
}
if [regexp "HCLK_CMT_CK_IN\[0-9\]+" $wire] {
set is_gclk_net 1
break
}
}
if {$is_gclk_net == 0} {
puts "$net not going to a HCLK port, skipping."
continue
}
foreach wire $wires {
set tile [lindex [split $wire /] 0]
set wire [lindex [split $wire /] 1]
set tile_type [get_property TILE_TYPE [get_tiles $tile]]
if { ![dict exists $todo_map $wire] } {
continue
}
set dsts [dict get $todo_map $wire]
# This net is interesting, see if it is already going somewhere we
# want.
set found_target 0
foreach other_wire $wires {
if { $found_target == 1 } {
break
}
set other_wire [lindex [split $other_wire /] 1]
if { $wire == $other_wire } {
continue
}
foreach dst $dsts {
set dst_tile_type [lindex $dst 0]
if {$dst_tile_type != $tile_type} {
continue
}
set dst_wire [lindex $dst 1]
if { $other_wire == $dst } {
set found_target 1
puts "Interesting net $net already going from $wire to $other_wire."
set_property IS_ROUTE_FIXED 1 $net
dict set used_destinations "$tile/$dst_wire" 1
break
}
}
}
if { $found_target == 1 } {
# Net has an interesting
continue
}
dict set todo_nets $net [list $tile $wire]
puts "Interesting net $net (including $wire) is being rerouted."
}
}
dict for {net tile_wire} $todo_nets {
set tile [lindex $tile_wire 0]
set wire [lindex $tile_wire 1]
set dsts [dict get $todo_map $wire]
puts "Rerouting net $net at $tile / $wire (type $tile_type)"
set tile_type [get_property TILE_TYPE [get_tiles $tile]]
set todos {}
foreach dst $dsts {
set dst_tile_type [lindex $dst 0]
if {$dst_tile_type != $tile_type} {
continue
}
set dst_wire [lindex $dst 1]
set is_gclk_net 0
if [regexp "HCLK_CMT_MUX_CLK_\[0-9\]+" $dst_wire] {
set is_gclk_net 1
}
if [regexp "HCLK_CMT_CK_IN\[0-9\]+" $dst_wire] {
set is_gclk_net 1
}
if {$is_gclk_net == 0} {
continue
}
lappend todos $dst_wire
}
puts "All todos for $tile_type / $wire"
foreach dst_wire $todos {
puts " - $dst_wire"
}
route_design -unroute -nets $net
# Find an input in the todo list that this can can drive.
foreach dst_wire $todos {
if { [dict exists $used_destinations "$tile/$dst_wire"] } {
puts "Not routing to $tile / $dst_wire, in use."
continue
}
puts "Attempting to route to $dst_wire for net $net."
set target_wire [get_wires "$tile/$dst_wire"]
set target_node [get_nodes -of_objects $target_wire]
if {[llength $target_node] == 0} {
error "Failed to find node for $tile/$dst_wire."
}
set old_nets [get_nets -of_objects $target_node]
if { $old_nets != {} } {
route_design -unroute -nets $old_nets
}
set origin_node [get_nodes -of_objects [get_site_pins -filter {DIRECTION == OUT} -of_objects $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"
# Only need to set route to one of the destinations.
# Router will handle the rest.
set_property FIXED_ROUTE $new_route $net
dict set used_destinations "$tile/$dst_wire" 1
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 {PDRC-29}]
set_property IS_ENABLED 0 [get_drc_checks {PDRC-38}]
set_property IS_ENABLED 0 [get_drc_checks {REQP-13}]
set_property IS_ENABLED 0 [get_drc_checks {REQP-123}]
set_property IS_ENABLED 0 [get_drc_checks {REQP-161}]
set_property IS_ENABLED 0 [get_drc_checks {REQP-1575}]
set_property IS_ENABLED 0 [get_drc_checks {REQP-1684}]
set_property IS_ENABLED 0 [get_drc_checks {REQP-1712}]
set_property IS_ENABLED 0 [get_drc_checks {AVAL-50}]
set_property IS_ENABLED 0 [get_drc_checks {AVAL-78}]
set_property IS_ENABLED 0 [get_drc_checks {AVAL-81}]
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,38 @@
proc print_tile_pips {tile_type filename} {
set fp [open $filename w]
set pips [dict create]
foreach tile [get_tiles -filter "TYPE == $tile_type"] {
puts "Dumping PIPs for tile $tile ($tile_type) to $filename."
foreach pip [lsort [get_pips -of_objects $tile]] {
set src [get_wires -uphill -of_objects $pip]
set dst [get_wires -downhill -of_objects $pip]
# Skip pips with disconnected nodes
set src_node [get_nodes -of_objects $src]
if { $src_node == {} } {
continue
}
set dst_node [get_nodes -of_objects $src]
if { $dst_node == {} } {
continue
}
if {[llength [get_nodes -uphill -of_objects [get_nodes -of_objects $dst]]] != 1} {
set pip_string "$tile_type.[regsub {.*/} $dst ""].[regsub {.*/} $src ""]"
if ![dict exists $pips $pip_string] {
puts $fp $pip_string
dict set pips $pip_string 1
}
}
}
}
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 HCLK_CMT_L hclk_cmt_l.txt
print_tile_pips HCLK_CMT hclk_cmt.txt

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 BUFMRCE BUFHCE IOB33M IOB18M BUFR} {
foreach site [get_sites -filter "SITE_TYPE == $site_type"] {
puts $fp "$site,[get_property CLOCK_REGION $site]"
}
}
close $fp

View File

@ -0,0 +1,449 @@
""" 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.lut_maker import LutMaker
from prjxray.db import Database
from io import StringIO
CMT_XY_FUN = util.create_xy_fun(prefix='')
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.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)
self.source_to_cmt[source] = cmt
def get_random_source(
self, cmt, uses_left_right_routing=False, no_repeats=False):
""" 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.
"""
choices = []
if cmt in self.sources:
choices.extend(self.sources[cmt])
if uses_left_right_routing:
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:
for source in self.sources[paired_cmt]:
if 'BUFHCE' not in source:
choices.append(source)
random.shuffle(choices)
if not uses_left_right_routing:
return choices[0]
for source in choices:
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()
if no_repeats and source in self.used_sources_from_cmt[source_cmt]:
continue
if len(self.used_sources_from_cmt[source_cmt]) >= 14:
continue
self.used_sources_from_cmt[source_cmt].add(source)
return source
return None
def get_paired_iobs(db, grid, tile_name):
""" The two IOB33M's above and below the HCLK row have dedicate clock lines.
"""
gridinfo = grid.gridinfo_at_tilename(tile_name)
loc = grid.loc_of_tilename(tile_name)
if gridinfo.tile_type.endswith('_L'):
inc = 1
lr = 'R'
else:
inc = -1
lr = 'L'
idx = 1
while True:
gridinfo = grid.gridinfo_at_loc((loc.grid_x + inc * idx, loc.grid_y))
if gridinfo.tile_type.startswith('HCLK_IOI'):
break
idx += 1
# Move from HCLK_IOI column to IOB column
idx += 1
for dy in [-1, -3, 2, 4]:
iob_loc = (loc.grid_x + inc * idx, loc.grid_y + dy)
gridinfo = grid.gridinfo_at_loc(iob_loc)
tile_name = grid.tilename_at_loc(iob_loc)
assert gridinfo.tile_type.startswith(lr + 'IOB'), (
gridinfo, lr + 'IOB')
for site, site_type in gridinfo.sites.items():
if site_type in ['IOB33M', 'IOB18M']:
yield tile_name, site, site_type[-3:-1]
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():
"""
HCLK_CMT switch box has the follow inputs:
4 IOBs above and below
14 MMCM outputs
8 PLL outputs
4 PHASER_IN outputs
2 INT connections
and the following outputs:
3 PLLE2 inputs
2 BUFMR inputs
3 MMCM inputs
~2 MMCM -> BUFR???
"""
clock_sources = ClockSources()
adv_clock_sources = ClockSources()
site_to_cmt = dict(read_site_to_cmt())
db = Database(util.get_db_root())
grid = db.grid()
def gen_sites(desired_site_type):
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 tile_name, site
hclk_cmts = set()
ins = []
iobs = StringIO()
hclk_cmt_tiles = set()
for tile_name, site in gen_sites('BUFMRCE'):
cmt = site_to_cmt[site]
hclk_cmts.add(cmt)
hclk_cmt_tiles.add(tile_name)
mmcm_pll_only = random.randint(0, 1)
mmcm_pll_dir = random.choice(('ODD', 'EVEN', 'BOTH'))
print(
'// mmcm_pll_only {} mmcm_pll_dir {}'.format(
mmcm_pll_only, mmcm_pll_dir))
for tile_name in sorted(hclk_cmt_tiles):
for _, site, volt in get_paired_iobs(db, grid, tile_name):
ins.append('input clk_{site}'.format(site=site))
if check_allowed(mmcm_pll_dir, site_to_cmt[site]):
clock_sources.add_clock_source(
'clock_IBUF_{site}'.format(site=site), site_to_cmt[site])
adv_clock_sources.add_clock_source(
'clock_IBUF_{site}'.format(site=site), site_to_cmt[site])
print(
"""
(* KEEP, DONT_TOUCH, LOC = "{site}" *)
wire clock_IBUF_{site};
IBUF #( .IOSTANDARD("LVCMOS{volt}") ) ibuf_{site} (
.I(clk_{site}),
.O(clock_IBUF_{site})
);
""".format(volt=volt, site=site),
file=iobs)
print(
'''
module top({inputs});
(* KEEP, DONT_TOUCH *)
LUT6 dummy();
'''.format(inputs=', '.join(ins)))
print(iobs.getvalue())
luts = LutMaker()
wires = StringIO()
bufhs = StringIO()
for _, site in gen_sites('MMCME2_ADV'):
mmcm_clocks = [
'mmcm_clock_{site}_{idx}'.format(site=site, idx=idx)
for idx in range(13)
]
if check_allowed(mmcm_pll_dir, site_to_cmt[site]):
for clk in mmcm_clocks:
clock_sources.add_clock_source(clk, site_to_cmt[site])
print(
"""
wire cin1_{site}, cin2_{site}, clkfbin_{site}, {c0}, {c1}, {c2}, {c3}, {c4}, {c5};
(* KEEP, DONT_TOUCH, LOC = "{site}" *)
MMCME2_ADV pll_{site} (
.CLKIN1(cin1_{site}),
.CLKIN2(cin2_{site}),
.CLKFBIN(clkfbin_{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(7)
]
if check_allowed(mmcm_pll_dir, site_to_cmt[site]):
for clk in pll_clocks:
clock_sources.add_clock_source(clk, site_to_cmt[site])
print(
"""
wire cin1_{site}, cin2_{site}, clkfbin_{site}, {c0}, {c1}, {c2}, {c3}, {c4}, {c5}, {c6};
(* KEEP, DONT_TOUCH, LOC = "{site}" *)
PLLE2_ADV pll_{site} (
.CLKIN1(cin1_{site}),
.CLKIN2(cin2_{site}),
.CLKFBIN(clkfbin_{site}),
.CLKOUT0({c0}),
.CLKOUT1({c1}),
.CLKOUT2({c2}),
.CLKOUT3({c3}),
.CLKOUT4({c4}),
.CLKOUT5({c5}),
.CLKFBOUT({c6})
);
""".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],
c6=pll_clocks[6],
))
for tile_name, site in gen_sites('BUFHCE'):
print(
"""
wire I_{site};
wire O_{site};
(* KEEP, DONT_TOUCH, LOC = "{site}" *)
BUFHCE buf_{site} (
.I(I_{site}),
.O(O_{site})
);
""".format(site=site, ),
file=bufhs)
if site_to_cmt[site] in hclk_cmts:
if not mmcm_pll_only:
clock_sources.add_clock_source(
'O_{site}'.format(site=site), site_to_cmt[site])
adv_clock_sources.add_clock_source(
'O_{site}'.format(site=site), site_to_cmt[site])
hclks_used_by_cmt = {}
for cmt in site_to_cmt.values():
hclks_used_by_cmt[cmt] = set()
def check_hclk_src(src, src_cmt):
if len(hclks_used_by_cmt[src_cmt]
) >= 12 and src not in hclks_used_by_cmt[src_cmt]:
return None
else:
hclks_used_by_cmt[src_cmt].add(src)
return src
if random.random() > .10:
for tile_name, site in gen_sites('BUFHCE'):
wire_name = clock_sources.get_random_source(
site_to_cmt[site],
uses_left_right_routing=True,
no_repeats=mmcm_pll_only)
if wire_name is not None and 'BUFHCE' in wire_name:
# Looping a BUFHCE to a BUFHCE requires using a hclk in the
# CMT of the source
src_cmt = clock_sources.source_to_cmt[wire_name]
wire_name = check_hclk_src(wire_name, src_cmt)
if wire_name is None:
continue
print(
"""
assign I_{site} = {wire_name};""".format(
site=site,
wire_name=wire_name,
),
file=bufhs)
for tile_name, site in gen_sites('BUFMRCE'):
pass
for l in luts.create_wires_and_luts():
print(l)
print(wires.getvalue())
print(bufhs.getvalue())
for _, site in gen_sites('BUFR'):
adv_clock_sources.add_clock_source(
'O_{site}'.format(site=site), site_to_cmt[site])
print(
"""
wire O_{site};
(* KEEP, DONT_TOUCH, LOC = "{site}" *)
BUFR bufr_{site} (
.O(O_{site})
);""".format(site=site))
for _, site in gen_sites('PLLE2_ADV'):
for cin in ('cin1', 'cin2', 'clkfbin'):
if random.random() > .2:
src = adv_clock_sources.get_random_source(site_to_cmt[site])
src_cmt = adv_clock_sources.source_to_cmt[src]
if 'IBUF' not in src and 'BUFR' not in src:
# Clocks from input pins do not require HCLK's, all other
# sources route from a global row clock.
src = check_hclk_src(src, src_cmt)
if src is None:
continue
print(
"""
assign {cin}_{site} = {csrc};
""".format(cin=cin, site=site, csrc=src))
for _, site in gen_sites('MMCME2_ADV'):
for cin in ('cin1', 'cin2', 'clkfbin'):
if random.random() > .2:
src = adv_clock_sources.get_random_source(site_to_cmt[site])
src_cmt = adv_clock_sources.source_to_cmt[src]
if 'IBUF' not in src and 'BUFR' not in src:
# Clocks from input pins do not require HCLK's, all other
# sources route from a global row clock.
src = check_hclk_src(src, src_cmt)
if src is None:
continue
print(
"""
assign {cin}_{site} = {csrc};
""".format(cin=cin, site=site, csrc=src))
print("endmodule")
if __name__ == '__main__':
main()

View File

@ -83,6 +83,8 @@ $(eval $(call fuzzer,040-clk-hrow-config,005-tilegrid))
$(eval $(call fuzzer,041-clk-hrow-pips,005-tilegrid))
$(eval $(call fuzzer,042-clk-bufg-config,005-tilegrid))
$(eval $(call fuzzer,043-clk-rebuf-pips,005-tilegrid))
$(eval $(call fuzzer,044-clk-bufg-pips,005-tilegrid))
$(eval $(call fuzzer,045-hclk-cmt-pips,005-tilegrid))
$(eval $(call fuzzer,048-int-piplist,005-tilegrid))
$(eval $(call fuzzer,049-int-imux-gfan,048-int-piplist))
$(eval $(call fuzzer,050-pip-seed,048-int-piplist))

View File

@ -33,7 +33,9 @@ def load_pipfile(pipfile, verbose=False):
return todos, tile_type
def maketodo(pipfile, dbfile, intre, not_endswith=None, verbose=False):
def maketodo(
pipfile, dbfile, intre, exclude_re=None, not_endswith=None,
verbose=False):
'''
db files start with INT., but pipfile lines start with INT_L
Normalize by removing before the first dot
@ -75,8 +77,15 @@ def maketodo(pipfile, dbfile, intre, not_endswith=None, verbose=False):
drops = 0
lines = 0
for line in todos:
if re.match(intre, line) and (not_endswith is None
or not line.endswith(not_endswith)):
include = re.match(intre, line) is not None
if include and not_endswith is not None:
include = not line.endswith(not_endswith)
if include and exclude_re is not None:
include = re.match(exclude_re, line) is None
if include:
print(line)
else:
drops += 1
@ -89,10 +98,12 @@ def run(
db_dir,
pip_dir,
intre,
sides,
l,
r,
pip_type,
seg_type,
exclude_re=None,
not_endswith=None,
verbose=False):
if db_dir is None:
@ -105,20 +116,22 @@ def run(
assert intre, "RE is required"
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)
for side in sides:
if side == "l" and not l:
continue
if side == "r" and not r:
continue
if side != "":
side = "_" + side
if r:
maketodo(
"%s/%s_r.txt" % (pip_dir, pip_type),
"%s/segbits_%s_r.db" % (db_dir, seg_type),
"%s/%s%s.txt" % (pip_dir, pip_type, side),
"%s/segbits_%s%s.db" % (db_dir, seg_type, side),
intre,
not_endswith,
exclude_re=exclude_re,
not_endswith=not_endswith,
verbose=verbose)
@ -133,8 +146,10 @@ def main():
parser.add_argument('--db-dir', default=None, help='')
parser.add_argument('--pip-dir', default=None, help='')
parser.add_argument('--re', required=True, help='')
parser.add_argument('--exclude-re', required=False, default=None, help='')
parser.add_argument('--pip-type', default="pips_int", help='')
parser.add_argument('--seg-type', default="int", help='')
parser.add_argument('--sides', default="l,r", help='')
util.add_bool_arg(parser, '--l', default=True, help='')
util.add_bool_arg(parser, '--r', default=True, help='')
parser.add_argument(
@ -146,6 +161,8 @@ def main():
db_dir=args.db_dir,
pip_dir=args.pip_dir,
intre=args.re,
exclude_re=args.exclude_re,
sides=args.sides.split(','),
l=args.l,
r=args.r,
pip_type=args.pip_type,

View File

@ -100,6 +100,11 @@ case "$1" in
clk_bufg_top_r)
sed < "$2" > "$tmp1" -e 's/^CLK_BUFG\./CLK_BUFG_TOP_R./' ;;
hclk_cmt)
cp "$2" "$tmp1" ;;
hclk_cmt_l)
sed < "$2" > "$tmp1" -e 's/^HCLK_CMT\./HCLK_CMT_L./' ;;
clk_bufg_rebuf)
cp "$2" "$tmp1" ;;