Fix some bugs present timing analysis script.

Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com>
This commit is contained in:
Keith Rothman 2020-02-13 13:12:24 -08:00
parent 541d88c999
commit d95eefc8de
5 changed files with 130 additions and 102 deletions

View File

@ -8,7 +8,7 @@ build/.touch:
touch build/.touch touch build/.touch
%.json: %.json5 %.json: %.json5
python3 clean_json5.py < $< > $@ python3 ${XRAY_UTILS_DIR}/clean_json5.py < $< > $@
CURDIR=$(shell pwd) CURDIR=$(shell pwd)
@ -18,14 +18,14 @@ define output_timing
# $(2) - DESIGN_NAME # $(2) - DESIGN_NAME
# $(3) - VERILOGS # $(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) rm -rf build/$(2)_$(1)
mkdir -p build/$(2)_$(1) mkdir -p build/$(2)_$(1)
export ITER=$(1) DESIGN_NAME=$(2) VERILOGS="$(3)" && cd 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 ${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 build/timing_$(2)_$(1).xlsx: build/$(2)_$(1)/timing_$(2)_$(1).json ${XRAY_UTILS_DIR}/create_timing_worksheet_db.py
python3 create_timing_worksheet_db.py \ python3 ${XRAY_UTILS_DIR}/create_timing_worksheet_db.py \
--timing_json build/$(2)_$(1)/timing_$(2)_$(1).json \ --timing_json build/$(2)_$(1)/timing_$(2)_$(1).json \
--db_root ${XRAY_FAMILY_DIR} \ --db_root ${XRAY_FAMILY_DIR} \
--part ${XRAY_PART} \ --part ${XRAY_PART} \

View File

@ -1,95 +1,4 @@
proc write_timing_info {filename} { source $::env(XRAY_UTILS_DIR)/write_timing_info.tcl
set fp [open $filename w]
puts $fp "\["
set nets [get_nets]
foreach net $nets {
if { $net == "<const0>" || $net == "<const1>" } {
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
}
proc create_design {design_name sig_mask verilogs} { proc create_design {design_name sig_mask verilogs} {
create_project -part $::env(XRAY_PART) -force design_$design_name \ create_project -part $::env(XRAY_PART) -force design_$design_name \

View File

@ -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 argparse
import json import json
from openpyxl import Workbook, utils from openpyxl import Workbook, utils
@ -92,7 +97,8 @@ class Net(object):
self.models = {} self.models = {}
for ipin in net['ipins']: 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 # Map of wire name to parent node
self.wire_to_node = {} self.wire_to_node = {}
@ -112,7 +118,7 @@ class Net(object):
dst_wire = pip['dst_wire'].split('/')[1] dst_wire = pip['dst_wire'].split('/')[1]
self.pips[(src_node, dst_wire)] = pip 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'] dst_node = self.wire_to_node[pip['dst_wire']]['name']
src_wire = pip['src_wire'].split('/')[1] src_wire = pip['src_wire'].split('/')[1]
self.pips[(dst_node, src_wire)] = pip self.pips[(dst_node, src_wire)] = pip
@ -235,7 +241,10 @@ class Net(object):
self.row += 1 self.row += 1
if current_node in self.ipin_nodes: 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 route_idx += 1
node = self.node_name_to_node[current_node] node = self.node_name_to_node[current_node]
@ -251,7 +260,7 @@ class Net(object):
ws['A{}'.format(self.row)] = ipin['name'] ws['A{}'.format(self.row)] = ipin['name']
ws['B{}'.format(self.row)] = 'Inpin' 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) assert isinstance(site_pin.timing, InPinTiming)
cells = {} cells = {}
@ -421,8 +430,9 @@ class Net(object):
def add_net(wb, net, timing_lookup): def add_net(wb, net, timing_lookup):
replace_underscore = str.maketrans('[]\\:/', '_____')
ws = wb.create_sheet( ws = wb.create_sheet(
title="Net {}".format(net['net'].replace('[', '_').replace(']', '_'))) title="Net {}".format(net['net'].translate(replace_underscore)))
# Header # Header
ws['A1'] = 'Name' ws['A1'] = 'Name'
@ -478,13 +488,14 @@ def main():
cur_col = chr(ord(cur_col) + 3) cur_col = chr(ord(cur_col) + 3)
summary_row = 2 summary_row = 2
for net in timing: for idx, net in enumerate(timing):
if '<' in net['route']: if '<' in net['route']:
print( print(
"WARNING: Skipping net {} because it has complicated route description." "WARNING: Skipping net {} because it has complicated route description."
.format(net['net'])) .format(net['net']))
continue continue
print('Process net {} ({} / {})'.format(net['net'], idx, len(timing)))
for summary_cells in add_net(wb, net, timing_lookup): for summary_cells in add_net(wb, net, timing_lookup):
summary_ws['A{}'.format(summary_row)] = summary_cells['Name'] summary_ws['A{}'.format(summary_row)] = summary_cells['Name']

108
utils/write_timing_info.tcl Normal file
View File

@ -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 == "<const0>" || $net == "<const1>" } {
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
}