diff --git a/fuzzers/007-timing/projects/placelut/Makefile b/fuzzers/007-timing/projects/placelut/Makefile index f1e10dc2..9c8b1947 100644 --- a/fuzzers/007-timing/projects/placelut/Makefile +++ b/fuzzers/007-timing/projects/placelut/Makefile @@ -1,53 +1,2 @@ -N := 1 -SPECIMENS := $(addprefix specimen_,$(shell seq -f '%03.0f' $(N))) -SPECIMENS_OK := $(addsuffix /OK,$(SPECIMENS)) -CSVS := $(addsuffix /timing3.csv,$(SPECIMENS)) -TIMFUZ_DIR=$(XRAY_DIR)/fuzzers/007-timing - -all: build/tilea.json - -$(SPECIMENS_OK): - bash generate.sh $(subst /OK,,$@) - touch $@ - -run: - $(MAKE) clean - $(MAKE) all - touch run.ok - -clean: - rm -rf specimen_[0-9][0-9][0-9]/ seg_clblx.segbits __pycache__ run.ok - rm -rf vivado*.log vivado_*.str vivado*.jou design *.bits *.dcp *.bit - rm -rf build - -.PHONY: database pushdb run clean - -build/sub.json: $(SPECIMENS_OK) - mkdir -p build - # Discover which variables can be separated - # This is typically the longest running operation - python3 $(TIMFUZ_DIR)/rref.py --simplify --out build/sub.json $(CSVS) - -build/grouped.csv: $(SPECIMENS_OK) build/sub.json - # Separate variables - python3 $(TIMFUZ_DIR)/csv_flat2group.py --sub-json build/sub.json --strict $(CSVS) build/grouped.csv - # Verify sub.json makes a solvable solution - # python3 $(TIMFUZ_DIR)/checksub.py --sub-json build/sub.json grouped.csv - -build/leastsq.csv: build/sub.json build/grouped.csv - # Create a rough timing model that approximately fits the given paths - python3 $(TIMFUZ_DIR)/solve_leastsq.py --sub-json build/sub.json build/grouped.csv --out build/leastsq.csv - -build/linprog.csv: build/leastsq.csv build/grouped.csv - # Tweak rough timing model, making sure all constraints are satisfied - python3 $(TIMFUZ_DIR)/solve_linprog.py --sub-json build/sub.json --sub-csv build/leastsq.csv --massage build/grouped.csv --out build/linprog.csv - -build/flat.csv: build/linprog.csv - # Take separated variables and back-annotate them to the original timing variables - python3 $(TIMFUZ_DIR)/csv_group2flat.py --sub-json build/sub.json --sort build/linprog.csv build/flat.csv - -build/tilea.json: build/flat.csv - # Final processing - # Insert timing delays into actual tile layouts - python3 $(TIMFUZ_DIR)/tile_annotate.py --tile-json $(TIMFUZ_DIR)/timgrid/build/timgrid.json build/flat.csv build/tilea.json +include ../project.mk diff --git a/fuzzers/007-timing/projects/project.mk b/fuzzers/007-timing/projects/project.mk new file mode 100644 index 00000000..f1e10dc2 --- /dev/null +++ b/fuzzers/007-timing/projects/project.mk @@ -0,0 +1,53 @@ +N := 1 +SPECIMENS := $(addprefix specimen_,$(shell seq -f '%03.0f' $(N))) +SPECIMENS_OK := $(addsuffix /OK,$(SPECIMENS)) +CSVS := $(addsuffix /timing3.csv,$(SPECIMENS)) +TIMFUZ_DIR=$(XRAY_DIR)/fuzzers/007-timing + +all: build/tilea.json + +$(SPECIMENS_OK): + bash generate.sh $(subst /OK,,$@) + touch $@ + +run: + $(MAKE) clean + $(MAKE) all + touch run.ok + +clean: + rm -rf specimen_[0-9][0-9][0-9]/ seg_clblx.segbits __pycache__ run.ok + rm -rf vivado*.log vivado_*.str vivado*.jou design *.bits *.dcp *.bit + rm -rf build + +.PHONY: database pushdb run clean + +build/sub.json: $(SPECIMENS_OK) + mkdir -p build + # Discover which variables can be separated + # This is typically the longest running operation + python3 $(TIMFUZ_DIR)/rref.py --simplify --out build/sub.json $(CSVS) + +build/grouped.csv: $(SPECIMENS_OK) build/sub.json + # Separate variables + python3 $(TIMFUZ_DIR)/csv_flat2group.py --sub-json build/sub.json --strict $(CSVS) build/grouped.csv + # Verify sub.json makes a solvable solution + # python3 $(TIMFUZ_DIR)/checksub.py --sub-json build/sub.json grouped.csv + +build/leastsq.csv: build/sub.json build/grouped.csv + # Create a rough timing model that approximately fits the given paths + python3 $(TIMFUZ_DIR)/solve_leastsq.py --sub-json build/sub.json build/grouped.csv --out build/leastsq.csv + +build/linprog.csv: build/leastsq.csv build/grouped.csv + # Tweak rough timing model, making sure all constraints are satisfied + python3 $(TIMFUZ_DIR)/solve_linprog.py --sub-json build/sub.json --sub-csv build/leastsq.csv --massage build/grouped.csv --out build/linprog.csv + +build/flat.csv: build/linprog.csv + # Take separated variables and back-annotate them to the original timing variables + python3 $(TIMFUZ_DIR)/csv_group2flat.py --sub-json build/sub.json --sort build/linprog.csv build/flat.csv + +build/tilea.json: build/flat.csv + # Final processing + # Insert timing delays into actual tile layouts + python3 $(TIMFUZ_DIR)/tile_annotate.py --tile-json $(TIMFUZ_DIR)/timgrid/build/timgrid.json build/flat.csv build/tilea.json + diff --git a/fuzzers/007-timing/projects/project.tcl b/fuzzers/007-timing/projects/project.tcl new file mode 100644 index 00000000..b1478201 --- /dev/null +++ b/fuzzers/007-timing/projects/project.tcl @@ -0,0 +1,174 @@ +proc pin_info {pin} { + set cell [get_cells -of_objects $pin] + set bel [get_bels -of_objects $cell] + set site [get_sites -of_objects $bel] + return "$site $bel" +} + +proc pin_bel {pin} { + set cell [get_cells -of_objects $pin] + set bel [get_bels -of_objects $cell] + return $bel +} + +# Changed to group wires and nodes +# This allows tracing the full path along with pips +proc write_info3 {} { + set outdir "." + set fp [open "$outdir/timing3.txt" w] + # bel as site/bel, so don't bother with site + puts $fp "net src_bel dst_bel ico fast_max fast_min slow_max slow_min pips inodes wires" + + set TIME_start [clock clicks -milliseconds] + set verbose 0 + set equations 0 + set site_src_nets 0 + set site_dst_nets 0 + set neti 0 + set nets [get_nets -hierarchical] + set nnets [llength $nets] + foreach net $nets { + incr neti + #if {$neti >= 10} { + # puts "Debug break" + # break + #} + + puts "Net $neti / $nnets: $net" + # The semantics of get_pins -leaf is kind of odd + # When no passthrough LUTs exist, it has no effect + # When passthrough LUT present: + # -w/o -leaf: some pins + passthrough LUT pins + # -w/ -leaf: different pins + passthrough LUT pins + # With OUT filter this seems to be sufficient + set src_pin [get_pins -leaf -filter {DIRECTION == OUT} -of_objects $net] + set src_bel [pin_bel $src_pin] + set src_site [get_sites -of_objects $src_bel] + # Only one net driver + set src_site_pins [get_site_pins -filter {DIRECTION == OUT} -of_objects $net] + + # Sometimes this is empty for reasons that escape me + # Emitting direction doesn't help + if {[llength $src_site_pins] < 1} { + if $verbose { + puts " Ignoring site internal net" + } + incr site_src_nets + continue + } + set dst_site_pins_net [get_site_pins -filter {DIRECTION == IN} -of_objects $net] + if {[llength $dst_site_pins_net] < 1} { + puts " Skipping site internal source net" + incr site_dst_nets + continue + } + foreach src_site_pin $src_site_pins { + if $verbose { + puts "Source: $src_pin at site $src_site:$src_bel, spin $src_site_pin" + } + + # Run with and without interconnect only + foreach ico "0 1" { + set ico_flag "" + if $ico { + set ico_flag "-interconnect_only" + set delays [get_net_delays $ico_flag -of_objects $net] + } else { + set delays [get_net_delays -of_objects $net] + } + foreach delay $delays { + set delaystr [get_property NAME $delay] + set dst_pins [get_property TO_PIN $delay] + set dst_pin [get_pins $dst_pins] + #puts " $delaystr: $src_pin => $dst_pin" + set dst_bel [pin_bel $dst_pin] + set dst_site [get_sites -of_objects $dst_bel] + if $verbose { + puts " Dest: $dst_pin at site $dst_site:$dst_bel" + } + + set dst_site_pins [get_site_pins -of_objects $dst_pin] + # Some nets are internal + # But should this happen on dest if we've already filtered source? + if {"$dst_site_pins" eq ""} { + continue + } + # Also apparantly you can have multiple of these as well + foreach dst_site_pin $dst_site_pins { + set fast_max [get_property "FAST_MAX" $delay] + set fast_min [get_property "FAST_MIN" $delay] + set slow_max [get_property "SLOW_MAX" $delay] + set slow_min [get_property "SLOW_MIN" $delay] + + # Want: + # Site / BEL at src + # Site / BEL at dst + # Pips in between + # Walk net, looking for interesting elements in between + set pips [get_pips -of_objects $net -from $src_site_pin -to $dst_site_pin] + if $verbose { + foreach pip $pips { + puts " PIP $pip" + } + } + set nodes [get_nodes -of_objects $net -from $src_site_pin -to $dst_site_pin] + #set wires [get_wires -of_objects $net -from $src_site_pin -to $dst_site_pin] + set wires [get_wires -of_objects $nodes] + + # puts $fp "$net $src_bel $dst_bel $ico $fast_max $fast_min $slow_max $slow_min $pips" + puts -nonewline $fp "$net $src_bel $dst_bel $ico $fast_max $fast_min $slow_max $slow_min" + + # Write pips w/ speed index + puts -nonewline $fp " " + set needspace 0 + foreach pip $pips { + if $needspace { + puts -nonewline $fp "|" + } + set speed_index [get_property SPEED_INDEX $pip] + puts -nonewline $fp "$pip:$speed_index" + set needspace 1 + } + + # Write nodes + #set nodes_str [string map {" " "|"} $nodes] + #puts -nonewline $fp " $nodes_str" + puts -nonewline $fp " " + set needspace 0 + foreach node $nodes { + if $needspace { + puts -nonewline $fp "|" + } + set nwires [llength [get_wires -of_objects $node]] + puts -nonewline $fp "$node:$nwires" + set needspace 1 + } + + # Write wires + puts -nonewline $fp " " + set needspace 0 + foreach wire $wires { + if $needspace { + puts -nonewline $fp "|" + } + set speed_index [get_property SPEED_INDEX $wire] + puts -nonewline $fp "$wire:$speed_index" + set needspace 1 + } + + puts $fp "" + + incr equations + break + } + } + } + } + } + close $fp + set TIME_taken [expr [clock clicks -milliseconds] - $TIME_start] + puts "Took ms: $TIME_taken" + puts "Generated $equations equations" + puts "Skipped $site_src_nets (+ $site_dst_nets) site nets" +} +