Refactor all existing tiles to fuzzer approach.

Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com>
This commit is contained in:
Keith Rothman 2019-01-25 10:37:23 -08:00
parent 8cbac3ee7a
commit 6a7acd4b23
20 changed files with 583 additions and 466 deletions

View File

@ -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

View File

@ -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:

View File

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

View File

@ -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

View File

@ -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()

View File

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

View File

@ -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

View File

@ -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()

View File

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

View File

@ -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

View File

@ -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()

View File

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

View File

@ -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

View File

@ -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()

View File

@ -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')

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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