| # Copyright (C) 2017-2020 The Project X-Ray Authors |
| # |
| # Use of this source code is governed by a ISC-style |
| # license that can be found in the LICENSE file or at |
| # https://opensource.org/licenses/ISC |
| # |
| # SPDX-License-Identifier: ISC |
| proc route_via { net nodes {assert 1} } { |
| # Route a simple source to dest net via one or more intermediate nodes |
| # the nodes do not have have to be directly reachable from each other |
| # net: net name string |
| # nodes: list of node or wires strings? |
| # Returns 1 on success (previously would silently failed with antenna nets) |
| |
| set net [get_nets $net] |
| # fixed_route: list of nodes in the full route |
| # Begins at implicit node |
| set fixed_route [get_nodes -of_objects [get_site_pins -filter {DIRECTION == OUT} -of_objects $net]] |
| # Implicit end node. Route it at the end |
| lappend nodes [get_nodes -of_objects [get_site_pins -filter {DIRECTION == IN} -of_objects $net]] |
| |
| puts "Routing net $net:" |
| |
| foreach to_node $nodes { |
| # convert wire string to node object |
| set to_node [get_nodes -of_objects [get_wires $to_node]] |
| # Start at the last point |
| set from_node [lindex $fixed_route end] |
| # Make vivado do the hard work |
| puts " set route \[find_routing_path -quiet -from $from_node -to $to_node\]" |
| set route [find_routing_path -quiet -from $from_node -to $to_node] |
| # TODO: check for this |
| if {$route == ""} { |
| # This can also happen if you try to route to a node already in the route |
| if { [ lsearch $route $to_node ] >= 0 } { |
| puts " WARNING: route_via loop. $to_node is already in the path, ignoring" |
| } else { |
| puts " $from_node -> $to_node: no route found - assuming direct PIP" |
| lappend fixed_route $to_node |
| } |
| } { |
| puts " $from_node -> $to_node: $route" |
| set fixed_route [concat $fixed_route [lrange $route 1 end]] |
| } |
| set_property -quiet FIXED_ROUTE $fixed_route $net |
| } |
| |
| # Earlier check should catch this now |
| set status [get_property ROUTE_STATUS $net] |
| if { $status != "ROUTED" } { |
| puts " Failed to route net $net, status $status, route: $fixed_route" |
| if { $assert } { |
| error "Failed to route net" |
| } |
| return 0 |
| } |
| |
| set_property -quiet FIXED_ROUTE $fixed_route $net |
| puts "" |
| return 1 |
| } |
| |
| proc tile_wire_pairs {tile1 tile2} { |
| set tile1 [get_tiles $tile1] |
| set tile2 [get_tiles $tile2] |
| |
| foreach wire1 [lsort [get_wires -of_objects $tile1]] { |
| set wire2 [get_wires -quiet -filter "TILE_NAME == $tile2" -of_objects [get_nodes -quiet -of_objects $wire1]] |
| if {$wire2 != ""} {puts "$wire1 $wire2"} |
| } |
| } |
| |
| proc randsample_list {num lst} { |
| set rlst {} |
| for {set i 0} {$i<$num} {incr i} { |
| set j [expr {int(rand()*[llength $lst])}] |
| lappend rlst [lindex $lst $j] |
| set lst [lreplace $lst $j $j] |
| } |
| return $rlst |
| } |
| |
| proc randplace_pblock {num pblock} { |
| set sites [randsample_list $num [get_sites -filter {SITE_TYPE == SLICEL || SITE_TYPE == SLICEM} -of_objects [get_pblocks $pblock]]] |
| set cells [randsample_list $num [get_cells -hierarchical -filter "PBLOCK == [get_pblocks $pblock] && REF_NAME == LUT6"]] |
| for {set i 0} {$i<$num} {incr i} { |
| set site [lindex $sites $i] |
| set cell [lindex $cells $i] |
| set_property LOC $site $cell |
| } |
| } |
| |
| proc roi_tiles {} { |
| return [get_tiles -filter "GRID_POINT_X >= $::env(XRAY_ROI_GRID_X1) && \ |
| GRID_POINT_X < $::env(XRAY_ROI_GRID_X2) && \ |
| GRID_POINT_Y >= $::env(XRAY_ROI_GRID_Y1) && \ |
| GRID_POINT_Y < $::env(XRAY_ROI_GRID_Y2)"] |
| } |
| |
| proc pblock_tiles {pblock} { |
| set clb_tiles [get_tiles -of_objects [get_sites -of_objects [get_pblocks $pblock]]] |
| set int_tiles [get_tiles [regsub -all {CLBL[LM]} $clb_tiles INT]] |
| return [get_tiles "$clb_tiles $int_tiles"] |
| } |
| |
| # returns list of unique tile types |
| proc get_tile_types {} { |
| set all_tiles [get_tiles] |
| set types {} |
| foreach tile $all_tiles { |
| set type [get_property TYPE $tile] |
| #ignore empty tiles |
| if {$type == "NULL"} { continue } |
| if {[lsearch -exact $types $type] == -1} {lappend types $type} |
| } |
| return $types |
| } |
| |
| proc lintersect {lst1 lst2} { |
| set rlst {} |
| foreach el $lst1 { |
| set idx [lsearch $lst2 $el] |
| if {$idx >= 0} {lappend rlst $el} |
| } |
| return $rlst |
| } |
| |
| proc putl {lst} { |
| foreach line $lst {puts $line} |
| } |
| |
| proc write_pip_txtdata {filename} { |
| puts "FUZ([pwd]): Writing $filename." |
| set fp [open $filename w] |
| set nets [get_nets -hierarchical] |
| set nnets [llength $nets] |
| set neti 0 |
| foreach net $nets { |
| incr neti |
| if {($neti % 100) == 0 } { |
| puts "FUZ([pwd]): Dumping pips from net $net ($neti / $nnets)" |
| } |
| foreach pip [get_pips -of_objects $net] { |
| set tile [get_tiles -of_objects $pip] |
| set src_wire [get_wires -uphill -of_objects $pip] |
| set dst_wire [get_wires -downhill -of_objects $pip] |
| set num_pips [llength [get_nodes -uphill -of_objects [get_nodes -of_objects $dst_wire]]] |
| set dir_prop [get_property IS_DIRECTIONAL $pip] |
| puts $fp "$tile $pip $src_wire $dst_wire $num_pips $dir_prop" |
| } |
| } |
| close $fp |
| } |
| |
| # Generic non-ROI'd generate.tcl template |
| proc generate_top {} { |
| create_project -force -part $::env(XRAY_PART) design design |
| read_verilog top.v |
| synth_design -top top |
| |
| set_property CFGBVS VCCO [current_design] |
| set_property CONFIG_VOLTAGE 3.3 [current_design] |
| set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design] |
| |
| place_design |
| route_design |
| |
| write_checkpoint -force design.dcp |
| write_bitstream -force design.bit |
| } |
| |
| # Dumps all pins of a site, with the direction info (clock, input, output) |
| proc dump_pins {file_name site_prefix} { |
| set fp [open $file_name w] |
| |
| puts $fp "name,is_input,is_output,is_clock" |
| set site [lindex [get_sites $site_prefix*] 0] |
| set bel [get_bels -of_objects $site] |
| set bel_pins [get_bel_pins -of_objects $bel] |
| |
| set bel_pins_dict [dict create] |
| foreach pin $bel_pins { |
| set pin_name [lindex [split $pin "/"] 2] |
| set is_clock [get_property IS_CLOCK $pin] |
| dict set bel_pins_dict $pin_name $is_clock |
| } |
| |
| set site_pins [get_site_pins -of_objects $site] |
| foreach pin $site_pins { |
| set connected_pip [get_pips -of_objects [get_nodes -of_objects $pin]] |
| |
| if { $connected_pip == "" } { |
| continue |
| } |
| |
| set pin_name [lindex [split $pin "/"] 1] |
| set is_input [get_property IS_INPUT $pin] |
| set is_output [get_property IS_OUTPUT $pin] |
| set is_clock [dict get $bel_pins_dict $pin_name] |
| |
| puts $fp "$pin_name,$is_input,$is_output,$is_clock" |
| } |
| close $fp |
| } |