Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
7e3d07d
mpl: notches display for mpl_debug
joaomai Dec 21, 2025
7d60fa8
mpl: consider fixed macros during notch penalty calculation
joaomai Dec 21, 2025
4764698
mpl: grid quantization and channels for notch penalty
joaomai Dec 21, 2025
47aede1
mpl: notch merging
joaomai Dec 22, 2025
13275b6
mpl: minor adjustments
joaomai Dec 23, 2025
3d18105
mpl: adjust graphics and notch openness consideration
joaomai Dec 24, 2025
93d2b8d
mpl: disallow expansion that changes the open direction
joaomai Dec 24, 2025
135cd5e
mpl: small refactor and formatting
joaomai Jan 18, 2026
1bdae97
formatting
joaomai Jan 18, 2026
407f91a
mpl: adjust calSegmentIndex function
joaomai Jan 18, 2026
a46e9a6
mpl: refactor calNotchPenalty
joaomai Jan 21, 2026
b735830
mpl: notches bugfixes
joaomai Jan 21, 2026
3cb7632
mpl: remove unecessary conversion to micron
joaomai Jan 21, 2026
e98234c
Merge branch 'master' into mpl-improve-notches
joaomai Jan 21, 2026
6868275
mpl: remove leftover comment
joaomai Jan 22, 2026
47c2f9a
Merge branch 'master' into mpl-improve-notches
joaomai Jan 22, 2026
5086c09
bazel: update mock_array MPL params
joaomai Jan 23, 2026
3912863
mpl: update tests
joaomai Jan 23, 2026
c5bcb53
Merge branch 'master' into mpl-improve-notches
joaomai Jan 24, 2026
99f71e2
Merge branch 'master' into mpl-improve-notches
joaomai Jan 27, 2026
38bf6ed
mpl: mock-array workaround
joaomai Jan 28, 2026
0147564
Merge branch 'master' into mpl-improve-notches
joaomai Jan 28, 2026
bfe2c4e
Merge branch 'master' into mpl-improve-notches
joaomai Jan 28, 2026
2a11a3e
Merge branch 'master' into mpl-improve-notches
joaomai Jan 29, 2026
3cf07f2
mpl: rename variable for clarity
joaomai Jan 29, 2026
2e83e45
Merge branch 'master' into mpl-improve-notches
joaomai Jan 31, 2026
a13a488
Merge branch 'master' into mpl-improve-notches
joaomai Feb 1, 2026
cae5a35
Merge branch 'master' into mpl-improve-notches
joaomai Feb 2, 2026
cd6f980
mpl: change static_cast in cal notch to avoid integer overflow
joaomai Feb 2, 2026
fc73bb5
Merge branch 'master' into mpl-improve-notches
joaomai Feb 3, 2026
33cc3b1
mpl: update tests
joaomai Feb 4, 2026
60bd6e7
update tinyRocket metrics
joaomai Feb 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/mpl/src/MplObserver.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ class MplObserver
virtual void setOutline(const odb::Rect& outline) {}
virtual void setGuides(const std::map<int, odb::Rect>& guides) {}
virtual void setFences(const std::map<int, odb::Rect>& fences) {}
virtual void addNotch(const odb::Rect& notch) {}
virtual void clearNotches() {}
virtual void setIOConstraintsMap(
const ClusterToBoundaryRegionMap& io_cluster_to_constraint)
{
Expand Down
243 changes: 196 additions & 47 deletions src/mpl/src/SACoreSoftMacro.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -624,15 +624,124 @@ void SACoreSoftMacro::attemptMacroClusterAlignment()
}
}

float SACoreSoftMacro::calSingleNotchPenalty(float width, float height)
void SACoreSoftMacro::fillCoordsLists(std::vector<int>& x_coords,
std::vector<int>& y_coords)
{
return std::sqrt((width * height)
/ block_->dbuAreaToMicrons(outline_.area()));
std::vector<int> x_point;
std::vector<int> y_point;

for (auto& macro : macros_) {
if (macro.isStdCellCluster()) {
continue;
}
x_point.push_back(macro.getX());
x_point.push_back(macro.getX() + macro.getWidth());
y_point.push_back(macro.getY());
y_point.push_back(macro.getY() + macro.getHeight());
}
x_point.push_back(0);
y_point.push_back(0);
x_point.push_back(outline_.dx());
y_point.push_back(outline_.dy());

std::ranges::sort(x_point);
std::ranges::sort(y_point);

int epsilon = outline_.dx() / 100;
for (int i = 0; i < x_point.size(); i++) {
if (i + 1 < x_point.size()
&& std::abs(x_point[i + 1] - x_point[i]) <= epsilon) {
Comment on lines +652 to +653
Copy link
Member

Choose a reason for hiding this comment

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

This has the potential to skip too many points. Imagine a series of points all 0.9 epsilon apart. You would collapse them all. It would be better to set a threshold from an accepted point and skip all points within that threshold.

Changing this will require another secure CI so I suggest you do it in a follow up PR.

continue;
}
x_coords.push_back(x_point[i]);
}

epsilon = outline_.dy() / 100;
for (int i = 0; i < y_point.size(); i++) {
if (i + 1 < y_point.size()
&& std::abs(y_point[i + 1] - y_point[i]) <= epsilon) {
continue;
}
y_coords.push_back(y_point[i]);
}
}

SACoreSoftMacro::Neighbors SACoreSoftMacro::findNeighbors(
std::vector<std::vector<bool>>& grid,
int start_row,
int start_col,
int end_row,
int end_col)
Comment on lines +669 to +674
Copy link
Member

Choose a reason for hiding this comment

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

same: const + static

{
int num_y = grid.size();
int num_x = grid.front().size();

Neighbors neighbors;
if (start_row > 0) {
for (int i = start_col; i <= end_col; i++) {
if (!grid[start_row - 1][i]) {
neighbors.bottom = false;
break;
}
}
}
if (end_row < num_y - 1) {
for (int i = start_col; i <= end_col; i++) {
if (!grid[end_row + 1][i]) {
neighbors.top = false;
break;
}
}
}
if (start_col > 0) {
for (int i = start_row; i <= end_row; i++) {
if (!grid[i][start_col - 1]) {
neighbors.left = false;
break;
}
}
}
if (end_col < num_x - 1) {
for (int i = start_row; i <= end_row; i++) {
if (!grid[i][end_col + 1]) {
neighbors.right = false;
break;
}
}
}

return neighbors;
}

bool SACoreSoftMacro::isSegmentEmpty(std::vector<std::vector<bool>>& grid,
int start_row,
int start_col,
int end_row,
int end_col)
Comment on lines +716 to +720
Copy link
Member

Choose a reason for hiding this comment

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

All arguments should be const and the method itself can be static.

{
for (int i = start_row; i <= end_row; i++) {
for (int j = start_col; j <= end_col; j++) {
if (grid[i][j]) {
return false;
}
}
}

return true;
}

float SACoreSoftMacro::calSingleNotchPenalty(int width, int height)
{
return std::sqrt((static_cast<double>(width) * height) / outline_.area());
}

// If there is no HardMacroCluster, we do not consider the notch penalty
void SACoreSoftMacro::calNotchPenalty()
{
if (graphics_) {
graphics_->clearNotches();
}

if (notch_weight_ <= 0.0) {
return;
}
Expand All @@ -649,37 +758,28 @@ void SACoreSoftMacro::calNotchPenalty()
if (!isValid()) {
width = std::max(width_, outline_.dx());
height = std::max(height_, outline_.dy());
notch_penalty_ = calSingleNotchPenalty(block_->dbuToMicrons(width),
block_->dbuToMicrons(height));
notch_penalty_ = calSingleNotchPenalty(width, height);

if (graphics_) {
graphics_->setNotchPenalty({.name = "Notch",
.weight = notch_weight_,
.value = notch_penalty_,
.normalization_factor = norm_notch_penalty_});
}
return;
}

// Create grids based on location of MixedCluster and HardMacroCluster
std::set<int> x_point;
std::set<int> y_point;
for (auto& macro : macros_) {
if (!macro.isMacroCluster() && !macro.isMixedCluster()) {
continue;
}
x_point.insert(macro.getX());
x_point.insert(macro.getX() + macro.getWidth());
y_point.insert(macro.getY());
y_point.insert(macro.getY() + macro.getHeight());
}
x_point.insert(0);
y_point.insert(0);
x_point.insert(outline_.dx());
y_point.insert(outline_.dy());
std::vector<int> x_coords;
std::vector<int> y_coords;
fillCoordsLists(x_coords, y_coords);

std::vector<int> x_coords(x_point.begin(), x_point.end());
std::vector<int> y_coords(y_point.begin(), y_point.end());
int num_x = x_coords.size() - 1;
int num_y = y_coords.size() - 1;

// Assign cluster locations for notch detection
std::vector<std::vector<bool>> grid(num_y, std::vector<bool>(num_x, false));
for (auto& macro : macros_) {
if (!macro.isMacroCluster() && !macro.isMixedCluster()) {
if (macro.isStdCellCluster()) {
continue;
}
int x_start = getSegmentIndex(macro.getX(), x_coords);
Expand All @@ -693,34 +793,83 @@ void SACoreSoftMacro::calNotchPenalty()
}
}

// An empty grid cell surrounded by 3 or more edges is considered a notch
for (int row = 0; row < num_y; row++) {
for (int col = 0; col < num_x; col++) {
if (grid[row][col]) {
for (int start_row = 0; start_row < num_y; start_row++) {
for (int start_col = 0; start_col < num_x; start_col++) {
if (grid[start_row][start_col]) {
continue;
}

int surroundings = 0;
if (row == 0 || grid[row - 1][col]) {
surroundings++;
}
if (row == num_y - 1 || grid[row + 1][col]) {
surroundings++;
}
if (col == 0 || grid[row][col - 1]) {
surroundings++;
}
if (col == num_x - 1 || grid[row][col + 1]) {
surroundings++;
int end_row = start_row;
int end_col = start_col;

Neighbors current_neighbors
= findNeighbors(grid, start_row, start_col, end_row, end_col);
bool expand_rows = true;
bool expand_cols = true;

while (expand_rows || expand_cols) {
if (expand_rows) {
end_row += 1;
if (end_row < num_y
&& isSegmentEmpty(grid, start_row, start_col, end_row, end_col)) {
Neighbors expanded_neighbors
= findNeighbors(grid, start_row, start_col, end_row, end_col);
if (expanded_neighbors.total() > current_neighbors.total()
|| expanded_neighbors == current_neighbors) {
current_neighbors = expanded_neighbors;
} else {
expand_rows = false;
end_row -= 1;
}
} else {
expand_rows = false;
end_row -= 1;
}
}

if (expand_cols) {
end_col += 1;
if (end_col < num_x
&& isSegmentEmpty(grid, start_row, start_col, end_row, end_col)) {
Neighbors expanded_neighbors
= findNeighbors(grid, start_row, start_col, end_row, end_col);
if (expanded_neighbors.total() > current_neighbors.total()
|| expanded_neighbors == current_neighbors) {
current_neighbors = expanded_neighbors;
} else {
expand_cols = false;
end_col -= 1;
}
} else {
expand_cols = false;
end_col -= 1;
}
}
}

if (surroundings >= 3) {
width = x_coords[col + 1] - x_coords[col];
height = y_coords[row + 1] - y_coords[row];
width = x_coords[end_col + 1] - x_coords[start_col];
height = y_coords[end_row + 1] - y_coords[start_row];

bool is_notch = false;
if (current_neighbors.total() == 4) {
is_notch = true;
Comment on lines +854 to +855
Copy link
Member

Choose a reason for hiding this comment

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

Pathological but you could have neighbors on all sides of a region larger than notch_h/v_th_ in both directions (e.g. a ring of macros). Probably that shouldn't be a notch.

} else if (current_neighbors.top && current_neighbors.bottom) {
if (height < notch_h_th_) {
is_notch = true;
}
} else if (current_neighbors.left && current_neighbors.right) {
if (width < notch_v_th_) {
is_notch = true;
}
}

if (width <= notch_h_th_ || height <= notch_v_th_) {
notch_penalty_ += calSingleNotchPenalty(block_->dbuToMicrons(width),
block_->dbuToMicrons(height));
if (is_notch) {
notch_penalty_ += calSingleNotchPenalty(width, height);
if (graphics_) {
graphics_->addNotch(odb::Rect(x_coords[start_col],
y_coords[start_row],
x_coords[end_col + 1],
y_coords[end_row + 1]));
}
}
}
Expand Down Expand Up @@ -1052,7 +1201,7 @@ void SACoreSoftMacro::attemptCentralization(const float pre_cost)
calPenalty();

// revert centralization
if (calNormCost() > pre_cost) {
if (calNormCost() > pre_cost && !force_centralization_) {
centralization_was_reverted_ = true;

setClustersLocations(clusters_locations);
Expand Down
29 changes: 28 additions & 1 deletion src/mpl/src/SACoreSoftMacro.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,22 @@ class SACoreSoftMacro : public SimulatedAnnealingCore<SoftMacro>

void enableEnhancements() { enhancements_on_ = true; };

void forceCentralization() { force_centralization_ = true; }

private:
// Used to calculate notches
struct Neighbors
Comment on lines +77 to +78
Copy link
Member

Choose a reason for hiding this comment

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

I had to read the code to understand the semantics of these bools. A better descriptive comment would be helpful.

{
bool top = true;
bool bottom = true;
bool left = true;
bool right = true;

int total() { return top + bottom + left + right; }

bool operator==(const Neighbors&) const = default;
};

float calNormCost() const override;
void calPenalty() override;

Expand All @@ -84,7 +99,18 @@ class SACoreSoftMacro : public SimulatedAnnealingCore<SoftMacro>
int getSegmentIndex(int segment, const std::vector<int>& coords);

void calBoundaryPenalty();
float calSingleNotchPenalty(float width, float height);
void fillCoordsLists(std::vector<int>& x_coords, std::vector<int>& y_coords);
Neighbors findNeighbors(std::vector<std::vector<bool>>& grid,
int start_row,
int start_col,
int end_row,
int end_col);
bool isSegmentEmpty(std::vector<std::vector<bool>>& grid,
int start_row,
int tart_col,
int end_row,
int end_col);
float calSingleNotchPenalty(int width, int height);
void calNotchPenalty();
void calMacroBlockagePenalty();
void calFixedMacrosPenalty();
Expand Down Expand Up @@ -136,6 +162,7 @@ class SACoreSoftMacro : public SimulatedAnnealingCore<SoftMacro>

bool enhancements_on_ = false;
bool centralization_was_reverted_ = false;
bool force_centralization_ = false;
};

} // namespace mpl
Loading