Merge pull request #205 from litghost/larger_roi

Expand ROI to all of CMT X0Y2.
This commit is contained in:
litghost 2018-10-30 17:16:43 -05:00 committed by GitHub
commit 26b95fb46e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 279 additions and 78 deletions

View File

@ -2,10 +2,13 @@ export XRAY_DATABASE="artix7"
export XRAY_PART="xc7a50tfgg484-1"
export XRAY_ROI_FRAMES="0x00000000:0xffffffff"
# Leave some CLBs to the left to allow easy ROI entering
export XRAY_ROI="SLICE_X8Y100:SLICE_X27Y149 RAMB18_X0Y40:RAMB18_X0Y59 RAMB36_X0Y20:RAMB36_X0Y29 DSP48_X0Y40:DSP48_X0Y59"
export XRAY_ROI_GRID_X1="18"
export XRAY_ROI_GRID_X2="47"
# All CLB's in part, all BRAM's in part, all DSP's in part.
export XRAY_ROI="SLICE_X0Y0:SLICE_X65Y99 SLICE_X0Y100:SLICE_X57Y149 RAMB18_X0Y0:RAMB18_X1Y59 RAMB36_X0Y0:RAMB36_X1Y29 RAMB18_X2Y0:RAMB18_X2Y39 RAMB36_X2Y0:RAMB36_X2Y19 DSP48_X0Y0:DSP48_X1Y59"
# ROI is all of CMT X0Y2.
export XRAY_ROI_GRID_X1="10"
export XRAY_ROI_GRID_X2="58"
# Y = 0 and Y 52 are VBRK rows, include them
export XRAY_ROI_GRID_Y1="0"
export XRAY_ROI_GRID_Y2="52"

View File

@ -3,7 +3,7 @@ database: build/tilegrid.json
pushdb:
cp build/tilegrid.json ${XRAY_DATABASE_DIR}/$(XRAY_DATABASE)/tilegrid.json
build/tilegrid.json: build/deltas
build/tilegrid.json: build/deltas generate.py
cd build && python3 ../generate.py design_*.delta > tilegrid.json
build/deltas:

View File

@ -145,6 +145,23 @@ def make_tiles_by_grid(tiles):
return tiles_by_grid
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
for tile_name in tiles:
database[tile_name]["segment"] = name
def make_segments(database, tiles_by_grid, tile_baseaddrs, verbose=False):
'''
Create segments data structure
@ -163,22 +180,6 @@ 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(name, tiles, segtype, 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)]
@ -186,16 +187,24 @@ def make_segments(database, tiles_by_grid, tile_baseaddrs, verbose=False):
int_tile_name = tiles_by_grid[(grid_x - 1, grid_y)]
add_segment(
database=database,
segments=segments,
name="SEG_" + tile_name,
tiles=[tile_name, int_tile_name],
segtype=tile_type.lower(),
baseaddr=tile_baseaddrs.get(tile_name, None))
baseaddr=tile_baseaddrs.get(tile_name, None),
verbose=verbose,
)
def process_hclk():
add_segment(
database=database,
segments=segments,
name="SEG_" + tile_name,
tiles=[tile_name],
segtype=tile_type.lower())
segtype=tile_type.lower(),
verbose=verbose,
)
def process_bram_dsp():
for k in range(5):
@ -222,12 +231,16 @@ def make_segments(database, tiles_by_grid, tile_baseaddrs, verbose=False):
baseaddr = None
add_segment(
database=database,
segments=segments,
# 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)
baseaddr=baseaddr,
verbose=verbose,
)
def process_default():
#verbose and nolr(tile_type) not in ('VBRK', 'INT', 'NULL') and print('make_segment: drop %s' % (tile_type,))
@ -263,6 +276,39 @@ def get_bramtile(database, segment):
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):
'''Populate segment base addresses: L/R along INT column'''
'''
@ -312,7 +358,11 @@ def seg_base_addr_lr_INT(database, segments, tiles_by_grid, verbose=False):
else:
assert 0
assert "segment" in database[tile]
if 'segment' not in database[tile]:
if database[tile]['type'] in ['T_TERM_INT']:
continue
create_segment_for_int_lr(
database, segments, tile, tiles_by_grid, verbose)
seg = database[tile]["segment"]
@ -366,6 +416,9 @@ def seg_base_addr_up_INT(database, segments, tiles_by_grid, verbose=False):
for i in range(50):
grid_y -= 1
if grid_y < 0:
break
dst_tile = database[tiles_by_grid[(grid_x, grid_y)]]
if wordbase == 50:
@ -373,6 +426,14 @@ def seg_base_addr_up_INT(database, segments, tiles_by_grid, verbose=False):
else:
wordbase += 2
if 'segment' not in dst_tile:
if dst_tile['type'] in ['T_TERM_INT']:
continue
create_segment_for_int_lr(
database, segments, tiles_by_grid[(grid_x,
grid_y)],
tiles_by_grid, verbose)
#verbose and print(' dst_tile', dst_tile)
dst_segment_name = dst_tile["segment"]
#verbose and print('up_INT: %s => %s' % (src_segment_name, dst_segment_name))
@ -417,6 +478,9 @@ def seg_base_addr_up_INT(database, segments, tiles_by_grid, verbose=False):
grid_y -= 1
wordbase += 1
if (grid_x, grid_y) not in tiles_by_grid:
continue
dst_tile = database[tiles_by_grid[(grid_x, grid_y)]]
assert nolr(dst_tile['type']) == 'BRAM', dst_tile

View File

@ -11,7 +11,10 @@ proc make_project {} {
create_pblock roi
add_cells_to_pblock [get_pblocks roi] [get_cells roi]
resize_pblock [get_pblocks roi] -add "$::env(XRAY_ROI)"
foreach roi "$::env(XRAY_ROI)" {
puts $roi
resize_pblock [get_pblocks roi] -add "$roi"
}
set_property CFGBVS VCCO [current_design]
set_property CONFIG_VOLTAGE 3.3 [current_design]
@ -27,20 +30,39 @@ proc loc_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 {
set tile [get_tile -of_objects $lut]
set grid_x [get_property GRID_POINT_X $tile]
set grid_y [get_property GRID_POINT_Y $tile]
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
if [regexp "X.*[02468]Y.*[05]0/" $lut] {
set cell [get_cells roi/luts[$lut_index].lut]
set_property LOC [get_sites -of_objects $lut] $cell
set lut_index [expr $lut_index + 1]
lappend selected_luts $lut
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
}
}
puts $selected_lut
set cell [get_cells roi/luts[$lut_index].lut]
set_property LOC [get_sites -of_objects [get_bels $selected_lut]] $cell
set lut_index [expr $lut_index + 1]
lappend selected_luts [get_bels $selected_lut]
}
return $selected_luts
}
@ -53,20 +75,38 @@ proc loc_brams {} {
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 $brams {
set tile [get_tile -of_objects $bram]
set grid_x [get_property GRID_POINT_X $tile]
set grid_y [get_property GRID_POINT_Y $tile]
regexp "RAMB36_X([0-9]+)Y([0-9]+)/" $bram match slice_x slice_y
# 10 per column => 10, 20, ,etc
# ex: RAMB36_X0Y10/RAMBFIFO36E1
if [regexp "Y.*0/" $bram] {
set cell [get_cells roi/brams[$bram_index].bram]
set_property LOC [get_sites -of_objects $bram] $cell
set bram_index [expr $bram_index + 1]
lappend selected_brams $bram
}
set y_column [expr ($slice_y / 10) * 10]
dict append lut_columns "X${slice_x}Y${y_column}" "$bram "
}
# Pick the smallest Y in each column.
dict for {column brams_in_column} $lut_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 $bram
}
}
puts ""
puts $selected_bram
set cell [get_cells roi/brams[$bram_index].bram]
set_property LOC [get_sites -of_objects [get_bels $selected_bram]] $cell
puts $selected_bram
set bram_index [expr $bram_index + 1]
lappend selected_brams [get_bels $selected_bram]
}
return $selected_brams
}
@ -132,7 +172,7 @@ proc run {} {
set selected_luts [loc_luts]
puts "Selected LUTs: [llength $selected_luts]"
set selected_brams [loc_brams]
puts "Selected LUTs: [llength $selected_brams]"
puts "Selected BRAMs: [llength $selected_brams]"
place_design
route_design

View File

@ -1,16 +1,24 @@
BUILD_DIR=build
HARNESS_DIR ?= harness
export BUILD_DIR
XRAY_PINCFG ?= BASYS3-SWBUT
export XRAY_PINCFG
HARNESS_FILES=$(BUILD_DIR)/design.bit $(BUILD_DIR)/design.txt $(BUILD_DIR)/design.json $(BUILD_DIR)/design.dcp
# official demo configuration
all:
all: $(HARNESS_FILES)
$(HARNESS_FILES): runme.sh runme.tcl
./runme.sh
copy: $(HARNESS_FILES)
mkdir -p $(HARNESS_DIR)
cp $(HARNESS_FILES) $(HARNESS_DIR)
clean:
rm -rf specimen_[0-9][0-9][0-9]/ seg_clblx.segbits vivado*.log vivado_*.str vivado*.jou design *.bits *.dcp *.bit design.txt .Xil
rm -rf $(BUILD_DIR) *~
rm -rf $(BUILD_DIR) $(HARNESS_DIR)
.PHONY: all clean
.PHONY: all clean copy

View File

@ -3,5 +3,5 @@ set -ex
BIT_IN=$1
BITS=$(tempfile --suffix .bits)
${XRAY_BITREAD} -F $XRAY_ROI_FRAMES -o ${BITS} -z -y ${BIT_IN}
${XRAY_BITREAD} -F $XRAY_ROI_FRAMES -o ${BITS} -z -y ${BIT_IN} > /dev/null
${XRAY_BITS2FASM} ${BITS}

View File

@ -2,6 +2,19 @@ import json
import csv
import argparse
import sys
from prjxray.db import Database
from prjxray.roi import Roi
from prjxray.util import get_db_root
def set_port_wires(ports, name, pin, wires_outside_roi):
for port in ports:
if name == port['name']:
port['wires_outside_roi'] = wires_outside_roi
assert port['pin'] == pin
return
assert False, name
def main():
@ -10,6 +23,7 @@ def main():
"Creates design.json from output of ROI generation tcl script.")
parser.add_argument('--design_txt', required=True)
parser.add_argument('--design_info_txt', required=True)
parser.add_argument('--pad_wires', required=True)
args = parser.parse_args()
@ -26,6 +40,36 @@ def main():
j['info'][name] = int(value)
db = Database(get_db_root())
grid = db.grid()
roi = Roi(
db=db,
x1=j['info']['GRID_X_MIN'],
y1=j['info']['GRID_Y_MIN'],
x2=j['info']['GRID_X_MAX'],
y2=j['info']['GRID_Y_MAX'],
)
with open(args.pad_wires) as f:
for l in f:
parts = l.strip().split(' ')
name = parts[0]
pin = parts[1]
wires = parts[2:]
wires_outside_roi = []
for wire in wires:
tile = wire.split('/')[0]
loc = grid.loc_of_tilename(tile)
if not roi.tile_in_roi(loc):
wires_outside_roi.append(wire)
set_port_wires(j['ports'], name, pin, wires_outside_roi)
json.dump(j, sys.stdout, indent=2, sort_keys=True)

View File

@ -30,14 +30,13 @@ if [ "$SMALL" = Y ] ; then
export DIN_N=8
export DOUT_N=8
export XRAY_ROI=SLICE_X12Y100:SLICE_X17Y117
# 16x by 50y CLBs (800)
# All of CMT X0Y2
else
echo "Design: large"
export PITCH=3
export DIN_N=8
export DOUT_N=8
export XRAY_ROI=SLICE_X12Y100:SLICE_X27Y149
#export XRAY_ROI=SLICE_X12Y100:SLICE_X5Y149
export PITCH=2
export DIN_N=16
export DOUT_N=16
export XRAY_ROI=SLICE_X0Y100:SLICE_X35Y149
fi
mkdir -p $BUILD_DIR
@ -60,7 +59,7 @@ ${XRAY_BITREAD} -F $XRAY_ROI_FRAMES -o design.bits -z -y design.bit
${XRAY_SEGPRINT} -zd design.bits >design.segp
${XRAY_DIR}/utils/bits2fasm.py --verbose design.bits > design.fasm
${XRAY_DIR}/utils/fasm2frames.py design.fasm design.frm
python3 ../create_design_json.py --design_info_txt design_info.txt --design_txt design.txt > design.json
python3 ../create_design_json.py --design_info_txt design_info.txt --design_txt design.txt --pad_wires design_pad_wires.txt > design.json
# Hack to get around weird clock error related to clk net not found
# Remove following lines:

View File

@ -31,7 +31,6 @@ set XRAY_ROI_Y1 [lindex [split "$::env(XRAY_ROI)" Y] 2]
set X_BASE $XRAY_ROI_X0
set Y_BASE $XRAY_ROI_Y0
# set Y_DIN_BASE 100
set Y_CLK_BASE $Y_BASE
# Clock lut in middle
set Y_DIN_BASE [expr "$Y_CLK_BASE + $PITCH"]
@ -282,22 +281,31 @@ if {$fixed_xdc eq ""} {
# Place ROI inputs
puts "Placing ROI inputs"
set y $Y_DIN_BASE
set y_left $Y_DIN_BASE
# Shift y_right up to avoid PCIe block that makes routing hard.
set y_right [expr {$Y_DIN_BASE + 24}]
for {set i 0} {$i < $DIN_N} {incr i} {
loc_lut_in $i $x $y
set y [expr {$y + $PITCH}]
if {[net_bank_left "din[$i]"]} {
loc_lut_in $i $XRAY_ROI_X0 $y_left
set y_left [expr {$y_left + $PITCH}]
} else {
loc_lut_in $i $XRAY_ROI_X1 $y_right
set y_right [expr {$y_right + $PITCH}]
}
}
# Place ROI outputs
set y $Y_DOUT_BASE
set y_left $Y_DOUT_BASE
set y_right $Y_DOUT_BASE
puts "Placing ROI outputs"
for {set i 0} {$i < $DOUT_N} {incr i} {
if {[net_bank_left "dout[$i]"]} {
loc_lut_out $i $XRAY_ROI_X0 $y
loc_lut_out $i $XRAY_ROI_X0 $y_left
set y_left [expr {$y_left + $PITCH}]
} else {
loc_lut_out $i $XRAY_ROI_X1 $y
loc_lut_out $i $XRAY_ROI_X1 $y_right
set y_right [expr {$y_right + $PITCH}]
}
set y [expr {$y + $PITCH}]
}
}
@ -373,6 +381,7 @@ close $fp
# XXX: maybe add IOB?
set fp [open "design.txt" w]
set fp_wires [open "design_pad_wires.txt" w]
puts $fp "name node pin wire"
# Manual routing
if {$fixed_xdc eq ""} {
@ -391,54 +400,67 @@ if {$fixed_xdc eq ""} {
puts "Routing ROI inputs"
# Arbitrary offset as observed
set y [expr {$Y_DIN_BASE - 1}]
set y_left $Y_DIN_BASE
set y_right [expr {$Y_DIN_BASE + 24}]
for {set i 0} {$i < $DIN_N} {incr i} {
# needed to force routes away to avoid looping into ROI
#set x_EE2BEG3 [expr {$x - 2}]
set x_EE2BEG3 7
set x_NE2BEG3 9
set node "INT_R_X${x_NE2BEG3}Y${y}/NE2BEG3"
route_via2 "din_IBUF[$i]" "INT_R_X${x_EE2BEG3}Y${y}/EE2BEG3 $node"
if {[net_bank_left "din[$i]"]} {
set node "INT_L_X0Y${y_left}/EE2BEG2"
route_via2 "din_IBUF[$i]" "$node"
set y_left [expr {$y_left + $PITCH}]
} else {
set node "INT_R_X25Y${y_right}/WW2BEG1"
route_via2 "din_IBUF[$i]" "$node"
set y_right [expr {$y_right + $PITCH}]
}
set net "din[$i]"
set pin "$net2pin($net)"
set wire [node2wire $node]
puts $fp "$net $node $pin $wire"
set y [expr {$y + $PITCH}]
set wires [get_wires -of_objects [get_nets "din_IBUF[$i]"]]
puts $fp_wires "$net $pin $wires"
}
puts "Routing ROI outputs"
# Arbitrary offset as observed
set y [expr {$Y_DOUT_BASE + 0}]
set y_left [expr {$Y_DOUT_BASE + 0}]
set y_right [expr {$Y_DOUT_BASE + 0}]
for {set i 0} {$i < $DOUT_N} {incr i} {
if {[net_bank_left "dout[$i]"]} {
# XXX: find a better solution if we need harness long term
# works on 50t but not 35t
if {$part eq "xc7a50tfgg484-1"} {
set node "INT_L_X10Y${y}/WW2BEG0"
set node "INT_L_X1Y${y_left}/WW2BEG0"
route_via2 "roi/dout[$i]" "$node"
# works on 35t but not 50t
} elseif {$part eq "xc7a35tcsg324-1"} {
set node "INT_L_X10Y${y}/SW6BEG0"
set node "INT_L_X2Y${y_left}/SW6BEG0"
route_via2 "roi/dout[$i]" "$node"
} elseif {$part eq "xc7a35tcpg236-1"} {
set node "INT_L_X10Y${y}/SW6BEG0"
set node "INT_L_X2Y${y_left}/SW6BEG0"
route_via2 "roi/dout[$i]" "$node"
} else {
error "Routing: unsupported part $part"
}
set y_left [expr {$y_left + $PITCH}]
# XXX: only care about right ports on Arty
} else {
set node "INT_R_X17Y${y}/SE6BEG0"
set node "INT_R_X23Y${y_right}/LH12"
route_via2 "roi/dout[$i]" "$node"
set y_right [expr {$y_right + $PITCH}]
}
set net "dout[$i]"
set pin "$net2pin($net)"
set wire [node2wire $node]
puts $fp "$net $node $pin $wire"
set y [expr {$y + $PITCH}]
set wires [get_wires -of_objects [get_nets "roi/dout[$i]"]]
puts $fp_wires "$net $pin $wires"
}
}
close $fp
close $fp_wires
puts "routing design"
route_design

View File

@ -22,6 +22,9 @@ class FasmAssembler(object):
self.db = db
self.grid = db.grid()
self.seen_tile = set()
self.frames_in_use = set()
self.frames = {}
self.frames_line = {}
@ -29,7 +32,12 @@ class FasmAssembler(object):
if not sparse:
frames = self.frames_init()
else:
# Even in sparse mode, zero all frames for any tile that is
# setting a bit. This handles the case where the tile has
# multiple frames, but the FASM only specifies some of the frames.
frames = {}
for frame in self.frames_in_use:
init_frame_at_address(frames, frame)
for (frame_addr, word_addr, bit_index), is_set in self.frames.items():
init_frame_at_address(frames, frame_addr)
@ -112,6 +120,13 @@ class FasmAssembler(object):
segbits = self.db.get_tile_segbits(gridinfo.tile_type)
# Mark all frames used by this tile as in use.
if tile not in self.seen_tile:
for frame in segbits.frames(bits):
self.frames_in_use.add(frame)
self.seen_tile.add(tile)
db_k = '%s.%s' % (gridinfo.tile_type, feature)
try:

View File

@ -140,3 +140,9 @@ class TileSegbits(object):
else:
for bit in self.segbits[self.feature_addresses[feature][address]]:
yield bit
def frames(self, bits):
""" Iterate over frames this tile uses for a given bit location. """
for query_bits in self.segbits.values():
for bit in query_bits:
yield bits.base_address + bit.word_column

View File

@ -46,7 +46,7 @@ def main():
for pip in tile_type.pips:
if pip.net_from == parts[2] and pip.net_to == parts[1]:
yield '{}/{}.{}'.format(tile, gridinfo.tile_type, pip.name)
yield '{}/{}'.format(tile, pip.name)
print(
'highlight_objects [concat {}]'.format(