|
1 | 1 | #!/usr/bin/env python3 |
2 | 2 |
|
3 | | -# Read grt/rcx capacitance/wire length files for multiple designs and |
4 | | -# use linear regression to fit layer capacitances to rcx net capacitances. |
5 | | -# Use ORFS 'make write_net_rc' to write cap files. |
| 3 | +# Script for generating and comparing per-layer parasitics values. |
| 4 | +# These values are used by set_layer_rc and will be the base |
| 5 | +# values for the parasitics estimations across the flow. |
6 | 6 |
|
7 | 7 | import os |
8 | 8 | from sys import exit, stderr |
@@ -46,6 +46,13 @@ def parse_args(): |
46 | 46 | default=False, |
47 | 47 | help="Plot grt/rcx resistance differences", |
48 | 48 | ) |
| 49 | + parser.add_argument( |
| 50 | + "--mode", |
| 51 | + required=False, |
| 52 | + choices=["net", "segment"], |
| 53 | + default="net", |
| 54 | + help="Input mode: 'net' for net-level RC (make write_net_rc), 'segment' for segment-level RC (make write_segment_rc)", |
| 55 | + ) |
49 | 56 | parser.add_argument( |
50 | 57 | "rc_file", nargs="+", help="rc csv file written by make compare_rc" |
51 | 58 | ) |
@@ -120,43 +127,47 @@ def makeDict(): |
120 | 127 | continue |
121 | 128 |
|
122 | 129 | tokens = line.strip().split(",") |
123 | | - netName = tokens[0] |
124 | | - |
125 | | - data[design][netName] = { |
126 | | - "type": tokens[1], |
127 | | - "grt_res": float(tokens[2]), |
128 | | - "grt_cap": float(tokens[3]), |
129 | | - "rcx_res": float(tokens[4]), |
130 | | - "rcx_cap": float(tokens[5]), |
131 | | - } |
132 | | - |
133 | | - layer_lengths = [float(tok) for tok in tokens[6:]] |
134 | | - for i, length in enumerate(layer_lengths): |
135 | | - if length > 0: |
136 | | - active_layers.add(i) |
137 | | - |
138 | | - data[design][netName]["layer_lengths"] = layer_lengths |
139 | | - data[design][netName]["routable_layer_lengths"] = [ |
140 | | - length |
141 | | - for i, length in enumerate(layer_lengths) |
142 | | - # ignore non-routable layers |
143 | | - if stack[i][1] |
144 | | - ] |
145 | | - data[design][netName]["wire_length"] = sum( |
146 | | - length |
147 | | - for i, length in enumerate(layer_lengths) |
148 | | - # ignore non-routable layers |
149 | | - if stack[i][1] |
150 | | - ) |
151 | | - data[design][netName]["grt_via_res"] = sum( |
152 | | - (length * stack[i][2]) |
153 | | - for i, length in enumerate(layer_lengths) |
154 | | - if not stack[i][1] |
155 | | - ) |
| 130 | + |
| 131 | + if args.mode == "segment": |
| 132 | + pass |
| 133 | + else: |
| 134 | + netName = tokens[0] |
| 135 | + |
| 136 | + data[design][netName] = { |
| 137 | + "type": tokens[1], |
| 138 | + "grt_res": float(tokens[2]), |
| 139 | + "grt_cap": float(tokens[3]), |
| 140 | + "rcx_res": float(tokens[4]), |
| 141 | + "rcx_cap": float(tokens[5]), |
| 142 | + } |
| 143 | + |
| 144 | + layer_lengths = [float(tok) for tok in tokens[6:]] |
| 145 | + for i, length in enumerate(layer_lengths): |
| 146 | + if length > 0: |
| 147 | + active_layers.add(i) |
| 148 | + |
| 149 | + data[design][netName]["layer_lengths"] = layer_lengths |
| 150 | + data[design][netName]["routable_layer_lengths"] = [ |
| 151 | + length |
| 152 | + for i, length in enumerate(layer_lengths) |
| 153 | + # ignore non-routable layers |
| 154 | + if stack[i][1] |
| 155 | + ] |
| 156 | + data[design][netName]["wire_length"] = sum( |
| 157 | + length |
| 158 | + for i, length in enumerate(layer_lengths) |
| 159 | + # ignore non-routable layers |
| 160 | + if stack[i][1] |
| 161 | + ) |
| 162 | + data[design][netName]["grt_via_res"] = sum( |
| 163 | + (length * stack[i][2]) |
| 164 | + for i, length in enumerate(layer_lengths) |
| 165 | + if not stack[i][1] |
| 166 | + ) |
156 | 167 |
|
157 | 168 | ################################################################ |
158 | 169 |
|
159 | | -if args.plot_cap: |
| 170 | +if args.mode == "net" and args.plot_cap: |
160 | 171 | # Compare the GRT cap estimate vs. OpenRCX SPEF cap |
161 | 172 |
|
162 | 173 | diff_x = [] |
@@ -198,7 +209,7 @@ def makeDict(): |
198 | 209 |
|
199 | 210 | ################################################################ |
200 | 211 |
|
201 | | -if args.plot_res: |
| 212 | +if args.mode == "net" and args.plot_res: |
202 | 213 | # Compare the GRT res estimate vs. OpenRCX SPEF res |
203 | 214 |
|
204 | 215 | diff_x = [] |
@@ -241,96 +252,102 @@ def makeDict(): |
241 | 252 |
|
242 | 253 | ################################################################ |
243 | 254 |
|
244 | | -# Use linear regression to find updated layer resistances. |
245 | | - |
246 | | -x = [] |
247 | | -y = [] |
248 | | -for design in data: |
249 | | - for net in data[design]: |
250 | | - rcx_res = data[design][net]["rcx_res"] |
251 | | - if rcx_res > 0: |
252 | | - x.append(data[design][net]["routable_layer_lengths"]) |
253 | | - y.append(rcx_res - data[design][net]["grt_via_res"]) |
254 | | - |
255 | | -x = np.array(x) |
256 | | -y = np.array(y) |
257 | | - |
258 | | -res_model = LinearRegression(fit_intercept=False).fit(x, y) |
259 | | -r_sq = res_model.score(x, y) |
260 | | -print("# Resistance coefficient of determination: {:.4f}".format(r_sq)) |
261 | | - |
262 | | -################################################################ |
263 | | - |
264 | | -# Use linear regression to find updated layer capacitances. |
265 | | - |
266 | | -x = [] |
267 | | -y = [] |
268 | | -for design in data: |
269 | | - for net in data[design]: |
270 | | - x.append(data[design][net]["routable_layer_lengths"]) |
271 | | - y.append(data[design][net]["rcx_cap"]) |
272 | | - |
273 | | -x = np.array(x) |
274 | | -y = np.array(y) |
275 | | - |
276 | | -cap_model = LinearRegression(fit_intercept=False).fit(x, y) |
277 | | -r_sq = cap_model.score(x, y) |
278 | | -print("# Capacitance coefficient of determination: {:.4f}".format(r_sq)) |
279 | | -print("# Updated layer resistance {}/um capacitance {}/um".format(res_unit, cap_unit)) |
280 | | - |
281 | | -routable_layers = [layer for layer in stack if layer[1]] |
282 | | -for i, layer in enumerate(routable_layers): |
283 | | - res_coeff = res_model.coef_[i] |
284 | | - cap_coeff = cap_model.coef_[i] |
285 | | - if res_coeff != 0.0 or cap_coeff != 0.0: |
286 | | - print( |
287 | | - "set_layer_rc -layer {} -resistance {:.5E} -capacitance {:.5E}".format( |
288 | | - layer[0], res_coeff / res_scale, cap_coeff / cap_scale |
289 | | - ) |
290 | | - ) |
291 | | - |
292 | | -################################################################ |
293 | | - |
| 255 | +if args.mode == "net": |
| 256 | + # Use linear regression to find updated layer resistances. |
294 | 257 |
|
295 | | -def generic_rc_fit(type_sieve): |
296 | 258 | x = [] |
297 | 259 | y = [] |
298 | 260 | for design in data: |
299 | 261 | for net in data[design]: |
300 | | - net_type = data[design][net]["type"] |
301 | | - wire_res = data[design][net]["rcx_res"] |
302 | | - wire_length = data[design][net]["wire_length"] |
303 | | - if net_type in type_sieve and wire_res != 0.0: |
304 | | - x.append([wire_length]) |
305 | | - y.append(wire_res) |
| 262 | + rcx_res = data[design][net]["rcx_res"] |
| 263 | + if rcx_res > 0: |
| 264 | + x.append(data[design][net]["routable_layer_lengths"]) |
| 265 | + y.append(rcx_res - data[design][net]["grt_via_res"]) |
| 266 | + |
306 | 267 | x = np.array(x) |
307 | 268 | y = np.array(y) |
308 | | - wire_res_model = LinearRegression(fit_intercept=False).fit(x, y) |
309 | | - wire_res = wire_res_model.coef_[0] |
| 269 | + |
| 270 | + res_model = LinearRegression(fit_intercept=False).fit(x, y) |
| 271 | + r_sq = res_model.score(x, y) |
| 272 | + print("# Resistance coefficient of determination: {:.4f}".format(r_sq)) |
| 273 | + |
| 274 | + ################################################################ |
| 275 | + |
| 276 | + # Use linear regression to find updated layer capacitances. |
310 | 277 |
|
311 | 278 | x = [] |
312 | 279 | y = [] |
313 | 280 | for design in data: |
314 | 281 | for net in data[design]: |
315 | | - net_type = data[design][net]["type"] |
316 | | - if net_type in type_sieve: |
317 | | - wire_length = data[design][net]["wire_length"] |
318 | | - wire_cap = data[design][net]["rcx_cap"] |
319 | | - x.append([wire_length]) |
320 | | - y.append(wire_cap) |
| 282 | + x.append(data[design][net]["routable_layer_lengths"]) |
| 283 | + y.append(data[design][net]["rcx_cap"]) |
| 284 | + |
321 | 285 | x = np.array(x) |
322 | 286 | y = np.array(y) |
323 | | - wire_cap_model = LinearRegression(fit_intercept=False).fit(x, y) |
324 | | - wire_cap = wire_cap_model.coef_[0] |
325 | 287 |
|
326 | | - return "-resistance {:.5E} -capacitance {:.5E}".format( |
327 | | - wire_res / res_scale, wire_cap / cap_scale |
| 288 | + cap_model = LinearRegression(fit_intercept=False).fit(x, y) |
| 289 | + r_sq = cap_model.score(x, y) |
| 290 | + print("# Capacitance coefficient of determination: {:.4f}".format(r_sq)) |
| 291 | + print( |
| 292 | + "# Updated layer resistance {}/um capacitance {}/um".format(res_unit, cap_unit) |
328 | 293 | ) |
329 | 294 |
|
| 295 | + routable_layers = [layer for layer in stack if layer[1]] |
| 296 | + for i, layer in enumerate(routable_layers): |
| 297 | + res_coeff = res_model.coef_[i] |
| 298 | + cap_coeff = cap_model.coef_[i] |
| 299 | + if res_coeff != 0.0 or cap_coeff != 0.0: |
| 300 | + print( |
| 301 | + "set_layer_rc -layer {} -resistance {:.5E} -capacitance {:.5E}".format( |
| 302 | + layer[0], res_coeff / res_scale, cap_coeff / cap_scale |
| 303 | + ) |
| 304 | + ) |
| 305 | + |
| 306 | + ################################################################ |
| 307 | + |
| 308 | + def generic_rc_fit(type_sieve): |
| 309 | + x = [] |
| 310 | + y = [] |
| 311 | + for design in data: |
| 312 | + for net in data[design]: |
| 313 | + net_type = data[design][net]["type"] |
| 314 | + wire_res = data[design][net]["rcx_res"] |
| 315 | + wire_length = data[design][net]["wire_length"] |
| 316 | + if net_type in type_sieve and wire_res != 0.0: |
| 317 | + x.append([wire_length]) |
| 318 | + y.append(wire_res) |
| 319 | + x = np.array(x) |
| 320 | + y = np.array(y) |
| 321 | + wire_res_model = LinearRegression(fit_intercept=False).fit(x, y) |
| 322 | + wire_res = wire_res_model.coef_[0] |
| 323 | + |
| 324 | + x = [] |
| 325 | + y = [] |
| 326 | + for design in data: |
| 327 | + for net in data[design]: |
| 328 | + net_type = data[design][net]["type"] |
| 329 | + if net_type in type_sieve: |
| 330 | + wire_length = data[design][net]["wire_length"] |
| 331 | + wire_cap = data[design][net]["rcx_cap"] |
| 332 | + x.append([wire_length]) |
| 333 | + y.append(wire_cap) |
| 334 | + x = np.array(x) |
| 335 | + y = np.array(y) |
| 336 | + wire_cap_model = LinearRegression(fit_intercept=False).fit(x, y) |
| 337 | + wire_cap = wire_cap_model.coef_[0] |
| 338 | + |
| 339 | + return "-resistance {:.5E} -capacitance {:.5E}".format( |
| 340 | + wire_res / res_scale, wire_cap / cap_scale |
| 341 | + ) |
| 342 | + |
| 343 | + print("# Combined fit:") |
| 344 | + print("set_wire_rc " + generic_rc_fit(["signal", "clock"])) |
330 | 345 |
|
331 | | -print("# Combined fit:") |
332 | | -print("set_wire_rc " + generic_rc_fit(["signal", "clock"])) |
| 346 | + print("# Split signal/clock fit:") |
| 347 | + print("set_wire_rc -signal " + generic_rc_fit(["signal"])) |
| 348 | + print("set_wire_rc -clock " + generic_rc_fit(["clock"])) |
| 349 | + |
| 350 | +################################################################ |
333 | 351 |
|
334 | | -print("# Split signal/clock fit:") |
335 | | -print("set_wire_rc -signal " + generic_rc_fit(["signal"])) |
336 | | -print("set_wire_rc -clock " + generic_rc_fit(["clock"])) |
| 352 | +if args.mode == "segment": |
| 353 | + pass |
0 commit comments