Skip to content

odb: fix wire decoding when the target shape is connected to a colinear junction#9765

Merged
maliberty merged 1 commit intoThe-OpenROAD-Project:masterfrom
AcKoucher:odb-fix-wire-colinear-decoding
Mar 19, 2026
Merged

odb: fix wire decoding when the target shape is connected to a colinear junction#9765
maliberty merged 1 commit intoThe-OpenROAD-Project:masterfrom
AcKoucher:odb-fix-wire-colinear-decoding

Conversation

@AcKoucher
Copy link
Contributor

@AcKoucher AcKoucher commented Mar 14, 2026

Related to #3969.

Context

While using the new segment regression from #3989 to generate new set_layer_rc values for asap7, I stumbled into a behavior in which, only on M2, the regression coefficient of determination was very poor for resistance.

This didn't seem to make any sense, because, based on the fact that the RCX extraction model computes resistance as

R = sheet_resistance * length / width

And for minimum-width segments width is constant and we'd have:

R = (sheet_resistance / width) * length = reg_coef * length

The result is literally a linear relation, so we should have R² == 1 - which we do for all the other layers.

After some debugging I realized that in the generated RC .csv there was a couple of very large segments (literally the size of the entire core width) of a certain net with a much lower per-length resistance than the rest of the segments. After using the GUI to take a look at the net it became clear that the segments' shapes were being wrongly computed as it was a net with relatively short segments.

Example of a net (signal) with segments being wrongly computed by odb::Wire::getShape on asap7/ibex, A and B are the problematic segments:
image

Segment Shape (wrong coord. in bold)
image (58896, 63324) (118242, 63342)
image (-792, 65718) (61506, 65736)

As we can see the point is wrongly computed for the colinear junctions of these segments (right junction in the first one, left junction on the second one).

Problem

  1. Colinear junctions are not correctly handled by the decoder state machine in dbWire::getSegment. The decoder currently treats the junction as if it were non colinear and retrieves the extension value from the wrong data_ index. The extension value for a kColinear junction is stored in its own index (data_[idx]):
Entry Opcode Data
0 kJunction jct_id
1 kColinear | WOP_EXTENSION extension ← read from data_[idx]
2 kX x_coord

Currently, the decoder is reading the extension value from data_[idx+1] and giving the wrong extension value to the function that actually computes the geometry, resulting in wrong final geometry.

Changes

When decoding and stumbling into a kColinear junction, retrieve the extension value correctly.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request correctly fixes a bug in the wire decoding logic for kColinear junctions with extensions. The change ensures the extension value is read from the correct index. A new test case has been added to cover this specific scenario, which is great. My review focuses on a maintainability improvement: the fix introduces duplicated code in two overloads of the getSegment function. I've suggested refactoring this duplicated logic to improve code quality, aligning with the principle of encapsulating logic in helper functions to avoid duplication.

Comment on lines +559 to +560
const WireOp wire_op = static_cast<WireOp>(opcode & WOP_OPCODE_MASK);
cur_ext = wire_op == kColinear ? wire->data_[idx] : wire->data_[idx + 1];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This logic is duplicated in the getSegment overload at lines 790-791. To improve maintainability and avoid code duplication, consider extracting this logic into a static helper function. This aligns with the principle of encapsulating logic in helper functions to avoid duplication.

For example:

static int getCurExt(const _dbWire* wire, unsigned char opcode, int idx)
{
  const WireOp wire_op = static_cast<WireOp>(opcode & WOP_OPCODE_MASK);
  return wire_op == kColinear ? wire->data_[idx] : wire->data_[idx + 1];
}

This would allow you to call cur_ext = getCurExt(wire, opcode, idx); in both locations.

As a smaller change, this logic can be condensed into a single line.

      cur_ext = (static_cast<WireOp>(opcode & WOP_OPCODE_MASK) == kColinear) ? wire->data_[idx] : wire->data_[idx + 1];
References
  1. Encapsulate the logic for calculating master symmetry in a helper function to avoid code duplication.

Copy link
Contributor Author

@AcKoucher AcKoucher Mar 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that conceptually it would be better to refactor the entire state machine as there are two large blocks of code for it. That said, it would make the review rather painful if included in this PR.

@github-actions
Copy link
Contributor

clang-tidy review says "All clean, LGTM! 👍"

@AcKoucher AcKoucher requested a review from maliberty March 14, 2026 19:43
@maliberty
Copy link
Member

Please share an example net that shows the issue. Its is very messy, old code but also quite important.

@AcKoucher
Copy link
Contributor Author

Please share an example net that shows the issue. Its is very messy, old code but also quite important.

I added images to the description.

@AcKoucher AcKoucher changed the title odb: fix wire decoding for the subsequent segment of a kColinear junction with extensions odb: fix wire decoding when the target shape is connected to a kColinear junction Mar 18, 2026
@AcKoucher AcKoucher force-pushed the odb-fix-wire-colinear-decoding branch from 7ab00e5 to 3461544 Compare March 18, 2026 17:52
…ar junction

Signed-off-by: Arthur Koucher <arthurkoucher@precisioninno.com>
@AcKoucher AcKoucher force-pushed the odb-fix-wire-colinear-decoding branch from 3461544 to dd10742 Compare March 18, 2026 17:54
@AcKoucher AcKoucher changed the title odb: fix wire decoding when the target shape is connected to a kColinear junction odb: fix wire decoding when the target shape is connected to a colinear junction Mar 18, 2026
@AcKoucher
Copy link
Contributor Author

@maliberty I rebased to improve the commit message and fix the bazel.lock check failure that was happening.

This should be good to go.

@github-actions
Copy link
Contributor

clang-tidy review says "All clean, LGTM! 👍"

1 similar comment
@github-actions
Copy link
Contributor

clang-tidy review says "All clean, LGTM! 👍"

@maliberty
Copy link
Member

To really review this I would have to first fully grok the wire encoder and the representation it builds. I'm not prepared to spend the time on that now so I'll go with the empirical result.

@maliberty maliberty merged commit f7d3104 into The-OpenROAD-Project:master Mar 19, 2026
15 checks passed
@AcKoucher AcKoucher deleted the odb-fix-wire-colinear-decoding branch March 20, 2026 00:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants