From d95eefc8deef0f25ee2b2f77d001f8f769f255f5 Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Thu, 13 Feb 2020 13:12:24 -0800 Subject: [PATCH] Fix some bugs present timing analysis script. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- minitests/timing/Makefile | 8 +- minitests/timing/runme.tcl | 93 +-------------- {minitests/timing => utils}/clean_json5.py | 0 .../create_timing_worksheet_db.py | 23 +++- utils/write_timing_info.tcl | 108 ++++++++++++++++++ 5 files changed, 130 insertions(+), 102 deletions(-) rename {minitests/timing => utils}/clean_json5.py (100%) rename {minitests/timing => utils}/create_timing_worksheet_db.py (95%) create mode 100644 utils/write_timing_info.tcl diff --git a/minitests/timing/Makefile b/minitests/timing/Makefile index b5bd2a46..24aa6707 100644 --- a/minitests/timing/Makefile +++ b/minitests/timing/Makefile @@ -8,7 +8,7 @@ build/.touch: touch build/.touch %.json: %.json5 - python3 clean_json5.py < $< > $@ + python3 ${XRAY_UTILS_DIR}/clean_json5.py < $< > $@ CURDIR=$(shell pwd) @@ -18,14 +18,14 @@ define output_timing # $(2) - DESIGN_NAME # $(3) - VERILOGS -build/$(2)_$(1)/timing_$(2)_$(1).json5: build/.touch runme.tcl $(3) +build/$(2)_$(1)/timing_$(2)_$(1).json5: build/.touch runme.tcl ${XRAY_UTILS_DIR}/write_timing_info.tcl $(3) rm -rf build/$(2)_$(1) mkdir -p build/$(2)_$(1) export ITER=$(1) DESIGN_NAME=$(2) VERILOGS="$(3)" && cd build/$(2)_$(1) && \ ${XRAY_VIVADO} -mode batch -source ${CURDIR}/runme.tcl > design_$(2)_$(1)_vivado.log -build/timing_$(2)_$(1).xlsx: build/$(2)_$(1)/timing_$(2)_$(1).json create_timing_worksheet_db.py - python3 create_timing_worksheet_db.py \ +build/timing_$(2)_$(1).xlsx: build/$(2)_$(1)/timing_$(2)_$(1).json ${XRAY_UTILS_DIR}/create_timing_worksheet_db.py + python3 ${XRAY_UTILS_DIR}/create_timing_worksheet_db.py \ --timing_json build/$(2)_$(1)/timing_$(2)_$(1).json \ --db_root ${XRAY_FAMILY_DIR} \ --part ${XRAY_PART} \ diff --git a/minitests/timing/runme.tcl b/minitests/timing/runme.tcl index ad4f92ca..f3ee2986 100644 --- a/minitests/timing/runme.tcl +++ b/minitests/timing/runme.tcl @@ -1,95 +1,4 @@ -proc write_timing_info {filename} { - set fp [open $filename w] - puts $fp "\[" - - set nets [get_nets] - foreach net $nets { - if { $net == "" || $net == "" } { - continue - } - - if { [get_property ROUTE_STATUS [get_nets $net]] == "INTRASITE" } { - continue - } - if { [get_property ROUTE_STATUS [get_nets $net]] == "NOLOADS" } { - continue - } - - puts $fp "{" - puts $fp "\"net\":\"$net\"," - - set route [get_property ROUTE $net] - puts $fp "\"route\":\"$route\"," - - set pips [get_pips -of_objects $net] - puts $fp "\"pips\":\[" - foreach pip $pips { - puts $fp "{" - puts $fp "\"name\":\"$pip\"," - puts $fp "\"src_wire\":\"[get_wires -uphill -of_objects $pip]\"," - puts $fp "\"dst_wire\":\"[get_wires -downhill -of_objects $pip]\"," - puts $fp "\"speed_index\":\"[get_property SPEED_INDEX $pip]\"," - puts $fp "\"is_directional\":\"[get_property IS_DIRECTIONAL $pip]\"," - puts $fp "}," - } - puts $fp "\]," - puts $fp "\"nodes\":\[" - set nodes [get_nodes -of_objects $net] - foreach node $nodes { - puts $fp "{" - puts $fp "\"name\":\"$node\"," - puts $fp "\"cost_code\":\"[get_property COST_CODE $node]\"," - puts $fp "\"cost_code_name\":\"[get_property COST_CODE_NAME $node]\"," - puts $fp "\"speed_class\":\"[get_property SPEED_CLASS $node]\"," - puts $fp "\"wires\":\[" - set wires [get_wires -of_objects $node] - foreach wire $wires { - puts $fp "{" - puts $fp "\"name\":\"$wire\"," - puts $fp "\"cost_code\":\"[get_property COST_CODE $wire]\"," - puts $fp "\"speed_index\":\"[get_property SPEED_INDEX $wire]\"," - puts $fp "}," - } - puts $fp "\]," - puts $fp "}," - } - puts $fp "\]," - - set opin [get_pins -leaf -of_objects [get_nets $net] -filter {DIRECTION == OUT}] - puts $fp "\"opin\": {" - puts $fp "\"name\":\"$opin\"," - set opin_site_pin [get_site_pins -of_objects $opin] - puts $fp "\"site_pin\":\"$opin_site_pin\"," - puts $fp "\"site_pin_speed_index\":\"[get_property SPEED_INDEX $opin_site_pin]\"," - puts $fp "\"node\":\"[get_nodes -of_objects $opin_site_pin]\"," - puts $fp "\"wire\":\"[get_wires -of_objects [get_nodes -of_objects $opin_site_pin]]\"," - puts $fp "}," - set ipins [get_pins -of_objects [get_nets $net] -filter {DIRECTION == IN} -leaf] - puts $fp "\"ipins\":\[" - foreach ipin $ipins { - puts $fp "{" - set delay [get_net_delays -interconnect_only -of_objects $net -to $ipin] - puts $fp "\"name\":\"$ipin\"," - puts $fp "\"ic_delays\":{" - foreach prop {"FAST_MAX" "FAST_MIN" "SLOW_MAX" "SLOW_MIN"} { - puts $fp "\"$prop\":\"[get_property $prop $delay]\"," - } - puts $fp "}," - set ipin_site_pin [get_site_pin -of_objects $ipin] - puts $fp "\"site_pin\":\"$ipin_site_pin\"," - puts $fp "\"site_pin_speed_index\":\"[get_property SPEED_INDEX $ipin_site_pin]\"," - puts $fp "\"node\":\"[get_nodes -of_objects $ipin_site_pin]\"," - puts $fp "\"wire\":\"[get_wires -of_objects [get_nodes -of_objects $ipin_site_pin]]\"," - puts $fp "}," - } - puts $fp "\]," - - puts $fp "}," - } - - puts $fp "\]" - close $fp -} +source $::env(XRAY_UTILS_DIR)/write_timing_info.tcl proc create_design {design_name sig_mask verilogs} { create_project -part $::env(XRAY_PART) -force design_$design_name \ diff --git a/minitests/timing/clean_json5.py b/utils/clean_json5.py similarity index 100% rename from minitests/timing/clean_json5.py rename to utils/clean_json5.py diff --git a/minitests/timing/create_timing_worksheet_db.py b/utils/create_timing_worksheet_db.py similarity index 95% rename from minitests/timing/create_timing_worksheet_db.py rename to utils/create_timing_worksheet_db.py index 3e2ace86..b4536049 100644 --- a/minitests/timing/create_timing_worksheet_db.py +++ b/utils/create_timing_worksheet_db.py @@ -1,3 +1,8 @@ +""" This takes a JSON file generated with write_timing_info.tcl and generates +a spreadsheet with the prjxray timing model and compares it with the +interconnect timing output from Vivado. + +""" import argparse import json from openpyxl import Workbook, utils @@ -92,7 +97,8 @@ class Net(object): self.models = {} for ipin in net['ipins']: - self.ipin_nodes[ipin['node']] = ipin + for ipin_node in ipin['node'].strip().split(' '): + self.ipin_nodes[ipin_node] = ipin # Map of wire name to parent node self.wire_to_node = {} @@ -112,7 +118,7 @@ class Net(object): dst_wire = pip['dst_wire'].split('/')[1] self.pips[(src_node, dst_wire)] = pip - if not pip['is_directional']: + if not int(pip['is_directional']): dst_node = self.wire_to_node[pip['dst_wire']]['name'] src_wire = pip['src_wire'].split('/')[1] self.pips[(dst_node, src_wire)] = pip @@ -235,7 +241,10 @@ class Net(object): self.row += 1 if current_node in self.ipin_nodes: - assert route[route_idx] == '}' + assert route[route_idx] in ['}', 'IOB_O_OUT0', 'IOB_T_OUT0'], ( + route_idx, + route[route_idx], + ) route_idx += 1 node = self.node_name_to_node[current_node] @@ -251,7 +260,7 @@ class Net(object): ws['A{}'.format(self.row)] = ipin['name'] ws['B{}'.format(self.row)] = 'Inpin' - site_pin = timing_lookup.find_site_pin(ipin['node'], node_idx=-1) + site_pin = timing_lookup.find_site_pin(current_node, node_idx=-1) assert isinstance(site_pin.timing, InPinTiming) cells = {} @@ -421,8 +430,9 @@ class Net(object): def add_net(wb, net, timing_lookup): + replace_underscore = str.maketrans('[]\\:/', '_____') ws = wb.create_sheet( - title="Net {}".format(net['net'].replace('[', '_').replace(']', '_'))) + title="Net {}".format(net['net'].translate(replace_underscore))) # Header ws['A1'] = 'Name' @@ -478,13 +488,14 @@ def main(): cur_col = chr(ord(cur_col) + 3) summary_row = 2 - for net in timing: + for idx, net in enumerate(timing): if '<' in net['route']: print( "WARNING: Skipping net {} because it has complicated route description." .format(net['net'])) continue + print('Process net {} ({} / {})'.format(net['net'], idx, len(timing))) for summary_cells in add_net(wb, net, timing_lookup): summary_ws['A{}'.format(summary_row)] = summary_cells['Name'] diff --git a/utils/write_timing_info.tcl b/utils/write_timing_info.tcl new file mode 100644 index 00000000..46c85e14 --- /dev/null +++ b/utils/write_timing_info.tcl @@ -0,0 +1,108 @@ +# Writes a JSON5 to filename containing timing for current design. +# This can be used with create_timing_worksheet_db.py to compare prjxray model +# with Vivado timing model outputs. +proc write_timing_info {filename} { + set fp [open $filename w] + puts $fp "\[" + + set nets [get_nets] + set idx 0 + foreach net $nets { + puts "net: $net ($idx / [llength $nets])" + incr idx + if { $net == "" || $net == "" } { + continue + } + + if { [get_property TYPE [get_nets $net]] == "GROUND" } { + continue + } + if { [get_property TYPE [get_nets $net]] == "POWER" } { + continue + } + if { [get_property ROUTE_STATUS [get_nets $net]] == "INTRASITE" } { + continue + } + if { [get_property ROUTE_STATUS [get_nets $net]] == "NOLOADS" } { + continue + } + + puts $fp "{" + puts $fp "\"net\":\"$net\"," + + set route [get_property ROUTE $net] + puts $fp "\"route\":\"$route\"," + + set pips [get_pips -of_objects $net] + puts $fp "\"pips\":\[" + foreach pip $pips { + puts $fp "{" + puts $fp "\"name\":\"$pip\"," + puts $fp "\"src_wire\":\"[get_wires -uphill -of_objects $pip]\"," + puts $fp "\"dst_wire\":\"[get_wires -downhill -of_objects $pip]\"," + puts $fp "\"speed_index\":\"[get_property SPEED_INDEX $pip]\"," + puts $fp "\"is_directional\":\"[get_property IS_DIRECTIONAL $pip]\"," + puts $fp "}," + } + puts $fp "\]," + puts $fp "\"nodes\":\[" + set nodes [get_nodes -of_objects $net] + foreach node $nodes { + puts $fp "{" + puts $fp "\"name\":\"$node\"," + puts $fp "\"cost_code\":\"[get_property COST_CODE $node]\"," + puts $fp "\"cost_code_name\":\"[get_property COST_CODE_NAME $node]\"," + puts $fp "\"speed_class\":\"[get_property SPEED_CLASS $node]\"," + puts $fp "\"wires\":\[" + set wires [get_wires -of_objects $node] + foreach wire $wires { + puts $fp "{" + puts $fp "\"name\":\"$wire\"," + puts $fp "\"cost_code\":\"[get_property COST_CODE $wire]\"," + puts $fp "\"speed_index\":\"[get_property SPEED_INDEX $wire]\"," + puts $fp "}," + } + puts $fp "\]," + puts $fp "}," + } + puts $fp "\]," + + set opin [get_pins -leaf -of_objects [get_nets $net] -filter {DIRECTION == OUT}] + puts $fp "\"opin\": {" + puts $fp "\"name\":\"$opin\"," + set opin_site_pin [get_site_pins -of_objects $opin] + puts $fp "\"site_pin\":\"$opin_site_pin\"," + puts $fp "\"site_pin_speed_index\":\"[get_property SPEED_INDEX $opin_site_pin]\"," + puts $fp "\"node\":\"[get_nodes -of_objects $opin_site_pin]\"," + puts $fp "\"wire\":\"[get_wires -of_objects [get_nodes -of_objects $opin_site_pin]]\"," + puts $fp "}," + set ipins [get_pins -of_objects [get_nets $net] -filter {DIRECTION == IN} -leaf] + puts $fp "\"ipins\":\[" + foreach ipin $ipins { + set ipin_site_pin [get_site_pins -of_objects $ipin -quiet] + if { $ipin_site_pin == "" } { + # This connection is internal! + continue + } + puts $fp "{" + set delay [get_net_delays -interconnect_only -of_objects $net -to $ipin] + puts $fp "\"name\":\"$ipin\"," + puts $fp "\"ic_delays\":{" + foreach prop {"FAST_MAX" "FAST_MIN" "SLOW_MAX" "SLOW_MIN"} { + puts $fp "\"$prop\":\"[get_property $prop $delay]\"," + } + puts $fp "}," + puts $fp "\"site_pin\":\"$ipin_site_pin\"," + puts $fp "\"site_pin_speed_index\":\"[get_property SPEED_INDEX $ipin_site_pin]\"," + puts $fp "\"node\":\"[get_nodes -of_objects $ipin_site_pin]\"," + puts $fp "\"wire\":\"[get_wires -of_objects [get_nodes -of_objects $ipin_site_pin]]\"," + puts $fp "}," + } + puts $fp "\]," + + puts $fp "}," + } + + puts $fp "\]" + close $fp +}