harness: Add initial version of ROI harness Signed-off-by: Tomasz Michalak <tmichalak@antmicro.com>
diff --git a/minitests/roi_harness/Makefile b/minitests/roi_harness/Makefile new file mode 100644 index 0000000..573f416 --- /dev/null +++ b/minitests/roi_harness/Makefile
@@ -0,0 +1,31 @@ +URAY_PINCFG ?= ZYNQUSP-SWBUT +export URAY_PINCFG + +BUILD_DIR=build_$(URAY_PINCFG) +HARNESS_DIR ?= harness_$(URAY_PINCFG) +export BUILD_DIR + +HARNESS_FILES=$(BUILD_DIR)/design.bit $(BUILD_DIR)/design.txt $(BUILD_DIR)/design.json $(BUILD_DIR)/design.dcp + +# official demo configuration +all: $(BUILD_DIR)/run.ok + +$(BUILD_DIR)/run.ok: runme.sh runme.tcl + ./runme.sh + touch $(BUILD_DIR)/run.ok + +$(BUILD_DIR)/copy.ok: $(BUILD_DIR)/run.ok + mkdir -p $(HARNESS_DIR) + cp $(HARNESS_FILES) $(HARNESS_DIR) + touch $(BUILD_DIR)/copy.ok + +copy: $(BUILD_DIR)/copy.ok + +clean: + rm -rf build_* harness_* + +run: + +$(MAKE) clean + +$(MAKE) copy + +.PHONY: all clean copy run
diff --git a/minitests/roi_harness/Makefile_mini b/minitests/roi_harness/Makefile_mini new file mode 100644 index 0000000..79cddbe --- /dev/null +++ b/minitests/roi_harness/Makefile_mini
@@ -0,0 +1,34 @@ +PART = xczu7ev-ffvc1156-2-i +BIT2FASM_ARGS = --verbose +SOURCES = top_mini.v + +all: top.fasm top.bits segprint.log + +clean: + @rm -f *.bit + @rm -f *.bin + @rm -f *.bits + @rm -f *.fasm + @rm -f *.log + @rm -rf build + +.PHONY: all clean + +top.bit: $(VIVADO) $(SOURCES) runme.py + mkdir -p build + source ../zynqusp-swbut.sh; \ + cd build && python ../runme.py + cp build/*.bit ./ + +top.fasm: top.bit + PYTHONPATH="$(URAY_DIR):$(URAY_DIR)/utils:$(URAY_DIR)/third_party/fasm" \ + PATH="$(URAY_DIR)/build/tools:$(PATH)" \ + $(URAY_BIT2FASM) $(BIT2FASM_ARGS) \ + top.bit >top.fasm \ + || (rm -f top.fasm && exit 1) + +top.bits: top.bit + $(URAY_BITREAD) -part_file $(URAY_DIR)/database/zynqusp/$(PART)/part.yaml -o top.bits -z -y top.bit + +segprint.log: top.bits + $(URAY_SEGPRINT) -z -D -b top.bits > segprint.log
diff --git a/minitests/roi_harness/create_design_json.py b/minitests/roi_harness/create_design_json.py new file mode 100644 index 0000000..1c30fbd --- /dev/null +++ b/minitests/roi_harness/create_design_json.py
@@ -0,0 +1,120 @@ +import xjson +import csv +import argparse +import sys +import fasm +from prjxray.db import Database +from prjxray.roi import Roi +from prjxray.util import get_db_root, get_part +from prjxray.xjson import extract_numbers + + +def set_port_wires(ports, name, pin, wires_outside_roi): + for port in ports: + if name == port['name']: + port['wires_outside_roi'] = sorted( + wires_outside_roi, key=extract_numbers) + assert port['pin'] == pin + return + + assert False, name + + +def main(): + parser = argparse.ArgumentParser( + description= + "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) + parser.add_argument('--design_fasm', required=True) + + args = parser.parse_args() + + design_json = {} + design_json['ports'] = [] + design_json['info'] = {} + with open(args.design_txt) as f: + for d in csv.DictReader(f, delimiter=' '): + design_json['ports'].append(d) + + with open(args.design_info_txt) as f: + for l in f: + name, value = l.strip().split(' = ') + + design_json['info'][name] = int(value) + + db = Database(get_db_root(), get_part()) + grid = db.grid() + + roi = Roi( + db=db, + x1=design_json['info']['GRID_X_MIN'], + y1=design_json['info']['GRID_Y_MIN'], + x2=design_json['info']['GRID_X_MAX'], + y2=design_json['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(design_json['ports'], name, pin, wires_outside_roi) + + frames_in_use = set() + for tile in roi.gen_tiles(): + gridinfo = grid.gridinfo_at_tilename(tile) + + for bit in gridinfo.bits.values(): + frames_in_use.add(bit.base_address) + + required_features = [] + for fasm_line in fasm.parse_fasm_filename(args.design_fasm): + if fasm_line.annotations: + for annotation in fasm_line.annotations: + if annotation.name != 'unknown_segment': + continue + + unknown_base_address = int(annotation.value, 0) + + assert False, "Found unknown bit in base address 0x{:08x}".format( + unknown_base_address) + + if not fasm_line.set_feature: + continue + + tile = fasm_line.set_feature.feature.split('.')[0] + + loc = grid.loc_of_tilename(tile) + gridinfo = grid.gridinfo_at_tilename(tile) + + not_in_roi = not roi.tile_in_roi(loc) + + if not_in_roi: + required_features.append(fasm_line) + + design_json['required_features'] = sorted( + fasm.fasm_tuple_to_string(required_features, + canonical=True).split('\n'), + key=extract_numbers) + + design_json['ports'].sort(key=lambda x: extract_numbers(x['name'])) + + xjson.pprint(sys.stdout, design_json) + + +if __name__ == '__main__': + main()
diff --git a/minitests/roi_harness/fasm2bit.sh b/minitests/roi_harness/fasm2bit.sh new file mode 100755 index 0000000..ee1d389 --- /dev/null +++ b/minitests/roi_harness/fasm2bit.sh
@@ -0,0 +1,40 @@ +# Example pre-req +# ./runme.sh +# XRAY_ROIV=roi_inv.v XRAY_FIXED_XDC=out_xc7a35tcpg236-1_BASYS3-SWBUT_roi_basev/fixed_noclk.xdc ./runme.sh + +set -ex + +fasm_in=$1 +if [ -z "$fasm_in" ] ; then + echo "need .fasm arg" + exit +fi +bit_in=$2 +if [ -z "$bit_in" ] ; then + echo "need .bit arg" + exit +fi +bit_out=$3 +if [ -z "$bit_out" ] ; then + bit_out=$(echo $fasm_in |sed s/.fasm/.bit/) + if [ "$bit_out" = "$fasm_in" ] ; then + echo "Expected fasm file" + exit 1 + fi +fi + +echo "Design .fasm: $fasm_in" +echo "Harness .bit: $bit_in" +echo "Out .bit: $bit_out" + +${XRAY_FASM2FRAMES} --sparse $fasm_in roi_partial.frm + +${XRAY_TOOLS_DIR}/xc7patch \ + --part_name ${XRAY_PART} \ + --part_file ${XRAY_PART_YAML} \ + --bitstream_file $bit_in \ + --frm_file roi_partial.frm \ + --output_file $bit_out + +#openocd -f $XRAY_DIR/utils/openocd/board-digilent-basys3.cfg -c "init; pld load 0 $bit_out; exit" +
diff --git a/minitests/roi_harness/roi_base.v b/minitests/roi_harness/roi_base.v new file mode 100644 index 0000000..a77662c --- /dev/null +++ b/minitests/roi_harness/roi_base.v
@@ -0,0 +1,49 @@ +//See README and tcl for more info + +`include "defines.v" + +module roi(input clk, + input [DIN_N-1:0] din, output [DOUT_N-1:0] dout); + parameter DIN_N = `DIN_N; + parameter DOUT_N = `DOUT_N; + + genvar i; + generate + //CLK + (* KEEP, DONT_TOUCH *) + reg clk_reg; + always @(posedge clk) begin + clk_reg <= clk_reg; + end + + //DIN + for (i = 0; i < DIN_N; i = i+1) begin:ins + (* KEEP, DONT_TOUCH *) + LUT6 #( + .INIT(64'b01) + ) lut ( + .I0(din[i]), + .I1(1'b0), + .I2(1'b0), + .I3(1'b0), + .I4(1'b0), + .I5(1'b0), + .O()); + end + + //DOUT + for (i = 0; i < DOUT_N; i = i+1) begin:outs + (* KEEP, DONT_TOUCH *) + LUT6 #( + .INIT(64'b01) + ) lut ( + .I0(1'b0), + .I1(1'b0), + .I2(1'b0), + .I3(1'b0), + .I4(1'b0), + .I5(1'b0), + .O(dout[i])); + end + endgenerate +endmodule
diff --git a/minitests/roi_harness/runme.py b/minitests/roi_harness/runme.py new file mode 100644 index 0000000..a889124 --- /dev/null +++ b/minitests/roi_harness/runme.py
@@ -0,0 +1,57 @@ +import edalize +import os + +work_root = 'build' + +pins = { + 'di_0': os.environ['URAY_PIN_02'], + 'di_1': os.environ['URAY_PIN_03'], + 'do': os.environ['URAY_PIN_04'], +} + +xdc_file = os.path.realpath(os.path.join(work_root, 'top.xdc')) +pre_imp_file = os.path.realpath(os.path.join(work_root, 'pre.tcl')) +post_imp_file = os.path.realpath(os.path.join(work_root, 'post.tcl')) + +os.makedirs(work_root, exist_ok=True) + +synth_tool = 'yosys' if 'USE_YOSYS' in os.environ else 'vivado' + +with open(xdc_file, 'w') as f: + f.write('set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets *]\n') + for key, val in pins.items(): + f.write('set_property PACKAGE_PIN {} [get_ports {}]\n'.format(val, key)) + f.write('set_property IOSTANDARD LVCMOS33 [get_ports {}]\n'.format(key)) + +with open(pre_imp_file, 'w') as f: + f.write('create_pblock roi\n') + f.write('add_cells_to_pblock [get_pblocks roi] [get_cells roi]\n') + f.write('resize_pblock [get_pblocks roi] -add "{}"\n'.format(os.environ['URAY_ROI'])) + f.write('set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design]\n') + +with open(post_imp_file, 'w') as f: + f.write('write_checkpoint -force design.dcp') + +files = [ + {'name': os.path.realpath('top_mini.v'), 'file_type': 'verilogSource'}, + {'name': xdc_file, 'file_type': 'xdc'}, +] + +tool = 'vivado' + +edam = { + 'files' : files, + 'name' : 'design', + 'toplevel': 'top', + 'tool_options' : {'vivado' : { + 'part' : os.environ['URAY_PART'], + 'pre_imp' : pre_imp_file, + 'post_imp' : post_imp_file, + 'synth' : synth_tool + }} +} + +backend = edalize.get_edatool(tool)(edam=edam, work_root=work_root) + +backend.configure("") +backend.build()
diff --git a/minitests/roi_harness/runme.sh b/minitests/roi_harness/runme.sh new file mode 100755 index 0000000..d14e409 --- /dev/null +++ b/minitests/roi_harness/runme.sh
@@ -0,0 +1,78 @@ +#!/usr/bin/env bash + +# This script requires an XC7A50T family part + +set -ex + +source ${URAY_DIR}/utils/environment.sh + +export URAY_PINCFG=${URAY_PINCFG:-ZYNQUSP-SWBUT} +export BUILD_DIR=${BUILD_DIR:-build} + +# not part of the normal DB +# to generate: +#cat >/dev/null <<EOF +#pushd ${URAY_DIR} +#source minitests/roi_harness/basys3.sh +#pushd fuzzers/001-part-yaml +#make clean +#make +#make pushdb +#popd +#popd +#EOF +stat ${URAY_PART_YAML} >/dev/null + +# 6x by 18y CLBs (108) +if [ "$SMALL" = Y ] ; then + echo "Design: small" + export PITCH=${URAY_PITCH:-1} + export DIN_N=${URAY_DIN_N_SMALL:-8} + export DOUT_N=${URAY_DOUT_N_SMALL:-8} + export URAY_ROI=${URAY_ROI_SMALL:-SLICE_X12Y100:SLICE_X17Y117} +# All of CMT X0Y2 +else + echo "Design: large" + export PITCH=${URAY_PITCH:-2} + export DIN_N=${URAY_DIN_N_LARGE:-8} + export DOUT_N=${URAY_DOUT_N_LARGE:-8} + export URAY_ROI=${URAY_ROI_LARGE:-SLICE_X0Y100:SLICE_X35Y149} +fi + +echo ${DIN_N} +echo ${DOUT_N} +echo ${URAY_ROI} + +mkdir -p $BUILD_DIR +pushd $BUILD_DIR + +cat >defines.v <<EOF +\`ifndef DIN_N +\`define DIN_N $DIN_N +\`endif + +\`ifndef DOUT_N +\`define DOUT_N $DOUT_N +\`endif +EOF + +${URAY_VIVADO} -mode batch -source ../runme.tcl +test -z "$(fgrep CRITICAL vivado.log)" + +${URAY_BITREAD} -F $URAY_ROI_FRAMES -o design.bits -z -y design.bit +python3 ${URAY_DIR}/utils/bit2fasm.py --verbose design.bit > design.fasm +python3 ${URAY_DIR}/utils/fasm2frames.py design.fasm design.frm +PYTHONPATH=$PYTHONPATH:$URAY_DIR/utils python3 ../create_design_json.py \ + --design_info_txt design_info.txt \ + --design_txt design.txt \ + --pad_wires design_pad_wires.txt \ + --design_fasm design.fasm > design.json + +# Hack to get around weird clock error related to clk net not found +# Remove following lines: +#set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk_IBUF] +#set_property FIXED_ROUTE { { CLK_BUFG_BUFGCTRL0_O CLK_BUFG_CK_GCLK0 ... CLK_L1 CLBLM_M_CLK } } [get_nets clk_net] +if [ -f fixed.xdc ] ; then + cat fixed.xdc |fgrep -v 'CLOCK_DEDICATED_ROUTE FALSE' |fgrep -v 'set_property FIXED_ROUTE { { CLK_BUFG_BUFGCTRL0_O' >fixed_noclk.xdc +fi +popd
diff --git a/minitests/roi_harness/runme.tcl b/minitests/roi_harness/runme.tcl new file mode 100644 index 0000000..bfa7c99 --- /dev/null +++ b/minitests/roi_harness/runme.tcl
@@ -0,0 +1,432 @@ +# WARNING: this is somewhat paramaterized, but is only tested on A50T/A35T with the traditional ROI +# Your ROI should at least have a SLICEL on the left + +# Number of package inputs going to ROI +set DIN_N 8 +if { [info exists ::env(DIN_N) ] } { + set DIN_N "$::env(DIN_N)" +} +# Number of ROI outputs going to package +set DOUT_N 8 +if { [info exists ::env(DOUT_N) ] } { + set DOUT_N "$::env(DOUT_N)" +} +# How many rows between pins +# Reduces routing pressure +set PITCH 1 +if { [info exists ::env(PITCH) ] } { + set PITCH "$::env(PITCH)" +} + +if { [info exists ::env(URAY_ROI_HCLK)] } { + set URAY_ROI_HCLK "$::env(URAY_ROI_HCLK)" +} else { + puts "WARNING: No HCLK has been set" +} + +# Setting all the PIPs for DIN and DOUT +if { [info exists ::env(URAY_ROI_DIN_LPIP)] } { + set DIN_LPIP "$::env(URAY_ROI_DIN_LPIP)" +} else { puts "Warning: No left pip for DIN has been set" } + +if { [info exists ::env(URAY_ROI_DIN_RPIP)] } { + set DIN_RPIP "$::env(URAY_ROI_DIN_RPIP)" +} else { puts "Warning: No right pip for DIN has been set" } + +if { [info exists ::env(URAY_ROI_DOUT_LPIP)] } { + set DOUT_LPIP "$::env(URAY_ROI_DOUT_LPIP)" +} else { puts "Warning: No left pip for DOUT has been set" } + +if { [info exists ::env(URAY_ROI_DOUT_RPIP)] } { + set DOUT_RPIP "$::env(URAY_ROI_DOUT_RPIP)" +} else { puts "Warning: No right pip for DOUT has been set" } + +# Setting all INT_L/R tiles for DIN and DOUT X values +if { [info exists ::env(URAY_ROI_DIN_INT_L_X)] } { + set DIN_INT_L_X "$::env(URAY_ROI_DIN_INT_L_X)" +} else { puts "Warning: No INT_L for DIN has been set" } + +if { [info exists ::env(URAY_ROI_DIN_INT_R_X)] } { + set DIN_INT_R_X "$::env(URAY_ROI_DIN_INT_R_X)" +} else { puts "Warning: No INT_R for DIN has been set" } + +if { [info exists ::env(URAY_ROI_DOUT_INT_L_X)] } { + set DOUT_INT_L_X "$::env(URAY_ROI_DOUT_INT_L_X)" +} else { puts "Warning: No INT_L for DOUT has been set" } + +if { [info exists ::env(URAY_ROI_DOUT_INT_R_X)] } { + set DOUT_INT_R_X "$::env(URAY_ROI_DOUT_INT_R_X)" +} else { puts "Warning: No INT_R for DOUT has been set" } + +# X12 in the ROI, X10 just to the left +# Start at bottom left of ROI and work up +# (IOs are to left) +# SLICE_X12Y100:SLICE_X27Y149 +# set X_BASE 12 +set URAY_ROI_X0 [lindex [split [lindex [split "$::env(URAY_ROI)" Y] 0] X] 1] +set URAY_ROI_X1 [lindex [split [lindex [split "$::env(URAY_ROI)" X] 2] Y] 0] +set URAY_ROI_Y0 [lindex [split [lindex [split "$::env(URAY_ROI)" Y] 1] :] 0] +set URAY_ROI_Y1 [lindex [split "$::env(URAY_ROI)" Y] 2] + +set X_BASE $URAY_ROI_X0 +set Y_BASE $URAY_ROI_Y0 + +set Y_CLK_BASE $Y_BASE +# Clock lut in middle +set Y_DIN_BASE [expr "$Y_CLK_BASE + $PITCH"] +# Sequential +# set Y_DOUT_BASE [expr "$Y_DIN_BASE + $DIN_N"] +# At top. This relieves routing pressure by spreading things out +# Note: can actually go up one more if we want +set Y_DOUT_BASE [expr "$URAY_ROI_Y1 - $DOUT_N * $PITCH"] + +# Y_OFFSET: offset amount to shift the components on the y column to avoid hard blocks +set Y_OFFSET 24 + +set part "$::env(URAY_PART)" +set pincfg "" +if { [info exists ::env(URAY_PINCFG) ] } { + set pincfg "$::env(URAY_PINCFG)" +} +set roiv "../roi_base.v" +if { [info exists ::env(URAY_ROIV) ] } { + set roiv "$::env(URAY_ROIV)" +} +set roiv_trim [string map {.v v} $roiv] + +puts "Environment" +puts " URAY_ROI: $::env(URAY_ROI)" +puts " X_BASE: $X_BASE" +puts " Y_DIN_BASE: $Y_DIN_BASE" +puts " Y_CLK_BASE: $Y_CLK_BASE" +puts " Y_DOUT_BASE: $Y_DOUT_BASE" + +source ../../../utils/utils.tcl + +create_project -force -part $::env(URAY_PART) design design +read_verilog ../top.v +read_verilog $roiv +set fixed_xdc "" +if { [info exists ::env(URAY_FIXED_XDC) ] } { + set fixed_xdc "$::env(URAY_FIXED_XDC)" +} + +# added flatten_hierarchy +# dout_shr was getting folded into the pblock +# synth_design -top top -flatten_hierarchy none -no_lc -keep_equivalent_registers -resource_sharing off +synth_design -top top -flatten_hierarchy none -verilog_define DIN_N=$DIN_N -verilog_define DOUT_N=$DOUT_N + +if {$fixed_xdc ne ""} { + read_xdc $fixed_xdc +} + +# Map of top level net names to IOB pin names +array set net2pin [list] + +if {$part eq "xczu7ev-ffvc1156-2-i"} { + if {$pincfg eq "ZYNQUSP-SWBUT"} { + set sw_but "E4 D4" ;# DIP_SW_0 DIP_SW_1 + set leds "D5 D6" ;# LED0 LED1 + + # 125 MHz CLK onboard + set clkp "F23" + set clkn "E23" + set net2pin(clkp) $clkp + set net2pin(clk) $clkn + + # DIN + for {set i 0} {$i < $DIN_N} {incr i} { + set pin [lindex $sw_but $i] + set net2pin(din[$i]) $pin + } + + # DOUT + for {set i 0} {$i < $DOUT_N} {incr i} { + set pin [lindex $leds $i] + set net2pin(dout[$i]) $pin + } + + } else { + error "Unsupported config $pincfg" + } +} else { + error "Pins: unsupported part $part" +} + +# Now actually apply the pin definitions +puts "Applying pin definitions" +foreach {net pin} [array get net2pin] { + puts " Net $net to pin $pin" + set_property -dict "PACKAGE_PIN $pin IOSTANDARD LVCMOS33" [get_ports $net] +} + +if {$fixed_xdc eq ""} { + create_pblock roi + set_property EXCLUDE_PLACEMENT 1 [get_pblocks roi] + set_property CONTAIN_ROUTING true [get_pblocks roi] + set_property DONT_TOUCH true [get_cells roi] + add_cells_to_pblock [get_pblocks roi] [get_cells roi] + resize_pblock [get_pblocks roi] -add "$::env(URAY_ROI)" + + #set_property CFGBVS VCCO [current_design] + set_property CONFIG_VOLTAGE 3.3 [current_design] + + set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk_IBUF] + + #write_checkpoint -force synth.dcp +} + + +proc loc_roi_clk_left {ff_x ff_y} { + # Place an ROI clk on the left edge of the ROI + # It doesn't actually matter where we place this, just do it to keep things neat looking + # ff_x: ROI SLICE X position + # ff_yy: row primitives will be placed at + + set slice_ff "SLICE_X${ff_x}Y${ff_y}" + + # Fix FFs to guide route in + set cell [get_cells "roi/clk_reg_reg"] + set_property LOC $slice_ff $cell + set_property BEL AFF $cell +} + +proc loc_lut_in {index lut_x lut_y} { + # Place a lut at specified coordinates in BEL A + # index: input bus index + # lut_x: SLICE X position + # lut_y: SLICE Y position + + set slice_lut "SLICE_X${lut_x}Y${lut_y}" + + # Fix LUTs near the edge + set cell [get_cells "roi/ins[$index].lut"] + set_property LOC $slice_lut $cell + set_property BEL A6LUT $cell +} + +proc loc_lut_out {index lut_x lut_y} { + # Place a lut at specified coordinates in BEL A + # index: input bus index + # lut_x: SLICE X position + # lut_y: SLICE Y position + + set slice_lut "SLICE_X${lut_x}Y${lut_y}" + + # Fix LUTs near the edge + set cell [get_cells "roi/outs[$index].lut"] + set_property LOC $slice_lut $cell + set_property BEL A6LUT $cell +} + +proc net_bank_left {net} { + # return 1 if net goes to a leftmost die IO bank + # return 0 if net goes to a rightmost die IO bank + + set bank [get_property IOBANK [get_ports $net]] + set left_banks "14 15 16" + set right_banks "34 35" + + # left + if {[lsearch -exact $left_banks $bank] >= 0} { + return 1 + # right + } elseif {[lsearch -exact $right_banks $bank] >= 0} { + return 0 + } else { + error "Bad bank $bank" + } +} + +# Manual placement +if {$fixed_xdc eq ""} { + set x $X_BASE + + # Place ROI clock right after inputs + puts "Placing ROI clock" + loc_roi_clk_left $x $Y_CLK_BASE + + # Place ROI inputs + puts "Placing ROI inputs" + 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 + $Y_OFFSET}] + for {set i 0} {$i < $DIN_N} {incr i} { + if {[net_bank_left "din[$i]"]} { + loc_lut_in $i $URAY_ROI_X0 $y_left + set y_left [expr {$y_left + $PITCH}] + } else { + loc_lut_in $i $URAY_ROI_X1 $y_right + set y_right [expr {$y_right + $PITCH}] + } + } + + # Place ROI outputs + 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 $URAY_ROI_X0 $y_left + set y_left [expr {$y_left + $PITCH}] + } else { + loc_lut_out $i $URAY_ROI_X1 $y_right + set y_right [expr {$y_right + $PITCH}] + } + } +} + +place_design +#write_checkpoint -force placed.dcp + +# Version with more error checking for missing end node +# Will do best effort in this case +proc route_via2 {net nodes} { + # net: net as string + # nodes: string list of one or more intermediate routing nodes to visit + + set net [get_nets $net] + # Start at the net source + set fixed_route [get_nodes -of_objects [get_site_pins -filter {DIRECTION == OUT} -of_objects $net]] + # End at the net destination + # For sone reason this doesn't always show up + set site_pins [get_site_pins -filter {DIRECTION == IN} -of_objects $net] + if {$site_pins eq ""} { + puts "WARNING: could not find end node" + #error "Could not find end node" + } else { + set end_node [get_nodes -of_objects] + lappend nodes [$end_node] + } + + puts "" + puts "Routing net $net:" + + foreach to_node $nodes { + if {$to_node eq ""} { + error "Empty node" + } + + # Node string to object + set to_node [get_nodes -of_objects [get_wires $to_node]] + # Start at last routed position + set from_node [lindex $fixed_route end] + # Let vivado do heavy liftin in between + set route [find_routing_path -quiet -from $from_node -to $to_node] + if {$route == ""} { + # Some errors print a huge route + puts [concat [string range " $from_node -> $to_node" 0 1000] ": no route found - assuming direct PIP"] + lappend fixed_route $to_node + } { + puts [concat [string range " $from_node -> $to_node: $route" 0 1000] "routed"] + set fixed_route [concat $fixed_route [lrange $route 1 end]] + } + set_property -quiet FIXED_ROUTE $fixed_route $net + } + + set_property -quiet FIXED_ROUTE $fixed_route $net + puts "" +} + +# Return the wire on the ROI boundary +proc node2wire {node} { + set wires [get_wires -of_objects [get_nodes $node]] + set wire [lsearch -inline $wires *VBRK*] + return $wire +} + +proc write_grid_roi {fp} { + puts $fp "GRID_X_MIN = $::env(URAY_ROI_GRID_X1)" + puts $fp "GRID_X_MAX = $::env(URAY_ROI_GRID_X2)" + puts $fp "GRID_Y_MIN = $::env(URAY_ROI_GRID_Y1)" + puts $fp "GRID_Y_MAX = $::env(URAY_ROI_GRID_Y2)" +} + +set fp [open "design_info.txt" w] +write_grid_roi $fp +close $fp + +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 ""} { + set x $X_BASE + + # No routing strictly needed for clk + # It will go to high level interconnect that goes everywhere + # But we still need to record something, so lets force a route + # FIXME: very ROI specific + set node "$URAY_ROI_HCLK" + set wire [node2wire $node] + route_via2 "clk_IBUF_BUFG" "$node" + set net "clk" + set pin "$net2pin($net)" + puts $fp "$net $node $pin $wire" + + puts "Routing ROI inputs" + # Arbitrary offset as observed + set y_left $Y_DIN_BASE + set y_right [expr {$Y_DIN_BASE + $Y_OFFSET}] + for {set i 0} {$i < $DIN_N} {incr i} { + # needed to force routes away to avoid looping into ROI + if {[net_bank_left "din[$i]"]} { + set node "INT_L_X${DIN_INT_L_X}Y${y_left}/${DIN_LPIP}" + route_via2 "din_IBUF[$i]" "$node" + set y_left [expr {$y_left + $PITCH}] + } else { + set node "INT_R_X${DIN_INT_R_X}Y${y_right}/${DIN_RPIP}" + 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 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_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]"]} { + set node "INT_L_X${DOUT_INT_L_X}Y${y_left}/${DOUT_LPIP}" + route_via2 "roi/dout[$i]" "$node" + set y_left [expr {$y_left + $PITCH}] + # XXX: only care about right ports on Arty + } else { + set node "INT_R_X${DOUT_INT_R_X}Y${y_right}/${DOUT_RPIP}" + 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 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 + +# Don't set for user designs +# Makes things easier to debug +if {$fixed_xdc eq ""} { + set_property IS_ROUTE_FIXED 1 [get_nets -hierarchical] + #set_property IS_LOC_FIXED 1 [get_cells -hierarchical] + #set_property IS_BEL_FIXED 1 [get_cells -hierarchical] + write_xdc -force fixed.xdc +} + +write_checkpoint -force design.dcp +#set_property BITSTREAM.GENERAL.DEBUGBITSTREAM YES [current_design] +write_bitstream -force design.bit
diff --git a/minitests/roi_harness/top.v b/minitests/roi_harness/top.v new file mode 100644 index 0000000..c91257f --- /dev/null +++ b/minitests/roi_harness/top.v
@@ -0,0 +1,20 @@ +//See README and tcl for more info + +`include "defines.v" + +module top(input wire clkp, input wire clkn, + inout wire [DIN_N-1:0] din, output wire [DOUT_N-1:0] dout); + parameter DIN_N = `DIN_N; + parameter DOUT_N = `DOUT_N; + wire clk; + IBUFDS clk_input_buffer ( + .O(clk), + .I(clkp), + .IB(clkn) + ); + roi #(.DIN_N(DIN_N), .DOUT_N(DOUT_N)) roi ( + .clk(clk), + .din(din), .dout(dout) + ); +endmodule +
diff --git a/minitests/roi_harness/top_mini.v b/minitests/roi_harness/top_mini.v new file mode 100644 index 0000000..a4de1c4 --- /dev/null +++ b/minitests/roi_harness/top_mini.v
@@ -0,0 +1,22 @@ +//See README and tcl for more info + +module top( + input wire di_0, + input wire di_1, + output wire do +); + + (* LOC="SLICE_X44Y240", BEL="A6LUT", KEEP, DONT_TOUCH *) + LUT6 #( + .INIT(64'h0000_0000_0000_0001) + ) lut ( + .I0(di_0), + .I1(di_1), + .I2(1'b0), + .I3(1'b0), + .I4(1'b0), + .I5(1'b0), + .O(do)); + +endmodule +
diff --git a/minitests/roi_harness/zynqusp-common.sh b/minitests/roi_harness/zynqusp-common.sh new file mode 100644 index 0000000..7de9868 --- /dev/null +++ b/minitests/roi_harness/zynqusp-common.sh
@@ -0,0 +1,48 @@ +export URAY_PART="xczu7ev-ffvc1156-2-i" +export URAY_EQUIV_PART="xczu7ev-ffvc1156-2-i" + +if [ -z "$URAY_PINCFG" ]; then + echo "URAY_PINCFG not set" + return 1 +fi +if [ -z "$URAY_DIN_N_LARGE" ]; then + echo "URAY_DIN_N_LARGE not set" + return 1 +fi +if [ -z "$URAY_DOUT_N_LARGE" ]; then + echo "URAY_DOUT_N_LARGE not set" + return 1 +fi + +# For generating DB +export URAY_PIN_00="B4" #PB_SW_0 +export URAY_PIN_01="C4" #PB_SW_1 +export URAY_PIN_02="E4" #DIP_SW_0 +export URAY_PIN_03="D4" #DIP_SW_1 +export URAY_PIN_04="D5" #LED0 +export URAY_PIN_05="D6" #LED1 +export URAY_PIN_06="E23" #CLK_125_N +export URAY_PIN_07="F23" #CLK_125_P + +# ROI is in top right +export URAY_ROI_LARGE="" + +# HCS (Horizontal Clock Spine) Tile +export URAY_ROI_HCLK="" + +# PITCH +export URAY_PITCH=3 + +# INT_L/R for DOUT and DIN +export URAY_ROI_DIN_INT_L_X= +export URAY_ROI_DIN_INT_R_X= +export URAY_ROI_DOUT_INT_L_X= +export URAY_ROI_DOUT_INT_R_X= + +# PIPS for DOUT and DIN +export URAY_ROI_DIN_LPIP= +export URAY_ROI_DIN_RPIP= +export URAY_ROI_DOUT_LPIP= +export URAY_ROI_DOUT_RPIP= + +source $URAY_DIR/utils/environment.sh
diff --git a/minitests/roi_harness/zynqusp-swbut.sh b/minitests/roi_harness/zynqusp-swbut.sh new file mode 100644 index 0000000..e1bb901 --- /dev/null +++ b/minitests/roi_harness/zynqusp-swbut.sh
@@ -0,0 +1,17 @@ +export URAY_PINCFG=ZYNQUSP-SWBUT +export URAY_DIN_N_SMALL=2 +export URAY_DOUT_N_SMALL=1 +export HARNESS_DIR=$URAY_DIR/database/zynqusp/harness/swbut/ +export SMALL="Y" + +export URAY_PIN_00="B4" #PB_SW_0 +export URAY_PIN_01="C4" #PB_SW_1 +export URAY_PIN_02="E4" #DIP_SW_0 +export URAY_PIN_03="D4" #DIP_SW_1 +export URAY_PIN_04="D5" #LED0 +export URAY_PIN_05="D6" #LED1 +export URAY_PIN_06="E23" #CLK_125_N +export URAY_PIN_07="F23" #CLK_125_P + +source $URAY_DIR/minitests/roi_harness/zynqusp-common.sh +
diff --git a/utils/environment.sh b/utils/environment.sh index 863b05e..a04fa0a 100644 --- a/utils/environment.sh +++ b/utils/environment.sh
@@ -28,7 +28,7 @@ export URAY_MASKMERGE="bash ${URAY_UTILS_DIR}/maskmerge.sh" export URAY_SEGMATCH="${URAY_TOOLS_DIR}/segmatch" export URAY_SEGPRINT="python3 ${URAY_UTILS_DIR}/segprint.py" -export URAY_BIT2FASM="python3 ${URAY_UTILS_DIR}/bit2fasm.py" +export URAY_BIT2FASM="python3 ${URAY_UTILS_DIR}/bit2fasm.py --architecture ${URAY_ARCH}" export URAY_FASM2FRAMES="python3 ${URAY_UTILS_DIR}/fasm2frames.py" export URAY_BITTOOL="${URAY_TOOLS_DIR}/bittool" export URAY_BLOCKWIDTH="python3 ${URAY_UTILS_DIR}/blockwidth.py"