gpl/mbff: preserve hierarchy in cluster_flops#10338
gpl/mbff: preserve hierarchy in cluster_flops#10338openroad-ci wants to merge 5 commits intoThe-OpenROAD-Project:masterfrom
Conversation
Signed-off-by: dsengupta0628 <dsengupta@precisioninno.com>
Signed-off-by: dsengupta0628 <dsengupta@precisioninno.com>
Signed-off-by: dsengupta0628 <dsengupta@precisioninno.com>
|
clang-tidy review says "All clean, LGTM! 👍" |
1 similar comment
|
clang-tidy review says "All clean, LGTM! 👍" |
There was a problem hiding this comment.
Code Review
This pull request introduces hierarchical awareness to Multi-Bit Flip-Flop (MBFF) clustering, ensuring that flops are only grouped within their respective hierarchical modules. This is achieved by partitioning flops based on both their parent module and mask, and ensuring new trays are created within the correct module context. A new regression test, mbff_hier, has been added to verify this behavior. Review feedback suggests using module IDs instead of pointers as map keys to avoid non-deterministic iteration order and ensure bit-level reproducibility.
| ArrayMaskVector<Flop> flops_by_mask; | ||
| // Partition by (parent module, mask) so flops in different | ||
| // hierarchical modules are never clustered into the same tray. | ||
| std::map<std::pair<dbModule*, Mask>, std::vector<Flop>> flops_by_mod_mask; |
There was a problem hiding this comment.
Using dbModule* as part of a std::map key can lead to non-deterministic behavior across different runs because the iteration order depends on memory addresses. To ensure bit-level reproducibility, consider using a deterministic key such as dbModule::getId() or providing a custom comparator (e.g., std::lessodb::dbModule*) as iteration over a std::map with pointer keys is deterministic if a custom comparator is defined for the pointer type.
std::map<std::pair<uint, Mask>, std::vector<Flop>> flops_by_mod_mask;References
- Iteration over a std::map with pointer keys is deterministic if a custom comparator is defined for the pointer type.
| flops_by_mod_mask[{insts_[idx]->getModule(), vec_mask}].push_back( | ||
| flops_[idx]); |
There was a problem hiding this comment.
If the map key is changed to use the module ID for determinism, update the insertion logic accordingly. Note that you may also need to store the dbModule* pointer if it's required for later use (e.g., in the debug print), or look it up via the ID.
flops_by_mod_mask[{insts_[idx]->getModule()->getId(), vec_mask}].push_back(
flops_[idx]);|
@codex review |
|
Codex Review: Didn't find any major issues. Bravo. ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
| read_lib ./4BitTrayH4/asap7sc7p5t_DFFHQNV4X_LVT_TT_nldm_FAKE.lib | ||
|
|
||
| read_verilog ./mbff_hier.v | ||
| link_design mbff_hier |
There was a problem hiding this comment.
This is a flat flow. link_design -hier mbff_hier should be used to enable the hierarchical flow.
There was a problem hiding this comment.
Actually even with -hier I don't see crash. Same wrong-hierarchy output (tray in top, submods empty). Bug is silent corruption, not segfault.
There was a problem hiding this comment.
Do you have a testcase to show the crash by the way?
There was a problem hiding this comment.
This is the first issue reported.
https://github.com/The-OpenROAD-Project-private/OpenROAD-flow-scripts/issues/1628
There was a problem hiding this comment.
I created this issue that doesn't crash but doesn't give correct results either: #10339
|
An important part is missing. There is no The following logic should be added.
|
| ===== AFTER cluster_flops ===== | ||
| mbff_hier: 0 inst(s): | ||
| sub_a: 1 inst(s): _tray_size2_7 | ||
| sub_b: 1 inst(s): _tray_size2_6 |
There was a problem hiding this comment.
This is just a suggestion.
When hier flow is enabled, ff_a1_ff_a2 looks better than _tray_size2_7.
In flat flow, such name concatenation is not easy because the FF hierarchies are different and it will produce too long MBFF name.
But in hier flow, the MBFF name will not be very long.
Signed-off-by: dsengupta0628 <dsengupta@precisioninno.com>
|
This seems like rather negative regression. Is there a way to support merging flops in different modules? It feels like that would in general yield better PPA |
|
I guess in general the downside would be we would have to port punch a lot unless there's some way I'm not thinking about. module top_level (
input wire clk
);
// Wires connecting the sub-modules to the shared flop
wire [3:0] mod_a_d, mod_a_q;
wire [3:0] mod_b_d, mod_b_q;
// Instantiate Module A
module_a inst_a (
.clk(clk),
.data_out(mod_a_d), // Goes to D-pin of the shared flop
.data_in(mod_a_q) // Comes from Q-pin of the shared flop
);
// Instantiate Module B
module_b inst_b (
.clk(clk),
.data_out(mod_b_d),
.data_in(mod_b_q)
);
// Instantiate the shared 8-bit flip-flop
// Using concatenation {b, a} to merge the two 4-bit inputs
flop_8bit shared_ff_inst (
.clk(clk),
.d({mod_b_d, mod_a_d}),
.q({mod_b_q, mod_a_q})
);
endmodule |
|
clang-tidy review says "All clean, LGTM! 👍" |
Yes this does reduce banking ratio compared to flat leaving some QoR on the table as we are only clustering in current hierarchy in this change. However, currently the MBFF clustering is wrong in hier designs (I was told crash- can't reproduce, I see wrong results though), so I put this as an interim fix before a more elaborate change is applied that would collapse hierarchy, do clustering and then rebuild hierarchy. That will take some more thinking. |
|
If the massive port punching is ok, it is doable.
There can be a hybrid approach. Preserving hierarchies up to a certain level and flattens deep hierarchies. But current OpenROAD does not support this yet. |
|
Ah, operator swap could be the reason of preserving messy hierarchy because ALU swap cannot be done on flat netlist. |
Summary
Problem
cluster_flopsdestroyed module hierarchy. Original flip-flops liveinside hierarchical sub-modules (
dbModule), but MBFF created the newtray instance directly on the top
dbBlockand destroyed the originals.After clustering, sub-modules became empty shells and trays sat at the
top, breaking
write_verilog, hierarchical reports, scan stitching,power-domain assignment, and any downstream consumer that relies on
module ownership.
Root cause:
dbInst::create(block_, master, name)inMBFF::ModifyPinConnectionsignored the parentdbModule. Compoundingthis,
MBFF::SeparateFlopspartitioned candidate flops only by clocknet and
Mask, so flops from different modules could be merged into asingle tray with no valid home module.
Fix
Two surgical changes in
src/gpl/src/mbff.cpp:SeparateFlops: partition by(dbModule*, Mask)instead ofMaskalone. Flops in different modules can no longer share a tray.
ModifyPinConnections: pass the cluster's parent module to thedbInst::create(block, master, name, physical_only, parent_module)overload, so the new tray lands in the same module as the flops it
replaces. Same pattern already used by
cts/src/TritonCTS.cpp.Maskitself is untouched, so library-cell tables keyed byMask(
best_master_,pin_mappings_,slot_to_tray_x_, etc.) areunaffected.
Behavior
mbff_orig_nameregressionunchanged).
Cross-module clustering is no longer attempted; this is a small QoR
trade for correctness. If a future
-flatten_hierarchyflag isdesired, it can be added on top of this partitioning.
Test
New regression
src/gpl/test/mbff_hier.{v,tcl,ok}registered inCMakeLists.txtandBUILD:sub_a,sub_b).cluster_flopsand prints per-module instance counts beforeand after.
Pre-fix output:
AFTER: top={_tray_size4_7} sub_a={} sub_b={}
Post-fix golden:
AFTER: top={} sub_a={_tray_size2_X} sub_b={_tray_size2_Y}
Type of Change
Impact
Fix hier design' cluster flops
Verification
./etc/Build.sh).Related Issues
https://github.com/The-OpenROAD-Project-private/OpenROAD/issues/3392