Skip to content

Commit 61f8a3a

Browse files
authored
Merge pull request #3125 from The-OpenROAD-Project-staging/util-update-correlate-rc
util: Update and enhance correlateRC
2 parents 0273570 + b6ed935 commit 61f8a3a

File tree

3 files changed

+168
-107
lines changed

3 files changed

+168
-107
lines changed

flow/util/correlateRC.py

Lines changed: 116 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,19 @@
55
# Use ORFS 'make write_net_rc' to write cap files.
66

77
import os
8-
from sys import exit
8+
from sys import exit, stderr
99
from collections import defaultdict
1010

11+
import traceback
1112
import collections
1213
import argparse
1314
import re
1415
import numpy as np
1516
from sklearn.linear_model import LinearRegression
1617
import matplotlib.pyplot as plt
1718

19+
LAYER_HEADER_RE = re.compile("^([^\\(]+)\\(([^\\)]+)\\)$")
20+
1821
# Parse and validate arguments
1922
# =============================================================================
2023

@@ -81,39 +84,76 @@ def makeDict():
8184

8285
data = makeDict()
8386

87+
stack = []
88+
stack_line = None
89+
90+
# indices of relevant layers (routable layers or via layers)
91+
active_layers = set()
92+
8493
# Parse the cap CSV file generated by compare_rc_script.tcl
8594
for rc_file in args.rc_file:
8695
design = rc_file
8796
print("reading", design)
8897
with open(rc_file) as f:
8998
nonGrtNets = 0
9099
for line in f:
100+
if line.startswith("# stack: "):
101+
if stack_line is not None and stack_line != line:
102+
print(f"layer stack inconsistent", file=stderr)
103+
exit(1)
104+
elif stack_line is None:
105+
for layer in line.removeprefix("# stack: ").strip().split(" "):
106+
name = layer
107+
is_routing = False
108+
via_resist = 0.0
109+
if layer.endswith(")"):
110+
# layer name has extra data
111+
match = LAYER_HEADER_RE.match(layer)
112+
assert match
113+
name = match.group(1)
114+
if match.group(2) == "routing":
115+
is_routing = True
116+
else:
117+
via_resist = float(match.group(2))
118+
stack.append((name, is_routing, via_resist))
119+
continue
120+
91121
tokens = line.strip().split(",")
92122
netName = tokens[0]
93-
gpl_res = float(tokens[1])
94-
gpl_cap = float(tokens[2])
95-
grt_res = float(tokens[3])
96-
grt_cap = float(tokens[4])
97-
rcx_res = float(tokens[5])
98-
rcx_cap = float(tokens[6])
99-
100-
data[design][netName]["gpl_res"] = gpl_res
101-
data[design][netName]["gpl_cap"] = gpl_cap
102-
data[design][netName]["grt_res"] = grt_res
103-
data[design][netName]["grt_cap"] = grt_cap
104-
data[design][netName]["rcx_res"] = rcx_res
105-
data[design][netName]["rcx_cap"] = rcx_cap
106-
107-
layer_lengths = []
108-
layer_names = []
109-
wire_length = 0.0
110-
for i in range(7, len(tokens), 2):
111-
layer_names.append(tokens[i])
112-
layer_length = float(tokens[i + 1])
113-
layer_lengths.append(layer_length)
114-
wire_length += layer_length
123+
124+
data[design][netName] = {
125+
"type": tokens[1],
126+
"gpl_res": float(tokens[2]),
127+
"gpl_cap": float(tokens[3]),
128+
"grt_res": float(tokens[4]),
129+
"grt_cap": float(tokens[5]),
130+
"rcx_res": float(tokens[6]),
131+
"rcx_cap": float(tokens[7]),
132+
}
133+
134+
layer_lengths = [float(tok) for tok in tokens[8:]]
135+
for i, length in enumerate(layer_lengths):
136+
if length > 0:
137+
active_layers.add(i)
138+
115139
data[design][netName]["layer_lengths"] = layer_lengths
116-
data[design][netName]["wire_length"] = wire_length
140+
data[design][netName]["routable_layer_lengths"] = [
141+
length
142+
for i, length in enumerate(layer_lengths)
143+
# ignore non-routable layers
144+
if stack[i][1]
145+
]
146+
data[design][netName]["wire_length"] = sum(
147+
length
148+
for i, length in enumerate(layer_lengths)
149+
# ignore non-routable layers
150+
if stack[i][1]
151+
)
152+
data[design][netName]["grt_via_res"] = sum(
153+
(length * stack[i][2])
154+
for i, length in enumerate(layer_lengths)
155+
if not stack[i][1]
156+
)
117157

118158
################################################################
119159

@@ -210,16 +250,15 @@ def makeDict():
210250
for net in data[design]:
211251
rcx_res = data[design][net]["rcx_res"]
212252
if rcx_res > 0:
213-
layer_lengths = data[design][net]["layer_lengths"]
214-
x.append(layer_lengths)
215-
y.append(rcx_res)
253+
x.append(data[design][net]["routable_layer_lengths"])
254+
y.append(rcx_res - data[design][net]["grt_via_res"])
216255

217256
x = np.array(x)
218257
y = np.array(y)
219258

220259
res_model = LinearRegression(fit_intercept=False).fit(x, y)
221260
r_sq = res_model.score(x, y)
222-
print("Resistance coefficient of determination: {:.4f}".format(r_sq))
261+
print("# Resistance coefficient of determination: {:.4f}".format(r_sq))
223262

224263
################################################################
225264

@@ -229,60 +268,70 @@ def makeDict():
229268
y = []
230269
for design in data:
231270
for net in data[design]:
232-
layer_lengths = data[design][net]["layer_lengths"]
233-
x.append(layer_lengths)
271+
x.append(data[design][net]["routable_layer_lengths"])
234272
y.append(data[design][net]["rcx_cap"])
235273

236274
x = np.array(x)
237275
y = np.array(y)
238276

239277
cap_model = LinearRegression(fit_intercept=False).fit(x, y)
240278
r_sq = cap_model.score(x, y)
241-
print("Capacitance coefficient of determination: {:.4f}".format(r_sq))
242-
243-
print("Updated layer resistance {}/um capacitance {}/um".format(res_unit, cap_unit))
244-
for layer, res_coeff, cap_coeff in zip(layer_names, res_model.coef_, cap_model.coef_):
245-
if res_coeff > 0.0 or cap_coeff > 0.0:
279+
print("# Capacitance coefficient of determination: {:.4f}".format(r_sq))
280+
print("# Updated layer resistance {}/um capacitance {}/um".format(res_unit, cap_unit))
281+
282+
routable_layers = [layer for layer in stack if layer[1]]
283+
for i, layer in enumerate(routable_layers):
284+
res_coeff = res_model.coef_[i]
285+
cap_coeff = cap_model.coef_[i]
286+
if res_coeff != 0.0 or cap_coeff != 0.0:
246287
print(
247288
"set_layer_rc -layer {} -resistance {:.5E} -capacitance {:.5E}".format(
248-
layer, res_coeff / res_scale, cap_coeff / cap_scale
289+
layer[0], res_coeff / res_scale, cap_coeff / cap_scale
249290
)
250291
)
251292

252293
################################################################
253294

254-
x = []
255-
y = []
256-
for design in data:
257-
for net in data[design]:
258-
wire_res = data[design][net]["rcx_res"]
259-
wire_length = data[design][net]["wire_length"]
260-
if wire_res != 0.0:
261-
x.append([wire_length])
262-
y.append(wire_res)
263-
264-
x = np.array(x)
265-
y = np.array(y)
266-
267-
wire_res_model = LinearRegression(fit_intercept=False).fit(x, y)
268-
wire_res = wire_res_model.coef_[0]
269295

270-
x = []
271-
y = []
272-
for design in data:
273-
for net in data[design]:
274-
wire_length = data[design][net]["wire_length"]
275-
x.append([wire_length])
276-
y.append(data[design][net]["rcx_cap"])
296+
def generic_rc_fit(type_sieve):
297+
x = []
298+
y = []
299+
for design in data:
300+
for net in data[design]:
301+
net_type = data[design][net]["type"]
302+
wire_res = data[design][net]["rcx_res"]
303+
wire_length = data[design][net]["wire_length"]
304+
if net_type in type_sieve and wire_res != 0.0:
305+
x.append([wire_length])
306+
y.append(wire_res)
307+
x = np.array(x)
308+
y = np.array(y)
309+
wire_res_model = LinearRegression(fit_intercept=False).fit(x, y)
310+
wire_res = wire_res_model.coef_[0]
311+
312+
x = []
313+
y = []
314+
for design in data:
315+
for net in data[design]:
316+
net_type = data[design][net]["type"]
317+
if net_type in type_sieve:
318+
wire_length = data[design][net]["wire_length"]
319+
wire_cap = data[design][net]["rcx_cap"]
320+
x.append([wire_length])
321+
y.append(wire_cap)
322+
x = np.array(x)
323+
y = np.array(y)
324+
wire_cap_model = LinearRegression(fit_intercept=False).fit(x, y)
325+
wire_cap = wire_cap_model.coef_[0]
326+
327+
return "-resistance {:.5E} -capacitance {:.5E}".format(
328+
wire_res / res_scale, wire_cap / cap_scale
329+
)
277330

278-
x = np.array(x)
279-
y = np.array(y)
280331

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

284-
print(
285-
"set_wire_rc -resistance {:.5E} -capacitance {:.5E}".format(
286-
wire_res / res_scale, wire_cap / cap_scale
287-
)
288-
)
335+
print("# Split signal/clock fit:")
336+
print("set_wire_rc -signal " + generic_rc_fit(["signal"]))
337+
print("set_wire_rc -clock " + generic_rc_fit(["clock"]))

flow/util/write_net_rc.tcl

Lines changed: 50 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -37,25 +37,59 @@ proc write_rc_csv { filename } {
3737
upvar 1 grt rc_var2
3838
upvar 1 rcx rc_var3
3939

40-
set max_layer_name $::env(MAX_ROUTING_LAYER)
41-
set max_layer [[[ord::get_db_tech] findLayer $max_layer_name] getRoutingLevel]
42-
set min_layer_name $::env(MIN_ROUTING_LAYER)
43-
set min_layer [[[ord::get_db_tech] findLayer $min_layer_name] getRoutingLevel]
40+
set tech [ord::get_db_tech]
4441
set stream [open $filename "w"]
42+
43+
puts -nonewline $stream "# stack:"
44+
foreach layer [[ord::get_db_tech] getLayers] {
45+
set routing [expr [$layer getRoutingLevel] != 0]
46+
set is_routing([$layer getNumber]) $routing
47+
set is_routing([$layer getNumber]) $routing
48+
puts -nonewline $stream " [$layer getName]"
49+
if $routing {
50+
puts -nonewline $stream "(routing)"
51+
} else {
52+
# insert via resistance information
53+
set via_resist [$layer getResistance]
54+
if { $via_resist != 0.0 } {
55+
puts -nonewline $stream "([format %.4e $via_resist])"
56+
}
57+
}
58+
}
59+
puts $stream ""
60+
61+
set use_drt_data [env_var_exists_and_non_empty CORRELATE_DRT_WIRELENGTH]
62+
4563
foreach net [get_nets *] {
46-
set net_name [get_full_name $net]
47-
lassign $rc_var1($net_name) wire_res1 wire_cap1
48-
lassign $rc_var2($net_name) wire_res2 wire_cap2
49-
lassign $rc_var3($net_name) wire_res3 wire_cap3
50-
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]"
5164
set db_net [sta::sta_to_db_net $net]
52-
set layer_lengths [grt::route_layer_lengths $db_net]
53-
for {set layer $min_layer} {$layer <= $max_layer} {incr layer} {
54-
set layer_name [[[ord::get_db_tech] findRoutingLayer $layer] getName]
55-
set length [lindex $layer_lengths $layer]
56-
puts -nonewline $stream ",$layer_name,[ord::dbu_to_microns $length]"
65+
set type [$db_net getSigType]
66+
if {([string equal $type "CLOCK"] || [string equal $type "SIGNAL"]) &&
67+
(!$use_drt_data || [$db_net getWire] ne "NULL")} {
68+
set net_name [get_full_name $net]
69+
lassign $rc_var1($net_name) wire_res1 wire_cap1
70+
lassign $rc_var2($net_name) wire_res2 wire_cap2
71+
lassign $rc_var3($net_name) wire_res3 wire_cap3
72+
puts -nonewline $stream "[get_full_name $net],[expr {[string equal $type "CLOCK"] ? "clock" : "signal"}],"
73+
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]"
74+
set db_net [sta::sta_to_db_net $net]
75+
76+
if $use_drt_data {
77+
set layer_lengths [drt::route_layer_lengths [$db_net getWire]]
78+
} else {
79+
set layer_lengths [grt::route_layer_lengths $db_net]
80+
}
81+
82+
for {set layer 0} {$layer < [$tech getLayerCount]} {incr layer} {
83+
set length [lindex $layer_lengths $layer]
84+
if $is_routing($layer) {
85+
puts -nonewline $stream ",[ord::dbu_to_microns $length]"
86+
} else {
87+
puts -nonewline $stream ",$length"
88+
}
89+
}
90+
91+
puts $stream ""
5792
}
58-
puts $stream ""
5993
}
6094
close $stream
6195
}
@@ -73,19 +107,7 @@ proc record_wire_rc { var_name } {
73107

74108
# Only works or makes sense for 2 pin nets.
75109
proc net_wire_res { net } {
76-
set pins [get_pins -of_object $net]
77-
if { [llength $pins] == 2 } {
78-
lassign $pins pin1 pin2
79-
if { [$pin1 is_driver] } {
80-
set drvr $pin1
81-
} else {
82-
set drvr $pin2
83-
}
84-
lassign [sta::find_pi_elmore $drvr rise max] c2 rpi c1
85-
return $rpi
86-
} else {
87-
return 0.0
88-
}
110+
return [rsz::sum_parasitic_network_resist $net]
89111
}
90112

91113
proc net_wire_cap { net } {

flow/util/write_net_rc_script.tcl

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,15 @@
11
source $::env(SCRIPTS_DIR)/load.tcl
2-
# Note 6_final.def has wires that prevent global routing.
3-
load_design 4_1_cts.odb 4_cts.sdc
2+
load_design 6_final.odb 6_final.sdc
43

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

76
estimate_parasitics -placement
87
record_wire_rc gpl
98

10-
if {[env_var_exists_and_non_empty FASTROUTE_TCL]} {
11-
source $env(FASTROUTE_TCL)
12-
} else {
13-
set_global_routing_layer_adjustment $env(MIN_ROUTING_LAYER)-$env(MAX_ROUTING_LAYER) 0.5
14-
set_routing_layers -signal $env(MIN_ROUTING_LAYER)-$env(MAX_ROUTING_LAYER)
15-
}
16-
17-
global_route -congestion_iterations 100
18-
199
estimate_parasitics -global_routing
2010
record_wire_rc grt
2111

22-
read_spef -quiet -reduce_to pi_elmore $::env(RESULTS_DIR)/6_final.spef
12+
read_spef $::env(RESULTS_DIR)/6_final.spef
2313
record_wire_rc rcx
2414

2515
#compare_wire_rc 50 grt rcx

0 commit comments

Comments
 (0)