blob: 83c8cba08dc2ba5cb09aa735515c6fd8bcb7404b [file] [log] [blame]
# 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
}