Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mpl2: support snapping of macros with pins in multiple layers #5890

Merged
merged 16 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
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
294 changes: 180 additions & 114 deletions src/mpl2/src/hier_rtlmp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4075,7 +4075,7 @@ void HierRTLMP::updateMacroOnDb(const HardMacro* hard_macro)

void HierRTLMP::commitMacroPlacementToDb()
{
Snapper snapper;
Snapper snapper(logger_);

for (auto& [inst, hard_macro] : tree_->maps.inst_to_hard) {
if (!inst) {
Expand Down Expand Up @@ -4463,186 +4463,252 @@ bool Pusher::overlapsWithIOBlockage(const odb::Rect& cluster_box,

//////// Snapper ////////

Snapper::Snapper() : inst_(nullptr)
Snapper::Snapper(utl::Logger* logger) : logger_(logger), inst_(nullptr)
{
}

Snapper::Snapper(odb::dbInst* inst) : inst_(inst)
Snapper::Snapper(utl::Logger* logger, odb::dbInst* inst)
: logger_(logger), inst_(inst)
{
}

void Snapper::snapMacro()
{
const odb::Point snap_origin = computeSnapOrigin();
inst_->setOrigin(snap_origin.x(), snap_origin.y());
snap(true /*horizontal snap*/);
snap(false /*horizontal snap*/);
AcKoucher marked this conversation as resolved.
Show resolved Hide resolved
}

odb::Point Snapper::computeSnapOrigin()
void Snapper::snap(const bool horizontal_snap)
{
SnapParameters x, y;
SameDirectionLayersData layers_data
= computeSameDirectionLayersData(horizontal_snap);

std::set<odb::dbTechLayer*> snap_layers;
if (!layers_data.snap_layer) {
return;
}

odb::dbMaster* master = inst_->getMaster();
for (odb::dbMTerm* mterm : master->getMTerms()) {
if (mterm->getSigType() != odb::dbSigType::SIGNAL) {
continue;
}
int origin
= horizontal_snap ? inst_->getOrigin().x() : inst_->getOrigin().y();

for (odb::dbMPin* mpin : mterm->getMPins()) {
for (odb::dbBox* box : mpin->getGeometry()) {
odb::dbTechLayer* layer = box->getTechLayer();
odb::dbITerm* snap_pin = layers_data.layer_to_pin.at(layers_data.snap_layer);
const LayerParameters& snap_layer_params
= layers_data.layer_to_params.at(layers_data.snap_layer);

if (snap_layers.find(layer) != snap_layers.end()) {
continue;
}
if (!pinsAreAlignedWithTrackGrid(
snap_pin, snap_layer_params, horizontal_snap)) {
// The idea here is to first align the origin of the macro with
// the track-grid taking into account that the grid has a certain
// offset with regards to (0,0) and, then, compensate the offset
// of the pins themselves so that the lines of the grid cross
// their center.
origin
= std::round(origin / snap_layer_params.pitch) * snap_layer_params.pitch
+ snap_layer_params.offset - snap_layer_params.pin_offset;

snap_layers.insert(layer);
const int manufacturing_grid
= inst_->getDb()->getTech()->getManufacturingGrid();
origin = std::round(origin / manufacturing_grid) * manufacturing_grid;

if (layer->getDirection() == odb::dbTechLayerDir::HORIZONTAL) {
y = computeSnapParameters(layer, box, false);
} else {
x = computeSnapParameters(layer, box, true);
}
}
}
setOrigin(origin, horizontal_snap);
}

// The distance between the pins and the lower-left corner of the master of
// a macro instance may not be a multiple of the track-grid, in these cases,
// we need to compensate a small offset.
const int mterm_offset_x
= x.pitch != 0
? x.lower_left_to_first_pin
- std::floor(x.lower_left_to_first_pin / x.pitch) * x.pitch
: 0;
const int mterm_offset_y
= y.pitch != 0
? y.lower_left_to_first_pin
- std::floor(y.lower_left_to_first_pin / y.pitch) * y.pitch
: 0;

int pin_offset_x = x.pin_width / 2 + mterm_offset_x;
int pin_offset_y = y.pin_width / 2 + mterm_offset_y;

odb::dbOrientType orientation = inst_->getOrient();
attemptSnapToExtraLayers(
origin, layers_data, snap_layer_params, horizontal_snap);
}

if (orientation == odb::dbOrientType::MX) {
pin_offset_y = -pin_offset_y;
} else if (orientation == odb::dbOrientType::MY) {
pin_offset_x = -pin_offset_x;
} else if (orientation == odb::dbOrientType::R180) {
pin_offset_x = -pin_offset_x;
pin_offset_y = -pin_offset_y;
void Snapper::setOrigin(const int origin, const bool horizontal_snap)
{
if (horizontal_snap) {
inst_->setOrigin(origin, inst_->getOrigin().y());
} else {
inst_->setOrigin(inst_->getOrigin().x(), origin);
}
}

// This may NOT be the lower-left corner.
int origin_x = inst_->getOrigin().x();
int origin_y = inst_->getOrigin().y();
SameDirectionLayersData Snapper::computeSameDirectionLayersData(
const bool horizontal_snap)
{
SameDirectionLayersData data;

// Compute trackgrid alignment only if there are pins in the grid's direction.
// Note that we first align the macro origin with the track grid and then, we
// compensate the necessary offset.
if (x.pin_width != 0) {
origin_x = std::round(origin_x / x.pitch) * x.pitch + x.offset;
origin_x -= pin_offset_x;
}
if (y.pin_width != 0) {
origin_y = std::round(origin_y / y.pitch) * y.pitch + y.offset;
origin_y -= pin_offset_y;
}
// Note that, for a layer whose preferred track is vertical, i.e.,
// an arrangement of vertical lines, we'll move horizontally the
// macro to try aligning its pins.
const odb::dbTechLayerDir target_direction
= horizontal_snap ? odb::dbTechLayerDir::VERTICAL
: odb::dbTechLayerDir::HORIZONTAL;

const int manufacturing_grid
= inst_->getDb()->getTech()->getManufacturingGrid();
for (odb::dbITerm* iterm : inst_->getITerms()) {
if (iterm->getSigType() != odb::dbSigType::SIGNAL) {
continue;
}

origin_x = std::round(origin_x / manufacturing_grid) * manufacturing_grid;
origin_y = std::round(origin_y / manufacturing_grid) * manufacturing_grid;
for (odb::dbMPin* mpin : iterm->getMTerm()->getMPins()) {
for (odb::dbBox* box : mpin->getGeometry()) {
odb::dbTechLayer* layer = box->getTechLayer();
if (layer->getDirection() == target_direction) {
if (data.layer_to_pin.find(layer) != data.layer_to_pin.end()) {
continue;
}

const odb::Point snap_origin(origin_x, origin_y);
if (data.layer_to_pin.empty()) {
data.snap_layer = layer;
}

data.layer_to_pin[layer] = iterm;
data.layer_to_params[layer]
= computeLayerParameters(layer, iterm, horizontal_snap);
}
}
}
}

return snap_origin;
return data;
}

SnapParameters Snapper::computeSnapParameters(odb::dbTechLayer* layer,
odb::dbBox* box,
const bool vertical_layer)
LayerParameters Snapper::computeLayerParameters(odb::dbTechLayer* layer,
odb::dbITerm* pin,
const bool horizontal_snap)
{
SnapParameters params;
LayerParameters params;

odb::dbBlock* block = inst_->getBlock();
odb::dbTrackGrid* track_grid = block->findTrackGrid(layer);

if (track_grid) {
std::vector<int> coordinate_grid;
getTrackGrid(track_grid, coordinate_grid, vertical_layer);
getTrackGrid(track_grid, coordinate_grid, horizontal_snap);

params.offset = coordinate_grid[0];
params.pitch = coordinate_grid[1] - coordinate_grid[0];
} else {
params.pitch = getPitch(layer, vertical_layer);
params.offset = getOffset(layer, vertical_layer);
logger_->error(
MPL, 39, "No track-grid found for layer {}", layer->getName());
}

params.pin_width = getPinWidth(box, vertical_layer);
params.pin_width = getPinWidth(pin, horizontal_snap);
params.lower_left_to_first_pin
= getPinToLowerLeftDistance(box, vertical_layer);

return params;
}

int Snapper::getPitch(odb::dbTechLayer* layer, const bool vertical_layer)
{
int pitch = 0;
if (vertical_layer) {
pitch = layer->getPitchX();
} else {
pitch = layer->getPitchY();
}
return pitch;
}

int Snapper::getOffset(odb::dbTechLayer* layer, const bool vertical_layer)
{
int offset = 0;
if (vertical_layer) {
offset = layer->getOffsetX();
} else {
offset = layer->getOffsetY();
= getPinToLowerLeftDistance(pin, horizontal_snap);

// The distance between the pins and the lower-left corner
// of the master of a macro instance may not be a multiple
// of the track-grid, in these cases, we need to compensate
// a small offset.
int mterm_offset = 0;
if (params.pitch != 0) {
mterm_offset = params.lower_left_to_first_pin
- std::floor(params.lower_left_to_first_pin / params.pitch)
* params.pitch;
}
params.pin_offset = params.pin_width / 2 + mterm_offset;

const odb::dbOrientType& orientation = inst_->getOrient();
if (horizontal_snap) {
if (orientation == odb::dbOrientType::MY
|| orientation == odb::dbOrientType::R180) {
params.pin_offset = -params.pin_offset;
}
} else if (orientation == odb::dbOrientType::MX
|| orientation == odb::dbOrientType::R180) {
params.pin_offset = -params.pin_offset;
}
return offset;
return params;
}

int Snapper::getPinWidth(odb::dbBox* box, const bool vertical_layer)
int Snapper::getPinWidth(odb::dbITerm* pin, const bool horizontal_snap)
{
int pin_width = 0;
if (vertical_layer) {
pin_width = box->getDX();
if (horizontal_snap) {
pin_width = pin->getBBox().dx();
} else {
pin_width = box->getDY();
pin_width = pin->getBBox().dy();
}
return pin_width;
}

void Snapper::getTrackGrid(odb::dbTrackGrid* track_grid,
std::vector<int>& coordinate_grid,
const bool vertical_layer)
const bool horizontal_snap)
{
if (vertical_layer) {
if (horizontal_snap) {
track_grid->getGridX(coordinate_grid);
} else {
track_grid->getGridY(coordinate_grid);
}
}

int Snapper::getPinToLowerLeftDistance(odb::dbBox* box, bool vertical_layer)
int Snapper::getPinToLowerLeftDistance(odb::dbITerm* pin, bool horizontal_snap)
{
int pin_to_origin = 0;
if (vertical_layer) {
pin_to_origin = box->getBox().xMin();

odb::dbMTerm* mterm = pin->getMTerm();
if (horizontal_snap) {
pin_to_origin = mterm->getBBox().xMin();
} else {
pin_to_origin = box->getBox().yMin();
pin_to_origin = mterm->getBBox().yMin();
}

return pin_to_origin;
}

void Snapper::attemptSnapToExtraLayers(
const int origin,
const SameDirectionLayersData& layers_data,
const LayerParameters& snap_layer_params,
const bool horizontal_snap)
{
const int total_number_of_layers
= static_cast<int>(layers_data.layer_to_pin.size());
const int total_attempts = 5;
int remaining_attempts = total_attempts;

int best_origin = origin;
int best_number_of_snapped_layers = 1;
int new_origin = origin;
bool all_layers_snapped = false;

while (remaining_attempts > 0) {
// Move one track ahead.
new_origin += snap_layer_params.pitch;
AcKoucher marked this conversation as resolved.
Show resolved Hide resolved
setOrigin(new_origin, horizontal_snap);

int curr_number_of_snapped_layers = 1;
for (const auto [layer, pin] : layers_data.layer_to_pin) {
if (layer == layers_data.snap_layer) {
continue;
}

if (pinsAreAlignedWithTrackGrid(
pin, layers_data.layer_to_params.at(layer), horizontal_snap)) {
++curr_number_of_snapped_layers;
}

if (curr_number_of_snapped_layers == total_number_of_layers) {
all_layers_snapped = true;
break;
}
}

if (all_layers_snapped) {
return;
}

if (curr_number_of_snapped_layers > best_number_of_snapped_layers) {
AcKoucher marked this conversation as resolved.
Show resolved Hide resolved
best_origin = new_origin;
}

--remaining_attempts;
}

setOrigin(best_origin, horizontal_snap);
}

bool Snapper::pinsAreAlignedWithTrackGrid(odb::dbITerm* pin,
const LayerParameters& layer_params,
const bool horizontal_snap)
{
int pin_center
= horizontal_snap ? pin->getBBox().xCenter() : pin->getBBox().yCenter();
return (pin_center - layer_params.offset) % layer_params.pitch == 0;
}

} // namespace mpl2
Loading
Loading