diff --git a/minitests/roi_harness/.gitignore b/minitests/roi_harness/.gitignore index dd262534..b24efbad 100644 --- a/minitests/roi_harness/.gitignore +++ b/minitests/roi_harness/.gitignore @@ -7,3 +7,7 @@ /vivado* /design.txt /out_* +/*.fasm +/*.bit +/*.bin +/*.frm diff --git a/minitests/roi_harness/README.txt b/minitests/roi_harness/README.txt index 2f24f2da..c81a5ad7 100644 --- a/minitests/roi_harness/README.txt +++ b/minitests/roi_harness/README.txt @@ -17,3 +17,7 @@ To build the baseline harness: To build a sample Vivado design using the harness: XRAY_ROIV=roi_inv.v XRAY_FIXED_XDC=out_xc7a35tcpg236-1_BASYS3-SWBUT_roi_basev/fixed_noclk.xdc ./runme.sh Note: this was intended for verification only and not as an end user flow (they should use SymbiFlow) + +To use the harness for the basys3 demo, do something like: +python3 demo_sw_led.py out_xc7a35tcpg236-1_BASYS3-SWBUT_roi_basev 3 2 +This example connects switch 3 to LED 2 diff --git a/minitests/roi_harness/demo_sw_led.py b/minitests/roi_harness/demo_sw_led.py new file mode 100755 index 00000000..3ffb089d --- /dev/null +++ b/minitests/roi_harness/demo_sw_led.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 + +import subprocess +import demo_sw_led_fasm +import os + + +def run(roi_dir, swn, ledn): + design_txt_fn = roi_dir + '/design.txt' + bit_ref_fn = roi_dir + '/design.bit' + fasm_fn = 'demo_sw_led.fasm' + bit_out_fn = 'demo_sw_led.bit' + ocd_cfg = os.getenv( + 'XRAY_DIR') + '/utils/openocd/board-digilent-basys3.cfg' + + # Clean up old tmp files to be sure we are generating them fresh + subprocess.call('rm -f %s %s' % (fasm_fn, bit_out_fn), shell=True) + + # subprocess.shell("python3 demo_sw_led.py out_xc7a35tcpg236-1_BASYS3-SWBUT_roi_basev/design.txt 0 0 demo.fasm") + demo_sw_led_fasm.run( + open(design_txt_fn, 'r'), swn, ledn, open(fasm_fn, 'w')) + subprocess.check_call( + "./fasm2bit.sh %s %s %s" % (fasm_fn, bit_ref_fn, bit_out_fn), + shell=True) + subprocess.check_call( + 'openocd -f %s -c "init; pld load 0 %s; exit"' % (ocd_cfg, bit_out_fn), + shell=True) + + +if __name__ == '__main__': + import argparse + + parser = argparse.ArgumentParser( + description= + 'Basys3 switch to LED interconnect demo. Compiles and programs') + parser.add_argument( + 'roi_dir', help='ROI project dir for harness .bit and metadata.txt') + parser.add_argument('sw', type=int, help='Switch to use') + parser.add_argument('led', type=int, help='LED to use') + + args = parser.parse_args() + run(args.roi_dir, args.sw, args.led) diff --git a/minitests/roi_harness/demo_sw_led_fasm.py b/minitests/roi_harness/demo_sw_led_fasm.py new file mode 100755 index 00000000..e2027c8c --- /dev/null +++ b/minitests/roi_harness/demo_sw_led_fasm.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 + +import sys +import os +sys.path.append(os.getenv("XRAY_DIR") + "/tools") +import simpleroute + +print() +print('ready') + + +def load_design(f): + ''' + name node pin wire + clk CLK_HROW_TOP_R_X60Y130/CLK_HROW_CK_BUFHCLK_L0 W5 HCLK_VBRK_X34Y130/HCLK_VBRK_CK_BUFHCLK0 + din[0] INT_R_X9Y100/NE2BEG3 V17 VBRK_X29Y106/VBRK_NE2A3 + ''' + ret = {} + f.readline() + for l in f: + l = l.strip() + name, node, pin, wire = l.split(' ') + ret[name] = wire + return ret + + +def route2fasm(route, out_f): + pips = simpleroute.route(route) + for pip in pips: + # INT_L_X10Y122.NL1BEG2.NE2END3 + # to + # INT_L_X10Y122.NL1BEG2 NE2END3 + doti = pip.rfind('.') + pip = pip[0:doti] + ' ' + pip[doti + 1:] + out_f.write(pip + '\n') + + +def run(design_f, swn, ledn, out_f): + name2wire = load_design(design_f) + led_name = 'dout[%d]' % ledn + sw_name = 'din[%d]' % swn + led_wire = name2wire[led_name] + sw_wire = name2wire[sw_name] + print( + 'Routing %s (%s) => %s (%s)' % (sw_wire, sw_name, led_wire, led_name)) + + route2fasm((sw_wire, led_wire), out_f) + # XXX: terminate LEDs so they are off? + + +if __name__ == '__main__': + import argparse + + parser = argparse.ArgumentParser( + description='Switch to LED interconnect demo: FASM generator') + parser.add_argument('design_txt', help='ROI metadata file') + parser.add_argument('sw', type=int, help='Switch to use') + parser.add_argument('led', type=int, help='LED to use') + # For now can't use stdout since simpleroute is spewing out prints + parser.add_argument('out_fasm', help='Output .fasm file') + + args = parser.parse_args() + run( + open(args.design_txt, 'r'), args.sw, args.led, open( + args.out_fasm, 'w')) diff --git a/minitests/roi_harness/fasm2bit.sh b/minitests/roi_harness/fasm2bit.sh new file mode 100755 index 00000000..3e7798c9 --- /dev/null +++ b/minitests/roi_harness/fasm2bit.sh @@ -0,0 +1,57 @@ +# 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_DIR}/tools/fasm2frame.py $fasm_in roi_partial.frm + +${XRAY_TOOLS_DIR}/xc7patch \ + --part_file ${XRAY_PART_YAML} \ + --bitstream_file $bit_in \ + --frm_file roi_partial.frm \ + --output_file patched.bin + +# WARNING: these values need to be tweaked if anything about the +# Vivado-generated design changes. +xxd -p -l 0x147 $bit_in | xxd -r -p - init_sequence.bit + +# WARNING: these values need to be tweaked if anything about the +# Vivado-generated design changes. +xxd -p -s 0x18 patched.bin | xxd -r -p - no_headers.bin + +# WARNING: these values need to be tweaked if anything about the +# Vivado-generated design changes. +xxd -p -s 0x216abf $bit_in | \ + tr -d '\n' | \ + sed -e 's/30000001.\{8\}/3000800100000007/g' | \ + fold -w 40 | \ + xxd -r -p - final_sequence.bin + +cat init_sequence.bit no_headers.bin final_sequence.bin >$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_demoscene.v b/minitests/roi_harness/roi_demoscene.v new file mode 100644 index 00000000..8834d326 --- /dev/null +++ b/minitests/roi_harness/roi_demoscene.v @@ -0,0 +1,149 @@ +//See README and tcl for more info + +`default_nettype none + +`include "defines.v" + +module roi(input wire clk, + input wire [DIN_N-1:0] din, output wire [DOUT_N-1:0] dout); + parameter DIN_N = `DIN_N; + parameter DOUT_N = `DOUT_N; + + wire [DIN_N-1:0] din_lut; + wire [DOUT_N-1:0] dout_lut; + + 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(din_lut[i])); + end + + //DOUT + for (i = 0; i < DOUT_N; i = i+1) begin:outs + (* KEEP, DONT_TOUCH *) + LUT6 #( + .INIT(64'b01) + ) lut ( + .I0(dout_lut[i]), + .I1(1'b0), + .I2(1'b0), + .I3(1'b0), + .I4(1'b0), + .I5(1'b0), + .O(dout[i])); + end + endgenerate + + demoscene demoscene(.clk(clk), .din(din_lut), .dout(dout_lut)); +endmodule + +module demoscene(input wire clk, + input wire [DIN_N-1:0] din, output wire [DOUT_N-1:0] dout); + parameter DIN_N = `DIN_N; + parameter DOUT_N = `DOUT_N; + + //assign dout = 8'b10101010; + demoscene_scroll dut(.clk(clk), .din(din), .dout(dout)); +endmodule + +/* +Leftmost LED counts at one second +*/ +module demoscene_counter(input wire clk, + input wire [DIN_N-1:0] din, output wire [DOUT_N-1:0] dout); + parameter DIN_N = `DIN_N; + parameter DOUT_N = `DOUT_N; + /* + 100 MHz clock + Lets get MSB to 1 second + Need 27 bits + In [3]: math.log(100e6, 2) + Out[3]: 26.5754247590989 + */ + reg [26:0] div; + always @(posedge clk) begin + div <= div + 1'b1; + end + assign dout = div[26:19]; +endmodule + +//Loosely based on http://www.asic-world.com/code/hdl_models/lfsr.v +module lfsr(input wire clk, output wire dout); + reg [7:0] out = 8'hAA; + wire feedback = !(out[7] ^ out[3]); + + always @(posedge clk) begin + out <= {out[6],out[5], + out[4],out[3], + out[2],out[1], + out[0], feedback}; + end + assign dout = out[0]; +endmodule + +// http://www.fpga4fun.com/Counters3.html +module lfsr2(input wire clk, output wire dout); + reg [7:0] LFSR = 255; + wire feedback = LFSR[7]; + assign dout = LFSR[0]; + + always @(posedge clk) begin + LFSR[0] <= feedback; + LFSR[1] <= LFSR[0]; + LFSR[2] <= LFSR[1] ^ feedback; + LFSR[3] <= LFSR[2] ^ feedback; + LFSR[4] <= LFSR[3] ^ feedback; + LFSR[5] <= LFSR[4]; + LFSR[6] <= LFSR[5]; + LFSR[7] <= LFSR[6]; + end +endmodule +/* +Scrolls an LSFR across +*/ +module demoscene_scroll(input wire clk, + input wire [DIN_N-1:0] din, output wire [DOUT_N-1:0] dout); + parameter DIN_N = `DIN_N; + parameter DOUT_N = `DOUT_N; + + reg [26:0] div; + always @(posedge clk) begin + div <= div + 1'b1; + end + + wire randbit; + lfsr2 lfsr(.clk(clk), .dout(randbit)); + + reg [7:0] leds = 8'hCC; + reg last; + reg tick; + always @(posedge clk) begin + last <= div[23]; + tick <= div[23] ^ last; + + if (tick) begin + leds = {leds, randbit}; + end + end + + assign dout = leds; +endmodule + diff --git a/minitests/roi_harness/runme.tcl b/minitests/roi_harness/runme.tcl index 43f43748..bb793082 100644 --- a/minitests/roi_harness/runme.tcl +++ b/minitests/roi_harness/runme.tcl @@ -23,7 +23,7 @@ set X_BASE $XRAY_ROI_X0 set Y_BASE $XRAY_ROI_Y0 # set Y_DIN_BASE 100 -set Y_CLK_BASE $Y_BASE +set Y_CLK_BASE $Y_BASE # Clock lut in middle set Y_DIN_BASE [expr "$Y_CLK_BASE + 1"] # Sequential @@ -199,7 +199,7 @@ if {$fixed_xdc eq ""} { set_property CFGBVS VCCO [current_design] set_property CONFIG_VOLTAGE 3.3 [current_design] - set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design] + #set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design] set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk_IBUF] @@ -306,52 +306,59 @@ 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] + 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] - } + set end_node [get_nodes -of_objects] + lappend nodes [$end_node] + } - puts "" - puts "Routing net $net:" + puts "" + puts "Routing net $net:" - foreach to_node $nodes { + 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 - } + # 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 "" + 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 } # XXX: maybe add IOB? -set fp [open "design.txt" w] -puts $fp "name node pin" +set fp [open "$outdir/design.txt" w] +puts $fp "name node pin wire" # Manual routing if {$fixed_xdc eq ""} { set x $X_BASE @@ -361,10 +368,11 @@ if {$fixed_xdc eq ""} { # But we still need to record something, so lets force a route # FIXME: very ROI specific set node "CLK_HROW_TOP_R_X60Y130/CLK_HROW_CK_BUFHCLK_L0" + set wire [node2wire $node] route_via2 "clk_IBUF_BUFG" "$node" set net "clk" set pin "$net2pin($net)" - puts $fp "$net $node $pin" + puts $fp "$net $node $pin $wire" puts "Routing ROI inputs" # Arbitrary offset as observed @@ -378,7 +386,8 @@ if {$fixed_xdc eq ""} { route_via2 "din_IBUF[$i]" "INT_R_X${x_EE2BEG3}Y${y}/EE2BEG3 $node" set net "din[$i]" set pin "$net2pin($net)" - puts $fp "$net $node $pin" + set wire [node2wire $node] + puts $fp "$net $node $pin $wire" set y [expr {$y + $PITCH}] } @@ -409,7 +418,8 @@ if {$fixed_xdc eq ""} { } set net "dout[$i]" set pin "$net2pin($net)" - puts $fp "$net $node $pin" + set wire [node2wire $node] + puts $fp "$net $node $pin $wire" set y [expr {$y + $PITCH}] } } @@ -428,6 +438,6 @@ if {$fixed_xdc eq ""} { } write_checkpoint -force $outdir/design.dcp -set_property BITSTREAM.GENERAL.DEBUGBITSTREAM YES [current_design] +#set_property BITSTREAM.GENERAL.DEBUGBITSTREAM YES [current_design] write_bitstream -force $outdir/design.bit diff --git a/minitests/roi_harness/test_demo_sw_led.py b/minitests/roi_harness/test_demo_sw_led.py new file mode 100755 index 00000000..cd5b77fd --- /dev/null +++ b/minitests/roi_harness/test_demo_sw_led.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 + +import unittest +import demo_sw_led + + +class TestStringMethods(unittest.TestCase): + def test_all(self): + for i in range(8): + print() + print() + print() + print(i) + demo_sw_led.run('out_xc7a35tcpg236-1_BASYS3-SWBUT_roi_basev', i, i) + + +if __name__ == '__main__': + unittest.main() diff --git a/tools/fasm2frame.py b/tools/fasm2frame.py index c4e845a3..d844d264 100755 --- a/tools/fasm2frame.py +++ b/tools/fasm2frame.py @@ -226,7 +226,7 @@ def run(f_in, f_out, sparse=False, debug=False): except KeyError: raise FASMSyntaxError( "Segment DB %s, key %s not found from line '%s'" % - (segj['type'], db_k, l)) + (segj['type'], db_k, l)) from None if not value: # If its binary, allow omitted value default to 1 diff --git a/tools/simpleroute.py b/tools/simpleroute.py old mode 100644 new mode 100755 index 28ac5b04..86139616 --- a/tools/simpleroute.py +++ b/tools/simpleroute.py @@ -1,16 +1,7 @@ #!/usr/bin/env python3 -import getopt, sys, os, json, re - -if len(sys.argv) == 1 or (len(sys.argv) % 2) != 1: - print() - print("Usage: %s src1 dst1 [src2 dst2 [...]]" % sys.argv[0]) - print() - print( - "Example: %s VBRK_X29Y140/VBRK_ER1BEG2 VFRAME_X47Y113/VFRAME_EL1BEG2" % - sys.argv[0]) - print() - sys.exit(1) +import sys, os, json +import pickle class MergeFind: @@ -31,134 +22,178 @@ class MergeFind: return a -print("Reading database..") +def db_gen(): + print("Reading database..") -with open("%s/%s/tilegrid.json" % (os.getenv("XRAY_DATABASE_DIR"), - os.getenv("XRAY_DATABASE")), "r") as f: - tiles = json.load(f)["tiles"] + with open("%s/%s/tilegrid.json" % (os.getenv("XRAY_DATABASE_DIR"), + os.getenv("XRAY_DATABASE")), "r") as f: + tiles = json.load(f)["tiles"] -with open("%s/%s/tileconn.json" % (os.getenv("XRAY_DATABASE_DIR"), - os.getenv("XRAY_DATABASE")), "r") as f: - tileconn = json.load(f) + with open("%s/%s/tileconn.json" % (os.getenv("XRAY_DATABASE_DIR"), + os.getenv("XRAY_DATABASE")), "r") as f: + tileconn = json.load(f) -type_to_tiles = dict() -grid_to_tile = dict() -nodes = MergeFind() + type_to_tiles = dict() + grid_to_tile = dict() + nodes = MergeFind() -for tile, tiledata in tiles.items(): - if tiledata["type"] not in type_to_tiles: - type_to_tiles[tiledata["type"]] = list() - type_to_tiles[tiledata["type"]].append(tile) - grid_to_tile[(tiledata["grid_x"], tiledata["grid_y"])] = tile + for tile, tiledata in tiles.items(): + if tiledata["type"] not in type_to_tiles: + type_to_tiles[tiledata["type"]] = list() + type_to_tiles[tiledata["type"]].append(tile) + grid_to_tile[(tiledata["grid_x"], tiledata["grid_y"])] = tile -print("Processing tileconn..") + print("Processing tileconn..") -for entry in tileconn: - type_a, type_b = entry["tile_types"] - for tile_a in type_to_tiles[type_a]: - tiledata_a = tiles[tile_a] - grid_a = (tiledata_a["grid_x"], tiledata_a["grid_y"]) - grid_b = ( - grid_a[0] + entry["grid_deltas"][0], - grid_a[1] + entry["grid_deltas"][1]) + for entry in tileconn: + type_a, type_b = entry["tile_types"] + for tile_a in type_to_tiles[type_a]: + tiledata_a = tiles[tile_a] + grid_a = (tiledata_a["grid_x"], tiledata_a["grid_y"]) + grid_b = ( + grid_a[0] + entry["grid_deltas"][0], + grid_a[1] + entry["grid_deltas"][1]) - if grid_b not in grid_to_tile: - continue - - tile_b = grid_to_tile[grid_b] - tiledata_b = tiles[tile_b] - - if tiledata_b["type"] != type_b: - continue - - for pair in entry["wire_pairs"]: - nodes.merge((tile_a, pair[0]), (tile_b, pair[1])) - -print("Processing PIPs..") - -node_node_pip = dict() -reverse_node_node = dict() -blocked_nodes = set() -active_pips = set() - -for tile_type in ["int_l", "int_r"]: - with open("%s/%s/segbits_%s.db" % (os.getenv("XRAY_DATABASE_DIR"), - os.getenv("XRAY_DATABASE"), tile_type), - "r") as f: - for line in f: - _, dst, src = line.split()[0].split(".") - for tile in type_to_tiles[tile_type.upper()]: - src_node = nodes.find((tile, src)) - dst_node = nodes.find((tile, dst)) - if src_node not in node_node_pip: - node_node_pip[src_node] = dict() - if dst_node not in reverse_node_node: - reverse_node_node[dst_node] = set() - node_node_pip[src_node][dst_node] = "%s.%s.%s" % ( - tile, dst, src) - reverse_node_node[dst_node].add(src_node) - -for argidx in range((len(sys.argv) - 1) // 2): - src_tile, src_wire = sys.argv[2 * argidx + 1].split("/") - dst_tile, dst_wire = sys.argv[2 * argidx + 2].split("/") - - src_node = nodes.find((src_tile, src_wire)) - dst_node = nodes.find((dst_tile, dst_wire)) - - print("Routing %s -> %s:" % (src_node, dst_node)) - - node_scores = dict() - - def write_scores(nodes, count): - next_nodes = set() - for n in nodes: - if n in node_scores: + if grid_b not in grid_to_tile: continue - node_scores[n] = count - if n == src_node: - return - if n in reverse_node_node: - for nn in reverse_node_node[n]: - if nn not in node_scores and nn not in blocked_nodes: - next_nodes.add(nn) - write_scores(next_nodes, count + 1) - write_scores(set([dst_node]), 1) - print(" route length: %d" % node_scores[src_node]) + tile_b = grid_to_tile[grid_b] + tiledata_b = tiles[tile_b] - count = 0 - c = src_node - blocked_nodes.add(c) - print(" %4d: %s" % (count, c)) + if tiledata_b["type"] != type_b: + continue - score = node_scores[src_node] - while c != dst_node: - nn = None - for n in node_node_pip[c].keys(): - if n in node_scores and node_scores[n] < score: - nn, score = n, node_scores[n] + for pair in entry["wire_pairs"]: + nodes.merge((tile_a, pair[0]), (tile_b, pair[1])) - pip = node_node_pip[c][nn] - active_pips.add(pip) - print(" %s" % pip) + print("Processing PIPs..") - count += 1 - c = nn + node_node_pip = dict() + reverse_node_node = dict() + + for tile_type in ["int_l", "int_r"]: + with open("%s/%s/segbits_%s.db" % + (os.getenv("XRAY_DATABASE_DIR"), os.getenv("XRAY_DATABASE"), + tile_type), "r") as f: + for line in f: + _, dst, src = line.split()[0].split(".") + for tile in type_to_tiles[tile_type.upper()]: + src_node = nodes.find((tile, src)) + dst_node = nodes.find((tile, dst)) + if src_node not in node_node_pip: + node_node_pip[src_node] = dict() + if dst_node not in reverse_node_node: + reverse_node_node[dst_node] = set() + node_node_pip[src_node][dst_node] = "%s.%s.%s" % ( + tile, dst, src) + reverse_node_node[dst_node].add(src_node) + + return type_to_tiles, grid_to_tile, nodes, node_node_pip, reverse_node_node + + +def db_load(): + # Takes a while. Speed things up + picklef = os.getenv('XRAY_DIR') + '/tools/simpleroute.p' + if os.path.exists(picklef): + #print('Pickle: load') + db_res = pickle.load(open(picklef, 'rb')) + else: + #print('Pickle: rebuilding') + db_res = db_gen() + #print('Pickle: save') + pickle.dump(db_res, open(picklef, 'wb')) + return db_res + + +type_to_tiles, grid_to_tile, nodes, node_node_pip, reverse_node_node = db_load( +) + + +def route(args): + active_pips = set() + blocked_nodes = set() + + for argidx in range((len(args)) // 2): + src_tile, src_wire = args[2 * argidx].split("/") + dst_tile, dst_wire = args[2 * argidx + 1].split("/") + + src_node = nodes.find((src_tile, src_wire)) + dst_node = nodes.find((dst_tile, dst_wire)) + + print("Routing %s -> %s:" % (src_node, dst_node)) + + node_scores = dict() + + def write_scores(nodes, count): + next_nodes = set() + for n in nodes: + if n in node_scores: + continue + node_scores[n] = count + if n == src_node: + return + if n in reverse_node_node: + for nn in reverse_node_node[n]: + if nn not in node_scores and nn not in blocked_nodes: + next_nodes.add(nn) + write_scores(next_nodes, count + 1) + + try: + write_scores(set([dst_node]), 1) + except RecursionError as e: + raise Exception("Could not find route for node %s" % + (dst_node, )) from None + print(" route length: %d" % node_scores[src_node]) + + count = 0 + c = src_node blocked_nodes.add(c) print(" %4d: %s" % (count, c)) -print("====") -pipnames = list() + score = node_scores[src_node] + while c != dst_node: + nn = None + for n in node_node_pip[c].keys(): + if n in node_scores and node_scores[n] < score: + nn, score = n, node_scores[n] -for pip in sorted(active_pips): - tile, dst, src = pip.split(".") - pipnames.append("%s/%s.%s->>%s" % (tile, tile[0:5], src, dst)) + pip = node_node_pip[c][nn] + active_pips.add(pip) + print(" %s" % pip) -print( - "highlight_objects -color orange [get_nodes -of_objects [get_wires {%s}]]" - % " ".join(["%s/%s" % n for n in sorted(blocked_nodes)])) -print("highlight_objects -color orange [get_pips {%s}]" % " ".join(pipnames)) + count += 1 + c = nn + blocked_nodes.add(c) + print(" %4d: %s" % (count, c)) -print("====") -for pip in sorted(active_pips): - print(pip) + print("====") + pipnames = list() + + for pip in sorted(active_pips): + tile, dst, src = pip.split(".") + pipnames.append("%s/%s.%s->>%s" % (tile, tile[0:5], src, dst)) + + print( + "highlight_objects -color orange [get_nodes -of_objects [get_wires {%s}]]" + % " ".join(["%s/%s" % n for n in sorted(blocked_nodes)])) + print( + "highlight_objects -color orange [get_pips {%s}]" % " ".join(pipnames)) + + print("====") + for pip in sorted(active_pips): + print(pip) + return active_pips + + +if __name__ == '__main__': + if len(sys.argv) == 1 or (len(sys.argv) % 2) != 1: + print() + print("Usage: %s src1 dst1 [src2 dst2 [...]]" % sys.argv[0]) + print("Where entires as tile/wire") + print() + print( + "Example: %s VBRK_X29Y140/VBRK_ER1BEG2 VFRAME_X47Y113/VFRAME_EL1BEG2" + % sys.argv[0]) + print() + sys.exit(1) + route(sys.argv[1:])