tilegrid: generate products in parallel

Signed-off-by: John McMaster <johndmcmaster@gmail.com>
This commit is contained in:
John McMaster 2018-12-03 12:00:06 -08:00
parent 379ed08344
commit a77f7bd12e
13 changed files with 332 additions and 227 deletions

View File

@ -1,13 +1,29 @@
# TODO: parallelize
FUZDIR=$(shell pwd)
BUILD_DIR=$(FUZDIR)/build
database: build/tilegrid.json
pushdb:
cp build/tilegrid.json ${XRAY_DATABASE_DIR}/$(XRAY_DATABASE)/tilegrid.json
build/tilegrid.json: build/deltas generate.py
cd build && python3 ../generate.py design_*.delta > tilegrid.json
build/tiles/tiles.txt:
bash generate.sh build/tiles tiles
build/deltas:
bash generate.sh build
# TODO: only generate tiles
build/tilegrid_basic.json: build/tiles/tiles.txt build/clb/deltas build/bram/deltas generate.py
cd build && python3 ${FUZDIR}/generate.py --tiles $(FUZDIR)/build/tiles/tiles.txt */design_*.delta --out ${BUILD_DIR}/tilegrid_basic.json
build/clb/deltas:
bash generate.sh build/clb clb
build/bram/deltas:
bash generate.sh build/bram bram
# TODO: only generate addresses
build/tilegrid.json: build/tilegrid_basic.json
cd build && python3 ${FUZDIR}/generate_full.py --json-in tilegrid_basic.json --json-out ${BUILD_DIR}/tilegrid.json design_*.delta
run:
$(MAKE) clean

View File

@ -81,7 +81,9 @@ def load_baseaddrs(deltas_fns):
for arg in deltas_fns:
with open(arg) as f:
line = f.read().strip()
site = arg[7:-6]
# clb/design_SLICE_X10Y100.delta
# site = arg[7:-6]
site = re.match(r".*/design_(.*).delta", arg).group(1)
frame = int(line[5:5 + 8], 16)
# was "0x%08x"
site_baseaddr[site] = frame & ~0x7f
@ -112,6 +114,7 @@ def make_tile_baseaddrs(tiles, site_baseaddr, verbose=False):
verbose and print('')
verbose and print('%u tiles' % len(tiles))
verbose and print("%u baseaddrs" % len(site_baseaddr))
added = 0
for tile in tiles:
for site_name in tile["sites"].keys():
@ -131,7 +134,8 @@ def make_tile_baseaddrs(tiles, site_baseaddr, verbose=False):
(tile["name"], site_name, bt, framebaseaddr))
added += 1
assert added
assert added, "Failed to add any base addresses"
assert added == len(site_baseaddr)
return tile_baseaddrs

View File

@ -1,16 +1,20 @@
#!/bin/bash -x
PRJ=$2
export FUZDIR=$PWD
source ${XRAY_GENHEADER}
vivado -mode batch -source ../generate.tcl
vivado -mode batch -source $FUZDIR/generate_$PRJ.tcl
for x in design*.bit; do
${XRAY_BITREAD} -F $XRAY_ROI_FRAMES -o ${x}s -z -y $x
done
for x in design_*.bits; do
diff -u design.bits $x | grep '^[-+]bit' > ${x%.bits}.delta
done
touch deltas
if [ $PRJ != "tiles" ] ; then
for x in design*.bit; do
${XRAY_BITREAD} -F $XRAY_ROI_FRAMES -o ${x}s -z -y $x
done
for x in design_*.bits; do
diff -u design.bits $x | grep '^[-+]bit' > ${x%.bits}.delta
done
touch deltas
fi

View File

@ -1,209 +0,0 @@
proc make_project {} {
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 -dict "PACKAGE_PIN $::env(XRAY_PIN_01) IOSTANDARD LVCMOS33" [get_ports di]
set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_02) IOSTANDARD LVCMOS33" [get_ports do]
set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_03) IOSTANDARD LVCMOS33" [get_ports stb]
create_pblock roi
add_cells_to_pblock [get_pblocks roi] [get_cells roi]
foreach roi "$::env(XRAY_ROI_TILEGRID)" {
puts "ROI: $roi"
resize_pblock [get_pblocks roi] -add "$roi"
}
set_property CFGBVS VCCO [current_design]
set_property CONFIG_VOLTAGE 3.3 [current_design]
set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design]
set_param tcl.collectionResultDisplayLimit 0
set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk_IBUF]
}
proc loc_luts {} {
set luts [get_bels -of_objects [get_sites -of_objects [get_pblocks roi]] -filter {TYPE =~ LUT*} */A6LUT]
set selected_luts {}
set lut_index 0
# LOC one LUT (a "selected_lut") into each CLB segment configuration column (ie 50 per CMT column)
set lut_columns ""
foreach lut $luts {
regexp "SLICE_X([0-9]+)Y([0-9]+)/" $lut match slice_x slice_y
# Only even SLICEs should be used as column bases.
if { $slice_x % 2 != 0 } {
continue
}
# 50 per column => 50, 100, 150, etc
# ex: SLICE_X2Y50/A6LUT
# Only take one of the CLBs within a slice
set y_column [expr ($slice_y / 50) * 50]
dict append lut_columns "X${slice_x}Y${y_column}" "$lut "
}
# Pick the smallest Y in each column.
dict for {column luts_in_column} $lut_columns {
set min_slice_y 9999999
foreach lut $luts_in_column {
regexp "SLICE_X([0-9]+)Y([0-9]+)/" $lut slice_x slice_y
if { $slice_y < $min_slice_y } {
set selected_lut $lut
}
}
set cell [get_cells roi/luts[$lut_index].lut]
set lut_site [get_sites -of_objects [get_bels $selected_lut]]
puts "LOCing $selected_lut to $lut_site"
set_property LOC $lut_site $cell
set lut_index [expr $lut_index + 1]
lappend selected_luts [get_bels $selected_lut]
}
return $selected_luts
}
# Return a list of sites containing BRAMs
# sites are better than bels because site type may change and invalidate the bel
proc loc_brams {} {
# BRAM have multiple mutually exclusive sites
# They can be cycled by setting the site type
# Ex:
# - RAMB36_X0Y10/RAMBFIFO36E1
# - RAMB36_X0Y10/RAMB36E1
# Default is RAMBFIFO36E1?
# Work primarily on sites, not bels,
# to avoid issues when switching site type during PnR
set bram_sites [get_sites -of_objects [get_pblocks roi] -filter {SITE_TYPE =~ RAMBFIFO36E1*}]
set bram_bels [get_bels -of_objects $bram_sites]
set selected_bram_sites {}
set bram_index 0
# LOC one BRAM (a "selected_lut") into each BRAM segment configuration column (ie 10 per CMT column)
set bram_columns ""
foreach bram $bram_bels {
regexp "RAMB36_X([0-9]+)Y([0-9]+)/" $bram match slice_x slice_y
# 10 per column => 10, 20, ,etc
# ex: RAMB36_X0Y10/RAMBFIFO36E1
set y_column [expr ($slice_y / 10) * 10]
dict append bram_columns "X${slice_x}Y${y_column}" "$bram "
}
# Pick the smallest Y in each column.
dict for {column brams_in_column} $bram_columns {
set min_slice_y 9999999
foreach bram $brams_in_column {
regexp "RAMB36_X([0-9]+)Y([0-9]+)/" $bram match slice_x slice_y
if { $slice_y < $min_slice_y } {
set selected_bram_bel $bram
}
}
set selected_bram_bel [get_bels $selected_bram_bel]
set bram_site [get_sites -of_objects $selected_bram_bel]
puts "LOCing BEL: $selected_bram_bel to $bram_site"
set cell [get_cells roi/brams[$bram_index].bram]
set_property LOC $bram_site $cell
if {"$bram_site" == ""} {error "Bad site $bram_site from bel $selected_bram_bel"}
set bram_index [expr $bram_index + 1]
# Output site, not bel, to avoid reference issues after PnR
lappend selected_bram_sites $bram_site
}
return $selected_bram_sites
}
proc write_tiles_txt {} {
# Get all tiles, ie not just the selected LUTs
set tiles [get_tiles]
# Write tiles.txt with site metadata
set fp [open "tiles.txt" w]
foreach tile $tiles {
set type [get_property TYPE $tile]
set grid_x [get_property GRID_POINT_X $tile]
set grid_y [get_property GRID_POINT_Y $tile]
set sites [get_sites -quiet -of_objects $tile]
set typed_sites {}
if [llength $sites] {
set site_types [get_property SITE_TYPE $sites]
foreach t $site_types s $sites {
lappend typed_sites $t $s
}
}
puts $fp "$type $tile $grid_x $grid_y $typed_sites"
}
close $fp
}
proc write_clbs { selected_luts } {
puts "write_brams: [llength $selected_luts] LUTs"
puts ""
# Toggle one bit in each selected LUT to generate base addresses
for {set i 0} {$i < [llength $selected_luts]} {incr i} {
puts ""
set cell [get_cells roi/luts[$i].lut]
puts "LUT $cell"
set orig_init [get_property INIT $cell]
# Flip a bit by changing MSB 0 => 1
set new_init [regsub "h8" $orig_init "h0"]
puts "INIT $orig_init => $new_init"
set_property INIT $new_init $cell
set site [get_sites -of_objects [lindex $selected_luts $i]]
write_bitstream -force design_$site.bit
set_property INIT $orig_init $cell
}
}
proc write_brams { selected_brams_sites } {
puts "write_brams: [llength $selected_brams_sites] BRAMs"
puts ""
# Toggle one bit in each selected BRAM to generate base addresses
for {set i 0} {$i < [llength $selected_brams_sites]} {incr i} {
puts ""
set cell [get_cells roi/brams[$i].bram]
puts "BRAM $cell"
set orig_init [get_property INIT_00 $cell]
# Flip a bit by changing MSB 0 => 1
set new_init [regsub "h8" $orig_init "h0"]
puts "INIT_00 $orig_init => $new_init"
set_property INIT_00 $new_init $cell
set site [lindex $selected_brams_sites $i]
if {"$site" == ""} {error "Bad site $site"}
write_bitstream -force design_$site.bit
set_property INIT_00 $orig_init $cell
}
}
proc run {} {
make_project
set selected_luts [loc_luts]
puts "Selected LUTs: [llength $selected_luts]"
set selected_brams_sites [loc_brams]
puts "Selected BRAMs: [llength $selected_brams_sites]"
place_design
route_design
write_checkpoint -force design.dcp
write_bitstream -force design.bit
write_tiles_txt
write_clbs $selected_luts
write_brams $selected_brams_sites
}
run

View File

@ -0,0 +1,93 @@
source "$::env(FUZDIR)/util.tcl"
# Return a list of sites containing BRAMs
# sites are better than bels because site type may change and invalidate the bel
proc loc_brams {} {
# BRAM have multiple mutually exclusive sites
# They can be cycled by setting the site type
# Ex:
# - RAMB36_X0Y10/RAMBFIFO36E1
# - RAMB36_X0Y10/RAMB36E1
# Default is RAMBFIFO36E1?
# Work primarily on sites, not bels,
# to avoid issues when switching site type during PnR
set bram_sites [get_sites -of_objects [get_pblocks roi] -filter {SITE_TYPE =~ RAMBFIFO36E1*}]
set bram_bels [get_bels -of_objects $bram_sites]
set selected_bram_sites {}
set bram_index 0
# LOC one BRAM (a "selected_lut") into each BRAM segment configuration column (ie 10 per CMT column)
set bram_columns ""
foreach bram $bram_bels {
regexp "RAMB36_X([0-9]+)Y([0-9]+)/" $bram match slice_x slice_y
# 10 per column => 10, 20, ,etc
# ex: RAMB36_X0Y10/RAMBFIFO36E1
set y_column [expr ($slice_y / 10) * 10]
dict append bram_columns "X${slice_x}Y${y_column}" "$bram "
}
# Pick the smallest Y in each column.
dict for {column brams_in_column} $bram_columns {
set min_slice_y 9999999
foreach bram $brams_in_column {
regexp "RAMB36_X([0-9]+)Y([0-9]+)/" $bram match slice_x slice_y
if { $slice_y < $min_slice_y } {
set selected_bram_bel $bram
}
}
set selected_bram_bel [get_bels $selected_bram_bel]
set bram_site [get_sites -of_objects $selected_bram_bel]
puts "LOCing BEL: $selected_bram_bel to $bram_site"
set cell [get_cells roi/brams[$bram_index].bram]
set_property LOC $bram_site $cell
if {"$bram_site" == ""} {error "Bad site $bram_site from bel $selected_bram_bel"}
set bram_index [expr $bram_index + 1]
# Output site, not bel, to avoid reference issues after PnR
lappend selected_bram_sites $bram_site
}
return $selected_bram_sites
}
proc write_brams { selected_brams_sites } {
puts "write_brams: [llength $selected_brams_sites] BRAMs"
puts ""
# Toggle one bit in each selected BRAM to generate base addresses
for {set i 0} {$i < [llength $selected_brams_sites]} {incr i} {
puts ""
set cell [get_cells roi/brams[$i].bram]
puts "BRAM $cell"
set orig_init [get_property INIT_00 $cell]
# Flip a bit by changing MSB 0 => 1
set new_init [regsub "h8" $orig_init "h0"]
puts "INIT_00 $orig_init => $new_init"
set_property INIT_00 $new_init $cell
set site [lindex $selected_brams_sites $i]
if {"$site" == ""} {error "Bad site $site"}
write_bitstream -force design_$site.bit
set_property INIT_00 $orig_init $cell
}
}
proc run {} {
make_project
set selected_brams_sites [loc_brams]
puts "Selected BRAMs: [llength $selected_brams_sites]"
place_design
route_design
write_checkpoint -force design.dcp
write_bitstream -force design.bit
write_brams $selected_brams_sites
}
run

View File

@ -0,0 +1,81 @@
source "$::env(FUZDIR)/util.tcl"
proc loc_luts {} {
set luts [get_bels -of_objects [get_sites -of_objects [get_pblocks roi]] -filter {TYPE =~ LUT*} */A6LUT]
set selected_luts {}
set lut_index 0
# LOC one LUT (a "selected_lut") into each CLB segment configuration column (ie 50 per CMT column)
set lut_columns ""
foreach lut $luts {
regexp "SLICE_X([0-9]+)Y([0-9]+)/" $lut match slice_x slice_y
# Only even SLICEs should be used as column bases.
if { $slice_x % 2 != 0 } {
continue
}
# 50 per column => 50, 100, 150, etc
# ex: SLICE_X2Y50/A6LUT
# Only take one of the CLBs within a slice
set y_column [expr ($slice_y / 50) * 50]
dict append lut_columns "X${slice_x}Y${y_column}" "$lut "
}
# Pick the smallest Y in each column.
dict for {column luts_in_column} $lut_columns {
set min_slice_y 9999999
foreach lut $luts_in_column {
regexp "SLICE_X([0-9]+)Y([0-9]+)/" $lut slice_x slice_y
if { $slice_y < $min_slice_y } {
set selected_lut $lut
}
}
set cell [get_cells roi/luts[$lut_index].lut]
set lut_site [get_sites -of_objects [get_bels $selected_lut]]
puts "LOCing $selected_lut to $lut_site"
set_property LOC $lut_site $cell
set lut_index [expr $lut_index + 1]
lappend selected_luts [get_bels $selected_lut]
}
return $selected_luts
}
proc write_clbs { selected_luts } {
puts "write_brams: [llength $selected_luts] LUTs"
puts ""
# Toggle one bit in each selected LUT to generate base addresses
for {set i 0} {$i < [llength $selected_luts]} {incr i} {
puts ""
set cell [get_cells roi/luts[$i].lut]
puts "LUT $cell"
set orig_init [get_property INIT $cell]
# Flip a bit by changing MSB 0 => 1
set new_init [regsub "h8" $orig_init "h0"]
puts "INIT $orig_init => $new_init"
set_property INIT $new_init $cell
set site [get_sites -of_objects [lindex $selected_luts $i]]
write_bitstream -force design_$site.bit
set_property INIT $orig_init $cell
}
}
proc run {} {
make_project
set selected_luts [loc_luts]
puts "Selected LUTs: [llength $selected_luts]"
place_design
route_design
write_checkpoint -force design.dcp
write_bitstream -force design.bit
write_clbs $selected_luts
}
run

View File

@ -0,0 +1,45 @@
#!/usr/bin/env python3
import os, sys, json, re
def run(json_in_fn, json_out_fn, deltas_fns, verbose=False):
database = json.load(open(json_in_fn, "r"))
# TODO: move address processing here
# Save
json.dump(
database,
open(json_out_fn, "w"),
sort_keys=True,
indent=4,
separators=(",", ": "))
def main():
import argparse
import glob
parser = argparse.ArgumentParser(
description="Generate tilegrid.json from bitstream deltas")
parser.add_argument("--verbose", action="store_true", help="")
parser.add_argument(
"--json-in",
default="tiles_basic.json",
help="Input .json without addresses")
parser.add_argument(
"--json-out", default="tilegrid.json", help="Output JSON")
parser.add_argument(
"deltas", nargs="*", help=".bit diffs to create base addresses from")
args = parser.parse_args()
deltas = args.deltas
if not args.deltas:
deltas = glob.glob("*.delta")
run(args.json_in, args.json_out, deltas, verbose=args.verbose)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,40 @@
source "$::env(FUZDIR)/util.tcl"
proc write_tiles_txt {} {
# Get all tiles, ie not just the selected LUTs
set tiles [get_tiles]
# Write tiles.txt with site metadata
set fp [open "tiles.txt" w]
foreach tile $tiles {
set type [get_property TYPE $tile]
set grid_x [get_property GRID_POINT_X $tile]
set grid_y [get_property GRID_POINT_Y $tile]
set sites [get_sites -quiet -of_objects $tile]
set typed_sites {}
if [llength $sites] {
set site_types [get_property SITE_TYPE $sites]
foreach t $site_types s $sites {
lappend typed_sites $t $s
}
}
puts $fp "$type $tile $grid_x $grid_y $typed_sites"
}
close $fp
}
proc run {} {
make_project
place_design
route_design
write_checkpoint -force design.dcp
write_bitstream -force design.bit
write_tiles_txt
}
run

View File

@ -0,0 +1,27 @@
proc make_project {} {
create_project -force -part $::env(XRAY_PART) design design
read_verilog "$::env(FUZDIR)/top.v"
synth_design -top top
set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_00) IOSTANDARD LVCMOS33" [get_ports clk]
set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_01) IOSTANDARD LVCMOS33" [get_ports di]
set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_02) IOSTANDARD LVCMOS33" [get_ports do]
set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_03) IOSTANDARD LVCMOS33" [get_ports stb]
create_pblock roi
add_cells_to_pblock [get_pblocks roi] [get_cells roi]
foreach roi "$::env(XRAY_ROI_TILEGRID)" {
puts "ROI: $roi"
resize_pblock [get_pblocks roi] -add "$roi"
}
set_property CFGBVS VCCO [current_design]
set_property CONFIG_VOLTAGE 3.3 [current_design]
set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design]
set_param tcl.collectionResultDisplayLimit 0
set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk_IBUF]
}

View File

@ -12,9 +12,11 @@ clean:
build/env:
test "$(XRAY_PART)" = "xc7a50tfgg484-1"
# Didn't work
build/roi_io.diff:
$(MAKE) -f diff.mk OUT_DIFF=build/roi_io.diff PRJL=roi_io_a PRJR=roi_io_b
# Didn't work
build/roi_prop.diff:
$(MAKE) -f diff.mk OUT_DIFF=build/roi_prop.diff PRJL=roi_prop_a PRJR=roi_prop_b

View File

@ -17,6 +17,7 @@ set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk_IBUF]
place_design
route_design
write_checkpoint -force design.dcp
# set port [create_port -direction OUT myport]
# set_property -dict "PACKAGE_PIN D19 IOSTANDARD LVCMOS33" $port

View File

@ -8,12 +8,13 @@ fi
set -ex
# for some reason on sourced script set -e doesn't work
test $# = 1 || exit 1
# Scripts may have additional arguments, but first is reserved for build directory
test $# -ge 1 || exit 1
test ! -e "$SPECN"
SPECN=$1
rm -rf "$SPECN"
mkdir "$SPECN"
mkdir -p "$SPECN"
cd "$SPECN"
export SEED="$(echo $SPECN | md5sum | cut -c1-8)"

View File

@ -4,7 +4,7 @@
set -ex
FUZDIR=$PWD
export FUZDIR=$PWD
source ${XRAY_GENHEADER}
# Some projects have hard coded top.v, others are generated