diff --git a/fuzzers/005-tilegrid/Makefile b/fuzzers/005-tilegrid/Makefile index df2b9ba0..55d2e2c8 100644 --- a/fuzzers/005-tilegrid/Makefile +++ b/fuzzers/005-tilegrid/Makefile @@ -1,6 +1,14 @@ FUZDIR=$(shell pwd) BUILD_DIR=$(FUZDIR)/build -TILEGRID_TDB_DEPENDENCIES=iob/build/segbits_tilegrid.tdb mmcm/build/segbits_tilegrid.tdb pll/build/segbits_tilegrid.tdb monitor/build/segbits_tilegrid.tdb +TILEGRID_TDB_DEPENDENCIES= +TILEGRID_TDB_DEPENDENCIES += iob/build/segbits_tilegrid.tdb +TILEGRID_TDB_DEPENDENCIES += mmcm/build/segbits_tilegrid.tdb +TILEGRID_TDB_DEPENDENCIES += pll/build/segbits_tilegrid.tdb +TILEGRID_TDB_DEPENDENCIES += monitor/build/segbits_tilegrid.tdb +TILEGRID_TDB_DEPENDENCIES += bram/build/segbits_tilegrid.tdb +TILEGRID_TDB_DEPENDENCIES += bram_block/build/segbits_tilegrid.tdb +TILEGRID_TDB_DEPENDENCIES += clb/build/segbits_tilegrid.tdb +TILEGRID_TDB_DEPENDENCIES += clb_int/build/segbits_tilegrid.tdb GENERATE_FULL_ARGS= ifeq (${XRAY_DATABASE}, zynq7) @@ -18,19 +26,15 @@ build/tiles/tiles.txt: build/basicdb/tilegrid.json: generate.py build/tiles/tiles.txt mkdir -p build/basicdb - cd build && python3 ${FUZDIR}/generate.py --tiles $(FUZDIR)/build/tiles/tiles.txt --out ${BUILD_DIR}/basicdb/tilegrid.json + cd build && python3 ${FUZDIR}/generate.py \ + --tiles $(FUZDIR)/build/tiles/tiles.txt \ + --out ${BUILD_DIR}/basicdb/tilegrid.json -build/clb/deltas: - bash generate.sh build/clb clb +clb/build/segbits_tilegrid.tdb: build/basicdb/tilegrid.json + cd clb && $(MAKE) -build/bram/deltas: - bash generate.sh build/bram bram - -build/iob/deltas: - bash generate.sh build/iob iob - -build/tilegrid_tdb.json: add_tdb.py $(TILEGRID_TDB_DEPENDENCIES) - python3 add_tdb.py --fn-in build/basicdb/tilegrid.json --fn-out build/tilegrid_tdb.json +clb_int/build/segbits_tilegrid.tdb: build/basicdb/tilegrid.json + cd clb_int && $(MAKE) iob/build/segbits_tilegrid.tdb: build/basicdb/tilegrid.json cd iob && $(MAKE) @@ -47,10 +51,21 @@ ps7_int/build/segbits_tilegrid.tdb: build/basicdb/tilegrid.json monitor/build/segbits_tilegrid.tdb: build/basicdb/tilegrid.json cd monitor && $(MAKE) -build/tilegrid.json: generate_full.py build/tilegrid_tdb.json build/clb/deltas build/bram/deltas +bram/build/segbits_tilegrid.tdb: build/basicdb/tilegrid.json + cd bram && $(MAKE) + +bram_block/build/segbits_tilegrid.tdb: build/basicdb/tilegrid.json + cd bram_block && $(MAKE) + +build/tilegrid_tdb.json: add_tdb.py $(TILEGRID_TDB_DEPENDENCIES) + python3 add_tdb.py \ + --fn-in build/basicdb/tilegrid.json \ + --fn-out build/tilegrid_tdb.json + +build/tilegrid.json: generate_full.py build/tilegrid_tdb.json cd build && python3 ${FUZDIR}/generate_full.py \ --json-in tilegrid_tdb.json --json-out ${BUILD_DIR}/tilegrid.json \ - --tiles $(FUZDIR)/build/tiles/tiles.txt clb/design_*.delta bram/design_*.delta ${GENERATE_FULL_ARGS} + --tiles $(FUZDIR)/build/tiles/tiles.txt ${GENERATE_FULL_ARGS} run: $(MAKE) clean $(MAKE) database @@ -59,10 +74,15 @@ run: clean: rm -rf build run.ok + cd clb && $(MAKE) clean + cd clb_int && $(MAKE) clean cd iob && $(MAKE) clean cd mmcm && $(MAKE) clean cd pll && $(MAKE) clean cd ps7_int && $(MAKE) clean + cd bram && $(MAKE) clean + cd bram_block && $(MAKE) clean + cd monitor && $(MAKE) clean .PHONY: database pushdb clean run diff --git a/fuzzers/005-tilegrid/add_tdb.py b/fuzzers/005-tilegrid/add_tdb.py index 7d1dee99..fcb18f0e 100644 --- a/fuzzers/005-tilegrid/add_tdb.py +++ b/fuzzers/005-tilegrid/add_tdb.py @@ -51,6 +51,8 @@ def run(fn_in, fn_out, verbose=False): # FIXME: generate frames from part file (or equivilent) # See https://github.com/SymbiFlow/prjxray/issues/327 # FIXME: generate words from pitch + int_frames = 28 + int_words = 2 tdb_fns = [ ("iob/build/segbits_tilegrid.tdb", 42, 4), # FIXME: height @@ -58,6 +60,10 @@ def run(fn_in, fn_out, verbose=False): # FIXME: height ("pll/build/segbits_tilegrid.tdb", 30, 101), ("monitor/build/segbits_tilegrid.tdb", 30, 101), + ("bram/build/segbits_tilegrid.tdb", 28, 10), + ("bram_block/build/segbits_tilegrid.tdb", 128, 10), + ("clb/build/segbits_tilegrid.tdb", 36, 2), + ("clb_int/build/segbits_tilegrid.tdb", int_frames, int_words), ] for (tdb_fn, frames, words) in tdb_fns: diff --git a/fuzzers/005-tilegrid/bram/Makefile b/fuzzers/005-tilegrid/bram/Makefile new file mode 100644 index 00000000..b4962953 --- /dev/null +++ b/fuzzers/005-tilegrid/bram/Makefile @@ -0,0 +1,4 @@ +N ?= 30 +GENERATE_ARGS?="--oneval 1 --design params.csv --dword 2 --dframe 1B" +include ../fuzzaddr/common.mk + diff --git a/fuzzers/005-tilegrid/bram/generate.tcl b/fuzzers/005-tilegrid/bram/generate.tcl new file mode 100644 index 00000000..5e72d333 --- /dev/null +++ b/fuzzers/005-tilegrid/bram/generate.tcl @@ -0,0 +1,26 @@ +source "$::env(XRAY_DIR)/utils/utils.tcl" + +proc run {} { + create_project -force -part $::env(XRAY_PART) design design + read_verilog top.v + synth_design -top top + + set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_00) IOSTANDARD LVCMOS33" [get_ports clk] + set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_01) IOSTANDARD LVCMOS33" [get_ports stb] + set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_02) IOSTANDARD LVCMOS33" [get_ports di] + set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_03) IOSTANDARD LVCMOS33" [get_ports do] + + set_property CFGBVS VCCO [current_design] + set_property CONFIG_VOLTAGE 3.3 [current_design] + set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design] + + set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk_IBUF] + + place_design + route_design + + write_checkpoint -force design.dcp + write_bitstream -force design.bit +} + +run diff --git a/fuzzers/005-tilegrid/bram/top.py b/fuzzers/005-tilegrid/bram/top.py new file mode 100644 index 00000000..424005aa --- /dev/null +++ b/fuzzers/005-tilegrid/bram/top.py @@ -0,0 +1,94 @@ +import os +import random +random.seed(int(os.getenv("SEED"), 16)) +from prjxray import util +from prjxray.db import Database + + +def gen_sites(): + db = Database(util.get_db_root()) + grid = db.grid() + for tile_name in grid.tiles(): + loc = grid.loc_of_tilename(tile_name) + gridinfo = grid.gridinfo_at_loc(loc) + + for site_name, site_type in gridinfo.sites.items(): + if site_type in ['FIFO18E1']: + yield tile_name, site_name + + +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(input clk, stb, di, output do); + localparam integer DIN_N = 8; + localparam integer DOUT_N = 8; + + reg [DIN_N-1:0] din; + wire [DOUT_N-1:0] dout; + + reg [DIN_N-1:0] din_shr; + reg [DOUT_N-1:0] dout_shr; + + always @(posedge clk) begin + din_shr <= {din_shr, di}; + dout_shr <= {dout_shr, din_shr[DIN_N-1]}; + if (stb) begin + din <= din_shr; + dout_shr <= dout; + end + end + + assign do = dout_shr[DOUT_N-1]; + ''') + + params = {} + + sites = list(gen_sites()) + for (tile_name, site_name), isone in zip(sites, + util.gen_fuzz_states(len(sites))): + params[tile_name] = (site_name, isone) + + print( + ''' + (* KEEP, DONT_TOUCH, LOC = "%s" *) + RAMB18E1 #( + .DOA_REG(%u) + ) bram_%s ( + .CLKARDCLK(), + .CLKBWRCLK(), + .ENARDEN(), + .ENBWREN(), + .REGCEAREGCE(), + .REGCEB(), + .RSTRAMARSTRAM(), + .RSTRAMB(), + .RSTREGARSTREG(), + .RSTREGB(), + .ADDRARDADDR(), + .ADDRBWRADDR(), + .DIADI(), + .DIBDI(), + .DIPADIP(), + .DIPBDIP(), + .WEA(), + .WEBWE(), + .DOADO(), + .DOBDO(), + .DOPADOP(), + .DOPBDOP()); +''' % (site_name, isone, site_name)) + + print("endmodule") + write_params(params) + + +if __name__ == '__main__': + run() diff --git a/fuzzers/005-tilegrid/bram_block/Makefile b/fuzzers/005-tilegrid/bram_block/Makefile new file mode 100644 index 00000000..9cd23102 --- /dev/null +++ b/fuzzers/005-tilegrid/bram_block/Makefile @@ -0,0 +1,4 @@ +N ?= 30 +GENERATE_ARGS?="--oneval 1 --design params.csv --dword 0 --dframe 0" +include ../fuzzaddr/common.mk + diff --git a/fuzzers/005-tilegrid/bram_block/generate.tcl b/fuzzers/005-tilegrid/bram_block/generate.tcl new file mode 100644 index 00000000..5e72d333 --- /dev/null +++ b/fuzzers/005-tilegrid/bram_block/generate.tcl @@ -0,0 +1,26 @@ +source "$::env(XRAY_DIR)/utils/utils.tcl" + +proc run {} { + create_project -force -part $::env(XRAY_PART) design design + read_verilog top.v + synth_design -top top + + set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_00) IOSTANDARD LVCMOS33" [get_ports clk] + set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_01) IOSTANDARD LVCMOS33" [get_ports stb] + set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_02) IOSTANDARD LVCMOS33" [get_ports di] + set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_03) IOSTANDARD LVCMOS33" [get_ports do] + + set_property CFGBVS VCCO [current_design] + set_property CONFIG_VOLTAGE 3.3 [current_design] + set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design] + + set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk_IBUF] + + place_design + route_design + + write_checkpoint -force design.dcp + write_bitstream -force design.bit +} + +run diff --git a/fuzzers/005-tilegrid/bram_block/top.py b/fuzzers/005-tilegrid/bram_block/top.py new file mode 100644 index 00000000..0ea02f3b --- /dev/null +++ b/fuzzers/005-tilegrid/bram_block/top.py @@ -0,0 +1,94 @@ +import os +import random +random.seed(int(os.getenv("SEED"), 16)) +from prjxray import util +from prjxray.db import Database + + +def gen_sites(): + db = Database(util.get_db_root()) + grid = db.grid() + for tile_name in grid.tiles(): + loc = grid.loc_of_tilename(tile_name) + gridinfo = grid.gridinfo_at_loc(loc) + + for site_name, site_type in gridinfo.sites.items(): + if site_type in ['RAMBFIFO36E1']: + yield tile_name, site_name + + +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(input clk, stb, di, output do); + localparam integer DIN_N = 8; + localparam integer DOUT_N = 8; + + reg [DIN_N-1:0] din; + wire [DOUT_N-1:0] dout; + + reg [DIN_N-1:0] din_shr; + reg [DOUT_N-1:0] dout_shr; + + always @(posedge clk) begin + din_shr <= {din_shr, di}; + dout_shr <= {dout_shr, din_shr[DIN_N-1]}; + if (stb) begin + din <= din_shr; + dout_shr <= dout; + end + end + + assign do = dout_shr[DOUT_N-1]; + ''') + + params = {} + + sites = list(gen_sites()) + for (tile_name, site_name), isone in zip(sites, + util.gen_fuzz_states(len(sites))): + params[tile_name] = (site_name, isone) + + print( + ''' + (* KEEP, DONT_TOUCH, LOC = "%s" *) + RAMB36E1 #( + .INIT_00(256'b%u) + ) bram_%s ( + .CLKARDCLK(), + .CLKBWRCLK(), + .ENARDEN(), + .ENBWREN(), + .REGCEAREGCE(), + .REGCEB(), + .RSTRAMARSTRAM(), + .RSTRAMB(), + .RSTREGARSTREG(), + .RSTREGB(), + .ADDRARDADDR(), + .ADDRBWRADDR(), + .DIADI(), + .DIBDI(), + .DIPADIP(), + .DIPBDIP(), + .WEA(), + .WEBWE(), + .DOADO(), + .DOBDO(), + .DOPADOP(), + .DOPBDOP()); +''' % (site_name, isone, site_name)) + + print("endmodule") + write_params(params) + + +if __name__ == '__main__': + run() diff --git a/fuzzers/005-tilegrid/clb/Makefile b/fuzzers/005-tilegrid/clb/Makefile new file mode 100644 index 00000000..9cd23102 --- /dev/null +++ b/fuzzers/005-tilegrid/clb/Makefile @@ -0,0 +1,4 @@ +N ?= 30 +GENERATE_ARGS?="--oneval 1 --design params.csv --dword 0 --dframe 0" +include ../fuzzaddr/common.mk + diff --git a/fuzzers/005-tilegrid/clb/generate.tcl b/fuzzers/005-tilegrid/clb/generate.tcl new file mode 100644 index 00000000..5e72d333 --- /dev/null +++ b/fuzzers/005-tilegrid/clb/generate.tcl @@ -0,0 +1,26 @@ +source "$::env(XRAY_DIR)/utils/utils.tcl" + +proc run {} { + create_project -force -part $::env(XRAY_PART) design design + read_verilog top.v + synth_design -top top + + set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_00) IOSTANDARD LVCMOS33" [get_ports clk] + set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_01) IOSTANDARD LVCMOS33" [get_ports stb] + set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_02) IOSTANDARD LVCMOS33" [get_ports di] + set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_03) IOSTANDARD LVCMOS33" [get_ports do] + + set_property CFGBVS VCCO [current_design] + set_property CONFIG_VOLTAGE 3.3 [current_design] + set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design] + + set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk_IBUF] + + place_design + route_design + + write_checkpoint -force design.dcp + write_bitstream -force design.bit +} + +run diff --git a/fuzzers/005-tilegrid/clb/top.py b/fuzzers/005-tilegrid/clb/top.py new file mode 100644 index 00000000..839c6555 --- /dev/null +++ b/fuzzers/005-tilegrid/clb/top.py @@ -0,0 +1,70 @@ +import os +import random +random.seed(int(os.getenv("SEED"), 16)) +from prjxray import util +from prjxray.db import Database + + +def gen_sites(): + db = Database(util.get_db_root()) + grid = db.grid() + for tile_name in grid.tiles(): + loc = grid.loc_of_tilename(tile_name) + gridinfo = grid.gridinfo_at_loc(loc) + if gridinfo.tile_type in ['CLBLL_L', 'CLBLL_R', 'CLBLM_L', 'CLBLM_R']: + site_name = sorted(gridinfo.sites.keys())[0] + yield tile_name, site_name + + +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(input clk, stb, di, output do); + localparam integer DIN_N = 8; + localparam integer DOUT_N = 8; + + reg [DIN_N-1:0] din; + wire [DOUT_N-1:0] dout; + + reg [DIN_N-1:0] din_shr; + reg [DOUT_N-1:0] dout_shr; + + always @(posedge clk) begin + din_shr <= {din_shr, di}; + dout_shr <= {dout_shr, din_shr[DIN_N-1]}; + if (stb) begin + din <= din_shr; + dout_shr <= dout; + end + end + + assign do = dout_shr[DOUT_N-1]; + ''') + + params = {} + + sites = list(gen_sites()) + for (tile_name, site_name), isone in zip(sites, + util.gen_fuzz_states(len(sites))): + params[tile_name] = (site_name, isone) + + print( + ''' + (* KEEP, DONT_TOUCH, LOC = "%s" *) + CARRY4 carry4_%s ( + .CYINIT(%u)); +''' % (site_name, site_name, isone)) + + print("endmodule") + write_params(params) + + +if __name__ == '__main__': + run() diff --git a/fuzzers/005-tilegrid/clb_int/Makefile b/fuzzers/005-tilegrid/clb_int/Makefile new file mode 100644 index 00000000..02f7dc56 --- /dev/null +++ b/fuzzers/005-tilegrid/clb_int/Makefile @@ -0,0 +1,4 @@ +N ?= 30 +GENERATE_ARGS?="--oneval 0 --design params.csv --dword 1 --dframe 15" +include ../fuzzaddr/common.mk + diff --git a/fuzzers/005-tilegrid/clb_int/generate.tcl b/fuzzers/005-tilegrid/clb_int/generate.tcl new file mode 100644 index 00000000..9e8cab8a --- /dev/null +++ b/fuzzers/005-tilegrid/clb_int/generate.tcl @@ -0,0 +1,19 @@ +source "$::env(XRAY_DIR)/utils/utils.tcl" + +proc run {} { + create_project -force -part $::env(XRAY_PART) design design + read_verilog top.v + synth_design -top top + + set_property CFGBVS VCCO [current_design] + set_property CONFIG_VOLTAGE 3.3 [current_design] + set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design] + + place_design + route_design + + write_checkpoint -force design.dcp + write_bitstream -force design.bit +} + +run diff --git a/fuzzers/005-tilegrid/clb_int/top.py b/fuzzers/005-tilegrid/clb_int/top.py new file mode 100644 index 00000000..0f13ea0a --- /dev/null +++ b/fuzzers/005-tilegrid/clb_int/top.py @@ -0,0 +1,80 @@ +import os +import random +random.seed(int(os.getenv("SEED"), 16)) +from prjxray import util +from prjxray.db import Database + + +def gen_sites(): + db = Database(util.get_db_root()) + grid = db.grid() + for tile_name in grid.tiles(): + loc = grid.loc_of_tilename(tile_name) + gridinfo = grid.gridinfo_at_loc(loc) + if gridinfo.tile_type in ['CLBLL_L', 'CLBLL_R', 'CLBLM_L', 'CLBLM_R']: + site_name = sorted(gridinfo.sites.keys())[0] + if gridinfo.tile_type[-1] == 'L': + int_tile_loc = (loc.grid_x + 1, loc.grid_y) + else: + int_tile_loc = (loc.grid_x - 1, loc.grid_y) + + int_tile_name = grid.tilename_at_loc(int_tile_loc) + + if not int_tile_name.startswith('INT_'): + continue + + yield int_tile_name, site_name + + +def write_params(params): + pinstr = 'tile,val\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 = sorted(list(gen_sites())) + for (tile_name, site_name), isone in zip(sites, + util.gen_fuzz_states(len(sites))): + params[tile_name] = (site_name, isone) + + print( + ''' + wire lut_to_f7_{0}, f7_to_f8_{0}; + (* KEEP, DONT_TOUCH, LOC = "{0}" *) + LUT6_L #( + .INIT(0) + ) lut_rom_{0} ( + .I0(1), + .I1({1}), + .I2(0), + .I3(1), + .I4(1), + .I5(1), + .LO(lut_to_f7_{0}) + ); + (* KEEP, DONT_TOUCH, LOC = "{0}" *) + MUXF7_L f7_{0} ( + .I0(lut_to_f7_{0}), + .LO(f7_to_f8_{0}) + ); + (* KEEP, DONT_TOUCH, LOC = "{0}" *) + MUXF8 f8_{0} ( + .I0(f7_to_f8_{0}) + ); +''' .format(site_name, isone)) + + print("endmodule") + write_params(params) + + +if __name__ == '__main__': + run() diff --git a/fuzzers/005-tilegrid/generate.py b/fuzzers/005-tilegrid/generate.py index 6924b69b..86704caa 100644 --- a/fuzzers/005-tilegrid/generate.py +++ b/fuzzers/005-tilegrid/generate.py @@ -1,7 +1,5 @@ #!/usr/bin/env python3 -import os, sys, json, re - from utils import xjson @@ -64,7 +62,6 @@ def run(tiles_fn, json_fn, verbose=False): def main(): import argparse - import glob parser = argparse.ArgumentParser( description='Generate tilegrid.json from bitstream deltas') diff --git a/fuzzers/005-tilegrid/generate_bram.tcl b/fuzzers/005-tilegrid/generate_bram.tcl deleted file mode 100644 index 3e8ab45e..00000000 --- a/fuzzers/005-tilegrid/generate_bram.tcl +++ /dev/null @@ -1,55 +0,0 @@ -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 bram_columns [group_dut_cols $bram_bels 10] - # Output site, not bel, to avoid reference issues after PnR - return [loc_dut_col_sites $bram_columns {roi/brams[} {].bram}] -} - -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 deleted file mode 100644 index fea24a6a..00000000 --- a/fuzzers/005-tilegrid/generate_clb.tcl +++ /dev/null @@ -1,61 +0,0 @@ -source "$::env(FUZDIR)/util.tcl" - -proc group_lut_cols { lut_bels } { - # LOC one LUT (a "selected_lut") into each CLB segment configuration column (ie 50 per CMT column) - set lut_columns "" - foreach lut $lut_bels { - 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 => 0, 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 " - } - return $lut_columns -} - -proc loc_luts {} { - set lut_bels [get_bels -of_objects [get_sites -of_objects [get_pblocks roi]] -filter {TYPE =~ LUT*} */A6LUT] - set lut_columns [group_lut_cols $lut_bels] - return [loc_dut_col_bels $lut_columns {roi/luts[} {].lut}] -} - -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 index 0a37f3e0..74795aef 100644 --- a/fuzzers/005-tilegrid/generate_full.py +++ b/fuzzers/005-tilegrid/generate_full.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 -import os, sys, json, re +from __future__ import print_function +import sys, json +from utils import xjson ''' Historically we grouped data into "segments" These were a region of the bitstream that encoded one or more tiles @@ -11,7 +13,6 @@ A post processing step verifies that two tiles don't reference the same bitstrea ''' from generate import load_tiles -from prjxray import util import util as localutil @@ -28,22 +29,6 @@ def nolr(tile_type): return tile_type -def load_baseaddrs(deltas_fns): - site_baseaddr = dict() - for arg in deltas_fns: - with open(arg) as f: - line = f.read().strip() - # clb/design_SLICE_X10Y100.delta - # site = arg[7:-6] - site = re.match(r".*/design_(.*).delta", arg).group(1) - # +bit_00400026_100_02 - _, frame_str, _, _ = line.split('_') - frame = int(frame_str, 16) - site_baseaddr[site] = frame & ~0x7f - - return site_baseaddr - - def load_tdb_baseaddr(database, int_tdb, verbose=False): tdb_tile_baseaddrs = dict() for line in open(int_tdb, 'r'): @@ -64,27 +49,6 @@ def load_tdb_baseaddr(database, int_tdb, verbose=False): return tdb_tile_baseaddrs -def make_tile_baseaddrs(tiles, site_baseaddr, verbose=False): - # Look up a base address by tile name - tile_baseaddrs = dict() - 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(): - if site_name not in site_baseaddr: - continue - framebaseaddr = site_baseaddr[site_name] - localutil.add_baseaddr( - tile_baseaddrs, tile["name"], framebaseaddr, verbose) - added += 1 - - assert added, "Failed to add any base addresses" - assert added == len(site_baseaddr) - return tile_baseaddrs - - def make_tiles_by_grid(tiles): # lookup tile names by (X, Y) tiles_by_grid = dict() @@ -94,34 +58,40 @@ def make_tiles_by_grid(tiles): return tiles_by_grid +def add_int_bits(database, tile, baseaddr, offset): + """ + Add INT bits for given tile. + """ + if database[tile]['type'] not in ["INT_L", "INT_R"]: + return -def add_segment( - database, segments, name, tiles, segtype, verbose, baseaddr=None): - assert name not in segments - segment = segments.setdefault(name, {}) - segment["tiles"] = tiles - segment["type"] = segtype - if baseaddr: - verbose and print('make_segment: %s baseaddr %s' % ( - name, - baseaddr, - )) - segment["baseaddr"] = baseaddr + localutil.add_tile_bits( + tile, database[tile], baseaddr, offset, + frames=28, words=2, height=2) - for tile_name in tiles: - database[tile_name]["segment"] = name - - -def make_segments(database, tiles_by_grid, tile_baseaddrs, verbose=False): +def add_adjacent_int_tiles(database, tiles_by_grid, verbose=False): ''' - Create segments data structure - Indicates how tiles are related to bitstream locations - Also modify database to annotate which segment the tiles belong to - segments key examples: - SEG_CLBLM_R_X13Y72 - SEG_BRAM3_L_X6Y85 + Attaches INT tiles adjacent to tiles. ''' - segments = dict() + + def add_int_tile(inttile, parent_tile): + if not database[parent_tile]['bits']: + return + + grid_x = database[inttile]["grid_x"] + grid_y = database[inttile]["grid_y"] + + framebase = int(database[parent_tile]['bits']['CLB_IO_CLK']['baseaddr'], 0) + parent_wordbase = database[parent_tile]['bits']['CLB_IO_CLK']['offset'] + + for dst_tile, wordbase in localutil.propagate_up_INT( + grid_x, grid_y, database, tiles_by_grid, parent_wordbase): + dst_x = dst_tile['grid_x'] + dst_y = dst_tile['grid_y'] + + add_int_bits( + database, tiles_by_grid[(dst_x, dst_y)], framebase, + wordbase) verbose and print('') for tile_name, tile_data in database.items(): @@ -129,111 +99,42 @@ def make_segments(database, tiles_by_grid, tile_baseaddrs, verbose=False): grid_x = tile_data["grid_x"] grid_y = tile_data["grid_y"] - def add_segment(tiles, segtype, name=None, baseaddr=None): - assert name not in segments - segment = segments.setdefault(name, {}) - segment["tiles"] = tiles - segment["type"] = segtype - if baseaddr: - verbose and print( - 'make_segment: %s baseaddr %s' % ( - name, - baseaddr, - )) - segment["baseaddr"] = baseaddr - - for tile_name in tiles: - database[tile_name]["segment"] = name - def process_clb(): if tile_type in ["CLBLL_L", "CLBLM_L"]: int_tile_name = tiles_by_grid[(grid_x + 1, grid_y)] else: int_tile_name = tiles_by_grid[(grid_x - 1, grid_y)] - add_segment( - name="SEG_" + tile_name, - tiles=[tile_name, int_tile_name], - segtype=tile_type.lower(), - baseaddr=tile_baseaddrs.get(tile_name, None)) - - def process_hclk(): - add_segment( - name="SEG_" + tile_name, - tiles=[tile_name], - segtype=tile_type.lower()) + add_int_tile(int_tile_name, tile_name) def process_iob(): - tiles = [tile_name] - # FIXME mcmaster: removing INT for now - # Geometry doesn't line up with CLB, unclear if they are included if tile_type.startswith('LIOB'): # Two INT_L's - # tiles.append(tiles_by_grid[(grid_x + 4, grid_y)]) - # tiles.append(tiles_by_grid[(grid_x + 4, grid_y - 1)]) - # One IO interface tile - tiles.append(tiles_by_grid[(grid_x + 1, grid_y)]) + #add_int_tile(tiles_by_grid[(grid_x + 4, grid_y)], tile_name) + #add_int_tile(tiles_by_grid[(grid_x + 4, grid_y - 1)], tile_name) + pass else: # Two INT_R's - # tiles.append(tiles_by_grid[(grid_x - 4, grid_y)]) - # tiles.append(tiles_by_grid[(grid_x - 4, grid_y - 1)]) - # One IO interface tile - tiles.append(tiles_by_grid[(grid_x - 1, grid_y)]) - - add_segment( - name="SEG_" + tile_name, - tiles=tiles, - segtype=tile_type.lower(), - baseaddr=tile_baseaddrs.get(tile_name, None)) + #add_int_tile(tiles_by_grid[(grid_x - 4, grid_y)], tile_name) + #add_int_tile(tiles_by_grid[(grid_x - 4, grid_y - 1)], tile_name) + pass def process_iob_sing(): - # FIXME mcmaster: removing INT for now - # Geometry doesn't line up with CLB, unclear if they are included - tiles = [tile_name] if tile_type.startswith('LIOB'): - tiles.append(tiles_by_grid[(grid_x + 1, grid_y)]) - # tiles.append(tiles_by_grid[(grid_x + 4, grid_y)]) + add_int_tile(tiles_by_grid[(grid_x + 4, grid_y)], tile_name) else: - tiles.append(tiles_by_grid[(grid_x - 1, grid_y)]) - # tiles.append(tiles_by_grid[(grid_x - 4, grid_y)]) - - add_segment( - name="SEG_" + tile_name, - tiles=tiles, - segtype=tile_type.lower(), - baseaddr=tile_baseaddrs.get(tile_name, None)) + add_int_tile(tiles_by_grid[(grid_x - 4, grid_y)], tile_name) def process_bram_dsp(): for k in range(5): if tile_type in ["BRAM_L", "DSP_L"]: - interface_tile_name = tiles_by_grid[( - grid_x + 1, grid_y - k)] int_tile_name = tiles_by_grid[(grid_x + 2, grid_y - k)] elif tile_type in ["BRAM_R", "DSP_R"]: - interface_tile_name = tiles_by_grid[( - grid_x - 1, grid_y - k)] int_tile_name = tiles_by_grid[(grid_x - 2, grid_y - k)] else: assert 0 - ''' - BRAM/DSP itself is at the base y address - There is one huge switchbox on the right for the 5 tiles - These fan into 5 BRAM_INT_INTERFACE tiles each which feed into their own CENTER_INTER (just like a CLB has) - ''' - if k == 0: - tiles = [tile_name, interface_tile_name, int_tile_name] - baseaddr = tile_baseaddrs.get(tile_name, None) - else: - tiles = [interface_tile_name, int_tile_name] - baseaddr = None - add_segment( - # BRAM_L_X6Y70 => SEG_BRAM4_L_X6Y70 - name="SEG_" + tile_name.replace("_", "%d_" % k, 1), - tiles=tiles, - # BRAM_L => bram4_l - segtype=tile_type.lower().replace("_", "%d_" % k, 1), - baseaddr=baseaddr) + add_int_tile(int_tile_name, tile_name) def process_default(): verbose and nolr(tile_type) not in ( @@ -241,80 +142,20 @@ def make_segments(database, tiles_by_grid, tile_baseaddrs, verbose=False): 'make_segment: drop %s' % (tile_type, )) pass - """ - FIXME: review IOB + { + "CLBLL": process_clb, + "CLBLM": process_clb, + "HCLK": lambda: None, + "BRAM": lambda: None, + "DSP": lambda: None, "RIOB33": process_iob, "LIOB33": process_iob, "RIOB33_SING": process_iob_sing, "LIOB33_SING": process_iob_sing, - """ - { - "CLBLL": process_clb, - "CLBLM": process_clb, - "HCLK": process_hclk, - "BRAM": process_bram_dsp, - "DSP": process_bram_dsp, }.get(nolr(tile_type), process_default)() - return segments - -def get_inttile(database, segment): - '''Return interconnect tile for given segment''' - return ( - tile for tile in segment["tiles"] - if database[tile]["type"] in ["INT_L", "INT_R"]) - - -def get_iobtile(database, segment): - '''Return IOB tile for given segment''' - return ( - tile for tile in segment["tiles"] - if database[tile]["type"] in ["LIOB33_SING", "LIOB33"]) - - -def get_bramtile(database, segment): - inttiles = [ - tile for tile in segment["tiles"] - if database[tile]["type"] in ["BRAM_L", "BRAM_R"] - ] - assert len(inttiles) == 1 - return inttiles[0] - - -def create_segment_for_int_lr( - database, segments, tile, tiles_by_grid, verbose): - """ Creates INT_[LR] segment for interconnect's without direct connectivity. """ - # Some INT_[LR] tiles have no adjacent connectivity, create a segment. - grid_x = database[tile]["grid_x"] - grid_y = database[tile]["grid_y"] - if database[tile]["type"] == "INT_L": - grid_x -= 1 - adjacent_tile = tiles_by_grid[(grid_x, grid_y)] - elif database[tile]["type"] == "INT_R": - grid_x += 1 - adjacent_tile = tiles_by_grid[(grid_x, grid_y)] - else: - assert False, database[tile]["type"] - if (database[adjacent_tile]['type'].startswith('INT_INTERFACE_') or - database[adjacent_tile]['type'].startswith('PCIE_INT_INTERFACE_') - or - database[adjacent_tile]['type'].startswith('GTP_INT_INTERFACE')): - # This INT_[LR] tile has no adjacent connectivity, - # create a segment. - add_segment( - database=database, - segments=segments, - name='SEG_' + tile, - tiles=[tile], - segtype=database[tile]["type"], - verbose=verbose, - ) - else: - assert False, database[adjacent_tile]['type'] - - -def seg_base_addr_lr_INT(database, segments, tiles_by_grid, verbose=False): +def seg_base_addr_lr_INT(database, tiles_by_grid, verbose=False): '''Populate segment base addresses: L/R along INT column''' ''' Create BRAM base addresses based on nearby CLBs @@ -322,63 +163,42 @@ def seg_base_addr_lr_INT(database, segments, tiles_by_grid, verbose=False): ''' verbose and print('') - for segment_name in sorted(segments.keys()): - segment = segments[segment_name] - baseaddrs = segment.get("baseaddr", None) - if not baseaddrs: + for tile in database: + if database[tile]["type"] not in ["INT_L", "INT_R"]: continue - for block_type, (framebase, wordbase) in sorted(baseaddrs.items()): - verbose and print( - 'lr_INT: %s: %s.0x%08X:%u' % - (segment_name, block_type, framebase, wordbase)) - if block_type != 'CLB_IO_CLK': - verbose and print(' Skip non CLB') - continue + if not database[tile]["bits"]: + continue - for inttile in get_inttile(database, segment): - grid_x = database[inttile]["grid_x"] - grid_y = database[inttile]["grid_y"] + grid_x = database[tile]["grid_x"] + grid_y = database[tile]["grid_y"] + framebase = int(database[tile]["bits"]["CLB_IO_CLK"]["baseaddr"], 0) + wordbase = database[tile]["bits"]["CLB_IO_CLK"]["offset"] - if database[inttile]["type"] == "INT_L": - grid_x += 1 - framebase = framebase + 0x80 - elif database[inttile]["type"] == "INT_R": - grid_x -= 1 - framebase = framebase - 0x80 - else: - assert 0 + if database[tile]["type"] == "INT_L": + grid_x += 1 + framebase = framebase + 0x80 + elif database[tile]["type"] == "INT_R": + grid_x -= 1 + framebase = framebase - 0x80 + else: + assert 0 - # ROI at edge? - if (grid_x, grid_y) not in tiles_by_grid: - verbose and print(' Skip edge') - continue + # ROI at edge? + if (grid_x, grid_y) not in tiles_by_grid: + verbose and print(' Skip edge') + continue - tile = tiles_by_grid[(grid_x, grid_y)] + other_tile = tiles_by_grid[(grid_x, grid_y)] - if database[inttile]["type"] == "INT_L": - assert database[tile]["type"] == "INT_R" - elif database[inttile]["type"] == "INT_R": - assert database[tile]["type"] == "INT_L" - else: - assert 0 + if database[tile]["type"] == "INT_L": + assert database[other_tile]["type"] == "INT_R" + elif database[tile]["type"] == "INT_R": + assert database[other_tile]["type"] == "INT_L" + else: + assert 0 - if "segment" not in database[tile]: - continue - - seg = database[tile]["segment"] - - seg_baseaddrs = segments[seg].setdefault("baseaddr", {}) - # At least one duplicate when we re-compute the entry for the base address - # should give the same address - if block_type in seg_baseaddrs: - assert seg_baseaddrs[block_type] == [ - framebase, wordbase - ], (seg_baseaddrs[block_type], [framebase, wordbase]) - verbose and print(' Existing OK') - else: - seg_baseaddrs[block_type] = [framebase, wordbase] - verbose and print(' Add new') + add_int_bits(database, other_tile, framebase, wordbase) def seg_base_addr_up_INT(database, segments, tiles_by_grid, verbose=False): @@ -558,43 +378,29 @@ def db_int_fixup(database, tiles, tiles_by_grid): tile_name, tile, baseaddr, offset, frames, words, height) -def run( - json_in_fn, json_out_fn, tiles_fn, deltas_fns, int_tdb=None, - verbose=False): +def run(json_in_fn, json_out_fn, tiles_fn, int_tdb=None, verbose=False): # Load input files tiles = load_tiles(tiles_fn) - site_baseaddr = load_baseaddrs(deltas_fns) + #site_baseaddr = {} database = json.load(open(json_in_fn, "r")) - tile_baseaddrs = make_tile_baseaddrs(tiles, site_baseaddr, verbose=verbose) tiles_by_grid = make_tiles_by_grid(tiles) - segments = make_segments( - database, tiles_by_grid, tile_baseaddrs, verbose=verbose) - - # Reference adjacent CLBs to locate adjacent tiles by known offsets - seg_base_addr_lr_INT(database, segments, tiles_by_grid, verbose=verbose) - seg_base_addr_up_INT(database, segments, tiles_by_grid, verbose=verbose) - - db_add_bits(database, segments) - db_add_segments(database, segments) - if int_tdb is not None: tile_baseaddrs_fixup = load_tdb_baseaddr(database, int_tdb) db_int_fixup(database, tile_baseaddrs_fixup, tiles_by_grid) + #add_adjacent_int_tiles(database, tiles_by_grid, verbose=verbose) + + # Reference adjacent CLBs to locate adjacent tiles by known offsets + #seg_base_addr_lr_INT(database, tiles_by_grid, verbose=verbose) + # Save - json.dump( - database, - open(json_out_fn, "w"), - sort_keys=True, - indent=4, - separators=(",", ": ")) + xjson.pprint(open(json_out_fn, "w"), database) def main(): import argparse - import glob parser = argparse.ArgumentParser( description="Generate tilegrid.json from bitstream deltas") @@ -608,23 +414,16 @@ def main(): "--json-out", default="tilegrid.json", help="Output JSON") parser.add_argument( '--tiles', default='tiles.txt', help='Input tiles.txt tcl output') - parser.add_argument( - "deltas", nargs="*", help=".bit diffs to create base addresses from") parser.add_argument( "--int-tdb", default=None, help=".tdb diffs to fill the interconnects without any adjacent CLB") args = parser.parse_args() - deltas = args.deltas - if not args.deltas: - deltas = glob.glob("*.delta") - run( args.json_in, args.json_out, args.tiles, - deltas, args.int_tdb, verbose=args.verbose) diff --git a/fuzzers/005-tilegrid/generate_iob.tcl b/fuzzers/005-tilegrid/generate_iob.tcl deleted file mode 100644 index a8d72f95..00000000 --- a/fuzzers/005-tilegrid/generate_iob.tcl +++ /dev/null @@ -1,42 +0,0 @@ -source "$::env(FUZDIR)/util.tcl" - -proc loc_iob {} { - # Some pads are output only (ex: OPAD_X0Y0/PAD) => filt IOB_* - # XXX: GTX bank missing, deal with that later - set roi_sites [get_sites -of_objects [get_pblocks roi]] - set duts [get_bels -of_objects $roi_sites -filter {TYPE =~ PAD && NAME =~ IOB_*}] - - # Sort them into CMT columns - set dut_columns [group_dut_cols $duts 50] - # Assign one from each - return [loc_dut_col_sites $dut_columns {di_bufs[} {].ibuf} ] -} - -proc write_iob { sel_iob_sites } { - foreach site $sel_iob_sites { - puts "" - set port [get_ports -of_objects $site] - set tile [get_tiles -of_objects $site] - set pin [get_property PACKAGE_PIN $port] - puts "IOB $port $site $tile $pin" - set orig_init [get_property PULLTYPE $port] - set_property PULLTYPE PULLUP $port - write_bitstream -force design_$site.bit - set_property PULLTYPE "$orig_init" $port - } -} - -proc run {} { - make_project - set sel_iob_sites [loc_iob] - puts "Selected IOBs: [llength $sel_iob_sites]" - - place_design - route_design - write_checkpoint -force design.dcp - write_bitstream -force design.bit - - write_iob $sel_iob_sites -} - -run diff --git a/fuzzers/005-tilegrid/util.py b/fuzzers/005-tilegrid/util.py index cdf03dac..082c4083 100644 --- a/fuzzers/005-tilegrid/util.py +++ b/fuzzers/005-tilegrid/util.py @@ -11,7 +11,9 @@ def check_frames(addrlist): for addrstr in addrlist: frame = parse_addr(addrstr, get_base_frame=True) frames.add(frame) - assert len(frames) == 1, "More than one base address" + assert len(frames) == 1, ( + "More than one base address", map(hex,frames) + ) def parse_addr(line, only_frame=False, get_base_frame=False): @@ -120,8 +122,8 @@ def add_tile_bits( assert offset <= 100, (tile_name, offset) # Few rare cases at X=0 for double width tiles split in half => small negative offset - assert offset >= 0 or "IOB" in tile_name, (tile_name, offset) - assert 1 <= words <= 101 + assert offset >= 0 or "IOB" in tile_name, (tile_name, hex(baseaddr), offset) + assert 1 <= words <= 101, words assert offset + words <= 101, ( tile_name, offset + words, offset, words, block_type) @@ -131,7 +133,7 @@ def add_tile_bits( verbose and print( "%s: existing defintion for %s" % (tile_name, block_type)) assert block["baseaddr"] == baseaddr_str - assert block["frames"] == frames + assert block["frames"] == frames, (block, frames) assert block["offset"] == offset, "%s; orig offset %s, new %s" % ( tile_name, block["offset"], offset) assert block["words"] == words