Add column mux ratio for ratio = 1, 2, 4#10016
Add column mux ratio for ratio = 1, 2, 4#10016tnguy19 wants to merge 9 commits intoThe-OpenROAD-Project:masterfrom
Conversation
Signed-off-by: Thinh Nguyen <nguyenthinh19011@gmail.com>
Signed-off-by: Thinh Nguyen <nguyenthinh19011@gmail.com>
Signed-off-by: Thinh Nguyen <nguyenthinh19011@gmail.com>
Signed-off-by: Thinh Nguyen <nguyenthinh19011@gmail.com>
…OI22 Signed-off-by: Thinh Nguyen <nguyenthinh19011@gmail.com>
There was a problem hiding this comment.
Code Review
This pull request introduces support for column muxing (ratios 1, 2, and 4) in the RAM generator, involving updates to layout grid calculations and the addition of AOI22-based multiplexing logic. Feedback identifies a potential out-of-bounds access when the number of rows is less than 2 and suggests moving local lambdas to a namespace-level scope. Additionally, the reviewer recommended improving the robustness of the port extraction logic and replacing hardcoded magic numbers with named constants for better maintainability.
|
|
||
| int num_inputs = std::ceil(std::log2(num_words)); | ||
| // compute information to support col/mux ratio feature | ||
| int num_rows = num_words / column_mux_ratio; |
There was a problem hiding this comment.
The current implementation does not support cases where num_rows (calculated as num_words / column_mux_ratio) is less than 2. For example, if num_words=4 and column_mux_ratio=4, num_rows will be 1, which leads to an out-of-bounds access in addr_inputs_ at line 1136 (addr_inputs_[num_word_bits]) because num_word_bits will equal num_inputs. Please add a check to ensure num_rows >= 2.
| int num_rows = num_words / column_mux_ratio; | |
| int num_rows = num_words / column_mux_ratio; | |
| if (num_rows < 2) { | |
| logger_->error(RAM, | |
| 35, | |
| "The ram generator currently requires at least 2 rows " | |
| "(num_words / column_mux_ratio >= 2)."); | |
| } |
References
- Calls to logger_->error are expected to terminate the program, so additional error handling like returning an error code or throwing an exception is not necessary.
There was a problem hiding this comment.
Fine to include this suggestion (but can remove the word "currently" - there is no reason to support a single-row RAM)
| auto isNotPort = [](const sta::FuncExpr* e) { | ||
| return e && e->op() == sta::FuncExpr::Op::not_ && e->left() | ||
| && e->left()->op() == sta::FuncExpr::Op::port; | ||
| }; | ||
| auto isAndOfNots = [&isNotPort](const sta::FuncExpr* e) { | ||
| return e && e->op() == sta::FuncExpr::Op::and_ && isNotPort(e->left()) | ||
| && isNotPort(e->right()); | ||
| }; |
There was a problem hiding this comment.
According to the general rules, helper logic should be defined as a free function in a namespace rather than as a local lambda within a function. These lambdas (isNotPort and isAndOfNots) should be moved to a namespace-level scope.
References
- Helper logic should be defined as a free function in a namespace rather than as a local lambda within a function.
| if (f->op() == sta::FuncExpr::Op::not_) { | ||
| // Compact form: not_(or_(and_(A1,A2), and_(B1,B2))) | ||
| auto or_expr = f->left(); | ||
| auto and_a = or_expr->left(); | ||
| auto and_b = or_expr->right(); | ||
| aoi22_in_a1_ = and_a->left()->port()->name(); | ||
| aoi22_in_a2_ = and_a->right()->port()->name(); | ||
| aoi22_in_b1_ = and_b->left()->port()->name(); | ||
| aoi22_in_b2_ = and_b->right()->port()->name(); | ||
| } else { | ||
| // SOP expanded form used by sky130hd: | ||
| // or_(or_(or_(and_(not_(A1),not_(B1)), and_(not_(A1),not_(B2))), | ||
| // and_(not_(A2),not_(B1))), | ||
| // and_(not_(A2),not_(B2))) | ||
| // Port names are inside not_() wrappers, requiring an extra | ||
| // ->left() to reach the actual port compared to the compact form. | ||
| // e.g. and_(not_(A1), not_(B1))->left()->left()->port() gives A1 | ||
| // NOTE: this branch is PDK-specific to sky130hd's liberty | ||
| // representation. If adding support for other PDKs, verify their | ||
| // AOI22 function expression form and extend this extraction | ||
| // accordingly. | ||
| auto t1 = f->left()->left()->left(); | ||
| auto t2 = f->left()->left()->right(); | ||
| auto t3 = f->left()->right(); | ||
| aoi22_in_a1_ = t1->left()->left()->port()->name(); | ||
| aoi22_in_a2_ = t3->left()->left()->port()->name(); | ||
| aoi22_in_b1_ = t1->right()->left()->port()->name(); | ||
| aoi22_in_b2_ = t2->right()->left()->port()->name(); | ||
| } |
There was a problem hiding this comment.
The logic for extracting port names from the AOI22 function expression is brittle as it relies on a specific nesting structure of the sta::FuncExpr tree (especially for the SOP expanded form). If a library represents the AOI22 function differently, this extraction will fail or produce incorrect results. Consider implementing a more robust matching algorithm or providing a way to specify these port names via configuration if the automatic detection fails.
| "inv", | ||
| inv_cell_, | ||
| {{"A", aoi_out}, {"Y", q_outputs_[0][global_bit]->getNet()}}); | ||
| ram_grid_.addCell(std::move(mux_cell), base_col + 1); |
There was a problem hiding this comment.
The column offsets used for cell placement (e.g., base_col + 1, base_col + 2, base_col + 3) are hardcoded magic numbers. Following the general rules, these should be defined as named constants to improve code clarity and maintainability.
References
- Define tunable parameters as named constants instead of using hardcoded magic numbers.
| && isNotPort(e->right()); | ||
| }; | ||
| aoi22_cell_ = findMaster( | ||
| [&isNotPort, &isAndOfNots](sta::LibertyPort* port) { |
There was a problem hiding this comment.
warning: lambda capture 'isNotPort' is not used [clang-diagnostic-unused-lambda-capture]
| [&isNotPort, &isAndOfNots](sta::LibertyPort* port) { | |
| [ &isAndOfNots](sta::LibertyPort* port) { |
Signed-off-by: Thinh Nguyen <nguyenthinh19011@gmail.com>
1. Add -column_mux_ratio flag to generate_ram and generate_ram_netlist (default=1)
2. Mux created from inline AOI22 mux placement for ratio=2 (single AOI22+INV per bit) and ratio=4 (2-stage AOI22 tree)
3. Fix addr BTerm naming: addr[i] -> addr_rw[i]
4. Fix makeSlice prefix to include word_idx: storage_{row}_{word}_{bit}
5. Use num_rows for column generation instead of num_words
6. Update make_8x8.ok with new naming convention for cells
7. Add make_8x8_mux2.ok for test with col_mux_ratio=2
Signed-off-by: Thinh Nguyen <nguyenthinh19011@gmail.com>
Summary
Add
-column_mux_ratioparameter togenerate_ramandgenerate_ram_netlistwith default value = 1.The column_mux_ratio value indicate the number of words that will share the same physical row, and currently this implementation will work correctly for values = 1, 2, and 4*.
Muxes are implemented using AOI22s for ratio =2 (one AOI22+inverter) and ratio =4 (2 stage-1 AOI22s feeding a stage-2 AOI22).
Some changes to the code to accommodate this feature additions are also added.
*Mux_ratio=4 currently have correct functionality but faces congestion issue during cell placement
Type of Change
Impact
generate_ramandgenerate_ram_netlistcan be use with option-column_mux_ratiowith default value = 1. Scripts that do not havecolumn_mux_ratioare not affectednum_wordstonum_rowsto indicate the number of physical row that will be created. Forcolumn_mux_ratio>1,num_rows = num_words / column_mux_ratiophysical rows are generated. Column mux are placed in the buffer rowstorage_{row}_{bit}tostorage_{row}_{word}_{bit}to reflect the placement of multiple words in one row whencolumn_mux_ratio> 1Verification
./etc/Build.sh).Related Issues
N/A
@rovinski
NOTE: PR is reopened in #10018