diff --git a/fuzzers/005-tilegrid/Makefile b/fuzzers/005-tilegrid/Makefile index c2801373..92adb9bd 100644 --- a/fuzzers/005-tilegrid/Makefile +++ b/fuzzers/005-tilegrid/Makefile @@ -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 diff --git a/fuzzers/005-tilegrid/generate.py b/fuzzers/005-tilegrid/generate.py index bfddd12e..56cd707a 100644 --- a/fuzzers/005-tilegrid/generate.py +++ b/fuzzers/005-tilegrid/generate.py @@ -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 diff --git a/fuzzers/005-tilegrid/generate.sh b/fuzzers/005-tilegrid/generate.sh index a1674bc3..8720ab99 100644 --- a/fuzzers/005-tilegrid/generate.sh +++ b/fuzzers/005-tilegrid/generate.sh @@ -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 diff --git a/fuzzers/005-tilegrid/generate.tcl b/fuzzers/005-tilegrid/generate.tcl deleted file mode 100644 index 7677b14a..00000000 --- a/fuzzers/005-tilegrid/generate.tcl +++ /dev/null @@ -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 - diff --git a/fuzzers/005-tilegrid/generate_bram.tcl b/fuzzers/005-tilegrid/generate_bram.tcl new file mode 100644 index 00000000..a03f5f33 --- /dev/null +++ b/fuzzers/005-tilegrid/generate_bram.tcl @@ -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 + diff --git a/fuzzers/005-tilegrid/generate_clb.tcl b/fuzzers/005-tilegrid/generate_clb.tcl new file mode 100644 index 00000000..5870f381 --- /dev/null +++ b/fuzzers/005-tilegrid/generate_clb.tcl @@ -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 + diff --git a/fuzzers/005-tilegrid/generate_full.py b/fuzzers/005-tilegrid/generate_full.py new file mode 100644 index 00000000..63db7dae --- /dev/null +++ b/fuzzers/005-tilegrid/generate_full.py @@ -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() diff --git a/fuzzers/005-tilegrid/generate_tiles.tcl b/fuzzers/005-tilegrid/generate_tiles.tcl new file mode 100644 index 00000000..eb87c360 --- /dev/null +++ b/fuzzers/005-tilegrid/generate_tiles.tcl @@ -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 + diff --git a/fuzzers/005-tilegrid/util.tcl b/fuzzers/005-tilegrid/util.tcl new file mode 100644 index 00000000..ce56cf7b --- /dev/null +++ b/fuzzers/005-tilegrid/util.tcl @@ -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] +} + + diff --git a/minitests/iob/Makefile b/minitests/iob/Makefile index 6560eec1..33a80839 100644 --- a/minitests/iob/Makefile +++ b/minitests/iob/Makefile @@ -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 diff --git a/minitests/iob/template.tcl b/minitests/iob/template.tcl index 2fa1321e..4b1ada95 100644 --- a/minitests/iob/template.tcl +++ b/minitests/iob/template.tcl @@ -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 diff --git a/utils/genheader.sh b/utils/genheader.sh index edf0cbb5..39094a44 100644 --- a/utils/genheader.sh +++ b/utils/genheader.sh @@ -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)" diff --git a/utils/top_generate.sh b/utils/top_generate.sh index 41056b6b..3a52965c 100644 --- a/utils/top_generate.sh +++ b/utils/top_generate.sh @@ -4,7 +4,7 @@ set -ex -FUZDIR=$PWD +export FUZDIR=$PWD source ${XRAY_GENHEADER} # Some projects have hard coded top.v, others are generated