Latest version. Signed-off-by: Tim 'mithro' Ansell <tansell@google.com>
diff --git a/spec/bram_init.py b/spec/bram_init.py new file mode 100644 index 0000000..897311b --- /dev/null +++ b/spec/bram_init.py
@@ -0,0 +1,66 @@ +# Copyright 2020 Project U-Ray Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys +import numpy as np + +bram_init = [] # ypos -> init; initp + +for y in range(0, 24): + bram_init.append(( + np.random.randint(0, 2, size=16384), + np.random.randint(0, 2, size=2048), + )) + +with open(sys.argv[1] + "/braminit/bram.v", "w") as f: + print("module top;", file=f) + for y in range(0, 24): + print("(* KEEP, DONT_TOUCH, LOC=\"RAMB18_X1Y%d\" *)" % y, file=f) + print("RAMB18E2 #(", file=f) + for i in range(0, 64): + print(" .INIT_%02X(256'b%s)," % (i, "".join([str(x) for x in reversed(bram_init[y][0][ i*256 : (i+1)*256 ])])), file=f) + for i in range(0, 8): + print(" .INITP_%02X(256'b%s)," % (i, "".join([str(x) for x in reversed(bram_init[y][1][ i*256 : (i+1)*256 ])])), file=f) + print(" .DOA_REG(1'b0)", file=f) # just here for simpler commas + print(") bram_%d ();" % y, file=f) + print("endmodule", file=f) + +with open(sys.argv[1] + "/braminit/bram.txt", "w") as f: + for y in range(0, 24): + site_y = y % 2 + tile_y = y // 2 + startbit = tile_y * 240 + if tile_y >= 6: + startbit += 96 + for frame in range(0, 256): + print("%d %d %d %s %s" % + ( + frame, + startbit, + site_y, + "".join(str(x) for x in bram_init[y][0][ frame*64 : (frame+1)*64 ]), + "".join(str(x) for x in bram_init[y][1][ frame*8 : (frame+1)*8 ]), + ), file=f) +with open(sys.argv[1] + "/braminit/build.tcl", "w") as f: + print("add_files %s" % (sys.argv[1] + "/braminit/bram.v"), file=f) + print("synth_design -top top -part xczu7ev-ffvc1156-2-e", file=f) + print("# set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets]", file=f) + print("opt_design", file=f) + print("place_design", file=f) + print("route_design", file=f) + print("set_property SEVERITY {Warning} [get_drc_checks]", file=f) + print("set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design]", file=f) + print("write_checkpoint -force bram.dcp", file=f) + print("write_edif -force bram.edf", file=f) + print("write_bitstream -force bram.bit", file=f)
diff --git a/spec/bufce_fsr_tap.tcl b/spec/bufce_fsr_tap.tcl new file mode 100644 index 0000000..e1ec1d9 --- /dev/null +++ b/spec/bufce_fsr_tap.tcl
@@ -0,0 +1,81 @@ +// Copyright 2020 Project U-Ray Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +proc random_site {object type} { + while {1} { + set sites [get_sites -of_objects $object -filter "SITE_TYPE == $type" ] + if {[llength $sites] == 0} { + return {} + } + set site [lindex $sites [expr {int(rand()*[llength $sites])}]] + if {[llength [get_cells -of_objects $site]] == 0} { + break + } + } + return $site +} + +set run $::argv +create_project -force -part xczu7ev-ffvf1517-2-e design${run} design${run} + + +link_design +create_cell -reference LUT6 "misc_lut" +place_design +route_design + +remove_cell drv* ff* +remove_net clk* + +foreach tile [get_tiles -filter {TILE_TYPE == CMT_L}] { + if {[expr rand()] > 0.6} { + continue + } + set drv_site [random_site $tile "BUFGCE_DIV"] + create_cell -reference BUFGCE_DIV "driver_$tile" + set drv_bel "$drv_site/BUFGCE_DIV" + place_cell "driver_$tile" $drv_bel + create_net "clk_dly_fuzz_$tile" + set clk [get_nets "clk_dly_fuzz_$tile"] + connect_net -net $clk -objects [get_pins "driver_$tile/O"] + create_clock $clk -period 10 + foreach region [get_clock_regions] { + set ssite [random_site $region "SLICEL"] + if {$ssite == {}} { + continue + } + create_cell -reference FDRE "sink_$ssite" + place_cell "sink_$ssite" "$ssite/AFF" + connect_net -net $clk -objects [get_pins "sink_$ssite/C"] + } + set success 0 + while {$success == 0} { + set regions [get_clock_regions] + set region [lindex $regions [expr {int(rand()*[llength $regions])}]] + set_property USER_CLOCK_ROOT $region $clk + if {[catch {update_clock_routing}]} { + continue + } + set success 1 + } +} + +route_design + +set_property SEVERITY {Warning} [get_drc_checks] +set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design] +write_checkpoint -force ../specimen_clk/bufce_tap_a${run}.dcp +write_edif -force ../specimen_clk/bufce_tap_a${run}.edf +write_bitstream -force ../specimen_clk/bufce_tap_a${run}.bit +
diff --git a/spec/bufce_leaf_tap.tcl b/spec/bufce_leaf_tap.tcl new file mode 100644 index 0000000..16fef86 --- /dev/null +++ b/spec/bufce_leaf_tap.tcl
@@ -0,0 +1,60 @@ +// Copyright 2020 Project U-Ray Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +remove_cell ff* dlylut* driver* +remove_net clk* loop* + +set drv_site [get_sites "BUFGCE_DIV_X0Y16"] +create_cell -reference BUFGCE_DIV "driver_0" +set drv_bel "$drv_site/BUFGCE_DIV" +place_cell "driver_0" $drv_bel +create_net "clk_fuzz" +set clk [get_nets "clk_fuzz"] +connect_net -net $clk -objects [get_pins "driver_0/O"] + +create_clock $clk -period 2.7 + +for {set x 0} {$x < 112} {incr x 4} { + set site [get_sites "SLICE_X${x}Y260"] + set luts [get_bels -of_objects $site "*LUT"] + create_cell -reference FDRE "ff_launch_${site}" + place_cell "ff_launch_${site}" "${site}/AFF" + connect_net -net $clk -objects [get_pins "ff_launch_${site}/C"] + create_net "loop_init_${site}" + set q [get_nets "loop_init_${site}"] + connect_net -net $q -objects [get_pins "ff_launch_${site}/Q"] + set depth [expr {int(10 + 6*rand())}] + for {set i 0} {$i < $depth} {incr i} { + create_cell -reference LUT1 "dlylut_${i}_${site}" + set_property INIT 1 [get_cells "dlylut_${i}_${site}"] + place_cell "dlylut_${i}_${site}" [lindex $luts $i] + connect_net -net $q -objects [get_pins "dlylut_${i}_${site}/I0"] + create_net "loop_${i}_${site}" + set q [get_nets "loop_${i}_${site}"] + connect_net -net $q -objects [get_pins "dlylut_${i}_${site}/O"] + } + + set cx [expr {$x+2}] + set csite [get_sites "SLICE_X${cx}Y260"] + create_cell -reference FDRE "ff_capture_${site}" + place_cell "ff_capture_${site}" "${csite}/HFF" + connect_net -net $clk -objects [get_pins "ff_capture_${site}/C"] + connect_net -net $q -objects [get_pins "ff_capture_${site}/D"] +} + +route_design + +set_property SEVERITY {Warning} [get_drc_checks] +set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design] +
diff --git a/spec/clkroute.py b/spec/clkroute.py new file mode 100644 index 0000000..a9107a6 --- /dev/null +++ b/spec/clkroute.py
@@ -0,0 +1,44 @@ +# Copyright 2020 Project U-Ray Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys +root = sys.argv[1] + +X = 8 + +with open(root + "/rclkroute_leafdly/run.sh", "w") as f: + print("#/usr/bin/env bash", file=f) + print("set -ex", file=f) + print("vivado -mode batch -nolog -nojournal -source ../../ultra/spec/delayfuzz.tcl -tclargs $1", file=f) + print("if [ $? -eq 0 ]; then", file=f) + print(" ../../ultra/tools/dump_bitstream %s/specimen_clk/rclkroute_leafdly$1.bit %s/frames.txt > %s/specimen_clk/rclkroute_leafdly$1.dump" % (root, root, root), file=f) + print(" CLOCK_ONLY=1 python3 ../../ultra/tools/bits_to_tiles.py %s/tilebits.json %s/specimen_clk/rclkroute_leafdly$1.dump > %s/specimen_clk/rclkroute_leafdly$1.tbits" % (root, root, root), file=f) + #print(" rm %s/specimen_clk/rclkroute$1.bit" % (root, ), file=f) + #print(" rm %s/specimen_clk/rclkroute$1.dump" % (root, ), file=f) + print("else", file=f) + print(" rm %s/specimen_clk/rclkroute_leafdly$1.dump" % (root, ), file=f) + print(" rm %s/specimen_clk/rclkroute_leafdly$1.tbits" % (root, ), file=f) + print(" rm %s/specimen_clk/rclkroute_leafdly$1.dcp" % (root, ), file=f) + print(" rm %s/specimen_clk/rclkroute_leafdly$1.bit" % (root, ), file=f) + print(" rm %s/specimen_clk/rclkroute_leafdly$1.features" % (root, ), file=f) + print("fi", file=f) +with open(root + "/rclkroute_leafdly/Makefile", "w") as f: + print("all: %s" % " ".join(["%d.done" % i for i in range(X)]), file=f) + print("", file=f) + print("%.done: ", file=f) + print("\tbash run.sh $*", file=f) + print("\ttouch $@", file=f) + print("", file=f) + print("clean: ", file=f) + print("\trm -f *.done", file=f)
diff --git a/spec/clkroute_io.py b/spec/clkroute_io.py new file mode 100644 index 0000000..1151814 --- /dev/null +++ b/spec/clkroute_io.py
@@ -0,0 +1,44 @@ +# Copyright 2020 Project U-Ray Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys +root = sys.argv[1] + +X = 40 + +with open(root + "/xclkroute/run.sh", "w") as f: + print("#/usr/bin/env bash", file=f) + print("set -ex", file=f) + print("vivado -mode batch -nolog -nojournal -source ../../ultra/spec/xiphy_clk_mux.tcl -tclargs $1", file=f) + print("if [ $? -eq 0 ]; then", file=f) + print(" ../../ultra/tools/dump_bitstream %s/specimen_clk/xclkroute_a$1.bit %s/frames.txt > %s/specimen_clk/xclkroute_a$1.dump" % (root, root, root), file=f) + print(" CLOCK_ONLY=1 python3 ../../ultra/tools/bits_to_tiles.py %s/tilebits.json %s/specimen_clk/xclkroute_a$1.dump > %s/specimen_clk/xclkroute_a$1.tbits" % (root, root, root), file=f) + #print(" rm %s/specimen_clk/rclkroute$1.bit" % (root, ), file=f) + #print(" rm %s/specimen_clk/rclkroute$1.dump" % (root, ), file=f) + print("else", file=f) + print(" rm %s/specimen_clk/xclkroute_a$1.dump" % (root, ), file=f) + print(" rm %s/specimen_clk/xclkroute_a$1.tbits" % (root, ), file=f) + print(" rm %s/specimen_clk/xclkroute_a$1.dcp" % (root, ), file=f) + print(" rm %s/specimen_clk/xclkroute_a$1.bit" % (root, ), file=f) + print(" rm %s/specimen_clk/xclkroute_a$1.features" % (root, ), file=f) + print("fi", file=f) +with open(root + "/xclkroute/Makefile", "w") as f: + print("all: %s" % " ".join(["%d.done" % i for i in range(X)]), file=f) + print("", file=f) + print("%.done: ", file=f) + print("\tbash run.sh $*", file=f) + print("\ttouch $@", file=f) + print("", file=f) + print("clean: ", file=f) + print("\trm -f *.done", file=f)
diff --git a/spec/clkroute_tap.py b/spec/clkroute_tap.py new file mode 100644 index 0000000..60ae37e --- /dev/null +++ b/spec/clkroute_tap.py
@@ -0,0 +1,44 @@ +# Copyright 2020 Project U-Ray Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys +root = sys.argv[1] + +X = 20 + +with open(root + "/fsrtap/run.sh", "w") as f: + print("#/usr/bin/env bash", file=f) + print("set -ex", file=f) + print("vivado -mode batch -nolog -nojournal -source ../../ultra/spec/bufce_fsr_tap.tcl -tclargs $1", file=f) + print("if [ $? -eq 0 ]; then", file=f) + print(" ../../ultra/tools/dump_bitstream %s/specimen_clk/bufce_tap_a$1.bit %s/frames.txt > %s/specimen_clk/bufce_tap_a$1.dump" % (root, root, root), file=f) + print(" CLOCK_ONLY=1 python3 ../../ultra/tools/bits_to_tiles.py %s/tilebits.json %s/specimen_clk/bufce_tap_a$1.dump > %s/specimen_clk/bufce_tap_a$1.tbits" % (root, root, root), file=f) + #print(" rm %s/specimen_clk/rclkroute$1.bit" % (root, ), file=f) + #print(" rm %s/specimen_clk/rclkroute$1.dump" % (root, ), file=f) + print("else", file=f) + print(" rm %s/specimen_clk/bufce_tap_a$1.dump" % (root, ), file=f) + print(" rm %s/specimen_clk/bufce_tap_a$1.tbits" % (root, ), file=f) + print(" rm %s/specimen_clk/bufce_tap_a$1.dcp" % (root, ), file=f) + print(" rm %s/specimen_clk/bufce_tap_a$1.bit" % (root, ), file=f) + print(" rm %s/specimen_clk/bufce_tap_a$1.features" % (root, ), file=f) + print("fi", file=f) +with open(root + "/fsrtap/Makefile", "w") as f: + print("all: %s" % " ".join(["%d.done" % i for i in range(X)]), file=f) + print("", file=f) + print("%.done: ", file=f) + print("\tbash run.sh $*", file=f) + print("\ttouch $@", file=f) + print("", file=f) + print("clean: ", file=f) + print("\trm -f *.done", file=f)
diff --git a/spec/delayfuzz.tcl b/spec/delayfuzz.tcl new file mode 100644 index 0000000..82cd975 --- /dev/null +++ b/spec/delayfuzz.tcl
@@ -0,0 +1,281 @@ +// Copyright 2020 Project U-Ray Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +proc make_driver_cell {name netname celltype loc pinname} { + create_net $netname + set net [get_nets $netname] + create_cell -reference $celltype "${name}_drv" + place_cell "${name}_drv" $loc + connect_net -net $net -objects [get_pins "${name}_drv/${pinname}"] + return [list [get_cells "${name}_drv"] $net] +} + +proc make_user_cell {name celltype loc pinname net} { + create_cell -reference $celltype "${name}_usr" + place_cell "${name}_usr" $loc + connect_net -net $net -objects [get_pins "${name}_usr/${pinname}"] + return [list [get_cells "${name}_usr"] $net] +} + + +proc make_site_pin_driver {pin netname} { + set site [get_sites -of_objects $pin] + if { $site == {} } { + return {} + } + set sitetype [get_property SITE_TYPE $site] + set pinname [lindex [split $pin "/"] 1] + set objname "${site}_${pinname}" + if {[get_cells -of_objects $site] != {}} { + return {} + } + if {$sitetype == "BUFCE_ROW" && $pinname == "CLK_OUT"} { + return [make_driver_cell $objname $netname "BUFCE_ROW" "$site/BUFCE" "O"] + } elseif {$sitetype == "BUFCE_ROW_FSR" && $pinname == "CLK_OUT"} { + return [make_driver_cell $objname $netname "BUFCE_ROW" "$site/BUFCE" "O"] + } elseif {$sitetype == "BUFGCE" && $pinname == "CLK_OUT"} { + return [make_driver_cell $objname $netname "BUFGCE" "$site/BUFCE" "O"] + } elseif {$sitetype == "BUFGCE_HDIO" && $pinname == "CLK_OUT"} { + return [make_driver_cell $objname $netname "BUFGCE" "$site/BUFCE" "O"] + } elseif {$sitetype == "BUFGCE_DIV" && $pinname == "CLK_OUT"} { + set result [make_driver_cell $objname $netname "BUFGCE_DIV" "$site/BUFGCE_DIV" "O"] + set_property BUFGCE_DIVIDE 1 [lindex $result 0] + return $result + } elseif {$sitetype == "BUFGCTRL" && $pinname == "CLK_OUT"} { + return [make_driver_cell $objname "BUFGCTRL" "$site/BUFGCTRL" "O"] + } else { + return {} + } +} + +proc make_site_pin_user {pin net} { + set site [get_sites -of_objects $pin] + if { $site == {} } { + return {} + } + set sitetype [get_property SITE_TYPE $site] + set pinname [lindex [split $pin "/"] 1] + set objname "${site}_${pinname}" + if {[get_cells -of_objects $site] != {}} { + return {} + } + if {($sitetype == "SLICEM" || $sitetype == "SLICEL") && $pinname == "CLK1"} { + return [make_user_cell $objname "FDRE" "$site/AFF" "C" $net] + } elseif {($sitetype == "SLICEM" || $sitetype == "SLICEL") && $pinname == "CLK2"} { + return [make_user_cell $objname "FDRE" "$site/EFF" "C" $net] + } else { + return {} + } +} + +proc string_insert {string index insertString} { + # Convert end-relative and TIP 176 indexes to simple integers. + if {[regexp -expanded { + ^(end(?![\t\n\v\f\r ]) # "end" is never followed by whitespace + |[\t\n\v\f\r ]*[+-]?\d+) # m, with optional leading whitespace + (?:([+-]) # op, omitted when index is "end" + ([+-]?\d+))? # n, omitted when index is "end" + [\t\n\v\f\r ]*$ # optional whitespace (unless "end") + } $index _ m op n]} { + # Convert first index to an integer. + switch $m { + end {set index [string length $string]} + default {scan $m %d index} + } + + # Add or subtract second index, if provided. + switch $op { + + {set index [expr {$index + $n}]} + - {set index [expr {$index - $n}]} + } + } elseif {![string is integer -strict $index]} { + # Reject invalid indexes. + return -code error "bad index \"$index\": must be\ + integer?\[+-\]integer? or end?\[+-\]integer?" + } + + # Concatenate the pre-insert, insertion, and post-insert strings. + set a [string range $string 0 [expr {$index - 1}]] + set b [string range $string $index end] + return "${a}${insertString}${b}" +} + + +proc route_via {net sink_pin extra_node pip} { + set success 0 + set src [lindex [get_nodes -of_objects [get_site_pins -filter {DIRECTION == OUT} -of_objects $net]] 0] + set sink [get_nodes -of_objects [get_site_pins -filter {DIRECTION == IN} -of_objects $net ]] + if {$sink == {}} { + set sink [get_nodes -of_objects $sink_pin] + } + set_property IS_ROUTE_FIXED 0 $net + #route_design -unroute -nets $net + + set from_node [get_nodes -uphill -of_objects $pip] + set to_node [get_nodes -downhill -of_objects $pip] + if {$src == $from_node} { + set route_a $from_node + } else { + if {[catch {set route_a [find_routing_path -max_nodes 12 -from $src -to $from_node]}]} { + return 0 + } + if {$route_a == ""} { + return 0 + } + } + if {$sink == $to_node} { + set route_b $to_node + } else { + if {[catch {set route_b [find_routing_path -max_nodes 8 -from $to_node -to $sink]}]} { + return 0 + } + if {$route_b == ""} { + return 0 + } + } + + set route_b [string_insert $route_b [string first " " $route_b] " $extra_node "] + + if {[catch {set_property FIXED_ROUTE "$route_a $route_b" $net}]} { + return 0 + } + set_property IS_ROUTE_FIXED 1 $net + if {[get_property ROUTE_STATUS $net] != "ROUTED"} { + set_property IS_ROUTE_FIXED 0 $net + route_design -unroute -nets $net + return 0 + } + return 1 +} + +# https://wiki.tcl-lang.org/page/Shuffle+a+list +proc shuffle6 { list } { + set n [llength $list] + for { set i 1 } { $i < $n } { incr i } { + set j [expr { int( rand() * $n ) }] + set temp [lindex $list $i] + lset list $i [lindex $list $j] + lset list $j $temp + } + return $list + } + +set tile_types [list "RCLK_INT_L" "RCLK_INT_R"] + +set run $::argv +create_project -force -part xczu7ev-ffvf1517-2-e design${run} design${run} + + +link_design +create_cell -reference LUT6 "misc_lut" +place_design +route_design + +#remove_cell [get_cells] +#remove_net [get_nets] + +set count [expr {int(120 + rand()*80)}] +set delay_values [list 0 1 2 4 8] + +for {set i 0} {$i < $count} {incr i} { + puts "$i/$count" + for {set j 0} {$j < 20} {incr j} { + set tt [lindex $tile_types [expr {int(rand()*[llength $tile_types])}]] + set tiles [get_tiles -filter "TILE_TYPE == $tt"] + set tile [lindex $tiles [expr {int(rand()*[llength $tiles])}]] + set tile_pips [get_pips -of_objects $tile -filter {NAME !~ "*VCC_WIRE*"} "*CLK_IN*CLK_LEAF"] + puts $tile_pips + set pip [lindex $tile_pips [expr {int(rand()*[llength $tile_pips])}]] + if {[string first "CE_INT" $pip] != -1} { + continue + } + puts $pip + set wavefront_bwd $pip + set driver {} + set dly [lindex $delay_values [expr {int(rand()*[llength $delay_values])}]] + set netname "leaf_delay_${dly}_${i}" + for {set k 0} {$k < 12} {incr k} { + set wavefront_bwd [get_nodes -uphill -of_objects $wavefront_bwd] + + set wavefront_pins [get_site_pins -of_objects $wavefront_bwd] + foreach pin $wavefront_pins { + set driver [make_site_pin_driver $pin $netname] + if {$driver != {}} { + break + } + } + + if {$driver != {}} { + break + } + if {[llength $wavefront_bwd] > 20000} { + break + } + } + + puts $driver + + if {$driver == {}} { + continue + } + + set drv_cell [lindex $driver 0] + set net [lindex $driver 1] + + set wavefront_fwd $pip + set user {} + for {set k 0} {$k < 8} {incr k} { + set wavefront_fwd [get_nodes -downhill -of_objects $wavefront_fwd] + # Randomly skip to vary depth + if {rand() > 0.5} { + set wavefront_pins [get_site_pins -of_objects $wavefront_fwd] + foreach pin $wavefront_pins { + set user [make_site_pin_user $pin $net] + set sink_pin $pin + if {$user != {}} { + break + } + } + } + if {$user != {}} { + break + } + if {[llength $wavefront_fwd] > 20000} { + break + } + } + + if {$user == {}} { + remove_cell $drv_cell + remove_net $net + continue + } + + set success [route_via $net $sink_pin "NoTile/Delay_Arc_Index=${dly}" $pip] + if { $success == 0 } { + remove_cell $drv_cell + remove_cell [lindex $user 0] + remove_net $net + } else { + break + } + } +} + +set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design] +set_property SEVERITY {Warning} [get_drc_checks] +write_checkpoint -force ../specimen_clk/rclkroute_leafdly${run}.dcp +write_edif -force ../specimen_clk/rclkroute_leafdly${run}.edf +write_bitstream -force ../specimen_clk/rclkroute_leafdly${run}.bit +
diff --git a/spec/diff_io.py b/spec/diff_io.py new file mode 100644 index 0000000..a0116bf --- /dev/null +++ b/spec/diff_io.py
@@ -0,0 +1,276 @@ +# Copyright 2020 Project U-Ray Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import numpy as np +import sys + +X = 40 + +root = sys.argv[1] + +pins = [] +bank_to_pins = {} +bank_to_iotype = {} +site_to_pin = {} +pin_to_bank = {} +with open (root + "/iopins.txt", "r") as iof: + for line in iof: + sl = line.strip().split(",") + if len(sl) < 5: + continue + pin = sl[0] + bank = int(sl[1]) + func = sl[2] + site_name = sl[3] + site_type = sl[4] + pins.append((pin, bank, func, site_name, site_type)) + if bank not in bank_to_pins: + bank_to_pins[bank] = [] + bank_to_pins[bank].append(pin) + pin_to_bank[pin] = bank + if bank not in bank_to_iotype: + bank_to_iotype[bank] = site_type.split("_")[0] + site_to_pin[site_name] = pin + +for x in range(X): + used_pins = [] + io_config = [] + + bank_to_vcc = {} + bank_pod_used = set() + bank_pod_not_used = set() + lut_inputs = [] + lut_outputs = [] + bank_iref = {} + bound_pins = set() + def inp(): + sig = "li[%d]" % len(lut_inputs) + lut_inputs.append(sig) + return sig + def outp(): + sig = "lo[%d]" % len(lut_outputs) + lut_outputs.append(sig) + return sig + def maybe_inp(): + return inp() if np.random.choice([True, False]) else "" + def maybe_outp(): + return outp() if np.random.choice([True, False]) else "" + + for b, t in sorted(bank_to_iotype.items()): + if t == "HPIOB": + bank_to_vcc[b] = np.random.choice( + ["1.0", "1.2", "1.35", "1.5", "1.8"] + ) + elif t == "HDIOB": + bank_to_vcc[b] = np.random.choice( + ["1.2", "1.5", "1.8", "2.5", "3.3"] + ) + else: + assert False, t + standards = { + ("HPIOB", "1.8"): ["DIFF_SSTL18_I", "DIFF_SSTL18_I_DCI", "SLVS_400_18", "LVDS"], + ("HPIOB", "1.5"): ["DIFF_SSTL15", "DIFF_SSTL15_DCI"], + ("HPIOB", "1.35"): ["DIFF_SSTL135", "DIFF_SSTL135_DCI"], + ("HPIOB", "1.2"): ["DIFF_SSTL12", "DIFF_SSTL12_DCI", + "DIFF_HSUL_12", "DIFF_HSUL_12_DCI", + "DIFF_POD12", "DIFF_POD12_DCI"], + ("HPIOB", "1.0"): ["DIFF_POD10", "DIFF_POD10_DCI"], + } + + prims = { + "HPIOB": ["IBUFDS", "OBUFDS", "OBUFTDS", "IOBUFDS", "IOBUFDSE3"], + #"HDIOB": ["IBUF","OBUF", "OBUFT", "IOBUF"] + } + for (pin, bank, func, sn, st) in pins: + if "VREF" in func: + continue # conflict + if "VRP" in func or "VRN" in func: + continue # conflict + if "HPIOB_M" not in st: + continue + if np.random.choice([True, True, False]): + continue # improved fuzzing + params = {} + iot = st.split("_")[0] + assert (iot, bank_to_vcc[bank]) in standards, (pin, bank, iot, bank_to_vcc[bank]) + ios = np.random.choice(standards[iot, bank_to_vcc[bank]]) + if bank in bank_pod_used and ios in ("DIFF_HSTL_I_12", "DIFF_HSTL_I_DCI_12", "DIFF_SSTL12", "DIFF_SSTL12_DCI", "DIFF_HSUL_12", "DIFF_HSUL_12_DCI"): + continue + if bank in bank_pod_not_used and ios in ("DIFF_POD12", "DIFF_POD12_DCI"): + continue + params["IOSTANDARD"] = ios + prim = np.random.choice(prims[iot]) + + if ios == "SLVS_400_18": + prim = "IBUFDS" + + params["prim"] = prim + if prim in ("OBUFDS", "OBUFTDS", "IOBUFDS", "IOBUFDSE3"): + if iot == "HPIOB": + params["SLEW"] = np.random.choice(["SLOW", "MEDIUM", "FAST"]) + else: + params["SLEW"] = np.random.choice(["SLOW", "FAST"]) + if iot == "HPIOB" and ("POD" in ios or "SSTL" in ios): + params["OUTPUT_IMPEDANCE"] = np.random.choice(["RDRV_40_40", "RDRV_48_48", "RDRV_60_60"]) + if prim in ("IBUFDS", "IOBUFDS", "IOBUFDSE3", "IBUFDS_IBUFDISABLE", "IBUFDS_INTERMDISABLE"): + if "POD" in ios: + odt_choices = [] + if "DCI" not in ios: + odt_choices.append("RTT_NONE") + if "OUTPUT_IMPEDANCE" not in params or params["OUTPUT_IMPEDANCE"] != "RDRV_48_48": + odt_choices += ["RTT_40", "RTT_60"] + else: + odt_choices += ["RTT_48"] + params["ODT"] = np.random.choice(odt_choices) + if "POD12" in ios: + params["EQUALIZATION"] = np.random.choice(["EQ_LEVEL0", "EQ_LEVEL1", "EQ_LEVEL2", "EQ_LEVEL3", "EQ_LEVEL4", "EQ_NONE"]) + if "LVDS" in ios or "SLVS" in ios: + params["DIFF_TERM_ADV"] = np.random.choice(["TERM_NONE", "TERM_100"]) + used_pins.append(pin) + io_config.append(params) + + if ios in ("DIFF_POD12", "DIFF_POD12_DCI"): + bank_pod_used.add(bank) + if ios in ("DIFF_HSTL_I_12", "DIFF_HSTL_I_DCI_12", "DIFF_SSTL12", "DIFF_SSTL12_DCI", "DIFF_HSUL_12", "DIFF_HSUL_12_DCI"): + bank_pod_not_used.add(bank) + with open(root + "/diffio/diffio%d.v" % x, "w") as f: + print("module top(", file=f); + for i, params in enumerate(io_config): + prim = params["prim"] + bank = pin_to_bank[used_pins[i]] + if bank in bank_iref and bank_iref[bank] is not None: + params["int_vref"] = bank_iref[bank] + print ("(* %s *)" % ", ".join('X_%s="%s"' % (k, v) for k, v in sorted(params.items())), file=f) + if prim in ("IBUFDS", "IBUFDS_IBUFDISABLE"): + print("input p%d, pn%d%s" % (i, i, "," if i < len(io_config)-1 else ""), file=f) + elif prim in ("OBUFDS", "OBUFTDS"): + print("output p%d, pn%d%s" % (i, i, "," if i < len(io_config)-1 else ""), file=f) + elif prim in ("IOBUFDS", "IOBUFDSE3"): + print("inout p%d, pn%d%s" % (i, i, "," if i < len(io_config)-1 else ""), file=f) + print(");", file=f) + for i, params in enumerate(io_config): + print("(* KEEP, DONT_TOUCH *)", file=f) + prim = params["prim"] + if prim == "IBUFDS": + print(""" + IBUFDS buf_{i} ( + .I(p{i}), .IB(pn{i}), + .O({sig_o}) + ); + """.format(i=i, sig_o=maybe_inp()), file=f) + elif prim == "OBUFDS": + print(""" + OBUFDS buf_{i} ( + .O(p{i}), .OB(pn{i}), + .I({sig_i}) + ); + """.format(i=i, sig_i=maybe_outp()), file=f) + elif prim == "OBUFTDS": + print(""" + OBUFTDS buf_{i} ( + .O(p{i}), .OB(pn{i}), + .T({sig_t}), + .I({sig_i}) + ); + """.format(i=i, sig_t=outp(), sig_i=maybe_outp()), file=f) + elif prim == "IOBUFDS": + print(""" + IOBUFDS buf_{i} ( + .IO(p{i}), .IOB(pn{i}), + .T({sig_t}), + .I({sig_i}), + .O({sig_o}) + ); + """.format(i=i, sig_t=maybe_outp(), sig_i=maybe_outp(), sig_o=maybe_inp()), file=f) + elif prim == "IOBUFDSE3": + if np.random.choice([True, False]): + print("(* KEEP, DONT_TOUCH *)", file=f) + print(""" + IOBUFDSE3 buf_{i} ( + .IO(p{i}), .IOB(pn{i}), + .T({sig_t}), + .I({sig_i}), + .O({sig_o}), + .DCITERMDISABLE({dci_dis}), + .IBUFDISABLE({ibuf_dis}) + ); + """.format(i=i, sig_t=maybe_outp(), sig_i=maybe_outp(), sig_o=maybe_inp(), + dci_dis=maybe_outp(), ibuf_dis=maybe_outp()), file=f) + print("", file=f) + print("wire [%d:0] li;" % (len(lut_inputs)-1), file=f) + print("wire [%d:0] lo;" % (len(lut_outputs)-1), file=f) + + for i in range(max(len(lut_inputs)//6 + 1, len(lut_outputs))): + ip = ["1'b0" if (i * 6 + j) >= len(lut_inputs) else "li[%d]" % (i * 6 + j) for j in range(6)] + op = "lo[%d]" % i if i < len(lut_outputs) else "" + print(""" + (* KEEP, DONT_TOUCH *) + LUT6 lut{i} (.I0({i0}), .I1({i1}), .I2({i2}), .I3({i3}), .I4({i4}), .I5({i5}), .O({o})); + """.format( + i=i, i0=ip[0], i1=ip[1], i2=ip[2], i3=ip[3], i4=ip[4], i5=ip[5], o=op, + ), file=f) + print("endmodule", file=f) + with open(root + "/diffio/diffio%d.xdc" % x, "w") as f: + for i, params in enumerate(io_config): + pin = used_pins[i] + print("set_property PACKAGE_PIN %s [get_ports {p%d}]" % (pin, i), file=f) + for k, v in sorted(params.items()): + if k.isupper(): + print("set_property %s %s [get_ports {p%d}]" % (k, v, i), file=f) + for bank, iref in sorted(bank_iref.items()): + if iref is None: + continue + print("set_property INTERNAL_VREF {%s} [get_iobanks %d]" % (iref, bank), file=f) + with open(root + "/diffio/diffio%d.tcl" % x, "w") as f: + print("add_files %s" % (root + ("/diffio/diffio%d.v" % x)), file=f) + print("add_files %s" % (root + ("/diffio/diffio%d.xdc" % x)), file=f) + print("synth_design -top top -part xczu7ev-ffvf1517-2-e", file=f) + print("set_property SEVERITY {Warning} [get_drc_checks NSTD-1]", file=f) + print("set_property SEVERITY {Warning} [get_drc_checks UCIO-1]", file=f) + print("set_property SEVERITY {Warning} [get_drc_checks AVAL-*]", file=f) + print("set_property SEVERITY {Warning} [get_drc_checks REQP-*]", file=f) + print("set_property SEVERITY {Warning} [get_drc_checks BIVR-*]", file=f) + print("set_property SEVERITY {Warning} [get_drc_checks PLHDIO-1]", file=f) + print("opt_design", file=f) + print("place_design", file=f) + print("route_design", file=f) + print("set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design]", file=f) + print("write_checkpoint -force %s/specimen_io/diffio%d.dcp" % (root, x), file=f) + print("write_edif -force %s/specimen_io/diffio%d.edf" % (root, x), file=f) + print("write_bitstream -force %s/specimen_io/diffio%d.bit" % (root, x), file=f) +with open(root + "/diffio/run.sh", "w") as f: + print("#/usr/bin/env bash", file=f) + print("set -ex", file=f) + print("vivado -mode batch -nolog -nojournal -source diffio$1.tcl", file=f) + print("if [ $? -eq 0 ]; then", file=f) + print(" ../../ultra/tools/dump_bitstream %s/specimen_io/diffio$1.bit %s/frames.txt > %s/specimen_io/diffio$1.dump" % (root, root, root), file=f) + print(" python3 ../../ultra/tools/bits_to_tiles.py %s/tilebits.json %s/specimen_io/diffio$1.dump > %s/specimen_io/diffio$1.tbits" % (root, root, root), file=f) + #print(" rm %s/specimen_io/diffio$1.bit" % (root, ), file=f) + #print(" rm %s/specimen_io/diffio$1.dump" % (root, ), file=f) + print("else", file=f) + print(" rm %s/specimen_io/diffio$1.dump" % (root, ), file=f) + print(" rm %s/specimen_io/diffio$1.tbits" % (root, ), file=f) + print(" rm %s/specimen_io/diffio$1.dcp" % (root, ), file=f) + print(" rm %s/specimen_io/diffio$1.bit" % (root, ), file=f) + print(" rm %s/specimen_io/diffio$1.features" % (root, ), file=f) + print("fi", file=f) +with open(root + "/diffio/Makefile", "w") as f: + print("all: %s" % " ".join(["%d.done" % i for i in range(X)]), file=f) + print("", file=f) + print("%.done: ", file=f) + print("\tbash run.sh $*", file=f) + print("\ttouch $@", file=f) + print("", file=f) + print("clean: ", file=f) + print("\trm -f *.done", file=f) \ No newline at end of file
diff --git a/spec/fuzz_dump.sh b/spec/fuzz_dump.sh new file mode 100644 index 0000000..d8ee615 --- /dev/null +++ b/spec/fuzz_dump.sh
@@ -0,0 +1,20 @@ +#!/bin/bash +# Copyright 2020 Project U-Ray Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -ex +for bit in $1/specimen_clk/rclkroute*.bit; do + ../tools/dump_bitstream $bit $1/frames.txt > ${bit%.bit}.dump + python3 ../tools/bits_to_tiles.py $1/tilebits.json ${bit%.bit}.dump > ${bit%.bit}.tbits +done
diff --git a/spec/fuzzpins.tcl b/spec/fuzzpins.tcl new file mode 100644 index 0000000..ee612fa --- /dev/null +++ b/spec/fuzzpins.tcl
@@ -0,0 +1,76 @@ +// Copyright 2020 Project U-Ray Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +set gnd_pips [get_pips -of_objects [get_nets <const0>]] +set vcc_pips [get_pips -of_objects [get_nets <const1>]] + +foreach site [get_sites -filter {SITE_TYPE == BITSLICE_RX_TX && IS_USED == FALSE} ] { + if { rand() > 0.2 } { + continue + } + if {[llength [get_nets -of_objects [get_nodes -of_objects [get_site_pins -of_objects $site]]]] > 0} { + continue + } + set gnd_route 0 + foreach rtpip [get_pips -of_objects [get_nodes -of_objects [get_site_pins -of_objects $site]]]] { + if {[lsearch $gnd_pips $rtpip] != -1} { + set gnd_route 1 + } + if {[lsearch $vcc_pips $rtpip] != -1} { + set gnd_route 1 + } + } + if {$gnd_route == 1} { + continue + } + set sn [get_property NAME $site] + if { rand() > 0.5 } { + create_cell -reference IDELAYE3 "IDELAY_$sn" + if {[catch {place_cell "IDELAY_$sn" "$sn/IDELAY"}]} { + remove_cell "IDELAY_$sn" + continue + } + } else { + create_cell -reference OSERDESE3 "OSERDES_$sn" + if {[catch {place_cell "OSERDES_$sn" "$sn/OSERDES"}]} { + remove_cell "OSERDES_$sn" + continue + } + } + set_property MANUAL_ROUTING TRUE $site + set sitepips [get_property SITE_PIPS $site] + foreach sp [get_site_pips -of_objects $site] { + if { rand() > 0.2 } { + continue + } + if {[string match "*OPTINV*" $sp]} { + continue + } + regex {([A-Z0-9_]+)/([A-Z0-9_]+):([A-Z0-9_]+)} $sp match sp_site sp_bel sp_pin + if {[string first $sp_bel $sitepips] != -1} { + continue + } + puts $sp + append sitepips " " $sp_bel ":" $sp_pin + } + set_property SITE_PIPS $sitepips $site +} +set_property SEVERITY {Warning} [get_drc_checks AVAL-*] +set_property SEVERITY {Warning} [get_drc_checks REQP-*] +set_property SEVERITY {Warning} [get_drc_checks BIVR-*] +set_property SEVERITY {Warning} [get_drc_checks BSCK-*] +set_property SEVERITY {Warning} [get_drc_checks PLHDIO-1] +set_property SEVERITY {Warning} [get_drc_checks PDRC-203] +set_property SEVERITY {Warning} [get_drc_checks ADEF-911] +
diff --git a/spec/gclk_casc.py b/spec/gclk_casc.py new file mode 100644 index 0000000..d5d1aef --- /dev/null +++ b/spec/gclk_casc.py
@@ -0,0 +1,110 @@ +# Copyright 2020 Project U-Ray Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import numpy as np +import sys + +bufgctrls_by_tile = {} +with open(sys.argv[1], "r") as tf: + for line in tf: + sl = line.strip().split(",") + if len(sl) < 4: + continue + for site in sl[4:]: + if ("BUFGCTRL" in site) and "HDIO" not in site: + if sl[2] not in bufgctrls_by_tile: + bufgctrls_by_tile[sl[2]] = [] + bufgctrls_by_tile[sl[2]].append(site.split(":")[0]) + +X = 10 + +root = sys.argv[2] + +for x in range(X): + buffers = [] + + tiles = list(sorted(bufgctrls_by_tile.keys())) + np.random.shuffle(tiles) + + def random_inversion(pins): + return ", ".join([".IS_%s_INVERTED(%d)" % (p, np.random.randint(2)) for p in pins]) + + def random_control(pins): + return ", ".join([".%s(aux[%d])" % (p, np.random.randint(10)) for p in pins]) + + with open(root + "/clkroute7/gclk_casc_%d.v" % x, "w") as f: + print("module top(input [9:0] aux, output o);", file=f) + + for tile in tiles: + print("", file=f) + if np.random.randint(0, 3) == 0: + continue + sorted_bufgs = list(sorted(bufgctrls_by_tile[tile], key=lambda x: int(x[x.rfind('Y')+1:]))) + bufg_used = [np.random.choice([True, True, False]) for i in range(8)] + print("(* KEEP, DONT_TOUCH *) wire [7:0] %s_o;" % tile, file=f) + for i, loc in enumerate(sorted_bufgs): + if not bufg_used[i]: + continue + def get_inp(d): + if d == 0: + return "" + elif d == -1: + x = 7 if i == 0 else (i-1) + elif d == 1: + x = 0 if i == 7 else (i+1) + if bufg_used[x]: + return "%s_o[%d]" % (tile, x) + else: + return "" + i0 = get_inp(np.random.choice([-1, 0, +1])) + i1 = get_inp(np.random.choice([-1, 0, +1])) + print(" (* KEEP, DONT_TOUCH, LOC=\"%s\" *)" % loc, file=f) + print(" BUFGCTRL #(", file=f) + print(" %s," % random_inversion(["I0", "I1", "S0", "S1", "CE0", "CE1", "IGNORE0", "IGNORE1"]), file=f) + print(" .INIT_OUT(0), .PRESELECT_I0(\"TRUE\"), .PRESELECT_I1(\"FALSE\")", file=f) + print(" ) bufgctrl_%s_%d (" % (tile, i), file=f) + print(" .I0(%s), .I1(%s), " % (i0, i1), file=f) + print(" %s," % random_control(["S0", "S1", "CE0", "CE1", "IGNORE0", "IGNORE1"]), file=f) + print(" .O(%s_o[%d])" % (tile, i), file=f) + print(" );", file=f) + print("endmodule", file=f) + with open(root + "/clkroute7/gclk_casc_%d.tcl" % x, "w") as f: + print("add_files %s" % (root + ("/clkroute7/gclk_casc_%d.v" % x)), file=f) + #print("read_xdc %s" % (root + ("/clkroute7/gclk_casc_%d.xdc" % x)), file=f) + print("synth_design -top top -part xczu7ev-ffvc1156-2-e", file=f) + print("# set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets]", file=f) + print("opt_design", file=f) + print("place_design", file=f) + print("route_design", file=f) + print("set_property SEVERITY {Warning} [get_drc_checks NSTD-1]", file=f) + print("set_property SEVERITY {Warning} [get_drc_checks UCIO-1]", file=f) + print("set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design]", file=f) + print("write_checkpoint -force %s/specimen_clk/gclk_casc_%d.dcp" % (root, x), file=f) + print("write_edif -force %s/specimen_clk/gclk_casc_%d.edf" % (root, x), file=f) + print("write_bitstream -force %s/specimen_clk/gclk_casc_%d.bit" % (root, x), file=f) +with open(root + "/clkroute7/run.sh", "w") as f: + print("#/usr/bin/env bash", file=f) + #print("set -ex", file=f) + for x in range(X): + print("vivado -mode batch -nolog -nojournal -source gclk_casc_%d.tcl" % x, file=f) + print("if [ $? -eq 0 ]; then", file=f) + print(" ../../ultra/tools/dump_bitstream %s/specimen_clk/gclk_casc_%d.bit %s/frames.txt > %s/specimen_clk/gclk_casc_%d.dump" % (root, x, root, root, x), file=f) + print(" python3 ../../ultra/tools/bits_to_tiles.py %s/tilebits.json %s/specimen_clk/gclk_casc_%d.dump > %s/specimen_clk/gclk_casc_%d.tbits" % (root, root, x, root, x), file=f) + print("else", file=f) + print(" rm %s/specimen_clk/gclk_casc_%d.dump" % (root, x), file=f) + print(" rm %s/specimen_clk/gclk_casc_%d.tbits" % (root, x), file=f) + print(" rm %s/specimen_clk/gclk_casc_%d.dcp" % (root, x), file=f) + print(" rm %s/specimen_clk/gclk_casc_%d.bit" % (root, x), file=f) + print(" rm %s/specimen_clk/gclk_casc_%d.features" % (root, x), file=f) + print("fi", file=f) \ No newline at end of file
diff --git a/spec/gclk_pins.py b/spec/gclk_pins.py new file mode 100644 index 0000000..117641e --- /dev/null +++ b/spec/gclk_pins.py
@@ -0,0 +1,174 @@ +# Copyright 2020 Project U-Ray Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import numpy as np +import sys + +bufgces_by_tile = {} +tiles_by_xy = {} +rclk_int_l = [] +slices_by_tile = {} +with open(sys.argv[1], "r") as tf: + for line in tf: + sl = line.strip().split(",") + if len(sl) < 4: + continue + tiles_by_xy[int(sl[0]), int(sl[1])] = sl[2] + if sl[2].startswith("RCLK_INT_L"): + rclk_int_l.append((int(sl[0]), int(sl[1]), sl[2])) + for site in sl[4:]: + if ("BUFGCE" in site or "BUFGCTRL" in site) and "HDIO" not in site: + if sl[2] not in bufgces_by_tile: + bufgces_by_tile[sl[2]] = [] + bufgces_by_tile[sl[2]].append(site.split(":")) + elif "SLICE_" in site: + slices_by_tile[int(sl[0]), int(sl[1])] = site.split(":")[0] + +halfcolumn_slices_by_row = {} +for x, y, rclk in rclk_int_l: + hc_up = [] + hc_down = [] + if y not in halfcolumn_slices_by_row: + halfcolumn_slices_by_row[y] = [] + for yplus in range(y+1, y+31): + if (x, yplus) not in tiles_by_xy: + continue + if not tiles_by_xy[x, yplus].startswith("INT_"): + break + slice_x = x + np.random.choice([+1, -1]) + if (slice_x, yplus) not in slices_by_tile: + continue + hc_up.append(slices_by_tile[slice_x, yplus]) + for yminus in range(y-1, y-31, -1): + if (x, yminus) not in tiles_by_xy: + continue + if not tiles_by_xy[x, yminus].startswith("INT_"): + break + slice_x = x + np.random.choice([+1, -1]) + if (slice_x, yminus) not in slices_by_tile: + continue + hc_down.append(slices_by_tile[slice_x, yminus]) + halfcolumn_slices_by_row[y].append(hc_up) + halfcolumn_slices_by_row[y].append(hc_down) + +X = 2 + +root = sys.argv[2] + +for x in range(X): + buffers_by_type = {"BUFGCTRL": [], "BUFGCE": [], "BUFGCE_DIV": []} + + tiles = list(sorted(bufgces_by_tile.keys())) + np.random.shuffle(tiles) + + for tile in tiles: + shuffled_bufs = list(bufgces_by_tile[tile]) + np.random.shuffle(shuffled_bufs) + #tile_buffers = 8 + found_buffers = 0 + for buf, buftype in shuffled_bufs: + buffers_by_type[buftype].append(buf) + print("%s %s" % (tile, buf)) + found_buffers += 1 + np.random.shuffle(buffers_by_type["BUFGCE"]) + np.random.shuffle(buffers_by_type["BUFGCTRL"]) + np.random.shuffle(buffers_by_type["BUFGCE_DIV"]) + def random_inversion(pins): + return ", ".join([".IS_%s_INVERTED(%d)" % (p, np.random.randint(2)) for p in pins]) + + def random_control(pins): + return ", ".join([".%s(aux[%d])" % (p, np.random.randint(10)) for p in pins]) + + with open(root + "/clkroute6/gclkd_%d.v" % x, "w") as f: + print("module top(input [29:0] i, input [9:0] aux, input d, output o, q);", file=f) + N = 30 + print(" wire [29:0] r;", file=f) + # print(" assign r[0] = i;", file=f) + # print(" assign o = r[%d];" % N, file=f) + # for i in range(N): + # bg, buftype = buffers[i] + # #print("(* LOC=\"%s\" *)" % bg, file=f) + # if "BUFGCTRL" in buftype: + # print(" BUFGCTRL #(", file=f) + # print(" %s," % random_inversion(["I0", "I1", "S0", "S1", "CE0", "CE1", "IGNORE0", "IGNORE1"]), file=f) + # print(" .INIT_OUT(%d), .PRESELECT_I0(\"%s\"), .PRESELECT_I1(\"%s\")" % + # (np.random.randint(2), np.random.choice(["TRUE", "FALSE"]), np.random.choice(["TRUE", "FALSE"])), file=f) + # print(" ) bufgctrl_%d (" % i, file=f) + # print(" .I0(r[%d]), .I1(r[%d]), " % (i, np.random.randint(i+1)), file=f) + # print(" %s," % random_control(["S0", "S1", "CE0", "CE1", "IGNORE0", "IGNORE1"]), file=f) + # print(" .O(r[%d])" % (i+1), file=f) + # print(" );", file=f) + for i in range(15): + print(" (* LOC=\"%s\", KEEP, DONT_TOUCH *)" % buffers_by_type["BUFGCE_DIV"].pop(), file=f) + print(" BUFGCE_DIV #(", file=f) + print(" .BUFGCE_DIVIDE(%d)," % np.random.randint(1, 9), file=f) + print(" %s" % random_inversion(["I", "CE", "CLR"]), file=f) + print(" ) bufgce_div_%d (" % i, file=f) + if np.random.choice([True, False]): + print(" .I(i[%d])," % i, file=f) + print(" %s," % random_control(["CE", "CLR"]), file=f) + print(" .O(r[%d])" % (i), file=f) + print(" );", file=f) + for i in range(15): + print(" (* LOC=\"%s\", KEEP, DONT_TOUCH *)" % buffers_by_type["BUFGCTRL"].pop(), file=f) + print(" BUFGCTRL", file=f) + print(" bufgctrl_%d (" % i, file=f) + if np.random.choice([True, False]): + print(" .I0(i[%d])," % (i + 15), file=f) + elif np.random.choice([True, False]): + print(" .I1(i[%d])," % (i + 15), file=f) + print(" %s," % random_control(["S0", "S1", "CE0", "CE1", "IGNORE0", "IGNORE1"]), file=f) + print(" .O(r[%d])" % (i+15), file=f) + print(" );", file=f) + # for i in range(8): + # print(" (* LOC=\"%s\" *)" % buffers_by_type["BUFGCE"].pop(), file=f) + # print(" BUFGCE #(", file=f) + # print(" .CE_TYPE(\"%s\")," % np.random.choice(["SYNC", "ASYNC"]), file=f) + # print(" %s" % random_inversion(["I", "CE"]), file=f) + # print(" ) bufgce_%d (" % i, file=f) + # print(" .I(i[%d])," % (i+16), file=f) + # print(" %s," % random_control(["CE"]), file=f) + # print(" .O(r[%d])" % (i+16), file=f) + # print(" );", file=f) + + R2=0 + NS=64 + ffs="" + for i in range(30): + ffs += "FDCE ff_%d (.C(r[%d]), .CE(aux[%d]), .CLR(~aux[%d]), .D(r2[%d]), .Q(r2[%d]));\n" % (i, i, np.random.randint(10), np.random.randint(10), R2, R2+1) + R2 += 1 + print(" wire [%d:0] r2;" % R2, file=f) + print(" assign r2[0] = d;", file=f) + print(" assign q = r2[%d];" % R2, file=f) + print(ffs, file=f) + print("endmodule", file=f) + with open(root + "/clkroute6/gclkd_%d.tcl" % x, "w") as f: + print("add_files %s" % (root + ("/clkroute6/gclkd_%d.v" % x)), file=f) + #print("read_xdc %s" % (root + ("/clkroute6/gclkd_%d.xdc" % x)), file=f) + print("synth_design -top top -part xczu7ev-ffvf1517-2-e", file=f) + print("set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets]", file=f) + print("opt_design", file=f) + print("place_design", file=f) + print("route_design", file=f) + print("set_property SEVERITY {Warning} [get_drc_checks NSTD-1]", file=f) + print("set_property SEVERITY {Warning} [get_drc_checks UCIO-1]", file=f) + print("set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design]", file=f) + print("write_checkpoint -force %s/ioexp/gclkd_%d.dcp" % (root, x), file=f) + print("write_edif -force %s/ioexp/gclkd_%d.edf" % (root, x), file=f) + print("write_bitstream -force %s/ioexp/gclkd_%d.bit" % (root, x), file=f) +with open(root + "/clkroute6/run.sh", "w") as f: + print("#/usr/bin/env bash", file=f) + #print("set -ex", file=f) + for x in range(X): + print("vivado -mode batch -nolog -nojournal -source gclkd_%d.tcl" % x, file=f)
diff --git a/spec/io.py b/spec/io.py new file mode 100644 index 0000000..4153cfa --- /dev/null +++ b/spec/io.py
@@ -0,0 +1,313 @@ +# Copyright 2020 Project U-Ray Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import numpy as np +import sys + +X = 110 + +root = sys.argv[1] + +pins = [] +bank_to_pins = {} +bank_to_iotype = {} +site_to_pin = {} +pin_to_bank = {} +with open (root + "/iopins.txt", "r") as iof: + for line in iof: + sl = line.strip().split(",") + if len(sl) < 5: + continue + pin = sl[0] + bank = int(sl[1]) + func = sl[2] + site_name = sl[3] + site_type = sl[4] + pins.append((pin, bank, func, site_name, site_type)) + if bank not in bank_to_pins: + bank_to_pins[bank] = [] + bank_to_pins[bank].append(pin) + pin_to_bank[pin] = bank + if bank not in bank_to_iotype: + bank_to_iotype[bank] = site_type.split("_")[0] + site_to_pin[site_name] = pin + +for x in range(X): + used_pins = [] + io_config = [] + + bank_to_vcc = {} + bank_pod_used = set() + bank_pod_not_used = set() + lut_inputs = [] + lut_outputs = [] + bank_iref = {} + bound_pins = set() + def inp(): + sig = "li[%d]" % len(lut_inputs) + lut_inputs.append(sig) + return sig + def outp(): + sig = "lo[%d]" % len(lut_outputs) + lut_outputs.append(sig) + return sig + def maybe_inp(): + return inp() if np.random.choice([True, False]) else "" + def maybe_outp(): + return outp() if np.random.choice([True, False]) else "" + + for b, t in sorted(bank_to_iotype.items()): + if t == "HPIOB": + bank_to_vcc[b] = np.random.choice( + ["1.0", "1.2", "1.35", "1.5", "1.8"] + ) + elif t == "HDIOB": + bank_to_vcc[b] = np.random.choice( + ["1.2", "1.5", "1.8", "2.5", "3.3"] + ) + else: + assert False, t + standards = { + ("HPIOB", "1.8"): ["LVCMOS18", "LVDCI_18", "HSLVDCI_18", + "HSTL_I_18", "HSTL_I_DCI_18", + "SSTL18_I", "SSTL18_I_DCI"], + ("HPIOB", "1.5"): ["LVCMOS15", "LVDCI_15", "HSLVDCI_15", + "HSTL_I", "HSTL_I_DCI", + "SSTL15", "SSTL15_DCI"], + ("HPIOB", "1.35"): ["SSTL135", "SSTL135_DCI"], + ("HPIOB", "1.2"): ["LVCMOS12", "HSTL_I_12", "HSTL_I_DCI_12", + "SSTL12", "SSTL12_DCI", + "HSUL_12", "HSUL_12_DCI", + "POD12", "POD12_DCI"], + ("HPIOB", "1.0"): ["POD10", "POD10_DCI"], + + ("HDIOB", "3.3"): ["LVCMOS33", "LVTTL"], + ("HDIOB", "2.5"): ["LVCMOS25"], + ("HDIOB", "1.8"): ["LVCMOS18"], + ("HDIOB", "1.5"): ["LVCMOS15"], + ("HDIOB", "1.2"): ["LVCMOS12"] + } + + prims = { + "HPIOB": ["IBUF", "OBUF", "OBUFT", "IOBUF", "IOBUFE3", "IBUF_IBUFDISABLE"], + "HDIOB": ["IBUF","OBUF", "OBUFT", "IOBUF"] + } + + drives = { + ("HPIOB", "LVCMOS18"): ["2", "4", "6", "8", "12"], + ("HPIOB", "LVCMOS15"): ["2", "4", "6", "8", "12"], + ("HPIOB", "LVCMOS12"): ["2", "4", "6", "8"], + ("HDIOB", "LVCMOS33"): ["4", "8", "12", "16"], + ("HDIOB", "LVCMOS25"): ["4", "8", "12", "16"], + ("HDIOB", "LVCMOS18"): ["4", "8", "12", "16"], + ("HDIOB", "LVCMOS15"): ["4", "8", "12", "16"], + ("HDIOB", "LVCMOS12"): ["4", "8", "12"], + } + + for (pin, bank, func, sn, st) in pins: + if "VREF" in func: + continue # conflict + if "VRP" in func or "VRN" in func: + continue # conflict + if np.random.randint(1, 3) == 1: + continue # improved fuzzing + params = {} + iot = st.split("_")[0] + assert (iot, bank_to_vcc[bank]) in standards, (pin, bank, iot, bank_to_vcc[bank]) + ios = np.random.choice(standards[iot, bank_to_vcc[bank]]) + if bank in bank_pod_used and ios in ("HSTL_I_12", "HSTL_I_DCI_12", "SSTL12", "SSTL12_DCI", "HSUL_12", "HSUL_12_DCI"): + ios = "LVCMOS12" + if bank in bank_pod_not_used and ios in ("POD12", "POD12_DCI"): + ios = "LVCMOS12" + params["IOSTANDARD"] = ios + prim = np.random.choice(prims[iot]) + params["prim"] = prim + if prim in ("IBUF", "IOBUF", "IOBUFE3", "IBUF_IBUFDISABLE", "IBUF_INTERMDISABLE"): + params["PULLTYPE"] = np.random.choice(["NONE", "PULLUP", "PULLDOWN", "KEEPER"]) + if prim in ("OBUF", "OBUFT", "IOBUF", "IOBUFE3"): + if (iot, ios) in drives: + params["DRIVE"] = np.random.choice(drives[iot, ios]) + if iot == "HPIOB": + params["SLEW"] = np.random.choice(["SLOW", "MEDIUM", "FAST"]) + else: + params["SLEW"] = np.random.choice(["SLOW", "FAST"]) + if iot == "HPIOB" and ("POD" in ios or "SSTL" in ios): + params["OUTPUT_IMPEDANCE"] = np.random.choice(["RDRV_40_40", "RDRV_48_48", "RDRV_60_60"]) + if prim in ("IBUF", "IOBUF", "IOBUFE3", "IBUF_IBUFDISABLE", "IBUF_INTERMDISABLE"): + if "POD" in ios: + odt_choices = [] + if "DCI" not in ios: + odt_choices.append("RTT_NONE") + if "OUTPUT_IMPEDANCE" not in params or params["OUTPUT_IMPEDANCE"] != "RDRV_48_48": + odt_choices += ["RTT_40", "RTT_60"] + else: + odt_choices += ["RTT_48"] + params["ODT"] = np.random.choice(odt_choices) + if "POD12" in ios: + params["EQUALIZATION"] = np.random.choice(["EQ_LEVEL0", "EQ_LEVEL1", "EQ_LEVEL2", "EQ_LEVEL3", "EQ_LEVEL4", "EQ_NONE"]) + used_pins.append(pin) + io_config.append(params) + if iot == "HDIOB": + if ios in ( "HSTL_I_18", "SSTL18_I", "SSTL18_II"): + bank_iref[bank] = "0.90" + elif ios in ( "HSTL_I", "SSTL15", "SSTL15_II"): + bank_iref[bank] = "0.75" + elif ios in ("SSTL135", "SSTL135_II"): + bank_iref[bank] = "0.675" + elif ios == "SSTL12": + bank_iref[bank] = "0.60" + if ios in ("POD12", "POD12_DCI"): + bank_pod_used.add(bank) + bank_iref[bank] = np.random.choice([None, "0.84"]) + if ios in ("HSTL_I_12", "HSTL_I_DCI_12", "SSTL12", "SSTL12_DCI", "HSUL_12", "HSUL_12_DCI"): + bank_pod_not_used.add(bank) + bank_iref[bank] = np.random.choice([None, "0.60"]) + with open(root + "/io/io%d.v" % x, "w") as f: + print("module top(", file=f); + for i, params in enumerate(io_config): + prim = params["prim"] + bank = pin_to_bank[used_pins[i]] + if bank in bank_iref and bank_iref[bank] is not None: + params["internal_vref"] = bank_iref[bank] + print ("(* %s *)" % ", ".join('X_%s="%s"' % (k, v) for k, v in sorted(params.items())), file=f) + if prim in ("IBUF", "IBUF_IBUFDISABLE"): + print("input p%d%s" % (i, "," if i < len(io_config)-1 else ""), file=f) + elif prim in ("OBUF", "OBUFT"): + print("output p%d%s" % (i, "," if i < len(io_config)-1 else ""), file=f) + elif prim in ("IOBUF", "IOBUFE3"): + print("inout p%d%s" % (i, "," if i < len(io_config)-1 else ""), file=f) + print(");", file=f) + for i, params in enumerate(io_config): + print("(* KEEP, DONT_TOUCH *)", file=f) + prim = params["prim"] + if prim == "IBUF": + print(""" + IBUF buf_{i} ( + .I(p{i}), + .O({sig_o}) + ); + """.format(i=i, sig_o=maybe_inp()), file=f) + elif prim == "OBUF": + print(""" + OBUF buf_{i} ( + .O(p{i}), + .I({sig_i}) + ); + """.format(i=i, sig_i=maybe_outp()), file=f) + elif prim == "OBUFT": + print(""" + OBUFT buf_{i} ( + .O(p{i}), + .T({sig_t}), + .I({sig_i}) + ); + """.format(i=i, sig_t=outp(), sig_i=maybe_outp()), file=f) + elif prim == "IOBUF": + print(""" + IOBUF buf_{i} ( + .IO(p{i}), + .T({sig_t}), + .I({sig_i}), + .O({sig_o}) + ); + """.format(i=i, sig_t=maybe_outp(), sig_i=maybe_outp(), sig_o=maybe_inp()), file=f) + elif prim == "IBUF_IBUFDISABLE": + print(""" + IBUF_IBUFDISABLE buf_{i} ( + .I(p{i}), + .O({sig_o}), + .IBUFDISABLE({ibuf_dis}) + ); + """.format(i=i, sig_o=maybe_inp(), ibuf_dis=maybe_outp()), file=f) + elif prim == "IOBUFE3": + if np.random.choice([True, False]): + print("(* KEEP, DONT_TOUCH *)", file=f) + print(""" + IOBUFE3 buf_{i} ( + .IO(p{i}), + .T({sig_t}), + .I({sig_i}), + .O({sig_o}), + .DCITERMDISABLE({dci_dis}), + .IBUFDISABLE({ibuf_dis}) + ); + """.format(i=i, sig_t=maybe_outp(), sig_i=maybe_outp(), sig_o=maybe_inp(), + dci_dis=maybe_outp(), ibuf_dis=maybe_outp()), file=f) + print("", file=f) + print("wire [%d:0] li;" % (len(lut_inputs)-1), file=f) + print("wire [%d:0] lo;" % (len(lut_outputs)-1), file=f) + + for i in range(max(len(lut_inputs)//6 + 1, len(lut_outputs))): + ip = ["1'b0" if (i * 6 + j) >= len(lut_inputs) else "li[%d]" % (i * 6 + j) for j in range(6)] + op = "lo[%d]" % i if i < len(lut_outputs) else "" + print(""" + (* KEEP, DONT_TOUCH *) + LUT6 lut{i} (.I0({i0}), .I1({i1}), .I2({i2}), .I3({i3}), .I4({i4}), .I5({i5}), .O({o})); + """.format( + i=i, i0=ip[0], i1=ip[1], i2=ip[2], i3=ip[3], i4=ip[4], i5=ip[5], o=op, + ), file=f) + print("endmodule", file=f) + with open(root + "/io/io%d.xdc" % x, "w") as f: + for i, params in enumerate(io_config): + pin = used_pins[i] + print("set_property PACKAGE_PIN %s [get_ports {p%d}]" % (pin, i), file=f) + for k, v in sorted(params.items()): + if k.isupper(): + print("set_property %s %s [get_ports {p%d}]" % (k, v, i), file=f) + for bank, iref in sorted(bank_iref.items()): + if iref is None: + continue + print("set_property INTERNAL_VREF {%s} [get_iobanks %d]" % (iref, bank), file=f) + with open(root + "/io/io%d.tcl" % x, "w") as f: + print("add_files %s" % (root + ("/io/io%d.v" % x)), file=f) + print("add_files %s" % (root + ("/io/io%d.xdc" % x)), file=f) + print("synth_design -top top -part xczu7ev-ffvf1517-2-e", file=f) + print("set_property SEVERITY {Warning} [get_drc_checks NSTD-1]", file=f) + print("set_property SEVERITY {Warning} [get_drc_checks UCIO-1]", file=f) + print("set_property SEVERITY {Warning} [get_drc_checks AVAL-*]", file=f) + print("set_property SEVERITY {Warning} [get_drc_checks REQP-*]", file=f) + print("set_property SEVERITY {Warning} [get_drc_checks BIVR-*]", file=f) + print("set_property SEVERITY {Warning} [get_drc_checks PLHDIO-1]", file=f) + print("opt_design", file=f) + print("place_design", file=f) + print("route_design", file=f) + print("set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design]", file=f) + print("write_checkpoint -force %s/specimen_io/io%d.dcp" % (root, x), file=f) + print("write_edif -force %s/specimen_io/io%d.edf" % (root, x), file=f) + print("write_bitstream -force %s/specimen_io/io%d.bit" % (root, x), file=f) +with open(root + "/io/run.sh", "w") as f: + print("#/usr/bin/env bash", file=f) + print("set -ex", file=f) + print("vivado -mode batch -nolog -nojournal -source io$1.tcl", file=f) + print("if [ $? -eq 0 ]; then", file=f) + print(" ../../ultra/tools/dump_bitstream %s/specimen_io/io$1.bit %s/frames.txt > %s/specimen_io/io$1.dump" % (root, root, root), file=f) + print(" python3 ../../ultra/tools/bits_to_tiles.py %s/tilebits.json %s/specimen_io/io$1.dump > %s/specimen_io/io$1.tbits" % (root, root, root), file=f) + #print(" rm %s/specimen_io/io$1.bit" % (root, ), file=f) + #print(" rm %s/specimen_io/io$1.dump" % (root, ), file=f) + print("else", file=f) + print(" rm %s/specimen_io/io$1.dump" % (root, ), file=f) + print(" rm %s/specimen_io/io$1.tbits" % (root, ), file=f) + print(" rm %s/specimen_io/io$1.dcp" % (root, ), file=f) + print(" rm %s/specimen_io/io$1.bit" % (root, ), file=f) + print(" rm %s/specimen_io/io$1.features" % (root, ), file=f) + print("fi", file=f) +with open(root + "/io/Makefile", "w") as f: + print("all: %s" % " ".join(["%d.done" % i for i in range(X)]), file=f) + print("", file=f) + print("%.done: ", file=f) + print("\tbash run.sh $*", file=f) + print("\ttouch $@", file=f) + print("", file=f) + print("clean: ", file=f) + print("\trm -f *.done", file=f) \ No newline at end of file
diff --git a/spec/iologic.py b/spec/iologic.py new file mode 100644 index 0000000..2053a43 --- /dev/null +++ b/spec/iologic.py
@@ -0,0 +1,455 @@ +# Copyright 2020 Project U-Ray Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import numpy as np +import sys + +X = 100 + +root = sys.argv[1] + +pins = [] +bank_to_pins = {} +bank_to_iotype = {} +site_to_pin = {} +pin_to_iol = {} + +with open (root + "/iologic.txt", "r") as iof: + for line in iof: + sl = line.strip().split(",") + if len(sl) < 5: + continue + pin = sl[0] + bank = int(sl[1]) + func = sl[2] + site_name = sl[3] + site_type = sl[4] + iol_site = sl[5] + pins.append((pin, bank, func, site_name, site_type, iol_site)) + if bank not in bank_to_pins: + bank_to_pins[bank] = [] + bank_to_pins[bank].append(pin) + if bank not in bank_to_iotype: + bank_to_iotype[bank] = site_type.split("_")[0] + site_to_pin[site_name] = pin + +sr_sig = { + "FDRE": "R", "FDSE": "S", "FDPE": "PRE", "FDCE": "CLR", +} + +def make_ioff(name, sig_c, sig_d, sig_r, sig_e, sig_q, f): + fftype = np.random.choice(["FDRE", "FDSE", "FDPE", "FDCE"]) + print(""" + {t} #(.INIT({init})) {n} ( + .C({c}), .{sr}({r}), .CE({e}), .D({d}), .Q({q}) + ); + """.format( + t=fftype, + init=np.random.randint(0, 2), + n=name, + sr=sr_sig[fftype], + c=sig_c, r=sig_r, e=sig_e, d=sig_d, q=sig_q + ), file=f) + +def make_iddr(name, allow_inv, sig_c, sig_cb, sig_r, sig_d, sig_q1, sig_q2, f): + print(""" + IDDRE1 #(.DDR_CLK_EDGE("{e}"), .IS_C_INVERTED({ci}), .IS_CB_INVERTED({cbi})) {n} ( + .C({c}), .CB({cb}), .R({r}), .D({d}), .Q1({q1}), .Q2({q2}) + ); + """.format( + e=np.random.choice(["OPPOSITE_EDGE", "SAME_EDGE", "SAME_EDGE_PIPELINED"]), + ci=np.random.randint(0, 2) if allow_inv else 0, + cbi=np.random.randint(0, 2) if allow_inv else 1, + n=name, + c=sig_c, cb=sig_cb, r=sig_r, d=sig_d, q1=sig_q1, q2=sig_q2 + ), file=f) + +def make_oddr(name, srval, sig_c, c_inv, sig_d1, sig_d2, sig_sr, sig_q, f): + print(""" + ODDRE1 #(.IS_C_INVERTED({ci}), .SRVAL({srv})) {n} ( + .C({c}), .D1({d1}), .D2({d2}), .SR({sr}), .Q({q}) + ); + """.format( + ci=1 if c_inv else 0, + srv=srval, + n=name, + c=sig_c, d1=sig_d1, d2=sig_d2, sr=sig_sr, q=sig_q + ), file=f) +def make_iserdes(name, sig_clk, sig_clkdiv, sig_clk_b, sig_d, sig_rst, sig_q, f): + print(""" + ISERDESE3 #( + .DATA_WIDTH({dw}), + .IS_CLK_B_INVERTED({cbi}), + .IS_CLK_INVERTED({ci}), + .IS_RST_INVERTED({ri}) + ) {n} ( + .Q({q}), + .CLK({clk}), .CLKDIV({clkdiv}), .CLK_B({clk_b}), .D({d}), .RST({rst}) + ); + """.format( + dw=np.random.choice([4, 8]), + cbi=np.random.randint(0, 2), + ci=np.random.randint(0, 2), + ri=np.random.randint(0, 2), + n=name, + q=sig_q, + clk=sig_clk, clkdiv=sig_clkdiv, clk_b=sig_clk_b, rst=sig_rst, d=sig_d + ), file=f) +def make_oserdes(name, sig_clk, sig_clkdiv, sig_d, sig_rst, sig_t, sig_oq, sig_t_out, f): + print(""" + OSERDESE3 #( + .DATA_WIDTH({dw}), + .INIT({init}), + .IS_CLKDIV_INVERTED({cdi}), + .IS_CLK_INVERTED({ci}), + .IS_RST_INVERTED({ri}), + .OSERDES_D_BYPASS("{db}"), + .OSERDES_T_BYPASS("{dt}") + ) {n} ( + .OQ({oq}), .T_OUT({t_out}), + .CLK({clk}), .CLKDIV({clkdiv}), .D({d}), .RST({rst}), .T({t}) + ); + """.format( + dw=np.random.choice([4, 8]), + init=np.random.randint(0, 2), + cdi=np.random.randint(0, 2), + ci=np.random.randint(0, 2), + ri=np.random.randint(0, 2), + db=np.random.choice(["TRUE", "FALSE"]), + dt=np.random.choice(["TRUE", "FALSE"]), + n=name, + oq=sig_oq, t_out=sig_t_out, + clk=sig_clk, clkdiv=sig_clkdiv, d=sig_d, rst=sig_rst, t=sig_t, + ), file=f) + +def make_idelay(name, del_fmt, time_dly, sig_clk, sig_ce, sig_inc, sig_load, sig_rst, sig_en_vtc, sig_datain, sig_idatain, sig_dataout, f): + print(""" + IDELAYE3 #( + .DELAY_SRC("{ds}"), + .DELAY_TYPE("{dt}"), + .DELAY_VALUE({dv}), + .DELAY_FORMAT("{df}"), + .UPDATE_MODE("{um}"), + .IS_CLK_INVERTED({ci}), + .IS_RST_INVERTED({ri}), + .LOOPBACK("{lb}"), + .REFCLK_FREQUENCY(300.0) + ) {n} ( + .CLK({clk}), .CE({ce}), .INC({inc}), .LOAD({load}), .RST({rst}), .EN_VTC({en_vtc}), + .DATAIN({datain}), .IDATAIN({idatain}), .DATAOUT({dataout}) + ); + """.format( + ds=np.random.choice(["DATAIN", "IDATAIN"]), + dt=np.random.choice(["FIXED", "VAR_LOAD", "VARIABLE"]), + dv=np.random.randint(0, 512) if del_fmt == "COUNT" else time_dly, + df=del_fmt, + um=np.random.choice(["ASYNC", "SYNC", "MANUAL"]), + ci=np.random.randint(0, 2), + ri=np.random.randint(0, 2), + lb=np.random.choice(["FALSE", "TRUE"]), + n=name, + clk=sig_clk, ce=sig_ce, inc=sig_inc, load=sig_load, rst=sig_rst, en_vtc=sig_en_vtc, + datain=sig_datain, idatain=sig_idatain, dataout=sig_dataout + ), file=f) + +def make_odelay(name, del_fmt, time_dly, sig_clk, sig_ce, sig_inc, sig_load, sig_rst, sig_en_vtc, sig_odatain, sig_dataout, f): + print(""" + ODELAYE3 #( + .DELAY_TYPE("{dt}"), + .DELAY_VALUE({dv}), + .DELAY_FORMAT("{df}"), + .UPDATE_MODE("{um}"), + .IS_CLK_INVERTED({ci}), + .IS_RST_INVERTED({ri}), + .REFCLK_FREQUENCY(300.0) + ) {n} ( + .CLK({clk}), .CE({ce}), .INC({inc}), .LOAD({load}), .RST({rst}), .EN_VTC({en_vtc}), + .ODATAIN({odatain}), .DATAOUT({dataout}) + ); + """.format( + dt=np.random.choice(["FIXED", "VAR_LOAD", "VARIABLE"]), + dv=np.random.randint(0, 512) if del_fmt == "COUNT" else time_dly, + df=del_fmt, + um=np.random.choice(["ASYNC", "SYNC", "MANUAL"]), + ci=np.random.randint(0, 2), + ri=np.random.randint(0, 2), + n=name, + clk=sig_clk, ce=sig_ce, inc=sig_inc, load=sig_load, rst=sig_rst, en_vtc=sig_en_vtc, + odatain=sig_odatain, dataout=sig_dataout + ), file=f) + +for x in range(X): + used_pins = [] + io_config = [] + + lut_inputs = [] + lut_outputs = [] + bank_iref = {} + def inp(): + sig = "li[%d]" % len(lut_inputs) + lut_inputs.append(sig) + return sig + def outp(): + sig = "lo[%d]" % len(lut_outputs) + lut_outputs.append(sig) + return sig + def maybe_inp(): + return inp() if np.random.choice([True, False]) else "" + def maybe_outp(): + return outp() if np.random.choice([True, False]) else "" + def clock(): + return ("gclk[%d]" % np.random.randint(0, 6)) + def maybe_outp_z(): + return outp() if np.random.choice([True, False]) else "null" + def maybe(x): + return x if np.random.choice([True, False]) else "" + io_config = [] + used_pins = [] + for i in range(len(pins)): + if "XIPHY" in pins[i][5]: + prim = np.random.choice([None, None, None, None, None, "IBUF", "OBUF", "OBUFT", "IOBUF"]) + else: + prim = np.random.choice([None, None, None, None, None, "IBUF", "OBUF", "OBUFT", "IOBUF", "IOBUFE3"]) + if prim is not None: + io_config.append(prim) + used_pins.append(pins[i]) + with open(root + "/iologic/iologic%d.v" % x, "w") as f: + print("module top(", file=f); + for i, prim in enumerate(io_config): + if prim == "IBUF": + print("input p%d%s" % (i, "," if i < len(io_config)-1 else ""), file=f) + elif prim in ("OBUF", "OBUFT"): + print("output p%d%s" % (i, "," if i < len(io_config)-1 else ""), file=f) + elif prim in ("IOBUF", "IOBUFE3"): + print("inout p%d%s" % (i, "," if i < len(io_config)-1 else ""), file=f) + print(");", file=f) + print("wire null;", file=f) + print("wire [5:0] gclk;", file=f) + print("BUFG bufg_i[5:0] (.I({%s, %s, %s, %s, %s, %s}), .O(gclk));" % tuple(outp() for i in range(6)), file=f) + del_groups = set() + for i, prim in enumerate(io_config): + print("wire p{i}i, p{i}i_d, p{i}o, p{i}o_d, p{i}t;".format(i=i), file=f) + print("(* KEEP, DONT_TOUCH *)", file=f) + if prim == "IBUF": + print(""" + IBUF buf_{i} ( + .I(p{i}), + .O(p{i}o) + ); + """.format(i=i), file=f) + elif prim == "OBUF": + print(""" + OBUF buf_{i} ( + .O(p{i}), + .I(p{i}i_d) + ); + """.format(i=i), file=f) + elif prim == "OBUFT": + print(""" + OBUFT buf_{i} ( + .O(p{i}), + .T(p{i}t), + .I(p{i}i_d) + ); + """.format(i=i), file=f) + elif prim == "IOBUF": + print(""" + IOBUF buf_{i} ( + .IO(p{i}), + .T(p{i}t), + .I(p{i}i_d), + .O(p{i}o) + ); + """.format(i=i), file=f) + elif prim == "IOBUFE3": + print(""" + IOBUFE3 buf_{i} ( + .IO(p{i}), + .T(p{i}t), + .I(p{i}i_d), + .O(p{i}o), + .DCITERMDISABLE({dci_dis}) + ); + """.format(i=i, dci_dis=maybe_outp()), file=f) + iol_site = used_pins[i][5] + idelay_used = False + odelay_used = False + if "BITSLICE" in iol_site: + idelay_used = np.random.choice([False, True]) + odelay_used = np.random.choice([False, True]) + del_fmt = np.random.choice(["TIME", "COUNT"]) + time_dly = int(6666.667/np.random.uniform(7, 666)) + slow_clk = clock() + group = "B" + str(used_pins[i][1]) + if idelay_used: + print("(* KEEP, DONT_TOUCH, LOC=\"%s\", BEL=\"IDELAY\", IODELAY_GROUP=\"%s\" *)" % (iol_site, group), file=f) + make_idelay(name="idelay%d" % i, del_fmt=del_fmt, time_dly=time_dly, sig_clk=maybe(slow_clk), sig_ce=maybe_outp(), + sig_inc=maybe_outp(), sig_load=maybe_outp(), sig_rst=maybe_outp(), sig_en_vtc=maybe_outp(), + sig_datain=maybe_outp(), sig_idatain="p%do"%i, sig_dataout="p%do_d"%i, f=f) + del_groups.add(group) + if odelay_used: + print("(* KEEP, DONT_TOUCH, LOC=\"%s\", BEL=\"ODELAY\", IODELAY_GROUP=\"%s\" *)" % (iol_site, group), file=f) + make_odelay(name="odelay%d" % i, del_fmt=del_fmt, time_dly=time_dly, sig_clk=maybe(slow_clk), sig_ce=maybe_outp(), + sig_inc=maybe_outp(), sig_load=maybe_outp(), sig_rst=maybe_outp(), sig_en_vtc=maybe_outp(), + sig_odatain="p%di"%i, sig_dataout="p%di_d"%i, f=f) + del_groups.add(group) + input_mode = np.random.choice(["NONE", "BYP", "FF", "DDR", "SERDES"]) + if input_mode == "BYP": + print("assign %s = p%do%s;" % (inp(), i, "_d" if idelay_used else ""), file=f) + elif input_mode == "FF" and prim in ("IBUF", "IOBUF", "IOBUFE3"): + print("(* KEEP, DONT_TOUCH, LOC=\"%s\", BEL=\"IN_FF\" *)" % iol_site, file=f) + make_ioff(name="iff%d" % i, sig_c=slow_clk, sig_d="p%do_d" % i if idelay_used else ("p%do" % i), + sig_r=maybe_outp(), sig_e=maybe_outp(), sig_q=maybe_inp(), f=f) + elif input_mode == "DDR" and prim in ("IBUF", "IOBUF", "IOBUFE3"): + print("(* KEEP, DONT_TOUCH, LOC=\"%s\", BEL=\"ISERDES\" *)" % iol_site, file=f) + make_iddr(name="iddr%d" % i, allow_inv=True, sig_c=slow_clk, sig_cb=clock(), + sig_r=maybe_outp(), sig_d="p%do_d" % i if idelay_used else "p%do" % i, + sig_q1=maybe_inp(), sig_q2=maybe_inp(), f=f) + elif input_mode == "SERDES": + print("(* KEEP, DONT_TOUCH, LOC=\"%s\", BEL=\"ISERDES\" *)" % iol_site, file=f) + make_iserdes(name="iserdes%d" % i, sig_clk=clock(), sig_clkdiv=slow_clk, sig_clk_b=clock(), + sig_d="p%do_d" % i if idelay_used else "p%do" % i, sig_rst=maybe_outp(), + sig_q="{%s}" % (", ".join([inp() for i in range(8)])), f=f) + output_mode = np.random.choice(["NONE", "BYP", "FF", "DDR", "SERDES"]) + if output_mode == "SERDES": + print("(* KEEP, DONT_TOUCH, LOC=\"%s\", BEL=\"OSERDES\" *)" % iol_site, file=f) + make_oserdes(name="oserdes%d" % i, sig_clk=clock(), sig_clkdiv=slow_clk, sig_d="{%s}" % (", ".join([maybe_outp_z() for i in range(8)])), + sig_rst=maybe_outp(), sig_t=maybe_outp(), sig_oq="p%di" % i, sig_t_out="p%dt" % i, f=f) + else: + if output_mode == "BYP" or odelay_used: + print("assign p%di = %s;" % (i, outp()), file=f) + print("assign p%dt = %s;" % (i, outp()), file=f) + elif output_mode == "FF" and prim in ("OBUF", "OBUFT", "IOBUF", "IOBUFE3"): + print("(* KEEP, DONT_TOUCH, LOC=\"%s\", BEL=\"OUT_FF\" *)" % iol_site, file=f) + make_ioff(name="off%d" % i, sig_c=slow_clk, sig_d=maybe_inp(), + sig_r=maybe_outp(), sig_e=maybe_outp(), sig_q="p%di" % i, f=f) + elif output_mode == "DDR": + print("(* KEEP, DONT_TOUCH, LOC=\"%s\", BEL=\"OSERDES\" *)" % iol_site, file=f) + make_oddr(name="oddr%d" % i, srval=np.random.randint(0, 2), sig_c=slow_clk, c_inv=np.random.choice([True, False]), + sig_d1=outp(), sig_d2=outp(), sig_sr=maybe_outp(), sig_q="p%di" % i, f=f) + elif "HDIO" in iol_site: + slow_clk = clock() + reset = maybe_outp() + enable = maybe_outp() + input_mode = np.random.choice(["NONE", "BYP", "FF", "DDR"]) + if input_mode == "BYP": + print("assign %s = p%do;" % (inp(), i), file=f) + elif input_mode == "FF" and prim in ("IBUF", "IOBUF"): + print("(* KEEP, DONT_TOUCH, LOC=\"%s\", BEL=\"IPFF\" *)" % iol_site, file=f) + make_ioff(name="iff%d" % i, sig_c=slow_clk, sig_d="p%do" % i, + sig_r=reset, sig_e=maybe_outp(), sig_q=maybe_inp(), f=f) + elif input_mode == "DDR": + print("(* KEEP, DONT_TOUCH, LOC=\"%s\", BEL=\"IDDR\" *)" % iol_site, file=f) + make_iddr(name="iddr%d" % i, allow_inv=False, sig_c=slow_clk, sig_cb=clock(), + sig_r=reset, sig_d="p%do" % i, + sig_q1=maybe_inp(), sig_q2=maybe_inp(), f=f) + output_mode = np.random.choice(["NONE", "BYP", "FF", "DDR"]) + tristate_mode = np.random.choice(["NONE", "BYP", "FF", "DDR"]) + srval = np.random.randint(0, 2) + if output_mode == "BYP": + print("assign p%di = %s;" % (i, outp()), file=f) + elif output_mode == "FF" and prim in ("OBUF", "OBUFT", "IOBUF"): + print("(* KEEP, DONT_TOUCH, LOC=\"%s\", BEL=\"OPFF\" *)" % iol_site, file=f) + make_ioff(name="off%d" % i, sig_c=slow_clk, sig_d=maybe_inp(), + sig_r=reset, sig_e=enable, sig_q="p%di" % i, f=f) + elif output_mode == "DDR" and prim in ("OBUF", "OBUFT", "IOBUF"): + #print("(* KEEP, DONT_TOUCH, LOC=\"%s\" *)" % iol_site, file=f) + make_oddr(name="oddr%d" % i, srval=srval, sig_c=slow_clk, c_inv=False, + sig_d1=maybe_outp(), sig_d2=maybe_outp(), sig_sr=reset, sig_q="p%di" % i, f=f) + tristate_mode = "DDR" + if tristate_mode == "BYP": + print("assign p%dt = %s;" % (i, outp()), file=f) + elif tristate_mode == "FF" and prim in ("OBUFT", "IOBUF"): + print("(* KEEP, DONT_TOUCH, LOC=\"%s\", BEL=\"TFF\" *)" % iol_site, file=f) + make_ioff(name="tff%d" % i, sig_c=slow_clk, sig_d=maybe_inp(), + sig_r=reset, sig_e=enable, sig_q="p%dt" % i, f=f) + elif tristate_mode == "DDR" and prim in ("OBUFT", "IOBUF") and output_mode == "DDR": + #print("(* KEEP, DONT_TOUCH, LOC=\"%s\", BEL=\"OPTFF\" *)" % iol_site, file=f) + make_oddr(name="tddr%d" % i, srval=srval, sig_c=slow_clk, c_inv=False, + sig_d1=maybe_outp(), sig_d2=maybe_outp(), sig_sr=reset, sig_q="p%dt" % i, f=f) + if not odelay_used: + print("assign p%di_d = p%di;" % (i, i), file=f) + + print("", file=f) + for group in sorted(del_groups): + print("(* KEEP, DONT_TOUCH, IODELAY_GROUP=\"%s\" *)" % group, file=f) + print(" IDELAYCTRL ctrl_{n} (.REFCLK({c}), .RST({r}), .RDY({rd}));".format( + n=group, c=clock(), r=maybe_outp(), rd=maybe_inp(), + ), file=f) + print("wire [%d:0] li;" % (len(lut_inputs)-1), file=f) + print("wire [%d:0] lo;" % (len(lut_outputs)-1), file=f) + + for i in range(max(len(lut_inputs)//6 + 1, len(lut_outputs))): + ip = ["1'b0" if (i * 6 + j) >= len(lut_inputs) else "li[%d]" % (i * 6 + j) for j in range(6)] + op = "lo[%d]" % i if i < len(lut_outputs) else "" + print(""" + (* KEEP, DONT_TOUCH *) + LUT6 lut{i} (.I0({i0}), .I1({i1}), .I2({i2}), .I3({i3}), .I4({i4}), .I5({i5}), .O({o})); + """.format( + i=i, i0=ip[0], i1=ip[1], i2=ip[2], i3=ip[3], i4=ip[4], i5=ip[5], o=op, + ), file=f) + print("endmodule", file=f) + with open(root + "/iologic/iologic%d.xdc" % x, "w") as f: + for i, prim in enumerate(io_config): + pin = used_pins[i][0] + print("set_property PACKAGE_PIN %s [get_ports {p%d}]" % (pin, i), file=f) + print("set_property IOSTANDARD LVCMOS18 [get_ports {p%d}]" % (i), file=f) + + with open(root + "/iologic/iologic%d.tcl" % x, "w") as f: + print("add_files %s" % (root + ("/iologic/iologic%d.v" % x)), file=f) + print("add_files %s" % (root + ("/iologic/iologic%d.xdc" % x)), file=f) + print("synth_design -top top -part xczu7ev-ffvf1517-2-e", file=f) + print("set_property SEVERITY {Warning} [get_drc_checks NSTD-1]", file=f) + print("set_property SEVERITY {Warning} [get_drc_checks UCIO-1]", file=f) + print("set_property SEVERITY {Warning} [get_drc_checks AVAL-*]", file=f) + print("set_property SEVERITY {Warning} [get_drc_checks REQP-*]", file=f) + print("set_property SEVERITY {Warning} [get_drc_checks BIVR-*]", file=f) + print("set_property SEVERITY {Warning} [get_drc_checks BSCK-*]", file=f) + print("set_property SEVERITY {Warning} [get_drc_checks PLHDIO-1]", file=f) + print("set_property SEVERITY {Warning} [get_drc_checks PDRC-203]", file=f) + print("set_property SEVERITY {Warning} [get_drc_checks ADEF-911]", file=f) + print("set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets]", file=f) + print("opt_design", file=f) + print("place_design", file=f) + print("route_design", file=f) + print("source ../fuzzpins.tcl", file=f) + print("set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design]", file=f) + print("write_checkpoint -force %s/specimen_io/iologic%d.dcp" % (root, x), file=f) + print("write_edif -force %s/specimen_io/iologic%d.edf" % (root, x), file=f) + print("write_bitstream -force %s/specimen_io/iologic%d.bit" % (root, x), file=f) +with open(root + "/iologic/run.sh", "w") as f: + print("#/usr/bin/env bash", file=f) + print("set -ex", file=f) + print("vivado -mode batch -nolog -nojournal -source iologic$1.tcl", file=f) + print("if [ $? -eq 0 ]; then", file=f) + print(" ../../ultra/tools/dump_bitstream %s/specimen_io/iologic$1.bit %s/frames.txt > %s/specimen_io/iologic$1.dump" % (root, root, root), file=f) + print(" python3 ../../ultra/tools/bits_to_tiles.py %s/tilebits.json %s/specimen_io/iologic$1.dump > %s/specimen_io/iologic$1.tbits" % (root, root, root), file=f) + #print(" rm %s/specimen_io/iologic$1.bit" % (root, ), file=f) + #print(" rm %s/specimen_io/iologic$1.dump" % (root, ), file=f) + print("else", file=f) + print(" rm %s/specimen_io/iologic$1.dump" % (root, ), file=f) + print(" rm %s/specimen_io/iologic$1.tbits" % (root, ), file=f) + print(" rm %s/specimen_io/iologic$1.dcp" % (root, ), file=f) + print(" rm %s/specimen_io/iologic$1.bit" % (root, ), file=f) + print(" rm %s/specimen_io/iologic$1.features" % (root, ), file=f) + print("fi", file=f) +with open(root + "/iologic/Makefile", "w") as f: + print("all: %s" % " ".join(["%d.done" % i for i in range(X)]), file=f) + print("", file=f) + print("%.done: ", file=f) + print("\tbash run.sh $*", file=f) + print("\ttouch $@", file=f) + print("", file=f) + print("clean: ", file=f) + print("\trm -f *.done", file=f) \ No newline at end of file
diff --git a/spec/laguna_ff.py b/spec/laguna_ff.py new file mode 100644 index 0000000..aad9efe --- /dev/null +++ b/spec/laguna_ff.py
@@ -0,0 +1,137 @@ +# Copyright 2020 Project U-Ray Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import numpy as np +import sys + +top_slices_orig = [] +bot_slices_orig = [] +top_laguna_orig = [] +bot_laguna_orig = [] + +with open(sys.argv[1], "r") as tf: + for line in tf: + sl = line.strip().split(",") + if len(sl) < 4: + continue + for site in sl[4:]: + if site.startswith("SLICE_"): + if int(sl[1]) > 310 and int(sl[1]) < 355: + bot_slices_orig.append(site.split(":")[0]) + elif int(sl[1]) < 310 and int(sl[1]) > 275: + top_slices_orig.append(site.split(":")[0]) + elif site.startswith("LAGUNA"): + if int(sl[1]) > 310 and int(sl[1]) < 355: + bot_laguna_orig.append(site.split(":")[0]) + elif int(sl[1]) < 310 and int(sl[1]) > 249: + top_laguna_orig.append(site.split(":")[0]) + +X = 10 +root = sys.argv[2] + +for x in range(X): + top_slices = list(top_slices_orig) + bot_slices = list(bot_slices_orig) + top_laguna = list(top_laguna_orig) + bot_laguna = list(bot_laguna_orig) + + np.random.shuffle(top_slices) + np.random.shuffle(bot_slices) + + np.random.shuffle(top_laguna) + np.random.shuffle(bot_laguna) + + with open(root + "/lagff/lagff%d.v" % x, "w") as f: + print("module top;", file=f) + print("wire clk, sr, ce;", file=f) + print("(* KEEP, DONT_TOUCH *) LUT1 drv_clk (.O(clk));", file=f) + print("(* KEEP, DONT_TOUCH *) LUT1 drv_sr (.O(sr));", file=f) + print("(* KEEP, DONT_TOUCH *) LUT1 drv_ce (.O(ce));", file=f) + N = np.random.randint(1000, len(bot_laguna)) + for i in range(N): + top = False + rx = np.random.choice([True, False]) + print("wire d%d, q%d;" % (i, i), file=f) + if top: + lag = top_laguna.pop() + else: + lag = bot_laguna.pop() + if rx: + bel = "RX_REG%d" % (np.random.randint(0, 6)) + if top: + sink_slice = top_slices.pop() + source_slice = bot_slices.pop() + else: + sink_slice = bot_slices.pop() + source_slice = top_slices.pop() + else: + bel = "TX_REG%d" % (np.random.randint(0, 6)) + if top: + sink_slice = bot_slices.pop() + source_slice = top_slices.pop() + else: + sink_slice = top_slices.pop() + source_slice = bot_slices.pop() + if np.random.choice([True, False, False]): + # bypass + print("assign q%d = d%d;" % (i, i), file=f) + else: + prim, sr = np.random.choice(["FDRE_R", "FDSE_S", "FDPE_PRE", "FDCE_CLR"]).split("_") + print("(* KEEP, DONT_TOUCH, LOC=\"%s\", BEL=\"%s\" *)" % (lag, bel), file=f) + print("%s #(" % prim, file=f) + print(" .INIT(%d)," % np.random.randint(2), file=f) + print(" .IS_C_INVERTED(%d)," % np.random.randint(2), file=f) + print(" .IS_%s_INVERTED(%d)" % (sr, np.random.randint(2)), file=f) + print(") ff_%d (" % i, file=f) + print(" .C(%s)," % np.random.choice(["clk", ""]), file=f) + if np.random.choice([True, False]): + print(" .CE(ce),", file=f) + if np.random.choice([True, False]): + print(" .%s(sr)," % sr, file=f) + print(" .D(d%d)," % i, file=f) + print(" .Q(q%d)" % i, file=f) + print(");", file=f) + if np.random.choice([True, True, False]) or rx: + print("(* KEEP, DONT_TOUCH, LOC=\"%s\" *) LUT1 drv%d(.O(d%d));" % (source_slice, i, i), file=f) + if np.random.choice([True, True, False]) or not rx: + print("(* KEEP, DONT_TOUCH, LOC=\"%s\" *) LUT1 usr%d(.I0(q%d));" % (sink_slice, i, i), file=f) + print("endmodule", file=f) + + with open(root + "/lagff/lagff%d.tcl" % x, "w") as f: + print("add_files %s" % (root + ("/lagff/lagff%d.v" % x)), file=f) + print("synth_design -top top -part xcvu5p-flvc2104-2-e", file=f) + print("opt_design", file=f) + print("place_design", file=f) + print("route_design", file=f) + print("set_property SEVERITY {Warning} [get_drc_checks NSTD-1]", file=f) + print("set_property SEVERITY {Warning} [get_drc_checks UCIO-1]", file=f) + print("set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design]", file=f) + print("write_checkpoint -force %s/specimen_lag/lagff%d.dcp" % (root, x), file=f) + print("write_edif -force %s/specimen_lag/lagff%d.edf" % (root, x), file=f) + print("write_bitstream -force %s/specimen_lag/lagff%d.bit" % (root, x), file=f) +with open(root + "/lagff/run.sh", "w") as f: + print("#/usr/bin/env bash", file=f) + #print("set -ex", file=f) + for x in range(X): + print("vivado -mode batch -nolog -nojournal -source lagff%d.tcl" % x, file=f) + print("if [ $? -eq 0 ]; then", file=f) + print(" ../../ultra/tools/dump_bitstream %s/specimen_lag/lagff%d.bit %s/frames.txt > %s/specimen_lag/lagff%d.dump" % (root, x, root, root, x), file=f) + print(" python3 ../../ultra/tools/bits_to_tiles.py %s/tilebits.json %s/specimen_lag/lagff%d.dump > %s/specimen_lag/lagff%d.tbits" % (root, root, x, root, x), file=f) + print("else", file=f) + print(" rm %s/specimen_lag/lagff%d.dump" % (root, x), file=f) + print(" rm %s/specimen_lag/lagff%d.tbits" % (root, x), file=f) + print(" rm %s/specimen_lag/lagff%d.dcp" % (root, x), file=f) + print(" rm %s/specimen_lag/lagff%d.bit" % (root, x), file=f) + print(" rm %s/specimen_lag/lagff%d.features" % (root, x), file=f) + print("fi", file=f) \ No newline at end of file
diff --git a/spec/laguna_route.py b/spec/laguna_route.py new file mode 100644 index 0000000..ee8ca65 --- /dev/null +++ b/spec/laguna_route.py
@@ -0,0 +1,46 @@ +# Copyright 2020 Project U-Ray Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import numpy as np +import sys + +top_slices = [] +bot_slices = [] + +with open(sys.argv[1], "r") as tf: + for line in tf: + sl = line.strip().split(",") + if len(sl) < 4: + continue + for site in sl[4:]: + if site.startswith("SLICE_"): + if int(sl[1]) > 310 and int(sl[1]) < 355: + bot_slices.append(site.split(":")[0]) + elif int(sl[1]) < 310 and int(sl[1]) > 275: + top_slices.append(site.split(":")[0]) + +np.random.shuffle(top_slices) +np.random.shuffle(bot_slices) + +with open(sys.argv[2], "w") as f: + print("module top;", file=f) + for i in range(3000): + print("wire w%d;\n" % i, file=f) + sl1 = top_slices.pop() + sl2 = bot_slices.pop() + if np.random.choice([True, False]): + sl1, sl2 = sl2, sl1 + print("(* KEEP, DONT_TOUCH, LOC=\"%s\" *) LUT1 drv%d(.O(w%d));" % (sl1, i, i), file=f) + print("(* KEEP, DONT_TOUCH, LOC=\"%s\" *) LUT1 usr%d(.I0(w%d));" % (sl2, i, i), file=f) + print("endmodule", file=f)
diff --git a/spec/leaf_tap.py b/spec/leaf_tap.py new file mode 100644 index 0000000..067b02b --- /dev/null +++ b/spec/leaf_tap.py
@@ -0,0 +1,34 @@ +# Copyright 2020 Project U-Ray Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys +import numpy as np + +root = sys.argv[1] + +with open(root + "/leaftap/top.sv", "w") as f: + print("module top(input [7:0] clk, input d, output q);", file=f) + q = "d" + for c in range(8): + for x in range(200*c, 200*(c+1)): + depth = np.random.randint(5, 38) + print("wire [%d:0] lutchain_%d;" % (depth, x), file=f) + print("assign lutchain_%d[0] = %s;" % (x, q), file=f) + for i in range(depth): + print("(* keep, dont_touch *) LUT1 #(.INIT(2)) lut_%d_%d (.I0(lutchain_%d[%d]), .O(lutchain_%d[%d]));" % (x, i, x, i, x, i+1), file=f) + print("reg q_%d;" % x, file=f) + q = "q_%d" % x + print("always @(posedge clk[%d]) %s <= lutchain_%d[%d];" % (c, q, x, depth), file=f) + print("assign q = %s;\n" % q, file=f) + print("endmodule", file=f)
diff --git a/spec/mmcm_pll_used.py b/spec/mmcm_pll_used.py new file mode 100644 index 0000000..8e9bf27 --- /dev/null +++ b/spec/mmcm_pll_used.py
@@ -0,0 +1,206 @@ +# Copyright 2020 Project U-Ray Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import numpy as np +import sys + +X = 60 +root = sys.argv[1] + +def random_vector(size): + return "{%s}" % ", ".join(["d[%d]" % np.random.randint(40) for k in range(size)]) + +cmts = [] +with open(root + "/tiles.txt", "r") as tf: + for line in tf: + sl = line.strip().split(",") + if len(sl) < 4: + continue + if sl[3] != "CMT_L": + continue + mmcm = None + plls = [] + bufgces = [] + for site in sl[4:]: + sitename, sitetype = site.split(':') + if sitetype == "MMCM": + mmcm = site + elif sitetype == "PLL": + plls.append(sitename) + elif sitetype == "BUFGCE": + bufgces.append(sitename) + print(sl[2], plls) + cmts.append((sl[2], mmcm, plls, bufgces)) + +site_to_pin = {} +with open (root + "/iopins.txt", "r") as iof: + for line in iof: + sl = line.strip().split(",") + if len(sl) < 5: + continue + pin = sl[0] + bank = int(sl[1]) + func = sl[2] + site_name = sl[3] + site_type = sl[4] + if "GC" not in func or "HPIOB_M" not in site_type: + continue + site_to_pin[site_name] = pin + +for x in range(X): + np.random.shuffle(cmts) + with open(root + "/pllused/pllused%d.v" % x, "w") as f: + print("module top(input [%d:0] ccio, input psen, psincdec, pwrdwn, rst);" % (len(cmts)*4-1), file=f) + print("wire gr0, gr1;", file=f) + print("(* keep, dont_touch *) LUT6 lut0 (.O(gr0));", file=f) + print("(* keep, dont_touch *) LUT6 lut1 (.O(gr1));", file=f) + bufg_outputs = [] + for i, cmt in enumerate(cmts): + tile, mmcm, plls, bufgces = cmt + if np.random.choice([True, False, False, False]): + continue + bufg_inputs = ["1'b1"] + clock_inputs = ["1'b1"] + clock_inputs += ["ccio[%d]" % (i*4+j) for j in range(4)] + clock_inputs += ["gr0", "gr1"] + if len(bufg_outputs) > 0: + clock_inputs.append(np.random.choice(bufg_outputs)) + clock_inputs.append(np.random.choice(bufg_outputs)) + if np.random.choice([True, True, True, True, False]): + fb_mode = np.random.choice([ + "AUTO", "ZHOLD", "EXTERNAL", "INTERNAL", "BUF_IN", + ]) + print(" wire [12:0] mmcm_out_%d;\n" % i, file=f) + print("(* keep, dont_touch, LOC=\"%s\" *) MMCME4_ADV #(" % mmcm, file=f) + print(" .CLKIN1_PERIOD(10.0),", file=f) + print(" .CLKIN2_PERIOD(10.0),", file=f) + print(" .IS_PSEN_INVERTED(%d)," % np.random.randint(2), file=f) + print(" .IS_PSINCDEC_INVERTED(%d)," % np.random.randint(2), file=f) + print(" .IS_PWRDWN_INVERTED(%d)," % np.random.randint(2), file=f) + print(" .IS_RST_INVERTED(%d)," % np.random.randint(2), file=f) + print(" .COMPENSATION(\"%s\")" % fb_mode, file=f) + print(") mmcm_%d (" % i, file=f) + print(" .CLKIN1(%s)," % np.random.choice(clock_inputs), file=f) + print(" .CLKIN2(%s)," % np.random.choice(clock_inputs), file=f) + print(" .CLKFBIN(%s)," % (("mmcm_out_%d[0]" % i) if fb_mode in ("INTERNAL", "ZHOLD") else np.random.choice(clock_inputs)), file=f) + print(" .PSEN(psen),", file=f) + print(" .PSINCDEC(psincdec),", file=f) + print(" .PWRDWN(pwrdwn),", file=f) + print(" .RST(rst),", file=f) + print(" .CLKFBOUT(mmcm_out_%d[0])," % i, file=f) + print(" .CLKFBOUTB(mmcm_out_%d[1])," % i, file=f) + print(" .CLKOUT0(mmcm_out_%d[2])," % i, file=f) + print(" .CLKOUT0B(mmcm_out_%d[3])," % i, file=f) + print(" .CLKOUT1(mmcm_out_%d[4])," % i, file=f) + print(" .CLKOUT1B(mmcm_out_%d[5])," % i, file=f) + print(" .CLKOUT2(mmcm_out_%d[6])," % i, file=f) + print(" .CLKOUT2B(mmcm_out_%d[7])," % i, file=f) + print(" .CLKOUT3(mmcm_out_%d[8])," % i, file=f) + print(" .CLKOUT3B(mmcm_out_%d[9])," % i, file=f) + print(" .CLKOUT4(mmcm_out_%d[10])," % i, file=f) + print(" .CLKOUT5(mmcm_out_%d[11])," % i, file=f) + print(" .CLKOUT6(mmcm_out_%d[12])" % i, file=f) + print(");", file=f) + bufg_inputs += ["mmcm_out_%d[%d]" % (i, j) for j in range(13)] + # MMCM --> PLL + clock_inputs.append("mmcm_out_%d[2]" % i) + clock_inputs.append("mmcm_out_%d[4]" % i) + clock_inputs.append("mmcm_out_%d[6]" % i) + clock_inputs.append("mmcm_out_%d[8]" % i) + for p in range(2): + if np.random.choice([True, True, False]): + fb_mode = np.random.choice([ + "AUTO", "INTERNAL", "BUF_IN", + ]) + print(" wire [3:0] pll_out_%d_%d;\n" % (i, p), file=f) + print("(* keep, dont_touch, LOC=\"%s\" *) PLLE4_ADV #(" % plls[p], file=f) + print(" .CLKIN_PERIOD(10.0),", file=f) + print(" .IS_PWRDWN_INVERTED(%d)," % np.random.randint(2), file=f) + print(" .IS_RST_INVERTED(%d)," % np.random.randint(2), file=f) + print(" .COMPENSATION(\"%s\")" % fb_mode, file=f) + print(") pll_%d_%d (" % (i, p), file=f) + print(" .CLKIN(%s)," % np.random.choice(clock_inputs), file=f) + print(" .PWRDWN(pwrdwn),", file=f) + print(" .RST(rst),", file=f) + print(" .CLKFBIN(%s)," % (("pll_out_%d_%d[0]" % (i, p)) if fb_mode in ("INTERNAL", "ZHOLD") else np.random.choice(clock_inputs)), file=f) + print(" .CLKFBOUT(pll_out_%d_%d[0])," % (i, p), file=f) + print(" .CLKOUT0(pll_out_%d_%d[1])," % (i, p), file=f) + print(" .CLKOUT1(pll_out_%d_%d[2])," % (i, p), file=f) + print(" .CLKOUT1B(pll_out_%d_%d[3])" % (i, p), file=f) + print(");", file=f) + bufg_inputs += ["pll_out_%d_%d[%d]" % (i, p, j) for j in range(4)] + for j, bufg in enumerate(bufgces): + if np.random.choice([True, True, True, False]): + print("wire bufg_out_%d_%d;" % (i, j), file=f) + print("(* keep, dont_touch, LOC=\"%s\" *)" % bufg, file=f) + print("BUFGCE bufg_%d_%d (" % (i, j), file=f) + print(" .I(%s)," % np.random.choice(bufg_inputs), file=f) + print(" .O(bufg_out_%d_%d)" % (i, j), file=f) + print(");", file=f) + bufg_outputs.append("bufg_out_%d_%d" % (i, j)) + print("endmodule", file=f) + with open(root + "/pllused/pllused%d.xdc" % x, "w") as f: + for i, cmt in enumerate(cmts): + tile = cmt[0] + cmt_x = int(tile[tile.rfind('X')+1:tile.rfind('Y')]) + cmt_y = int(tile[tile.rfind('Y')+1:]) + ccio = 0 + for site, pin in site_to_pin.items(): + if ccio >= 4: + break + site_x = int(site[site.rfind('X')+1:site.rfind('Y')]) + site_y = int(site[site.rfind('Y')+1:]) + if (site_x//2) != (cmt_x//40) or (site_y//52) != (cmt_y//60): + continue + print("set_property PACKAGE_PIN %s [get_ports {ccio[%d]}]" % (pin, i*4+ccio), file=f) + print("set_property IOSTANDARD LVCMOS18 [get_ports {ccio[%d]}]" % (i*4+ccio), file=f) + ccio += 1 + assert ccio == 4, (ccio, tile) + print("set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets gr*]", file=f) + print("set_property CLOCK_DEDICATED_ROUTE ANY_CMT_COLUMN [get_nets bufg_out*]", file=f) + with open(root + "/pllused/pllused%d.tcl" % x, "w") as f: + print("add_files %s" % (root + ("/pllused/pllused%d.v" % x)), file=f) + print("add_files %s" % (root + ("/pllused/pllused%d.xdc" % x)), file=f) + print("synth_design -top top -part xczu7ev-ffvf1517-2-e", file=f) + print("opt_design", file=f) + print("set_property SEVERITY {Warning} [get_drc_checks]", file=f) + print("place_design", file=f) + print("route_design", file=f) + print("set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design]", file=f) + print("write_checkpoint -force %s/specimen_clk/pllused%d.dcp" % (root, x), file=f) + print("write_edif -force %s/specimen_clk/pllused%d.edf" % (root, x), file=f) + print("write_bitstream -force %s/specimen_clk/pllused%d.bit" % (root, x), file=f) +with open(root + "/pllused/run.sh", "w") as f: + print("#/usr/bin/env bash", file=f) + print("set -ex", file=f) + print("vivado -mode batch -nolog -nojournal -source pllused$1.tcl", file=f) + print("if [ $? -eq 0 ]; then", file=f) + print(" ../../ultra/tools/dump_bitstream %s/specimen_clk/pllused$1.bit %s/frames.txt > %s/specimen_clk/pllused$1.dump" % (root, root, root), file=f) + print(" CLOCK_ONLY=1 python3 ../../ultra/tools/bits_to_tiles.py %s/tilebits.json %s/specimen_clk/pllused$1.dump > %s/specimen_clk/pllused$1.tbits" % (root, root, root), file=f) + print("else", file=f) + print(" rm %s/specimen_clk/pllused$1.dump" % (root, ), file=f) + print(" rm %s/specimen_clk/pllused$1.tbits" % (root, ), file=f) + print(" rm %s/specimen_clk/pllused$1.dcp" % (root, ), file=f) + print(" rm %s/specimen_clk/pllused$1.bit" % (root, ), file=f) + print(" rm %s/specimen_clk/pllused$1.features" % (root, ), file=f) + print("fi", file=f) +with open(root + "/pllused/Makefile", "w") as f: + print("all: %s" % " ".join(["%d.done" % i for i in range(X)]), file=f) + print("", file=f) + print("%.done: ", file=f) + print("\tbash run.sh $*", file=f) + print("\ttouch $@", file=f) + print("", file=f) + print("clean: ", file=f) + print("\trm -f *.done", file=f)
diff --git a/spec/pin_routing_fuzz.tcl b/spec/pin_routing_fuzz.tcl new file mode 100644 index 0000000..05ef046 --- /dev/null +++ b/spec/pin_routing_fuzz.tcl
@@ -0,0 +1,88 @@ +// Copyright 2020 Project U-Ray Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +set cells [get_cells -filter {PRIMITIVE_TYPE =~ *BUFG*}] +for {set k 0} {$k < 25} {incr k} { +foreach cell $cells { + set net [get_nets -of_objects [get_pins $cell/O]] + set success 0 + set src [lindex [get_nodes -of_objects [get_site_pins -filter {DIRECTION == OUT} -of_objects $net]] 0] + set sink [get_nodes -of_objects [get_site_pins -filter {DIRECTION == IN} -of_objects $net ]] + set orig_route [get_property FIXED_ROUTE $net] + set_property IS_ROUTE_FIXED 0 $net + route_design -unroute -nets $net + for {set i 0} {$i < 15} {incr i} { + # try and route using an interesting pip + set cursor $src + for {set j 0} {$j < 4} {incr j} { + if {[llength [get_nodes -downhill -of_objects $cursor]] > 1} { + break + } + set cursor [lindex [get_nodes -downhill -of_objects $cursor] 0] + } + set nodes [get_nodes -downhill -of_objects $cursor] + set from_node $cursor + set to_node [lindex $nodes [expr {int(rand()*[llength $nodes])}]] + puts "$k $i $net $src $from_node $to_node $sink" + # pre-reject dud pips + #if {[llength [get_nodes -uphill -of_objects $from_node]] == 0 || [llength [get_nodes -downhill -of_objects $to_node]] == 0} { + # continue + #} + if {[string first $from_node $orig_route] != -1} { + continue + } + if {$src != $from_node} { + if {[catch {set route_a [find_routing_path -max_nodes 10 -from $src -to $from_node]}]} { + continue + } + if {$route_a == ""} { + continue + } + } else { + set route_a $from_node + } + if {[catch {set route_b [find_routing_path -max_nodes 100 -from $to_node -to $sink]}]} { + continue + } + if {$route_b == ""} { + continue + } + if {[catch {set_property FIXED_ROUTE "$route_a $route_b" $net}]} { + continue + } + set_property IS_ROUTE_FIXED 1 $net + if {[get_property ROUTE_STATUS $net] != "ROUTED"} { + set_property IS_ROUTE_FIXED 0 $net + route_design -unroute -nets $net + continue + } + set success 1 + break + } + if {$success == 0} { + # route simply\\\\\\ + set_property FIXED_ROUTE [find_routing_path -from $src -to $sink] $net + } +} +set_property SEVERITY {Warning} [get_drc_checks NSTD-1] +set_property SEVERITY {Warning} [get_drc_checks UCIO-1] +set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design] + +#write_edif -force "./results/specimen_clk/bufgroute$k.edf" +#write_checkpoint -force "./results/specimen_clk/bufgroute$k.dcp" +#write_bitstream -force "./results/specimen_clk/bufgroute$k.bit" + +break + +} \ No newline at end of file
diff --git a/spec/pll_drp.py b/spec/pll_drp.py new file mode 100644 index 0000000..c7c0882 --- /dev/null +++ b/spec/pll_drp.py
@@ -0,0 +1,294 @@ +# Copyright 2020 Project U-Ray Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# From UG572 + +mmcm_regions = [ + (0x00, [ + (1, "IS_CLKIN1_INVERTED"), + (2, "IS_CLKIN2_INVERTED"), + (3, "IS_CLKFBIN_INVERTED"), + ((15, 4), "RESERVED_00", 4), + ]), + (0x02, [ + ((15, 0), "RESERVED_02", 0), + ]), + (0x04, [ + ((2, 0), "SS_STEPS", 0), + ((5, 3), "SS_STEPS_INIT", 0), + ((15, 6), "RESERVED_04", 6) + ]), + (0x05, [ + ((15, 0), "RESERVED_05", 0), + ]), + (0x06, [ + ((15, 13), "CLKOUT5_PM", 0), + (12, "CLKOUT5_EN"), + ((11, 6), "CLKOUT5_HT", 0), + ((5, 0), "CLKOUT5_LT", 0), + ]), + (0x07, [ + ((15, 13), "CLKOUT0_PM_F", 0), + (12, "CLKOUT0_FRAC_WF_F"), + #(10, "CLKOUT0_CDDC_EN"), + (7, "CLKOUT5_EDGE"), + (6, "CLKOUT5_NOCOUNT"), + ((5, 0), "CLKOUT5_DT", 0), + ]), + (0x08, [ + ((15, 13), "CLKOUT0_PM_R", 0), + (12, "CLKOUT0_EN"), + ((11, 6), "CLKOUT0_HT", 0), + ((5, 0), "CLKOUT0_LT", 0), + ]), + (0x09, [ + #(15, "CLKOUT0_CDDC_EN") + ((14, 12), "CLKOUT0_FRAC", 0), + (11, "CLKOUT0_FRAC_EN"), + (10, "CLKOUT0_FRAC_WF_R"), + (7, "CLKOUT0_EDGE"), + (6, "CLKOUT0_NOCOUNT"), + ((5, 0), "CLKOUT0_DT", 0), + ]), + (0x0A, [ + ((15, 13), "CLKOUT1_PM", 0), + (12, "CLKOUT1_EN"), + ((11, 6), "CLKOUT1_HT", 0), + ((5, 0), "CLKOUT1_LT", 0), + ]), + (0x0B, [ + (7, "CLKOUT1_EDGE"), + (6, "CLKOUT1_NOCOUNT"), + ((5, 0), "CLKOUT1_DT", 0), + ]), + (0x0C, [ + ((15, 13), "CLKOUT2_PM", 0), + (12, "CLKOUT2_EN"), + ((11, 6), "CLKOUT2_HT", 0), + ((5, 0), "CLKOUT2_LT", 0), + ]), + (0x0D, [ + (7, "CLKOUT2_EDGE"), + (6, "CLKOUT2_NOCOUNT"), + ((5, 0), "CLKOUT2_DT", 0), + ]), + (0x0E, [ + ((15, 13), "CLKOUT3_PM", 0), + (12, "CLKOUT3_EN"), + ((11, 6), "CLKOUT3_HT", 0), + ((5, 0), "CLKOUT3_LT", 0), + ]), + (0x0F, [ + (7, "CLKOUT3_EDGE"), + (6, "CLKOUT3_NOCOUNT"), + ((5, 0), "CLKOUT3_DT", 0), + ]), + (0x10, [ + ((15, 13), "CLKOUT4_PM", 0), + (12, "CLKOUT4_EN"), + ((11, 6), "CLKOUT4_HT", 0), + ((5, 0), "CLKOUT4_LT", 0), + ]), + (0x11, [ + (7, "CLKOUT4_EDGE"), + (6, "CLKOUT4_NOCOUNT"), + ((5, 0), "CLKOUT4_DT", 0), + ]), + (0x12, [ + ((15, 13), "CLKOUT6_PM", 0), + (12, "CLKOUT6_EN"), + ((11, 6), "CLKOUT6_HT", 0), + ((5, 0), "CLKOUT6_LT", 0), + ]), + (0x13, [ + ((15, 13), "CLKFBOUT_PM_F", 0), + (12, "CLKFBOUT_FRAC_WF_F"), + (7, "CLKOUT6_EDGE"), + (6, "CLKOUT6_NOCOUNT"), + ((5, 0), "CLKOUT6_DT", 0), + ]), + (0x14, [ + ((15, 13), "CLKFBOUT_PM_R", 0), + (12, "CLKFBOUT_EN"), + ((11, 6), "CLKFBOUT_HT", 0), + ((5, 0), "CLKFBOUT_LT", 0), + ]), + (0x15, [ + ((14, 12), "CLKFBOUT_FRAC", 0), + (11, "CLKFBOUT_FRAC_EN"), + (10, "CLKFBOUT_FRAC_WF_R"), + (7, "CLKFBOUT_EDGE"), + (6, "CLKFBOUT_NOCOUNT"), + ((5, 0), "CLKFBOUT_DT", 0), + ]), + (0x16, [ + (13, "DIVCLK_EDGE"), + (12, "DIVCLK_NOCOUNT"), + ((11, 6), "DIVCLK_HT", 0), + ((5, 0), "DIVCLK_LT", 0), + ]), + (0x18, [ + ((9, 0), "LOCK_COUNT", 0) + ]), + (0x19, [ + ((14, 10), "LOCK_FB_DLY", 0), + ((9, 0), "LOCK_FB_SAT_HIGH", 0), + ]), + (0x1A, [ + ((14, 10), "LOCK_REF_DLY", 0), + ((9, 0), "LOCK_REF_SAT_HIGH", 0), + ]), + (0x20, [ + ((15, 0), "RESERVED_20", 0), + ]), + (0x21, [ + ((15, 0), "RESERVED_21", 0), + ]), + (0x27, [ + (15, "INTERP_EN[7]"), + (12, "INTERP_EN[6]"), + (11, "INTERP_EN[5]"), + (8, "INTERP_EN[4]"), + (7, "INTERP_EN[3]"), + (4, "INTERP_EN[2]"), + (3, "INTERP_EN[1]"), + (0, "INTERP_EN[0]"), + ]), + (0x2C, [ + ((15, 0), "RESERVED_2C", 0), + ]), + (0x2D, [ + ((15, 0), "RESERVED_2D", 0), + ]), + (0x2F, [ + ((15, 0), "RESERVED_2F", 0), + ]), + (0x30, [ + ((15, 0), "RESERVED_30", 0), + ]), + (0x31, [ + ((15, 0), "RESERVED_31", 0), + ]), + (0x37, [ + ((15, 0), "RESERVED_37", 0), + ]), + (0x38, [ + ((15, 0), "RESERVED_38", 0), + ]), + (0x3C, [ + ((15, 0), "RESERVED_3C", 0), + ]), + (0x49, [ + ((15, 0), "RESERVED_49", 0), + ]), + (0x4A, [ + ((15, 0), "RESERVED_4A", 0), + ]), + (0x4E, [ + (15, "CHARGE_PUMP[3]"), + (12, "CHARGE_PUMP[2]"), + (11, "CHARGE_PUMP[1]"), + (8, "CHARGE_PUMP[0]"), + ((7, 0), "RESERVED_4E", 0), + ]), + (0x4F, [ + (15, "RES[3]"), + (12, "RES[2]"), + (11, "RES[1]"), + (8, "RES[0]"), + (7, "LFHF[1]"), + (4, "LFHF[0]"), + ]), + (0x72, [ + ((15, 0), "RESERVED_72", 0), + ]), + (0x73, [ + (15, "GTS_WAIT"), + (14, "STARTUP_WAIT"), + (13, "SS_EN"), + (12, "MMCM_EN"), + ]), + (0x74, [ + ((15, 0), "RESERVED_74", 0), + ]), + (0x76, [ + ((15, 0), "RESERVED_76", 0), + ]), + (0x77, [ + ((15, 0), "RESERVED_77", 0), + ]), + (0x78, [ + ((15, 0), "RESERVED_78", 0), + ]), + (0x79, [ + ((15, 0), "RESERVED_79", 0), + ]), + (0x7A, [ + ((15, 0), "RESERVED_7A", 0), + ]), + (0x7B, [ + ((15, 0), "RESERVED_7B", 0), + ]), + (0x7C, [ + ((15, 0), "RESERVED_7C", 0), + ]), + (0x7D, [ + ((15, 0), "RESERVED_7D", 0), + ]), + (0x7E, [ + ((15, 0), "RESERVED_7E", 0), + ]), + (0x7F, [ + ((15, 0), "RESERVED_7F", 0), + ]), +] + +cmt_height = 60*48 +mmcm_start_bit = 1824 + +def drp_to_cmt_bit(addr, bit): + frame = (bit % 2) + if addr >= 0x0C and addr <= 0x15: + addr -= 0x08 + frame += 2 + elif addr in (0x16, 0x17): + addr -= 0x10 + elif addr in (0x06, 0x17): + addr += 0x10 + elif addr >= 0x40 and addr <= 0x60: + addr -= 2 + elif addr >= 0x18 and addr <= 0x1A: + addr += 6 + elif addr >= 0x20 and addr <= 0x22: # fixme + addr -= 20 + elif addr == 0x27: + addr = 0x23 + elif addr >= 0x16: + addr -= 12 + data_bit = addr * 8 + data_bit += (bit // 2) + return frame * cmt_height + mmcm_start_bit + data_bit + +p = "MMCM." + +for addr, dbits in mmcm_regions: + for dbit in dbits: + if isinstance(dbit[0], tuple): + r, n, o = dbit + for i in range(r[1], r[0]+1): + print("%s%s[%d] %d" % (p, n, (i - r[1]) + o, drp_to_cmt_bit(addr, i))) + else: + b, n = dbit + print("%s%s %d" % (p, n, drp_to_cmt_bit(addr, b))) +
diff --git a/spec/process_bram_init.py b/spec/process_bram_init.py new file mode 100644 index 0000000..d81965f --- /dev/null +++ b/spec/process_bram_init.py
@@ -0,0 +1,92 @@ +# Copyright 2020 Project U-Ray Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import re +frame_set_bits = {} +group_set_bits = {} + +line_re = re.compile(r'F(0x[0-9A-Fa-f]+)W(\d+)B(\d+)') + +with open("bram.dump", "r") as df: + for line in df: + m = line_re.match(line) + if not m: + continue + frame = int(m[1], 16) + if (frame >> 24) != 0x01: + continue + frame = frame & 0xFF + if frame not in frame_set_bits: + frame_set_bits[frame] = set() + framebit = int(m[2]) * 32 + int(m[3]) + frame_set_bits[frame].add(framebit) +with open("bram.txt", "r") as ef: + for line in ef: + frame, startbit, site_y, data, parity = line.strip().split(" ") + frame = int(frame) + startbit = int(startbit) + site_y = int(site_y) + data = [int(x) for x in data] + parity = [int(x) for x in parity] + if (frame, startbit) not in group_set_bits: + group_set_bits[frame, startbit] = set() + for i, d in enumerate(data): + if d != 1: + continue + group_set_bits[frame, startbit].add("%d_%d" % (site_y, i)) + for i, d in enumerate(parity): + if d != 1: + continue + group_set_bits[frame, startbit].add("%d_P%d" % (site_y, i)) + +#features = [] +#for y in range(2): +# features += ["%d_%d" % (y, i) for i in range(64)] +# features += ["%d_P%d" % (y, i) for i in range(8)] + + +bram_permute = [] +for i, prefix in enumerate(("0_", "0_P", "1_", "1_P")): + permute = [] + for j in range(8 if prefix.endswith("P") else 64): + f = "%s%d" % (prefix, j) + candidates = None + for group, features in group_set_bits.items(): + if f not in features: + continue + frame, startbit = group + if frame not in frame_set_bits: + continue + set_bits = frame_set_bits[frame] + if candidates is None: + candidates = set() + for b in range(startbit, startbit + 240): + if b in set_bits: + candidates.add(b - startbit) + else: + todelete = [] + for c in candidates: + if (startbit + c) not in set_bits: + todelete.append(c) + for t in todelete: + candidates.remove(t) + print("%s: %s" % (f, " ".join([str(c) for c in sorted(candidates)]))) + permute.append(list(candidates)[0]) + bram_permute.append(permute) + +for i, cname in enumerate(("bram_y0_permute", "bram_p_y0_permute", "bram_y1_permute", "bram_p_y1_permute")): + p = bram_permute[i] + print("static const int %s[%d] = {%s};" % ( + cname, len(p), ", ".join(str(x) for x in p) + ))
diff --git a/spec/rclk_routing_fuzz_2.tcl b/spec/rclk_routing_fuzz_2.tcl new file mode 100644 index 0000000..53d97e8 --- /dev/null +++ b/spec/rclk_routing_fuzz_2.tcl
@@ -0,0 +1,275 @@ +// Copyright 2020 Project U-Ray Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +proc make_driver_cell {name celltype loc pinname} { + create_net "${name}_net" + set net [get_nets "${name}_net"] + create_cell -reference $celltype "${name}_drv" + place_cell "${name}_drv" $loc + connect_net -net $net -objects [get_pins "${name}_drv/${pinname}"] + return [list [get_cells "${name}_drv"] $net] +} + +proc make_user_cell {name celltype loc pinname net} { + create_cell -reference $celltype "${name}_usr" + place_cell "${name}_usr" $loc + connect_net -net $net -objects [get_pins "${name}_usr/${pinname}"] + return [list [get_cells "${name}_usr"] $net] +} + + +proc make_site_pin_driver {pin} { + set site [get_sites -of_objects $pin] + if { $site == {} } { + return {} + } + set sitetype [get_property SITE_TYPE $site] + set pinname [lindex [split $pin "/"] 1] + set objname "${site}_${pinname}" + if {[get_cells -of_objects $site] != {}} { + return {} + } + if {$sitetype == "BUFCE_ROW" && $pinname == "CLK_OUT"} { + return [make_driver_cell $objname "BUFCE_ROW" "$site/BUFCE" "O"] + } elseif {$sitetype == "BUFCE_ROW_FSR" && $pinname == "CLK_OUT"} { + return [make_driver_cell $objname "BUFCE_ROW" "$site/BUFCE" "O"] + } elseif {$sitetype == "BUFCE_LEAF" && $pinname == "CLK_OUT"} { + return [make_driver_cell $objname "BUFCE_LEAF" "$site/BUFCE" "O"] + } elseif {$sitetype == "BUFGCE" && $pinname == "CLK_OUT"} { + return [make_driver_cell $objname "BUFGCE" "$site/BUFCE" "O"] + } elseif {$sitetype == "BUFGCE_HDIO" && $pinname == "CLK_OUT"} { + return [make_driver_cell $objname "BUFGCE" "$site/BUFCE" "O"] + } elseif {$sitetype == "BUFGCE_DIV" && $pinname == "CLK_OUT"} { + set result [make_driver_cell $objname "BUFGCE_DIV" "$site/BUFGCE_DIV" "O"] + set_property BUFGCE_DIVIDE 1 [lindex $result 0] + return $result + } elseif {$sitetype == "BUFGCTRL" && $pinname == "CLK_OUT"} { + return [make_driver_cell $objname "BUFGCTRL" "$site/BUFGCTRL" "O"] + } elseif {$sitetype == "BUFG_GT" && $pinname == "CLK_OUT"} { + return [make_driver_cell $objname "BUFG_GT" "$site/BUFG_GT" "O"] + } elseif {($sitetype == "SLICEL" || $sitetype == "SLICEM") && [string range $pinname 1 4] == "MUX"} { + set eighth [string range $pinname 0 0] + return [make_driver_cell $objname "LUT6" "$site/${eighth}6LUT" "O"] + } else { + return {} + } +} + +proc make_site_pin_user {pin net} { + set site [get_sites -of_objects $pin] + if { $site == {} } { + return {} + } + set sitetype [get_property SITE_TYPE $site] + set pinname [lindex [split $pin "/"] 1] + set objname "${site}_${pinname}" + if {[get_cells -of_objects $site] != {}} { + return {} + } + if {$sitetype == "BUFCE_LEAF" && $pinname == "CLK_IN"} { + return [make_user_cell $objname "BUFCE_LEAF" "$site/BUFCE" "I" $net] + } elseif {$sitetype == "BUFCE_LEAF" && $pinname == "CE_INT"} { + return [make_user_cell $objname "BUFCE_LEAF" "$site/BUFCE" "CE" $net] + } elseif {$sitetype == "BUFGCE" && $pinname == "CLK_IN"} { + return [make_user_cell $objname "BUFGCE" "$site/BUFCE" "I" $net] + } elseif {$sitetype == "BUFGCE_HDIO" && $pinname == "CLK_IN"} { + return [make_user_cell $objname "BUFGCE" "$site/BUFCE" "I" $net] + } elseif {$sitetype == "BUFGCE_DIV" && $pinname == "CLK_IN"} { + set result [make_user_cell $objname "BUFGCE_DIV" "$site/BUFGCE_DIV" "I" $net] + set_property BUFGCE_DIVIDE 1 [lindex $result 0] + return $result + } elseif {$sitetype == "BUFGCTRL" && $pinname == "CLK_I0"} { + return [make_user_cell $objname "BUFGCTRL" "$site/BUFGCTRL" "I0" $net] + } elseif {$sitetype == "BUFGCTRL" && $pinname == "CLK_I1"} { + return [make_user_cell $objname "BUFGCTRL" "$site/BUFGCTRL" "I1" $net] + } elseif {$sitetype == "BUFG_GT" && $pinname == "CLK_IN"} { + return [make_user_cell $objname "BUFG_GT" "$site/BUFG_GT" "I" $net] + } elseif {$sitetype == "SLICEM" && $pinname == "LCLK"} { + return [make_user_cell $objname "SRL16E" "$site/H6LUT" "CLK" $net] + } elseif {($sitetype == "SLICEM" || $sitetype == "SLICEL") && $pinname == "CLK1"} { + return [make_user_cell $objname "FDRE" "$site/AFF" "C" $net] + } elseif {($sitetype == "SLICEM" || $sitetype == "SLICEL") && $pinname == "CLK2"} { + return [make_user_cell $objname "FDRE" "$site/EFF" "C" $net] + } elseif {$sitetype == "BITSLICE_RX_TX" && $pinname == "RX_CLK"} { + return [make_user_cell $objname "IDELAYE3" "$site/IDELAY" "CLK" $net] + } elseif {$sitetype == "BITSLICE_RX_TX" && $pinname == "RX_CLK_C"} { + return [make_user_cell $objname "ISERDESE3" "$site/ISERDES" "CLK" $net] + } elseif {$sitetype == "BITSLICE_RX_TX" && $pinname == "RX_CLKDIV"} { + return [make_user_cell $objname "ISERDESE3" "$site/ISERDES" "CLKDIV" $net] + } elseif {$sitetype == "BITSLICE_RX_TX" && $pinname == "TX_OCLK"} { + return [make_user_cell $objname "OSERDESE3" "$site/OSERDES" "CLK" $net] + } else { + return {} + } +} + +proc route_via {net sink_pin pip} { + set success 0 + set src [lindex [get_nodes -of_objects [get_site_pins -filter {DIRECTION == OUT} -of_objects $net]] 0] + set sink [get_nodes -of_objects [get_site_pins -filter {DIRECTION == IN} -of_objects $net ]] + if {$sink == {}} { + set sink $sink_pin + } + set_property IS_ROUTE_FIXED 0 $net + #route_design -unroute -nets $net + + set from_node [get_nodes -uphill -of_objects $pip] + set to_node [get_nodes -downhill -of_objects $pip] + if {$src == $from_node} { + set route_a $from_node + } else { + if {[catch {set route_a [find_routing_path -max_nodes 15 -from $src -to $from_node]}]} { + return 0 + } + if {$route_a == ""} { + return 0 + } + } + if {$sink == $to_node} { + set route_b $to_node + } else { + if {[catch {set route_b [find_routing_path -max_nodes 15 -from $to_node -to $sink]}]} { + return 0 + } + if {$route_b == ""} { + return 0 + } + } + + if {[catch {set_property FIXED_ROUTE "$route_a $route_b" $net}]} { + return 0 + } + set_property IS_ROUTE_FIXED 1 $net + if {[get_property ROUTE_STATUS $net] != "ROUTED"} { + set_property IS_ROUTE_FIXED 0 $net + route_design -unroute -nets $net + return 0 + } + return 1 +} + +# https://wiki.tcl-lang.org/page/Shuffle+a+list +proc shuffle6 { list } { + set n [llength $list] + for { set i 1 } { $i < $n } { incr i } { + set j [expr { int( rand() * $n ) }] + set temp [lindex $list $i] + lset list $i [lindex $list $j] + lset list $j $temp + } + return $list + } + +set tile_types [list "CMT_L" "CMT_L" "CMT_L" "RCLK_BRAM_INTF_L" \ + "RCLK_CLEL_L_L" "RCLK_CLEM_CLKBUF_L" "RCLK_CLEM_L" \ + "RCLK_DSP_INTF_R" "RCLK_DSP_INTF_CLKBUF_L" "RCLK_INT_L"\ + "RCLK_INT_R" "RCLK_RCLK_XIPHY_INNER_FT" "RCLK_HDIO" "RCLK_RCLK_URAM_INTF_L_FT"] + +set run $::argv +create_project -force -part xczu7ev-ffvf1517-2-e design${run} design${run} + + +link_design +create_cell -reference LUT6 "misc_lut" +place_design +route_design + +#remove_cell [get_cells] +#remove_net [get_nets] + +set count [expr {int(110 + rand()*80)}] + +for {set i 0} {$i < $count} {incr i} { + puts "$i/$count" + for {set j 0} {$j < 10} {incr j} { + set tt [lindex $tile_types [expr {int(rand()*[llength $tile_types])}]] + set tiles [get_tiles -filter "TILE_TYPE == $tt"] + set tile [lindex $tiles [expr {int(rand()*[llength $tiles])}]] + set tile_pips [get_pips -of_objects $tile -filter {NAME !~ "*VCC_WIRE*"}] + set pip [lindex $tile_pips [expr {int(rand()*[llength $tile_pips])}]] + set wavefront_bwd $pip + set driver {} + for {set k 0} {$k < 10} {incr k} { + set wavefront_bwd [get_nodes -uphill -of_objects $wavefront_bwd] + # Randomly skip to vary depth + if {rand() > 0.5} { + set wavefront_pins [shuffle6 [get_site_pins -of_objects $wavefront_bwd]] + foreach pin $wavefront_pins { + set driver [make_site_pin_driver $pin] + if {$driver != {}} { + break + } + } + } + if {$driver != {}} { + break + } + if {[llength $wavefront_bwd] > 20000} { + break + } + } + + if {$driver == {}} { + continue + } + + set drv_cell [lindex $driver 0] + set net [lindex $driver 1] + + set wavefront_fwd $pip + set user {} + for {set k 0} {$k < 10} {incr k} { + set wavefront_fwd [get_nodes -downhill -of_objects $wavefront_fwd] + # Randomly skip to vary depth + if {rand() > 0.5} { + set wavefront_pins [shuffle6 [get_site_pins -of_objects $wavefront_fwd]] + foreach pin $wavefront_pins { + set user [make_site_pin_user $pin $net] + set sink_pin $pin + if {$user != {}} { + break + } + } + } + if {$user != {}} { + break + } + if {[llength $wavefront_fwd] > 20000} { + break + } + } + + if {$user == {}} { + remove_cell $drv_cell + remove_net $net + continue + } + + set success [route_via $net $sink_pin $pip] + if { $success == 0 } { + remove_cell $drv_cell + remove_cell [lindex $user 0] + remove_net $net + } else { + break + } + } +} + +set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design] +set_property SEVERITY {Warning} [get_drc_checks] +write_checkpoint -force ../specimen_clk/rclkroute_b${run}.dcp +write_edif -force ../specimen_clk/rclkroute_b${run}.edf +write_bitstream -force ../specimen_clk/rclkroute_b${run}.bit +
diff --git a/spec/rclk_routing_fuzz_3.tcl b/spec/rclk_routing_fuzz_3.tcl new file mode 100644 index 0000000..e117311 --- /dev/null +++ b/spec/rclk_routing_fuzz_3.tcl
@@ -0,0 +1,317 @@ +// Copyright 2020 Project U-Ray Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +proc make_driver_cell {name celltype loc pinname} { + set existing_cell [get_cells -of_objects [get_bels $loc]] + if {$existing_cell != {}} { + set existing_net [get_nets -of_objects [get_pins "${existing_cell}/${pinname}"]] + if {$existing_net != {}} { + return {} + } + create_net "${name}_net" + set net [get_nets "${name}_net"] + connect_net -net $net -objects [get_pins "${existing_cell}/${pinname}"] + return [list $existing_cell $net] + } + create_net "${name}_net" + set net [get_nets "${name}_net"] + create_cell -reference $celltype "${name}_drv" + place_cell "${name}_drv" $loc + connect_net -net $net -objects [get_pins "${name}_drv/${pinname}"] + return [list [get_cells "${name}_drv"] $net] +} + +proc make_user_cell {name celltype loc pinname net} { + set existing_cell [get_cells -of_objects [get_bels $loc]] + if {$existing_cell != {}} { + set existing_net [get_nets -of_objects [get_pins "${existing_cell}/${pinname}"]] + if {$existing_net != {}} { + return {} + } + connect_net -net $net -objects [get_pins "${existing_cell}/${pinname}"] + return [list $existing_cell $net] + } + create_cell -reference $celltype "${name}_usr" + place_cell "${name}_usr" $loc + connect_net -net $net -objects [get_pins "${name}_usr/${pinname}"] + return [list [get_cells "${name}_usr"] $net] +} + + +proc make_site_pin_driver {pin} { + set site [get_sites -of_objects $pin] + if { $site == {} } { + return {} + } + set sitetype [get_property SITE_TYPE $site] + set pinname [lindex [split $pin "/"] 1] + set objname "${site}_${pinname}" + if {$sitetype == "BUFCE_ROW" && $pinname == "CLK_OUT"} { + return [make_driver_cell $objname "BUFCE_ROW" "$site/BUFCE" "O"] + } elseif {$sitetype == "BUFCE_ROW_FSR" && $pinname == "CLK_OUT"} { + return [make_driver_cell $objname "BUFCE_ROW" "$site/BUFCE" "O"] + } elseif {$sitetype == "BUFCE_LEAF" && $pinname == "CLK_OUT"} { + return [make_driver_cell $objname "BUFCE_LEAF" "$site/BUFCE" "O"] + } elseif {$sitetype == "BUFGCE" && $pinname == "CLK_OUT"} { + return [make_driver_cell $objname "BUFGCE" "$site/BUFCE" "O"] + } elseif {$sitetype == "BUFGCE_HDIO" && $pinname == "CLK_OUT"} { + return [make_driver_cell $objname "BUFGCE" "$site/BUFCE" "O"] + } elseif {$sitetype == "BUFGCE_DIV" && $pinname == "CLK_OUT"} { + set result [make_driver_cell $objname "BUFGCE_DIV" "$site/BUFGCE_DIV" "O"] + if {$result == {}} { + return {} + } + set_property BUFGCE_DIVIDE 1 [lindex $result 0] + return $result + } elseif {$sitetype == "BUFGCTRL" && $pinname == "CLK_OUT"} { + return [make_driver_cell $objname "BUFGCTRL" "$site/BUFGCTRL" "O"] + } elseif {$sitetype == "BUFG_GT" && $pinname == "CLK_OUT"} { + return [make_driver_cell $objname "BUFG_GT" "$site/BUFG_GT" "O"] + } elseif {($sitetype == "SLICEL" || $sitetype == "SLICEM") && [string range $pinname 1 4] == "MUX"} { + set eighth [string range $pinname 0 0] + return [make_driver_cell $objname "LUT6" "$site/${eighth}6LUT" "O"] + } elseif {$sitetype == "MMCM" && [string first "CLK" $pinname] != -1 && [string first "OUT" $pinname] != -1} { + return [make_driver_cell $objname "MMCME4_ADV" "$site/MMCM" $pinname] + } elseif {$sitetype == "PLL" && [string first "CLK" $pinname] != -1 && [string first "OUT" $pinname] != -1} { + return [make_driver_cell $objname "PLLE4_ADV" "$site/PLL" $pinname] + } else { + return {} + } +} + +proc make_site_pin_user {pin net} { + set site [get_sites -of_objects $pin] + if { $site == {} } { + return {} + } + set sitetype [get_property SITE_TYPE $site] + set pinname [lindex [split $pin "/"] 1] + set objname "${site}_${pinname}" + if {[get_nets -of_objects $pin] != {}} { + return {} + } + if {$sitetype == "BUFCE_LEAF" && $pinname == "CLK_IN"} { + return [make_user_cell $objname "BUFCE_LEAF" "$site/BUFCE" "I" $net] + } elseif {$sitetype == "BUFCE_LEAF" && $pinname == "CE_INT"} { + return [make_user_cell $objname "BUFCE_LEAF" "$site/BUFCE" "CE" $net] + } elseif {$sitetype == "BUFCE_ROW_FSR" && $pinname == "CE_PRE_OPTINV"} { + return [make_user_cell $objname "BUFCE_ROW" "$site/BUFCE" "CE" $net] + } elseif {$sitetype == "BUFCE_ROW" && $pinname == "CE_PRE_OPTINV"} { + return [make_user_cell $objname "BUFCE_ROW" "$site/BUFCE" "CE" $net] + } elseif {$sitetype == "BUFGCE" && $pinname == "CLK_IN"} { + return [make_user_cell $objname "BUFGCE" "$site/BUFCE" "I" $net] + } elseif {$sitetype == "BUFGCE_HDIO" && $pinname == "CLK_IN"} { + return [make_user_cell $objname "BUFGCE" "$site/BUFCE" "I" $net] + } elseif {$sitetype == "BUFGCE_DIV" && $pinname == "CLK_IN"} { + set result [make_user_cell $objname "BUFGCE_DIV" "$site/BUFGCE_DIV" "I" $net] + set_property BUFGCE_DIVIDE 1 [lindex $result 0] + return $result + } elseif {$sitetype == "BUFGCTRL" && $pinname == "CLK_I0"} { + return [make_user_cell $objname "BUFGCTRL" "$site/BUFGCTRL" "I0" $net] + } elseif {$sitetype == "BUFGCTRL" && $pinname == "CLK_I1"} { + return [make_user_cell $objname "BUFGCTRL" "$site/BUFGCTRL" "I1" $net] + } elseif {$sitetype == "BUFG_GT" && $pinname == "CLK_IN"} { + return [make_user_cell $objname "BUFG_GT" "$site/BUFG_GT" "I" $net] + } elseif {$sitetype == "SLICEM" && $pinname == "LCLK"} { + return [make_user_cell $objname "SRL16E" "$site/H6LUT" "CLK" $net] + } elseif {($sitetype == "SLICEM" || $sitetype == "SLICEL") && $pinname == "CLK1"} { + return [make_user_cell $objname "FDRE" "$site/AFF" "C" $net] + } elseif {($sitetype == "SLICEM" || $sitetype == "SLICEL") && $pinname == "CLK2"} { + return [make_user_cell $objname "FDRE" "$site/EFF" "C" $net] + } elseif {$sitetype == "BITSLICE_RX_TX" && $pinname == "RX_CLK"} { + return [make_user_cell $objname "IDELAYE3" "$site/IDELAY" "CLK" $net] + } elseif {$sitetype == "BITSLICE_RX_TX" && $pinname == "RX_CLK_C"} { + return [make_user_cell $objname "ISERDESE3" "$site/ISERDES" "CLK" $net] + } elseif {$sitetype == "BITSLICE_RX_TX" && $pinname == "RX_CLKDIV"} { + return [make_user_cell $objname "ISERDESE3" "$site/ISERDES" "CLKDIV" $net] + } elseif {$sitetype == "BITSLICE_RX_TX" && $pinname == "TX_OCLK"} { + return [make_user_cell $objname "OSERDESE3" "$site/OSERDES" "CLK" $net] + } elseif {$sitetype == "MMCM" && $pinname == "CLKIN1"} { + return [make_user_cell $objname "MMCME4_ADV" "$site/MMCM" "CLKIN1" $net] + } elseif {$sitetype == "MMCM" && $pinname == "CLKIN2"} { + return [make_user_cell $objname "MMCME4_ADV" "$site/MMCM" "CLKIN2" $net] + } elseif {$sitetype == "MMCM" && $pinname == "CLKFBIN"} { + return [make_user_cell $objname "MMCME4_ADV" "$site/MMCM" "CLKFBIN" $net] + } elseif {$sitetype == "PLL" && $pinname == "CLKIN"} { + return [make_user_cell $objname "PLLE4_ADV" "$site/PLL" "CLKIN" $net] + } elseif {$sitetype == "PLL" && $pinname == "CLKFBIN"} { + return [make_user_cell $objname "PLLE4_ADV" "$site/PLL" "CLKFBIN" $net] + } else { + return {} + } +} + +proc route_via {net sink_pin pip} { + set success 0 + set src [lindex [get_nodes -of_objects [get_site_pins -filter {DIRECTION == OUT} -of_objects $net]] 0] + set sink [get_nodes -of_objects [get_site_pins -filter {DIRECTION == IN} -of_objects $net ]] + if {$sink == {}} { + set sink [get_nodes -of_objects $sink_pin] + } + set_property IS_ROUTE_FIXED 0 $net + #route_design -unroute -nets $net + + set from_node [get_nodes -uphill -of_objects $pip] + set to_node [get_nodes -downhill -of_objects $pip] + if {$src == $from_node} { + set route_a $from_node + } else { + if {[catch {set route_a [find_routing_path -max_nodes 15 -from $src -to $from_node]}]} { + return 0 + } + if {$route_a == ""} { + return 0 + } + } + if {$sink == $to_node} { + set route_b $to_node + } else { + if {[catch {set route_b [find_routing_path -max_nodes 15 -from $to_node -to $sink]}]} { + return 0 + } + if {$route_b == ""} { + return 0 + } + } + + if {[catch {set_property FIXED_ROUTE "$route_a $route_b" $net}]} { + return 0 + } + set_property IS_ROUTE_FIXED 1 $net + if {[get_property ROUTE_STATUS $net] != "ROUTED"} { + set_property IS_ROUTE_FIXED 0 $net + route_design -unroute -nets $net + return 0 + } + return 1 +} + +# https://wiki.tcl-lang.org/page/Shuffle+a+list +proc shuffle6 { list } { + set n [llength $list] + for { set i 1 } { $i < $n } { incr i } { + set j [expr { int( rand() * $n ) }] + set temp [lindex $list $i] + lset list $i [lindex $list $j] + lset list $j $temp + } + return $list + } + +set tile_types [list "CMT_L" "CMT_L" "CMT_L" "RCLK_INT_L" "RCLK_RCLK_XIPHY_INNER_FT"] + +set run $::argv +create_project -force -part xczu7ev-ffvf1517-2-e design${run} design${run} + + +link_design +create_cell -reference LUT6 "misc_lut" +place_design +route_design + +#remove_cell [get_cells] +#remove_net [get_nets] + +set count [expr {int(110 + rand()*80)}] + +for {set i 0} {$i < $count} {incr i} { + puts "$i/$count" + set tt [lindex $tile_types [expr {int(rand()*[llength $tile_types])}]] + for {set j 0} {$j < 10} {incr j} { + set tiles [get_tiles -filter "TILE_TYPE == $tt"] + set tile [lindex $tiles [expr {int(rand()*[llength $tiles])}]] + set tile_pips [get_pips -of_objects $tile -filter {NAME !~ "*VCC_WIRE*"}] + set pip [lindex $tile_pips [expr {int(rand()*[llength $tile_pips])}] "*CLK_LEAF*"] + set wavefront_bwd $pip + set driver {} + for {set k 0} {$k < 10} {incr k} { + set wavefront_bwd [get_nodes -uphill -of_objects $wavefront_bwd] + # Randomly skip to vary depth + if {rand() > 0.5 || [llength [get_nodes -uphill -of_objects $wavefront_bwd]] == 0} { + set wavefront_pins [shuffle6 [get_site_pins -of_objects $wavefront_bwd]] + foreach pin $wavefront_pins { + set driver [make_site_pin_driver $pin] + if {$driver != {}} { + break + } + } + } + if {$driver != {}} { + break + } + if {[llength $wavefront_bwd] > 20000} { + break + } + } + + if {$driver == {}} { + continue + } + + set drv_cell [lindex $driver 0] + set net [lindex $driver 1] + + set wavefront_fwd $pip + set user {} + for {set k 0} {$k < 10} {incr k} { + set wavefront_fwd [get_nodes -downhill -of_objects $wavefront_fwd] + # Randomly skip to vary depth + if {rand() > 0.5 || [llength [get_nodes -downhill -of_objects $wavefront_fwd]] == 0} { + set wavefront_pins [shuffle6 [get_site_pins -of_objects $wavefront_fwd]] + foreach pin $wavefront_pins { + set user [make_site_pin_user $pin $net] + set sink_pin $pin + if {$user != {}} { + break + } + } + } + if {$user != {}} { + break + } + if {[llength $wavefront_fwd] > 20000} { + break + } + } + + if {$user == {}} { + if {[llength [get_nets -of_objects $drv_cell]] == 1} { + remove_cell $drv_cell + } + remove_net $net + continue + } + + set success [route_via $net $sink_pin $pip] + if { $success == 0 } { + if {[llength [get_nets -of_objects $drv_cell]] == 1} { + remove_cell $drv_cell + } + set user_cell [lindex $user 0] + if {[llength [get_nets -of_objects $user_cell]] == 1} { + remove_cell $user_cell + } + remove_net $net + } else { + break + } + } +} + +set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design] +set_property SEVERITY {Warning} [get_drc_checks] +write_checkpoint -force ../specimen_clk/rclkroute_pll${run}.dcp +write_edif -force ../specimen_clk/rclkroute_pll${run}.edf +write_bitstream -force ../specimen_clk/rclkroute_pll${run}.bit +
diff --git a/spec/rclk_routing_fuzz_io.tcl b/spec/rclk_routing_fuzz_io.tcl new file mode 100644 index 0000000..e7ba73e --- /dev/null +++ b/spec/rclk_routing_fuzz_io.tcl
@@ -0,0 +1,274 @@ +// Copyright 2020 Project U-Ray Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +proc make_driver_cell {name celltype loc pinname} { + create_net "${name}_net" + set net [get_nets "${name}_net"] + create_cell -reference $celltype "${name}_drv" + place_cell "${name}_drv" $loc + connect_net -net $net -objects [get_pins "${name}_drv/${pinname}"] + return [list [get_cells "${name}_drv"] $net] +} + +proc make_user_cell {name celltype loc pinname net} { + create_cell -reference $celltype "${name}_usr" + place_cell "${name}_usr" $loc + connect_net -net $net -objects [get_pins "${name}_usr/${pinname}"] + return [list [get_cells "${name}_usr"] $net] +} + + +proc make_site_pin_driver {pin} { + set site [get_sites -of_objects $pin] + if { $site == {} } { + return {} + } + set sitetype [get_property SITE_TYPE $site] + set pinname [lindex [split $pin "/"] 1] + set objname "${site}_${pinname}" + if {[get_cells -of_objects $site] != {}} { + return {} + } + if {$sitetype == "BUFCE_ROW" && $pinname == "CLK_OUT"} { + return [make_driver_cell $objname "BUFCE_ROW" "$site/BUFCE" "O"] + } elseif {$sitetype == "BUFCE_ROW_FSR" && $pinname == "CLK_OUT"} { + return [make_driver_cell $objname "BUFCE_ROW" "$site/BUFCE" "O"] + } elseif {$sitetype == "BUFCE_LEAF" && $pinname == "CLK_OUT"} { + return [make_driver_cell $objname "BUFCE_LEAF" "$site/BUFCE" "O"] + } elseif {$sitetype == "BUFGCE" && $pinname == "CLK_OUT"} { + return [make_driver_cell $objname "BUFGCE" "$site/BUFCE" "O"] + } elseif {$sitetype == "BUFGCE_HDIO" && $pinname == "CLK_OUT"} { + return [make_driver_cell $objname "BUFGCE" "$site/BUFCE" "O"] + } elseif {$sitetype == "BUFGCE_DIV" && $pinname == "CLK_OUT"} { + set result [make_driver_cell $objname "BUFGCE_DIV" "$site/BUFGCE_DIV" "O"] + set_property BUFGCE_DIVIDE 1 [lindex $result 0] + return $result + } elseif {$sitetype == "BUFGCTRL" && $pinname == "CLK_OUT"} { + return [make_driver_cell $objname "BUFGCTRL" "$site/BUFGCTRL" "O"] + } elseif {$sitetype == "BUFG_GT" && $pinname == "CLK_OUT"} { + return [make_driver_cell $objname "BUFG_GT" "$site/BUFG_GT" "O"] + } elseif {($sitetype == "SLICEL" || $sitetype == "SLICEM") && [string range $pinname 1 4] == "MUX"} { + set eighth [string range $pinname 0 0] + return [make_driver_cell $objname "LUT6" "$site/${eighth}6LUT" "O"] + } else { + return {} + } +} + +proc make_site_pin_user {pin net} { + set site [get_sites -of_objects $pin] + if { $site == {} } { + return {} + } + set sitetype [get_property SITE_TYPE $site] + set pinname [lindex [split $pin "/"] 1] + set objname "${site}_${pinname}" + if {[get_cells -of_objects $site] != {}} { + return {} + } + if {$sitetype == "BUFCE_LEAF" && $pinname == "CLK_IN"} { + return [make_user_cell $objname "BUFCE_LEAF" "$site/BUFCE" "I" $net] + } elseif {$sitetype == "BUFCE_LEAF" && $pinname == "CE_INT"} { + return [make_user_cell $objname "BUFCE_LEAF" "$site/BUFCE" "CE" $net] + } elseif {$sitetype == "BUFGCE" && $pinname == "CLK_IN"} { + return [make_user_cell $objname "BUFGCE" "$site/BUFCE" "I" $net] + } elseif {$sitetype == "BUFGCE_HDIO" && $pinname == "CLK_IN"} { + return [make_user_cell $objname "BUFGCE" "$site/BUFCE" "I" $net] + } elseif {$sitetype == "BUFGCE_DIV" && $pinname == "CLK_IN"} { + set result [make_user_cell $objname "BUFGCE_DIV" "$site/BUFGCE_DIV" "I" $net] + set_property BUFGCE_DIVIDE 1 [lindex $result 0] + return $result + } elseif {$sitetype == "BUFGCTRL" && $pinname == "CLK_I0"} { + return [make_user_cell $objname "BUFGCTRL" "$site/BUFGCTRL" "I0" $net] + } elseif {$sitetype == "BUFGCTRL" && $pinname == "CLK_I1"} { + return [make_user_cell $objname "BUFGCTRL" "$site/BUFGCTRL" "I1" $net] + } elseif {$sitetype == "BUFG_GT" && $pinname == "CLK_IN"} { + return [make_user_cell $objname "BUFG_GT" "$site/BUFG_GT" "I" $net] + } elseif {$sitetype == "SLICEM" && $pinname == "LCLK"} { + return [make_user_cell $objname "SRL16E" "$site/H6LUT" "CLK" $net] + } elseif {($sitetype == "SLICEM" || $sitetype == "SLICEL") && $pinname == "CLK1"} { + return [make_user_cell $objname "FDRE" "$site/AFF" "C" $net] + } elseif {($sitetype == "SLICEM" || $sitetype == "SLICEL") && $pinname == "CLK2"} { + return [make_user_cell $objname "FDRE" "$site/EFF" "C" $net] + } elseif {$sitetype == "BITSLICE_RX_TX" && $pinname == "RX_CLK"} { + return [make_user_cell $objname "IDELAYE3" "$site/IDELAY" "CLK" $net] + } elseif {$sitetype == "BITSLICE_RX_TX" && $pinname == "RX_CLK_C"} { + return [make_user_cell $objname "ISERDESE3" "$site/ISERDES" "CLK" $net] + } elseif {$sitetype == "BITSLICE_RX_TX" && $pinname == "RX_CLKDIV"} { + return [make_user_cell $objname "ISERDESE3" "$site/ISERDES" "CLKDIV" $net] + } elseif {$sitetype == "BITSLICE_RX_TX" && $pinname == "TX_OCLK"} { + return [make_user_cell $objname "OSERDESE3" "$site/OSERDES" "CLK" $net] + } elseif {$sitetype == "BITSLICE_RX_TX" && $pinname == "TX_OCLKDIV"} { + return [make_user_cell $objname "OSERDESE3" "$site/OSERDES" "CLKDIV" $net] + } else { + return {} + } +} + +proc route_via {net sink_pin pip} { + set success 0 + set src [lindex [get_nodes -of_objects [get_site_pins -filter {DIRECTION == OUT} -of_objects $net]] 0] + set sink [get_nodes -of_objects [get_site_pins -filter {DIRECTION == IN} -of_objects $net ]] + if {$sink == {}} { + set sink $sink_pin + } + set_property IS_ROUTE_FIXED 0 $net + #route_design -unroute -nets $net + + set from_node [get_nodes -uphill -of_objects $pip] + set to_node [get_nodes -downhill -of_objects $pip] + if {$src == $from_node} { + set route_a $from_node + } else { + if {[catch {set route_a [find_routing_path -max_nodes 15 -from $src -to $from_node]}]} { + return 0 + } + if {$route_a == ""} { + return 0 + } + } + if {$sink == $to_node} { + set route_b $to_node + } else { + if {[catch {set route_b [find_routing_path -max_nodes 15 -from $to_node -to $sink]}]} { + return 0 + } + if {$route_b == ""} { + return 0 + } + } + + if {[catch {set_property FIXED_ROUTE "$route_a $route_b" $net}]} { + return 0 + } + set_property IS_ROUTE_FIXED 1 $net + if {[get_property ROUTE_STATUS $net] != "ROUTED"} { + set_property IS_ROUTE_FIXED 0 $net + route_design -unroute -nets $net + return 0 + } + return 1 +} + +# https://wiki.tcl-lang.org/page/Shuffle+a+list +proc shuffle6 { list } { + set n [llength $list] + for { set i 1 } { $i < $n } { incr i } { + set j [expr { int( rand() * $n ) }] + set temp [lindex $list $i] + lset list $i [lindex $list $j] + lset list $j $temp + } + return $list + } + +set tile_types [list "RCLK_RCLK_XIPHY_INNER_FT" "RCLK_HDIO" "RCLK_RCLK_URAM_INTF_L_FT"] + +set run $::argv +create_project -force -part xczu7ev-ffvf1517-2-e design${run} design${run} + + +link_design +create_cell -reference LUT6 "misc_lut" +place_design +route_design + +#remove_cell [get_cells] +#remove_net [get_nets] + +set count [expr {int(90 + rand()*80)}] + +for {set i 0} {$i < $count} {incr i} { + puts "$i/$count" + set tt [lindex $tile_types [expr {int(rand()*[llength $tile_types])}]] + set tiles [get_tiles -filter "TILE_TYPE == $tt"] + for {set j 0} {$j < 10} {incr j} { + set tile [lindex $tiles [expr {int(rand()*[llength $tiles])}]] + set tile_pips [get_pips -of_objects $tile -filter {NAME !~ "*VCC_WIRE*"}] + set pip [lindex $tile_pips [expr {int(rand()*[llength $tile_pips])}]] + set wavefront_bwd $pip + set driver {} + for {set k 0} {$k < 11} {incr k} { + set wavefront_bwd [get_nodes -uphill -of_objects $wavefront_bwd] + # Randomly skip to vary depth + if {rand() > 0.25} { + set wavefront_pins [shuffle6 [get_site_pins -of_objects $wavefront_bwd]] + foreach pin $wavefront_pins { + set driver [make_site_pin_driver $pin] + if {$driver != {}} { + break + } + } + } + if {$driver != {}} { + break + } + if {[llength $wavefront_bwd] > 20000} { + break + } + } + + if {$driver == {}} { + continue + } + + set drv_cell [lindex $driver 0] + set net [lindex $driver 1] + + set wavefront_fwd $pip + set user {} + for {set k 0} {$k < 12} {incr k} { + set wavefront_fwd [get_nodes -downhill -of_objects $wavefront_fwd] + # Randomly skip to vary depth + if {rand() > 0.25} { + set wavefront_pins [shuffle6 [get_site_pins -of_objects $wavefront_fwd]] + foreach pin $wavefront_pins { + set user [make_site_pin_user $pin $net] + set sink_pin $pin + if {$user != {}} { + break + } + } + } + if {$user != {}} { + break + } + if {[llength $wavefront_fwd] > 20000} { + break + } + } + + if {$user == {}} { + remove_cell $drv_cell + remove_net $net + continue + } + + set success [route_via $net $sink_pin $pip] + if { $success == 0 } { + remove_cell $drv_cell + remove_cell [lindex $user 0] + remove_net $net + } else { + break + } + } +} + +set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design] +set_property SEVERITY {Warning} [get_drc_checks] +write_checkpoint -force ../specimen_clk/rclkroute_c${run}.dcp +write_edif -force ../specimen_clk/rclkroute_c${run}.edf +write_bitstream -force ../specimen_clk/rclkroute_c${run}.bit +
diff --git a/spec/routing_fuzz.tcl b/spec/routing_fuzz.tcl new file mode 100644 index 0000000..3d7cf98 --- /dev/null +++ b/spec/routing_fuzz.tcl
@@ -0,0 +1,74 @@ +// Copyright 2020 Project U-Ray Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +set nets [get_nets fz*] +set tiles [get_tiles -filter {TILE_TYPE == "RCLK_CLEM_R" || TILE_TYPE == "RCLK_CLEM_L" || TILE_TYPE == "RCLK_CLEL_R" || TILE_TYPE == "RCLK_CLEL_L"}] +for {set k 0} {$k < 30} {incr k} { +foreach net $nets { + set success 0 + set src [lindex [get_nodes -of_objects [get_site_pins -filter {DIRECTION == OUT} -of_objects $net]] 0] + set sink [get_nodes -of_objects [get_site_pins -filter {DIRECTION == IN} -of_objects $net ]] + set_property IS_ROUTE_FIXED 0 $net + route_design -unroute -nets $net + for {set i 0} {$i < 12} {incr i} { + # try and route using an interesting pip + set tile [lindex $tiles [expr {int(rand()*[llength $tiles])}]] + set tile_pips [get_pips -of_objects $tile -filter {NAME !~ "*VCC_WIRE*"}] + set pip [lindex $tile_pips [expr {int(rand()*[llength $tile_pips])}]] + puts $pip + set from_node [get_nodes -uphill -of_objects $pip] + set to_node [get_nodes -downhill -of_objects $pip] + puts "$k $i $net $src $from_node $to_node $sink" + # pre-reject dud pips + if {[llength [get_nodes -uphill -of_objects $from_node]] == 0 || [llength [get_nodes -downhill -of_objects $to_node]] == 0} { + continue + } + if {[catch {set route_a [find_routing_path -max_nodes 60 -from $src -to $from_node]}]} { + continue + } + if {$route_a == ""} { + continue + } + if {[catch {set route_b [find_routing_path -max_nodes 60 -from $to_node -to $sink]}]} { + continue + } + if {$route_b == ""} { + continue + } + if {[catch {set_property FIXED_ROUTE "$route_a $route_b" $net}]} { + continue + } + set_property IS_ROUTE_FIXED 1 $net + if {[get_property ROUTE_STATUS $net] != "ROUTED"} { + set_property IS_ROUTE_FIXED 0 $net + route_design -unroute -nets $net + continue + } + set success 1 + break + } + if {$success == 0} { + # route simply\\\\\\ + set_property FIXED_ROUTE [find_routing_path -from $src -to $sink] $net + } +} +set_property SEVERITY {Warning} [get_drc_checks NSTD-1] +set_property SEVERITY {Warning} [get_drc_checks UCIO-1] +set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design] + +write_edif -force "./results/specimen_clk/rclkroute$k.edf" +write_checkpoint -force "./results/specimen_clk/rclkroute$k.dcp" +write_bitstream -force "./results/specimen_clk/rclkroute$k.bit" + +} \ No newline at end of file
diff --git a/spec/routing_fuzz_simple.tcl b/spec/routing_fuzz_simple.tcl new file mode 100644 index 0000000..5aaf81d --- /dev/null +++ b/spec/routing_fuzz_simple.tcl
@@ -0,0 +1,273 @@ +// Copyright 2020 Project U-Ray Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +proc make_driver_cell {name celltype loc pinname} { + create_net "${name}_net" + set net [get_nets "${name}_net"] + create_cell -reference $celltype "${name}_drv" + place_cell "${name}_drv" $loc + connect_net -net $net -objects [get_pins "${name}_drv/${pinname}"] + return [list [get_cells "${name}_drv"] $net] +} + +proc make_user_cell {name celltype loc pinname net} { + create_cell -reference $celltype "${name}_usr" + place_cell "${name}_usr" $loc + connect_net -net $net -objects [get_pins "${name}_usr/${pinname}"] + return [list [get_cells "${name}_usr"] $net] +} + + +proc make_site_pin_driver {pin} { + set site [get_sites -of_objects $pin] + if { $site == {} } { + return {} + } + set sitetype [get_property SITE_TYPE $site] + set pinname [lindex [split $pin "/"] 1] + set objname "${site}_${pinname}" + if {[get_cells -of_objects $site] != {}} { + return {} + } + if {$sitetype == "BUFCE_ROW" && $pinname == "CLK_OUT"} { + return [make_driver_cell $objname "BUFCE_ROW" "$site/BUFCE" "O"] + } elseif {$sitetype == "BUFCE_ROW_FSR" && $pinname == "CLK_OUT"} { + return [make_driver_cell $objname "BUFCE_ROW" "$site/BUFCE" "O"] + } elseif {$sitetype == "BUFCE_LEAF" && $pinname == "CLK_OUT"} { + return [make_driver_cell $objname "BUFCE_LEAF" "$site/BUFCE" "O"] + } elseif {$sitetype == "BUFGCE" && $pinname == "CLK_OUT"} { + return [make_driver_cell $objname "BUFGCE" "$site/BUFCE" "O"] + } elseif {$sitetype == "BUFGCE_HDIO" && $pinname == "CLK_OUT"} { + return [make_driver_cell $objname "BUFGCE" "$site/BUFCE" "O"] + } elseif {$sitetype == "BUFGCE_DIV" && $pinname == "CLK_OUT"} { + set result [make_driver_cell $objname "BUFGCE_DIV" "$site/BUFGCE_DIV" "O"] + set_property BUFGCE_DIVIDE 1 [lindex $result 0] + return $result + } elseif {$sitetype == "BUFGCTRL" && $pinname == "CLK_OUT"} { + return [make_driver_cell $objname "BUFGCTRL" "$site/BUFGCTRL" "O"] + } elseif {$sitetype == "BUFG_GT" && $pinname == "CLK_OUT"} { + return [make_driver_cell $objname "BUFG_GT" "$site/BUFG_GT" "O"] + } elseif {($sitetype == "SLICEL" || $sitetype == "SLICEM") && [string range $pinname 1 4] == "MUX"} { + set eighth [string range $pinname 0 0] + return [make_driver_cell $objname "LUT6" "$site/${eighth}6LUT" "O"] + } else { + return {} + } +} + +proc make_site_pin_user {pin net} { + set site [get_sites -of_objects $pin] + if { $site == {} } { + return {} + } + set sitetype [get_property SITE_TYPE $site] + set pinname [lindex [split $pin "/"] 1] + set objname "${site}_${pinname}" + if {[get_cells -of_objects $site] != {}} { + return {} + } + if {$sitetype == "BUFCE_LEAF" && $pinname == "CLK_IN"} { + return [make_user_cell $objname "BUFCE_LEAF" "$site/BUFCE" "I" $net] + } elseif {$sitetype == "BUFGCE" && $pinname == "CLK_IN"} { + return [make_user_cell $objname "BUFGCE" "$site/BUFCE" "I" $net] + } elseif {$sitetype == "BUFGCE_DIV" && $pinname == "CLK_IN"} { + set result [make_user_cell $objname "BUFGCE_DIV" "$site/BUFGCE_DIV" "I" $net] + set_property BUFGCE_DIVIDE 1 [lindex $result 0] + return $result + } elseif {$sitetype == "BUFGCTRL" && $pinname == "CLK_I0"} { + return [make_user_cell $objname "BUFGCTRL" "$site/BUFGCTRL" "I0" $net] + } elseif {$sitetype == "BUFGCTRL" && $pinname == "CLK_I1"} { + return [make_user_cell $objname "BUFGCTRL" "$site/BUFGCTRL" "I1" $net] + } elseif {$sitetype == "BUFG_GT" && $pinname == "CLK_IN"} { + return [make_user_cell $objname "BUFG_GT" "$site/BUFG_GT" "I" $net] + } elseif {$sitetype == "SLICEM" && $pinname == "LCLK"} { + return [make_user_cell $objname "SRL16E" "$site/H6LUT" "CLK" $net] + } elseif {($sitetype == "SLICEM" || $sitetype == "SLICEL") && $pinname == "CLK1"} { + return [make_user_cell $objname "FDRE" "$site/AFF" "C" $net] + } elseif {($sitetype == "SLICEM" || $sitetype == "SLICEL") && $pinname == "CLK2"} { + return [make_user_cell $objname "FDRE" "$site/EFF" "C" $net] + } elseif {$sitetype == "BITSLICE_RX_TX" && $pinname == "RX_CLK"} { + return [make_user_cell $objname "IDELAYE3" "$site/IDELAY" "CLK" $net] + } elseif {$sitetype == "BITSLICE_RX_TX" && $pinname == "RX_CLK_C"} { + return [make_user_cell $objname "ISERDESE3" "$site/ISERDES" "CLK" $net] + } else { + return {} + } +} + +proc route_via {net sink_pin pip} { + set success 0 + set src [lindex [get_nodes -of_objects [get_site_pins -filter {DIRECTION == OUT} -of_objects $net]] 0] + set sink [get_nodes -of_objects [get_site_pins -filter {DIRECTION == IN} -of_objects $net ]] + if {$sink == {}} { + set sink $sink_pin + } + set_property IS_ROUTE_FIXED 0 $net + #route_design -unroute -nets $net + + set from_node [get_nodes -uphill -of_objects $pip] + set to_node [get_nodes -downhill -of_objects $pip] + if {$src == $from_node} { + set route_a $from_node + } else { + if {[catch {set route_a [find_routing_path -max_nodes 15 -from $src -to $from_node]}]} { + return 0 + } + if {$route_a == ""} { + return 0 + } + } + if {$sink == $to_node} { + set route_b $to_node + } else { + if {[catch {set route_b [find_routing_path -max_nodes 15 -from $to_node -to $sink]}]} { + return 0 + } + if {$route_b == ""} { + return 0 + } + } + + if {[catch {set_property FIXED_ROUTE "$route_a $route_b" $net}]} { + return 0 + } + set_property IS_ROUTE_FIXED 1 $net + if {[get_property ROUTE_STATUS $net] != "ROUTED"} { + set_property IS_ROUTE_FIXED 0 $net + route_design -unroute -nets $net + return 0 + } + return 1 +} + +# https://wiki.tcl-lang.org/page/Shuffle+a+list +proc shuffle6 { list } { + set n [llength $list] + for { set i 1 } { $i < $n } { incr i } { + set j [expr { int( rand() * $n ) }] + set temp [lindex $list $i] + lset list $i [lindex $list $j] + lset list $j $temp + } + return $list + } + +set tile_types [list "CMT_L" "CMT_L" "CMT_L" "RCLK_BRAM_INTF_L" "RCLK_BRAM_INTF_TD_L" "RCLK_BRAM_INTF_TD_R"\ + "RCLK_CLEL_L_L" "RCLK_CLEL_L_R" "RCLK_CLEM_CLKBUF_L" "RCLK_CLEM_L" "RCLK_CLEM_R"\ + "RCLK_DSP_INTF_L" "RCLK_DSP_INTF_CLKBUF_L" "RCLK_INT_L" "RCLK_RCLK_XIPHY_INNER_FT"] + +set run $::argv +create_project -force -part xczu7ev-ffvf1517-2-e design${run} design${run} + + +link_design +create_cell -reference LUT6 "misc_lut" +place_design +route_design + +#remove_cell [get_cells] +#remove_net [get_nets] + +set count [expr {int(90 + rand()*70)}] + +for {set i 0} {$i < $count} {incr i} { + puts "$i/$count" + for {set j 0} {$j < 10} {incr j} { + set tt [lindex $tile_types [expr {int(rand()*[llength $tile_types])}]] + set tiles [get_tiles -filter "TILE_TYPE == $tt"] + set tile [lindex $tiles [expr {int(rand()*[llength $tiles])}]] + set tile_pips [get_pips -of_objects $tile -filter {NAME !~ "*VCC_WIRE*"}] + set pip [lindex $tile_pips [expr {int(rand()*[llength $tile_pips])}]] + set wavefront_bwd $pip + set driver {} + for {set k 0} {$k < 10} {incr k} { + set wavefront_bwd [get_nodes -uphill -of_objects $wavefront_bwd] + # Randomly skip to vary depth + if {rand() > 0.5} { + set wavefront_pins [shuffle6 [get_site_pins -of_objects $wavefront_bwd]] + foreach pin $wavefront_pins { + set driver [make_site_pin_driver $pin] + if {$driver != {}} { + break + } + } + } + if {$driver != {}} { + break + } + if {[llength $wavefront_bwd] > 20000} { + break + } + } + + if {$driver == {}} { + continue + } + + set drv_cell [lindex $driver 0] + set net [lindex $driver 1] + + set wavefront_fwd $pip + set user {} + for {set k 0} {$k < 10} {incr k} { + set wavefront_fwd [get_nodes -downhill -of_objects $wavefront_fwd] + # Randomly skip to vary depth + if {rand() > 0.5} { + set wavefront_pins [shuffle6 [get_site_pins -of_objects $wavefront_fwd]] + foreach pin $wavefront_pins { + set user [make_site_pin_user $pin $net] + set sink_pin $pin + if {$user != {}} { + break + } + } + } + if {$user != {}} { + break + } + if {[llength $wavefront_fwd] > 20000} { + break + } + } + + if {$user == {}} { + remove_cell $drv_cell + remove_net $net + continue + } + + set success [route_via $net $sink_pin $pip] + if { $success == 0 } { + remove_cell $drv_cell + remove_cell [lindex $user 0] + remove_net $net + } else { + break + } + } +} + +set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design] +set_property SEVERITY {Warning} [get_drc_checks PDCN-*] +set_property SEVERITY {Warning} [get_drc_checks RTRES-*] +set_property SEVERITY {Warning} [get_drc_checks AVAL-*] +set_property SEVERITY {Warning} [get_drc_checks REQP-*] +set_property SEVERITY {Warning} [get_drc_checks BIVR-*] +set_property SEVERITY {Warning} [get_drc_checks PDRC-203] +set_property SEVERITY {Warning} [get_drc_checks ADEF-911] + +write_checkpoint -force ../specimen_clk/rclkroute${run}.dcp +write_edif -force ../specimen_clk/rclkroute${run}.edf +write_bitstream -force ../specimen_clk/rclkroute${run}.bit +
diff --git a/spec/slice.v b/spec/slice.v index ce33903..b049083 100644 --- a/spec/slice.v +++ b/spec/slice.v
@@ -215,4 +215,4 @@ "CY": assign OUT = CY; endcase endgenerate -endmodule \ No newline at end of file +endmodule
diff --git a/spec/slice_carry.v b/spec/slice_carry.v index 4eaeaee..853aef8 100644 --- a/spec/slice_carry.v +++ b/spec/slice_carry.v
@@ -283,4 +283,4 @@ "X": assign OUT = X; endcase endgenerate -endmodule \ No newline at end of file +endmodule
diff --git a/spec/slice_memory.v b/spec/slice_memory.v index efe2fe7..f696882 100644 --- a/spec/slice_memory.v +++ b/spec/slice_memory.v
@@ -381,4 +381,4 @@ $error("unsupported mode"); end endgenerate -endmodule \ No newline at end of file +endmodule
diff --git a/spec/uram.py b/spec/uram.py new file mode 100644 index 0000000..af93e64 --- /dev/null +++ b/spec/uram.py
@@ -0,0 +1,136 @@ +# Copyright 2020 Project U-Ray Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import numpy as np +import sys + +X = 12 +N = 60 + +root = sys.argv[2] + +def random_vector(size): + return "{%s}" % ", ".join(["d[%d]" % np.random.randint(40) for k in range(size)]) + +for x in range(X): + with open(root + "/uram/uram%d.v" % x, "w") as f: + print("module top(input [7:0] clk, cen, rst, input [39:0] d, input [7:0] sel, output [63:0] q);", file=f) + print(" wire [8:0] r = {1'b0, rst}, e = {1'b1, cen};", file=f) + print(" wire [63:0] int_q[0:%d];" % (N-1), file=f) + for i in range(N): + print(" (* KEEP, DONT_TOUCH *)", file=f) + print(" URAM288 #(", file=f) + print(" .AUTO_SLEEP_LATENCY(%d)," % np.random.randint(3, 16), file=f) + print(" .BWE_MODE_A(\"%s\")," % np.random.choice(["PARITY_INTERLEAVED", "PARITY_INDEPENDENT"]), file=f) + print(" .BWE_MODE_B(\"%s\")," % np.random.choice(["PARITY_INTERLEAVED", "PARITY_INDEPENDENT"]), file=f) + print(" .EN_AUTO_SLEEP_MODE(\"%s\")," % np.random.choice(["FALSE", "TRUE"]), file=f) + print(" .EN_ECC_RD_A(\"%s\")," % np.random.choice(["FALSE", "TRUE"]), file=f) + print(" .EN_ECC_RD_B(\"%s\")," % np.random.choice(["FALSE", "TRUE"]), file=f) + print(" .EN_ECC_WR_A(\"%s\")," % np.random.choice(["FALSE", "TRUE"]), file=f) + print(" .EN_ECC_WR_B(\"%s\")," % np.random.choice(["FALSE", "TRUE"]), file=f) + print(" .IREG_PRE_A(\"%s\")," % np.random.choice(["FALSE", "TRUE"]), file=f) + print(" .IREG_PRE_B(\"%s\")," % np.random.choice(["FALSE", "TRUE"]), file=f) + print(" .IS_CLK_INVERTED(%d)," % np.random.randint(2), file=f) + print(" .IS_EN_A_INVERTED(%d)," % np.random.randint(2), file=f) + print(" .IS_EN_B_INVERTED(%d)," % np.random.randint(2), file=f) + print(" .IS_RDB_WR_A_INVERTED(%d)," % np.random.randint(2), file=f) + print(" .IS_RDB_WR_B_INVERTED(%d)," % np.random.randint(2), file=f) + print(" .IS_RST_A_INVERTED(%d)," % np.random.randint(2), file=f) + print(" .IS_RST_B_INVERTED(%d)," % np.random.randint(2), file=f) + print(" .OREG_A(\"%s\")," % np.random.choice(["FALSE", "TRUE"]), file=f) + print(" .OREG_B(\"%s\")," % np.random.choice(["FALSE", "TRUE"]), file=f) + print(" .OREG_ECC_A(\"%s\")," % np.random.choice(["FALSE", "TRUE"]), file=f) + print(" .OREG_ECC_B(\"%s\")," % np.random.choice(["FALSE", "TRUE"]), file=f) + print(" .REG_CAS_A(\"%s\")," % np.random.choice(["FALSE", "TRUE"]), file=f) + print(" .REG_CAS_B(\"%s\")," % np.random.choice(["FALSE", "TRUE"]), file=f) + print(" .RST_MODE_A(\"%s\")," % np.random.choice(["SYNC", "ASYNC"]), file=f) + print(" .RST_MODE_B(\"%s\")," % np.random.choice(["SYNC", "ASYNC"]), file=f) + print(" .SELF_ADDR_A(11'd%d)," % np.random.randint(2**11), file=f) + print(" .SELF_ADDR_B(11'd%d)," % np.random.randint(2**11), file=f) + print(" .SELF_MASK_A(11'd%d)," % np.random.randint(2**11), file=f) + print(" .SELF_MASK_B(11'd%d)," % np.random.randint(2**11), file=f) + print(" .USE_EXT_CE_A(\"%s\")," % np.random.choice(["FALSE", "TRUE"]), file=f) + print(" .USE_EXT_CE_B(\"%s\")" % np.random.choice(["FALSE", "TRUE"]), file=f) + print(" ) uram_%d (" % i, file=f) + print(" .ADDR_A(%s)," % random_vector(23), file=f) + print(" .ADDR_B(%s)," % random_vector(23), file=f) + print(" .BWE_A(%s)," % random_vector(9), file=f) + print(" .BWE_B(%s)," % random_vector(9), file=f) + print(" .CLK(clk[%d])," % np.random.randint(8), file=f) + print(" .DIN_A(%s)," % random_vector(72), file=f) + print(" .DIN_B(%s)," % random_vector(72), file=f) + print(" .EN_A(e[%d])," % np.random.randint(9), file=f) + print(" .EN_B(e[%d])," % np.random.randint(9), file=f) + print(" .INJECT_DBITERR_A(%s)," % random_vector(1), file=f) + print(" .INJECT_DBITERR_B(%s)," % random_vector(1), file=f) + print(" .INJECT_SBITERR_A(%s)," % random_vector(1), file=f) + print(" .INJECT_SBITERR_B(%s)," % random_vector(1), file=f) + print(" .OREG_CE_A(e[%d])," % np.random.randint(9), file=f) + print(" .OREG_CE_B(e[%d])," % np.random.randint(9), file=f) + print(" .OREG_ECC_CE_A(e[%d])," % np.random.randint(9), file=f) + print(" .OREG_ECC_CE_B(e[%d])," % np.random.randint(9), file=f) + print(" .RDB_WR_A(%s)," % random_vector(1), file=f) + print(" .RDB_WR_B(%s)," % random_vector(1), file=f) + print(" .RST_A(r[%d])," % np.random.randint(9), file=f) + print(" .RST_B(r[%d])," % np.random.randint(9), file=f) + o_bit = np.random.randint(-1, 150) + if o_bit < 72: + print(" .DOUT_A({int_q[%d][0]%s})," % (i, ", {%d{1'bx}}" % o_bit if o_bit > 0 else ""), file=f) + elif o_bit < 144: + print(" .DOUT_A({int_q[%d][0]%s})," % (i, ", {%d{1'bx}}" % (o_bit-72) if o_bit > 72 else ""), file=f) + elif o_bit == 144: + print(" .RDACCESS_A(int_q[%d][0])," % i, file=f) + elif o_bit == 145: + print(" .RDACCESS_B(int_q[%d][0])," % i, file=f) + elif o_bit == 146: + print(" .DBITERR_A(int_q[%d][0])," % i, file=f) + elif o_bit == 147: + print(" .DBITERR_B(int_q[%d][0])," % i, file=f) + elif o_bit == 148: + print(" .SBITERR_A(int_q[%d][0])," % i, file=f) + elif o_bit == 149: + print(" .SBITERR_B(int_q[%d][0])," % i, file=f) + print(" .SLEEP(%s)" % random_vector(1), file=f) + print(");", file=f) + print(" assign q = int_q[sel];", file=f) + print("endmodule", file=f) + with open(root + "/uram/uram%d.tcl" % x, "w") as f: + print("add_files %s" % (root + ("/uram/uram%d.v" % x)), file=f) + print("synth_design -top top -part xczu7ev-ffvc1156-2-e", file=f) + print("opt_design", file=f) + print("place_design", file=f) + print("route_design", file=f) + print("set_property SEVERITY {Warning} [get_drc_checks NSTD-1]", file=f) + print("set_property SEVERITY {Warning} [get_drc_checks UCIO-1]", file=f) + print("set_property SEVERITY {Warning} [get_drc_checks AVAL-*]", file=f) + print("set_property SEVERITY {Warning} [get_drc_checks REQP-*]", file=f) + print("set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design]", file=f) + print("write_checkpoint -force %s/specimen_bram/uram%d.dcp" % (root, x), file=f) + print("write_edif -force %s/specimen_bram/uram%d.edf" % (root, x), file=f) + print("write_bitstream -force %s/specimen_bram/uram%d.bit" % (root, x), file=f) +with open(root + "/uram/run.sh", "w") as f: + print("#/usr/bin/env bash", file=f) + print("set -ex", file=f) + for x in range(X): + print("vivado -mode batch -nolog -nojournal -source uram%d.tcl" % x, file=f) + print("if [ $? -eq 0 ]; then", file=f) + print(" ../../ultra/tools/dump_bitstream %s/specimen_bram/uram%d.bit %s/frames.txt > %s/specimen_bram/uram%d.dump" % (root, x, root, root, x), file=f) + print(" python3 ../../ultra/tools/bits_to_tiles.py %s/tilebits.json %s/specimen_bram/uram%d.dump > %s/specimen_bram/uram%d.tbits" % (root, root, x, root, x), file=f) + print("else", file=f) + print(" rm %s/specimen_bram/uram%d.dump" % (root, x), file=f) + print(" rm %s/specimen_bram/uram%d.tbits" % (root, x), file=f) + print(" rm %s/specimen_bram/uram%d.dcp" % (root, x), file=f) + print(" rm %s/specimen_bram/uram%d.bit" % (root, x), file=f) + print(" rm %s/specimen_bram/uram%d.features" % (root, x), file=f) + print("fi", file=f)
diff --git a/spec/xiphy_clk_mux.tcl b/spec/xiphy_clk_mux.tcl new file mode 100644 index 0000000..cd1273c --- /dev/null +++ b/spec/xiphy_clk_mux.tcl
@@ -0,0 +1,72 @@ +// Copyright 2020 Project U-Ray Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +set run $::argv +create_project -force -part xczu7ev-ffvf1517-2-e design${run} design${run} + + +link_design +create_cell -reference LUT6 "misc_lut" +place_design +route_design + +remove_net xiphy_* +remove_cell xiphy_* + +foreach tile [get_tiles -filter {TILE_TYPE == RCLK_RCLK_XIPHY_INNER_FT}] { + set i 0 + foreach pip [get_pips -uphill -of_objects [get_wires "$tile/CLK_TO_XIPHY_BYTES_TOP0" -of_objects $tile]] { + set drv_node [get_nodes -uphill -of_objects $pip] + puts $drv_node + set pins [get_site_pins -of_objects [get_nodes -uphill -of_objects $drv_node] "BUFCE_ROW*"] + if {[llength $pins] != 1} { + continue + } + create_net "xiphy_${tile}_clk${i}" + set net [get_nets "xiphy_${tile}_clk${i}"] + create_cell -reference BUFCE_ROW "xiphy_${tile}_clk${i}_buf" + set site [get_sites -of_objects [lindex $pins 0]] + place_cell "xiphy_${tile}_clk${i}_buf" "${site}/BUFCE" + connect_net -net $net -objects [get_pins "xiphy_${tile}_clk${i}_buf/O"] + incr i + } + foreach sink_node [get_nodes -downhill -of_objects [get_nodes "$tile/CLK_HDISTR_ONE0"] "*CLK_TO_XIPHY*"] { + puts $sink_node + foreach pin [get_site_pins -of_objects [get_nodes -downhill -of_objects $sink_node] "BITSLICE_RX_TX*/*TX_OCLK"] { + set site [get_sites -of_objects $pin] + if {[llength [get_cells -of_objects $site]] > 0 } { + continue + } + create_cell -reference OSERDESE3 "xiphy_sink_${site}" + place_cell "xiphy_sink_${site}" "${site}/OSERDES" + while {1} { + set net_idx [expr int(rand() * $i)] + if {[lsearch [get_nets -of_objects [get_tiles -of_objects $site]] "xiphy_${tile}_clk${net_idx}"] == -1} { + break + } + } + set net [get_nets "xiphy_${tile}_clk${net_idx}"] + connect_net -net $net -objects [get_pins "xiphy_sink_${site}/CLK"] + break + } + } +} + +set_property SEVERITY Warning [get_drc_checks] +route_design +set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design] +write_checkpoint -force ../specimen_clk/xclkroute_a${run}.dcp +write_edif -force ../specimen_clk/xclkroute_a${run}.edf +write_bitstream -force ../specimen_clk/xclkroute_a${run}.bit +