dbSta: escape brackets in scalar net/port names (not bus selects)#10760
dbSta: escape brackets in scalar net/port names (not bus selects)#10760oharboe wants to merge 1 commit into
Conversation
write_verilog emits bus-select syntax (foo[7]) for any net/port whose name parses as a clean, unescaped bus member. That is correct when foo is a declared bus, but wrong for a single-bit "escaped-scalar" signal declared as `input \foo[7] ;` with no bus declaration: the port dcl escapes the brackets (portVerilogName) while the net reference renders them as a bus select (netVerilogName), so Verilator sees a bit-select on an undeclared 1-bit signal and errors with "Illegal bit or array select; type does not have a bit range". Such per-bit escaped-scalar boundary signals are produced by partition synthesis and by repair_design buffer insertion across module boundaries. Per the upstream discussion (jjcherry56 on parallaxsw/OpenSTA#453: "The problem is in the upstream name. foo[7] should be foo\[7\] if it is not doing a bus select."), fix the name dbNetwork hands to STA rather than the writer. dbNetwork::name() now escapes the brackets of a clean bus-member name when, in the owning module, a per-bit module boundary terminal (dbModBTerm) of that exact name exists but the bus prefix has no bus-aggregate dbModBTerm. Genuine bus members are left untouched: sub-module bus bits carry a sibling bus aggregate, and top-level bus bits have no per-bit dbModBTerm at all, so neither is escaped. This is the bracket analogue of the recent escaped-slash fix in dbNetwork::name(Port*)/stripParentPrefix. Add a dbsta_unittest regression (TestDbSta.EscapeScalarBracketName) covering scalar port and net escaping and the genuine-bus-member negative cases. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
|
@jjcherry56 FYI - if this doesn't do it, then I'll see about creating a confidential issue for @maliberty |
There was a problem hiding this comment.
Code Review
This pull request introduces escapeBracketsIfScalar in dbNetwork to escape brackets in scalar signal names (e.g., foo[7] to foo\[7\]) when they do not belong to a declared bus, preventing incorrect bus select outputs in write_verilog. A regression test was also added to verify this behavior. The feedback suggests optimizing this new function with a fast-path check using std::string::find to avoid unnecessary overhead for names without brackets.
| if (scope == nullptr) { | ||
| return name; | ||
| } | ||
| bool is_bus = false; |
There was a problem hiding this comment.
Since escapeBracketsIfScalar is called on every port and net name lookup when modbterm or modnet is present, we can optimize the common case where names do not contain brackets. Adding a fast-path check using std::string::find avoids the overhead of calling parseBusName and allocating std::string bus_name for non-bus names.
if (scope == nullptr) {
return name;
}
if (name.find('[') == std::string::npos) {
return name;
}
bool is_bus = false;
Problem
write_verilogemits bus-select syntax (foo[7]) for any net/port whose name parses as a clean, unescaped bus member. That is correct whenfoois a declared bus (input [hi:lo] foo;/wire [hi:lo] foo;), but wrong for a single-bit escaped-scalar signal declared asinput \foo[7] ;with no bus declaration.The two name renderers disagree on such a name:
portVerilogNameescapes the brackets → the port dcl isinput \foo[7] ;netVerilogNametreats them as a bus subscript → the reference isfoo[7]Verilator then implicitly declares a 1-bit
logic fooand rejects the bit-select:These per-bit escaped-scalar boundary signals arise from partition synthesis and from
repair_designbuffer insertion across module boundaries.Fix
Following the upstream guidance on parallaxsw/OpenSTA#453 — "The problem is in the upstream name. foo[7] should be foo\[7\] if it is not doing a bus select." — this fixes the name
dbNetworkhands to STA rather than patching the writer.dbNetwork::name(const Port*)/name(const Net*)now escape the brackets of a clean bus-member name only when, in the owning module:dbModBTerm) of that exact name exists (positive evidence it is a scalar port, not a pure bus select), anddbModBTerm(isBusPort()).Genuine bus members are left untouched: sub-module bus bits carry a sibling bus aggregate, and top-level bus bits have no per-bit
dbModBTermat all, so neither path escapes them. This is the bracket analogue of the recent escaped-slash fix indbNetwork::name(Port*)/stripParentPrefix(hier_escape_port).This supersedes the write-side workaround proposed in parallaxsw/OpenSTA#453.
Testing
dbsta_unittestregressionTestDbSta.EscapeScalarBracketName: covers scalar port escaping, scalar-net escaping (net sharing a name with a scalar boundary port), and the genuine bus-member negative cases (member port and member net stay unescaped). Confirmed to fail without the fix and pass with it.//src/dbSta/test:all(74 tests) and//src/rsz/test:all(254 tests) pass — including the hierarchical write-verilog goldens (hierwrite,hier3,hierclock) that exercise real top-level and sub-module buses.🤖 Generated with Claude Code