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

mpl: add support for IO Pads #6600

Merged
merged 1 commit into from
Feb 7, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion src/mpl/src/SimulatedAnnealingCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ void SimulatedAnnealingCore<T>::calWirelength()
T& source = macros_[net.terminals.first];
T& target = macros_[net.terminals.second];

if (target.isIOCluster()) {
if (target.isClusterOfUnplacedIOPins()) {
addBoundaryDistToWirelength(source, target, net.weight);
continue;
}
Expand Down
122 changes: 88 additions & 34 deletions src/mpl/src/clusterEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,12 @@ void ClusteringEngine::run()
createRoot();
setBaseThresholds();

mapIOPinsAndPads();
createDataFlow();

createIOClusters();
classifyBoundariesStateForIOs();

createDataFlow();

if (design_metrics_->getNumStdCell() == 0) {
logger_->warn(MPL, 25, "Design has no standard cells!");
tree_->has_std_cells = false;
Expand Down Expand Up @@ -357,13 +358,20 @@ void ClusteringEngine::setBaseThresholds()
tree_->base_min_std_cell);
}

// Group IOs with the same constraints:
// 1. If an IO has a constraint region in a certain boundary,
// it is constrained to that entire boundary.
// 2. If an IO has no constraints, it is constrained to all boundaries.
// An IO Cluster may represent:
// 1. A Group of Unplaced Pins;
// 2. An IO Pad.
//
// For the former, we group IO pins with the same constraints based on:
// - If an IO pin has a constraint region in a certain boundary,
// it is constrained to that entire boundary;
// - If an IO pin has no constraints, it is constrained to all boundaries.
void ClusteringEngine::createIOClusters()
{
mapIOPads();
if (!tree_->maps.pad_to_bterm.empty()) {
createIOPadClusters();
return;
}

// Boundary with constrained IOs -> cluster
std::map<Boundary, Cluster*> boundary_to_cluster;
Expand Down Expand Up @@ -434,7 +442,7 @@ void ClusteringEngine::createIOCluster(
setIOClusterDimensions(die, constraint_boundary, x, y, width, height);
}

cluster->setAsIOCluster(
cluster->setAsClusterOfUnplacedIOPins(
std::pair<float, float>(block_->dbuToMicrons(x), block_->dbuToMicrons(y)),
block_->dbuToMicrons(width),
block_->dbuToMicrons(height),
Expand Down Expand Up @@ -512,7 +520,7 @@ void ClusteringEngine::setIOClusterDimensions(const odb::Rect& die,
}
}

void ClusteringEngine::mapIOPads()
void ClusteringEngine::mapIOPinsAndPads()
{
bool design_has_io_pads = false;
for (auto inst : block_->getInsts()) {
Expand All @@ -531,17 +539,56 @@ void ClusteringEngine::mapIOPads()
continue;
}

// If the design has IO pads, there is a net
// connecting the IO pin and IO pad instance
for (odb::dbBTerm* bterm : net->getBTerms()) {
for (odb::dbITerm* iterm : net->getITerms()) {
odb::dbInst* inst = iterm->getInst();
tree_->maps.bterm_to_inst[bterm] = inst;
tree_->maps.pad_to_bterm[inst] = bterm;
tree_->maps.bterm_to_pad[bterm] = inst;
}
}
}
}

void ClusteringEngine::createIOPadClusters()
{
for (const auto& io_pad_path : data_connections_.io_and_regs) {
// Registers or Macros
const PathInsts& connected_insts = io_pad_path.second;
bool path_is_empty = true;
for (const std::set<odb::dbInst*>& insts_of_curr_hop_dist :
connected_insts) {
if (!insts_of_curr_hop_dist.empty()) {
path_is_empty = false;
break;
}
}

if (path_is_empty) {
continue;
}

odb::dbBTerm* bterm = io_pad_path.first;
odb::dbInst* pad = tree_->maps.bterm_to_pad.at(bterm);

createIOPadCluster(pad, bterm);
}
}

void ClusteringEngine::createIOPadCluster(odb::dbInst* pad, odb::dbBTerm* bterm)
{
auto cluster = std::make_unique<Cluster>(id_, pad->getName(), logger_);
tree_->maps.bterm_to_cluster_id[bterm] = id_;
tree_->maps.id_to_cluster[id_++] = cluster.get();

const odb::Rect& pad_bbox = pad->getBBox()->getBox();

cluster->setAsIOPadCluster({block_->dbuToMicrons(pad_bbox.xMin()),
block_->dbuToMicrons(pad_bbox.yMin())},
block_->dbuToMicrons(pad_bbox.dx()),
block_->dbuToMicrons(pad_bbox.dy()));
tree_->root->addChild(std::move(cluster));
}

// Dataflow is used to improve quality of macro placement.
// Here we model each std cell instance, IO pin and macro pin as vertices.
void ClusteringEngine::createDataFlow()
Expand Down Expand Up @@ -682,23 +729,25 @@ DataFlowHypergraph ClusteringEngine::computeHypergraph(
graph.backward_vertices.resize(num_of_vertices);

for (odb::dbNet* net : block_->getNets()) {
if (net->getSigType().isSupply()) {
if (!isValidNet(net)) {
continue;
}

int driver_id = -1;
std::set<int> loads_id;
bool ignore = false;
bool net_has_stdcell_without_liberty = false;
for (odb::dbITerm* iterm : net->getITerms()) {
odb::dbInst* inst = iterm->getInst();
if (isIgnoredInst(inst)) {
ignore = true;
break;
}

int vertex_id = -1;

if (inst->isBlock()) {
vertex_id = odb::dbIntProperty::find(iterm, "vertex_id")->getValue();
} else if (inst->isPad()) {
// To properly consider the path of a signal that travels from a PAD
// to the core we use the path's bterm as the vertex.
odb::dbBTerm* pad_bterm = tree_->maps.pad_to_bterm.at(inst);
vertex_id
= odb::dbIntProperty::find(pad_bterm, "vertex_id")->getValue();
} else {
odb::dbIntProperty* int_prop
= odb::dbIntProperty::find(inst, "vertex_id");
Expand All @@ -707,7 +756,7 @@ DataFlowHypergraph ClusteringEngine::computeHypergraph(
if (int_prop) {
vertex_id = int_prop->getValue();
} else {
ignore = true;
net_has_stdcell_without_liberty = true;
break;
}
}
Expand All @@ -719,7 +768,7 @@ DataFlowHypergraph ClusteringEngine::computeHypergraph(
}
}

if (ignore) {
if (net_has_stdcell_without_liberty) {
continue;
}

Expand Down Expand Up @@ -1733,21 +1782,15 @@ void ClusteringEngine::updateConnections()
}

for (odb::dbNet* net : block_->getNets()) {
if (net->getSigType().isSupply()) {
if (!isValidNet(net)) {
continue;
}

int driver_cluster_id = -1;
std::vector<int> load_clusters_ids;
bool net_has_pad_or_cover = false;

for (odb::dbITerm* iterm : net->getITerms()) {
odb::dbInst* inst = iterm->getInst();
if (isIgnoredInst(inst)) {
net_has_pad_or_cover = true;
break;
}

const int cluster_id = tree_->maps.inst_to_cluster_id.at(inst);

if (iterm->getIoType() == odb::dbIoType::OUTPUT) {
Expand All @@ -1757,10 +1800,6 @@ void ClusteringEngine::updateConnections()
}
}

if (net_has_pad_or_cover) {
continue;
}

bool net_has_io_pin = false;
for (odb::dbBTerm* bterm : net->getBTerms()) {
const int cluster_id = tree_->maps.bterm_to_cluster_id.at(bterm);
Expand Down Expand Up @@ -1789,6 +1828,21 @@ void ClusteringEngine::updateConnections()
}
}

bool ClusteringEngine::isValidNet(odb::dbNet* net)
{
if (net->getSigType().isSupply()) {
return false;
}

for (odb::dbITerm* iterm : net->getITerms()) {
if (!isIgnoredInst(iterm->getInst())) {
return true;
}
}

return false;
}

void ClusteringEngine::fetchMixedLeaves(
Cluster* parent,
std::vector<std::vector<Cluster*>>& mixed_leaves)
Expand Down Expand Up @@ -2162,7 +2216,7 @@ void ClusteringEngine::printPhysicalHierarchyTree(Cluster* parent, int level)
parent->getId(),
parent->getClusterTypeString());

if (parent->isIOCluster()) {
if (parent->isClusterOfUnplacedIOPins()) {
int number_of_pins = 0;
for (const auto [pin, cluster_id] : tree_->maps.bterm_to_cluster_id) {
if (cluster_id == parent->getId()) {
Expand All @@ -2171,7 +2225,7 @@ void ClusteringEngine::printPhysicalHierarchyTree(Cluster* parent, int level)
}

line += fmt::format(" Pins: {}", number_of_pins);
} else {
} else if (!parent->isIOPadCluster()) {
line += fmt::format(" {}, StdCells: {} ({} μ²), Macros: {} ({} μ²)",
parent->getIsLeafString(),
parent->getNumStdCell(),
Expand Down
19 changes: 11 additions & 8 deletions src/mpl/src/clusterEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ namespace mpl {

using InstToHardMap = std::map<odb::dbInst*, std::unique_ptr<HardMacro>>;
using ModuleToMetricsMap = std::map<odb::dbModule*, std::unique_ptr<Metrics>>;
using PathInsts = std::vector<std::set<odb::dbInst*>>;

struct DataFlowHypergraph
{
Expand All @@ -80,20 +81,17 @@ struct DataFlow

// Macro Pins --> Registers
// Registers --> Macro Pins
std::vector<std::pair<odb::dbITerm*, std::vector<std::set<odb::dbInst*>>>>
macro_pins_and_regs;
std::vector<std::pair<odb::dbITerm*, PathInsts>> macro_pins_and_regs;

// IO --> Register
// Register --> IO
// IO --> Macro Pin
// Macro Pin --> IO
std::vector<std::pair<odb::dbBTerm*, std::vector<std::set<odb::dbInst*>>>>
io_and_regs;
std::vector<std::pair<odb::dbBTerm*, PathInsts>> io_and_regs;

// Macro Pin --> Macros
// Macros --> Macro Pin
std::vector<std::pair<odb::dbITerm*, std::vector<std::set<odb::dbInst*>>>>
macro_pins_and_macros;
std::vector<std::pair<odb::dbITerm*, PathInsts>> macro_pins_and_macros;
};

struct PhysicalHierarchyMaps
Expand All @@ -106,7 +104,8 @@ struct PhysicalHierarchyMaps
ModuleToMetricsMap module_to_metrics;

// Only for designs with IO Pads
std::map<odb::dbBTerm*, odb::dbInst*> bterm_to_inst;
std::map<odb::dbInst*, odb::dbBTerm*> pad_to_bterm;
std::map<odb::dbBTerm*, odb::dbInst*> bterm_to_pad;
};

struct PhysicalHierarchy
Expand Down Expand Up @@ -191,6 +190,8 @@ class ClusteringEngine
void createRoot();
void setBaseThresholds();
void createIOClusters();
void createIOPadClusters();
void createIOPadCluster(odb::dbInst* pad, odb::dbBTerm* bterm);
void classifyBoundariesStateForIOs();
std::map<Boundary, float> computeBlockageExtensionMap();
Boundary getConstraintBoundary(const odb::Rect& die,
Expand All @@ -205,7 +206,7 @@ class ClusteringEngine
int& y,
int& width,
int& height);
void mapIOPads();
void mapIOPinsAndPads();
void treatEachMacroAsSingleCluster();
void incorporateNewCluster(std::unique_ptr<Cluster> cluster, Cluster* parent);
void setClusterMetrics(Cluster* cluster);
Expand Down Expand Up @@ -279,6 +280,8 @@ class ClusteringEngine
void printPhysicalHierarchyTree(Cluster* parent, int level);
float computeMicronArea(odb::dbInst* inst);

bool isValidNet(odb::dbNet* net);

odb::dbBlock* block_;
sta::dbNetwork* network_;
utl::Logger* logger_;
Expand Down
4 changes: 2 additions & 2 deletions src/mpl/src/graphics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ void Graphics::drawObjects(gui::Painter& painter)
continue;
}

if (cluster->isIOCluster()) {
if (cluster->isClusterOfUnplacedIOPins()) {
continue;
}

Expand Down Expand Up @@ -607,7 +607,7 @@ void Graphics::drawBundledNets(gui::Painter& painter,
const T& source = macros[bundled_net.terminals.first];
const T& target = macros[bundled_net.terminals.second];

if (target.isIOCluster()) {
if (target.isClusterOfUnplacedIOPins()) {
drawDistToIoConstraintBoundary(painter, source, target);
continue;
}
Expand Down
Loading