Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
183 changes: 116 additions & 67 deletions flow/util/correlateRC.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,19 @@
# Use ORFS 'make write_net_rc' to write cap files.

import os
from sys import exit
from sys import exit, stderr
from collections import defaultdict

import traceback
import collections
import argparse
import re
import numpy as np
from sklearn.linear_model import LinearRegression
import matplotlib.pyplot as plt

LAYER_HEADER_RE = re.compile("^([^\\(]+)\\(([^\\)]+)\\)$")

# Parse and validate arguments
# =============================================================================

Expand Down Expand Up @@ -81,39 +84,76 @@ def makeDict():

data = makeDict()

stack = []
stack_line = None

# indices of relevant layers (routable layers or via layers)
active_layers = set()

# Parse the cap CSV file generated by compare_rc_script.tcl
for rc_file in args.rc_file:
design = rc_file
print("reading", design)
with open(rc_file) as f:
nonGrtNets = 0
for line in f:
if line.startswith("# stack: "):
if stack_line is not None and stack_line != line:
print(f"layer stack inconsistent", file=stderr)
exit(1)
elif stack_line is None:
for layer in line.removeprefix("# stack: ").strip().split(" "):
name = layer
is_routing = False
via_resist = 0.0
if layer.endswith(")"):
# layer name has extra data
match = LAYER_HEADER_RE.match(layer)
assert match
name = match.group(1)
if match.group(2) == "routing":
is_routing = True
else:
via_resist = float(match.group(2))
stack.append((name, is_routing, via_resist))
continue

tokens = line.strip().split(",")
netName = tokens[0]
gpl_res = float(tokens[1])
gpl_cap = float(tokens[2])
grt_res = float(tokens[3])
grt_cap = float(tokens[4])
rcx_res = float(tokens[5])
rcx_cap = float(tokens[6])

data[design][netName]["gpl_res"] = gpl_res
data[design][netName]["gpl_cap"] = gpl_cap
data[design][netName]["grt_res"] = grt_res
data[design][netName]["grt_cap"] = grt_cap
data[design][netName]["rcx_res"] = rcx_res
data[design][netName]["rcx_cap"] = rcx_cap

layer_lengths = []
layer_names = []
wire_length = 0.0
for i in range(7, len(tokens), 2):
layer_names.append(tokens[i])
layer_length = float(tokens[i + 1])
layer_lengths.append(layer_length)
wire_length += layer_length

data[design][netName] = {
"type": tokens[1],
"gpl_res": float(tokens[2]),
"gpl_cap": float(tokens[3]),
"grt_res": float(tokens[4]),
"grt_cap": float(tokens[5]),
"rcx_res": float(tokens[6]),
"rcx_cap": float(tokens[7]),
}

layer_lengths = [float(tok) for tok in tokens[8:]]
for i, length in enumerate(layer_lengths):
if length > 0:
active_layers.add(i)

data[design][netName]["layer_lengths"] = layer_lengths
data[design][netName]["wire_length"] = wire_length
data[design][netName]["routable_layer_lengths"] = [
length
for i, length in enumerate(layer_lengths)
# ignore non-routable layers
if stack[i][1]
]
data[design][netName]["wire_length"] = sum(
length
for i, length in enumerate(layer_lengths)
# ignore non-routable layers
if stack[i][1]
)
data[design][netName]["grt_via_res"] = sum(
(length * stack[i][2])
for i, length in enumerate(layer_lengths)
if not stack[i][1]
)

################################################################

Expand Down Expand Up @@ -210,16 +250,15 @@ def makeDict():
for net in data[design]:
rcx_res = data[design][net]["rcx_res"]
if rcx_res > 0:
layer_lengths = data[design][net]["layer_lengths"]
x.append(layer_lengths)
y.append(rcx_res)
x.append(data[design][net]["routable_layer_lengths"])
y.append(rcx_res - data[design][net]["grt_via_res"])

x = np.array(x)
y = np.array(y)

res_model = LinearRegression(fit_intercept=False).fit(x, y)
r_sq = res_model.score(x, y)
print("Resistance coefficient of determination: {:.4f}".format(r_sq))
print("# Resistance coefficient of determination: {:.4f}".format(r_sq))

################################################################

Expand All @@ -229,60 +268,70 @@ def makeDict():
y = []
for design in data:
for net in data[design]:
layer_lengths = data[design][net]["layer_lengths"]
x.append(layer_lengths)
x.append(data[design][net]["routable_layer_lengths"])
y.append(data[design][net]["rcx_cap"])

x = np.array(x)
y = np.array(y)

cap_model = LinearRegression(fit_intercept=False).fit(x, y)
r_sq = cap_model.score(x, y)
print("Capacitance coefficient of determination: {:.4f}".format(r_sq))

print("Updated layer resistance {}/um capacitance {}/um".format(res_unit, cap_unit))
for layer, res_coeff, cap_coeff in zip(layer_names, res_model.coef_, cap_model.coef_):
if res_coeff > 0.0 or cap_coeff > 0.0:
print("# Capacitance coefficient of determination: {:.4f}".format(r_sq))
print("# Updated layer resistance {}/um capacitance {}/um".format(res_unit, cap_unit))

routable_layers = [layer for layer in stack if layer[1]]
for i, layer in enumerate(routable_layers):
res_coeff = res_model.coef_[i]
cap_coeff = cap_model.coef_[i]
if res_coeff != 0.0 or cap_coeff != 0.0:
print(
"set_layer_rc -layer {} -resistance {:.5E} -capacitance {:.5E}".format(
layer, res_coeff / res_scale, cap_coeff / cap_scale
layer[0], res_coeff / res_scale, cap_coeff / cap_scale
)
)

################################################################

x = []
y = []
for design in data:
for net in data[design]:
wire_res = data[design][net]["rcx_res"]
wire_length = data[design][net]["wire_length"]
if wire_res != 0.0:
x.append([wire_length])
y.append(wire_res)

x = np.array(x)
y = np.array(y)

wire_res_model = LinearRegression(fit_intercept=False).fit(x, y)
wire_res = wire_res_model.coef_[0]

x = []
y = []
for design in data:
for net in data[design]:
wire_length = data[design][net]["wire_length"]
x.append([wire_length])
y.append(data[design][net]["rcx_cap"])
def generic_rc_fit(type_sieve):
x = []
y = []
for design in data:
for net in data[design]:
net_type = data[design][net]["type"]
wire_res = data[design][net]["rcx_res"]
wire_length = data[design][net]["wire_length"]
if net_type in type_sieve and wire_res != 0.0:
x.append([wire_length])
y.append(wire_res)
x = np.array(x)
y = np.array(y)
wire_res_model = LinearRegression(fit_intercept=False).fit(x, y)
wire_res = wire_res_model.coef_[0]

x = []
y = []
for design in data:
for net in data[design]:
net_type = data[design][net]["type"]
if net_type in type_sieve:
wire_length = data[design][net]["wire_length"]
wire_cap = data[design][net]["rcx_cap"]
x.append([wire_length])
y.append(wire_cap)
x = np.array(x)
y = np.array(y)
wire_cap_model = LinearRegression(fit_intercept=False).fit(x, y)
wire_cap = wire_cap_model.coef_[0]

return "-resistance {:.5E} -capacitance {:.5E}".format(
wire_res / res_scale, wire_cap / cap_scale
)

x = np.array(x)
y = np.array(y)

wire_cap_model = LinearRegression(fit_intercept=False).fit(x, y)
wire_cap = wire_cap_model.coef_[0]
print("# Combined fit:")
print("set_wire_rc " + generic_rc_fit(["signal", "clock"]))

print(
"set_wire_rc -resistance {:.5E} -capacitance {:.5E}".format(
wire_res / res_scale, wire_cap / cap_scale
)
)
print("# Split signal/clock fit:")
print("set_wire_rc -signal " + generic_rc_fit(["signal"]))
print("set_wire_rc -clock " + generic_rc_fit(["clock"]))
78 changes: 50 additions & 28 deletions flow/util/write_net_rc.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -37,25 +37,59 @@ proc write_rc_csv { filename } {
upvar 1 grt rc_var2
upvar 1 rcx rc_var3

set max_layer_name $::env(MAX_ROUTING_LAYER)
set max_layer [[[ord::get_db_tech] findLayer $max_layer_name] getRoutingLevel]
set min_layer_name $::env(MIN_ROUTING_LAYER)
set min_layer [[[ord::get_db_tech] findLayer $min_layer_name] getRoutingLevel]
set tech [ord::get_db_tech]
set stream [open $filename "w"]

puts -nonewline $stream "# stack:"
foreach layer [[ord::get_db_tech] getLayers] {
set routing [expr [$layer getRoutingLevel] != 0]
set is_routing([$layer getNumber]) $routing
set is_routing([$layer getNumber]) $routing
puts -nonewline $stream " [$layer getName]"
if $routing {
puts -nonewline $stream "(routing)"
} else {
# insert via resistance information
set via_resist [$layer getResistance]
if { $via_resist != 0.0 } {
puts -nonewline $stream "([format %.4e $via_resist])"
}
}
}
puts $stream ""

set use_drt_data [env_var_exists_and_non_empty CORRELATE_DRT_WIRELENGTH]

foreach net [get_nets *] {
set net_name [get_full_name $net]
lassign $rc_var1($net_name) wire_res1 wire_cap1
lassign $rc_var2($net_name) wire_res2 wire_cap2
lassign $rc_var3($net_name) wire_res3 wire_cap3
puts -nonewline $stream "[get_full_name $net],[format %.3e $wire_res1],[format %.3e $wire_cap1],[format %.3e $wire_res2],[format %.3e $wire_cap2],[format %.3e $wire_res3],[format %.3e $wire_cap3]"
set db_net [sta::sta_to_db_net $net]
set layer_lengths [grt::route_layer_lengths $db_net]
for {set layer $min_layer} {$layer <= $max_layer} {incr layer} {
set layer_name [[[ord::get_db_tech] findRoutingLayer $layer] getName]
set length [lindex $layer_lengths $layer]
puts -nonewline $stream ",$layer_name,[ord::dbu_to_microns $length]"
set type [$db_net getSigType]
if {([string equal $type "CLOCK"] || [string equal $type "SIGNAL"]) &&
(!$use_drt_data || [$db_net getWire] ne "NULL")} {
set net_name [get_full_name $net]
lassign $rc_var1($net_name) wire_res1 wire_cap1
lassign $rc_var2($net_name) wire_res2 wire_cap2
lassign $rc_var3($net_name) wire_res3 wire_cap3
puts -nonewline $stream "[get_full_name $net],[expr {[string equal $type "CLOCK"] ? "clock" : "signal"}],"
puts -nonewline $stream "[format %.3e $wire_res1],[format %.3e $wire_cap1],[format %.3e $wire_res2],[format %.3e $wire_cap2],[format %.3e $wire_res3],[format %.3e $wire_cap3]"
set db_net [sta::sta_to_db_net $net]

if $use_drt_data {
set layer_lengths [drt::route_layer_lengths [$db_net getWire]]
} else {
set layer_lengths [grt::route_layer_lengths $db_net]
}

for {set layer 0} {$layer < [$tech getLayerCount]} {incr layer} {
set length [lindex $layer_lengths $layer]
if $is_routing($layer) {
puts -nonewline $stream ",[ord::dbu_to_microns $length]"
} else {
puts -nonewline $stream ",$length"
}
}

puts $stream ""
}
puts $stream ""
}
close $stream
}
Expand All @@ -73,19 +107,7 @@ proc record_wire_rc { var_name } {

# Only works or makes sense for 2 pin nets.
proc net_wire_res { net } {
set pins [get_pins -of_object $net]
if { [llength $pins] == 2 } {
lassign $pins pin1 pin2
if { [$pin1 is_driver] } {
set drvr $pin1
} else {
set drvr $pin2
}
lassign [sta::find_pi_elmore $drvr rise max] c2 rpi c1
return $rpi
} else {
return 0.0
}
return [rsz::sum_parasitic_network_resist $net]
}

proc net_wire_cap { net } {
Expand Down
14 changes: 2 additions & 12 deletions flow/util/write_net_rc_script.tcl
Original file line number Diff line number Diff line change
@@ -1,25 +1,15 @@
source $::env(SCRIPTS_DIR)/load.tcl
# Note 6_final.def has wires that prevent global routing.
load_design 4_1_cts.odb 4_cts.sdc
load_design 6_final.odb 6_final.sdc

source $::env(UTILS_DIR)/write_net_rc.tcl

estimate_parasitics -placement
record_wire_rc gpl

if {[env_var_exists_and_non_empty FASTROUTE_TCL]} {
source $env(FASTROUTE_TCL)
} else {
set_global_routing_layer_adjustment $env(MIN_ROUTING_LAYER)-$env(MAX_ROUTING_LAYER) 0.5
set_routing_layers -signal $env(MIN_ROUTING_LAYER)-$env(MAX_ROUTING_LAYER)
}

global_route -congestion_iterations 100

estimate_parasitics -global_routing
record_wire_rc grt

read_spef -quiet -reduce_to pi_elmore $::env(RESULTS_DIR)/6_final.spef
read_spef $::env(RESULTS_DIR)/6_final.spef
record_wire_rc rcx

#compare_wire_rc 50 grt rcx
Expand Down