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

ant: return CAR and CSR violations to repair_antennas #5242

Merged
Merged
Show file tree
Hide file tree
Changes from 4 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
16 changes: 13 additions & 3 deletions src/ant/include/ant/AntennaChecker.hh
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ using GraphNodes = std::vector<GraphNode*>;
using LayerToGraphNodes = std::unordered_map<odb::dbTechLayer*, GraphNodes>;
using GateToLayerToNodeInfo = std::map<std::string, LayerToNodeInfo>;
using Violations = std::vector<Violation>;
using GateToViolationLayers
= std::unordered_map<std::string, std::unordered_set<odb::dbTechLayer*>>;

class AntennaChecker
{
Expand Down Expand Up @@ -158,9 +160,7 @@ class AntennaChecker
std::vector<std::pair<double, std::vector<odb::dbITerm*>>>
getViolatedWireLength(odb::dbNet* net, int routing_level);
bool isValidGate(odb::dbMTerm* mterm);
void buildLayerMaps(odb::dbNet* net,
LayerToGraphNodes& node_by_layer_map,
GateToLayerToNodeInfo& gate_info);
void buildLayerMaps(odb::dbNet* net, LayerToGraphNodes& node_by_layer_map);
void checkNet(odb::dbNet* net,
bool verbose,
bool report_if_no_violation,
Expand All @@ -177,6 +177,16 @@ class AntennaChecker
GateToLayerToNodeInfo& gate_info);
void calculatePAR(GateToLayerToNodeInfo& gate_info);
void calculateCAR(GateToLayerToNodeInfo& gate_info);
bool checkRatioViolations(odb::dbTechLayer* layer,
const NodeInfo& node_info,
bool verbose,
bool report,
std::ofstream& report_file);
void reportNet(odb::dbNet* db_net,
GateToLayerToNodeInfo& gate_info,
GateToViolationLayers& gates_with_violations,
bool verbose,
std::ofstream& report_file);
int checkGates(odb::dbNet* db_net,
bool verbose,
bool report_if_no_violation,
Expand Down
230 changes: 119 additions & 111 deletions src/ant/src/AntennaChecker.cc
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,92 @@ bool AntennaChecker::checkCSR(odb::dbTechLayer* tech_layer,
return violation;
}

bool AntennaChecker::checkRatioViolations(odb::dbTechLayer* layer,
const NodeInfo& node_info,
bool verbose,
bool report,
std::ofstream& report_file)
{
bool node_has_violation = false;
auto par_violation = checkPAR(layer, node_info, verbose, report, report_file);
bool car_violation = checkCAR(layer, node_info, verbose, report, report_file);
node_has_violation = par_violation.first || car_violation;
Copy link
Member

Choose a reason for hiding this comment

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

There's no need to define node_has_violation and then set it afterwards, just combine 749 & 752


if (layer->getRoutingLevel() != 0) {
auto psr_violation
= checkPSR(layer, node_info, verbose, report, report_file);
bool csr_violation
= checkCSR(layer, node_info, verbose, report, report_file);
node_has_violation
= node_has_violation || psr_violation.first || csr_violation;
}
Copy link
Member

Choose a reason for hiding this comment

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

Does check* have a side-effect or should we skip this if node_has_violation was already set by PAR/CAR?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We should not skip because a net can have both PAR/CAR and PSR/CSR. Skipping it will give us the wrong number of violations and make the report incorrect.


return node_has_violation;
}

void AntennaChecker::reportNet(odb::dbNet* db_net,
GateToLayerToNodeInfo& gate_info,
GateToViolationLayers& gates_with_violations,
bool verbose,
std::ofstream& report_file)
{
std::string net_name = fmt::format("Net: {}", db_net->getConstName());
if (verbose) {
logger_->report("{}", net_name);
}
if (report_file.is_open()) {
report_file << net_name << "\n";
}
for (const auto& [node, layer_to_node] : gate_info) {
if (!verbose
&& gates_with_violations.find(node) == gates_with_violations.end()) {
continue;
}
std::string pin_name = fmt::format(" Pin: {}", node);
if (verbose) {
logger_->report("{}", pin_name);
}
if (report_file.is_open()) {
report_file << pin_name << "\n";
}
for (const auto& [layer, node_info] : layer_to_node) {
if (!verbose
&& gates_with_violations[node].find(layer)
== gates_with_violations[node].end()) {
continue;
}
std::string layer_name
= fmt::format(" Layer: {}", layer->getConstName());
if (verbose) {
logger_->report("{}", layer_name);
}
if (report_file.is_open()) {
report_file << layer_name << "\n";
}
// re-check to report violations
checkRatioViolations(layer, node_info, verbose, true, report_file);
if (verbose) {
logger_->report("");
}
if (report_file.is_open()) {
report_file << "\n";
}
}
if (verbose) {
logger_->report("");
}
if (report_file.is_open()) {
report_file << "\n";
}
}
if (verbose) {
logger_->report("");
}
if (report_file.is_open()) {
report_file << "\n";
}
}

int AntennaChecker::checkGates(odb::dbNet* db_net,
bool verbose,
bool report_if_no_violation,
Expand All @@ -752,42 +838,19 @@ int AntennaChecker::checkGates(odb::dbNet* db_net,
ratio_margin_ = ratio_margin;
int pin_violation_count = 0;

std::unordered_map<std::string, std::unordered_set<odb::dbTechLayer*>>
gates_with_violations;
GateToViolationLayers gates_with_violations;

for (const auto& gate_info : gate_info) {
for (const auto& [node, layer_to_node] : gate_info) {
bool pin_has_violation = false;

for (const auto& layer_info : gate_info.second) {
bool node_has_violation = false;
if (layer_info.first->hasDefaultAntennaRule()) {
// check if node has violation
if (layer_info.first->getRoutingLevel() != 0) {
auto par_violation = checkPAR(
layer_info.first, layer_info.second, false, false, report_file);
auto psr_violation = checkPSR(
layer_info.first, layer_info.second, false, false, report_file);
bool car_violation = checkCAR(
layer_info.first, layer_info.second, false, false, report_file);
bool csr_violation = checkCSR(
layer_info.first, layer_info.second, false, false, report_file);
for (const auto& [layer, node_info] : layer_to_node) {
if (layer->hasDefaultAntennaRule()) {
bool node_has_violation
= checkRatioViolations(layer, node_info, false, false, report_file);

if (par_violation.first || psr_violation.first || car_violation
|| csr_violation) {
node_has_violation = true;
}
} else {
auto par_violation = checkPAR(
layer_info.first, layer_info.second, false, false, report_file);
bool car_violation = checkCAR(
layer_info.first, layer_info.second, false, false, report_file);
if (par_violation.first || car_violation) {
node_has_violation = true;
}
}
if (node_has_violation) {
pin_has_violation = true;
gates_with_violations[gate_info.first].insert(layer_info.first);
gates_with_violations[node].insert(layer);
}
}
}
Expand All @@ -799,95 +862,25 @@ int AntennaChecker::checkGates(odb::dbNet* db_net,
// iterate the gates with violations to report
if (((pin_violation_count > 0) || report_if_no_violation)
&& diode_mterm == nullptr) {
std::string net_name = fmt::format("Net: {}", db_net->getConstName());
if (verbose) {
logger_->report("{}", net_name);
}
if (report_file.is_open()) {
report_file << net_name << "\n";
}
for (const auto& gate_it : gate_info) {
if (!verbose
&& gates_with_violations.find(gate_it.first)
== gates_with_violations.end()) {
continue;
}
std::string pin_name = fmt::format(" Pin: {}", gate_it.first);
if (verbose) {
logger_->report("{}", pin_name);
}
if (report_file.is_open()) {
report_file << pin_name << "\n";
}
for (const auto& layer_info : gate_info[gate_it.first]) {
if (!verbose
&& gates_with_violations[gate_it.first].find(layer_info.first)
== gates_with_violations[gate_it.first].end()) {
continue;
}
std::string layer_name
= fmt::format(" Layer: {}", layer_info.first->getConstName());
if (verbose) {
logger_->report("{}", layer_name);
}
if (report_file.is_open()) {
report_file << layer_name << "\n";
}
// re-check to report violations
if (layer_info.first->getRoutingLevel() != 0) {
checkPAR(
layer_info.first, layer_info.second, verbose, true, report_file);
checkPSR(
layer_info.first, layer_info.second, verbose, true, report_file);
checkCAR(
layer_info.first, layer_info.second, verbose, true, report_file);
checkCSR(
layer_info.first, layer_info.second, verbose, true, report_file);
} else {
checkPAR(
layer_info.first, layer_info.second, verbose, true, report_file);
checkCAR(
layer_info.first, layer_info.second, verbose, true, report_file);
}
if (verbose) {
logger_->report("");
}
if (report_file.is_open()) {
report_file << "\n";
}
}
if (verbose) {
logger_->report("");
}
if (report_file.is_open()) {
report_file << "\n";
}
}
if (verbose) {
logger_->report("");
}
if (report_file.is_open()) {
report_file << "\n";
}
reportNet(db_net, gate_info, gates_with_violations, verbose, report_file);
}

std::unordered_map<odb::dbTechLayer*, std::unordered_set<std::string>>
pin_added;
// if checkGates is used by repair antennas
if (pin_violation_count > 0) {
for (const auto& gate_iter : gates_with_violations) {
for (const auto& layer_info : gate_iter.second) {
for (const auto& [gate, violation_layers] : gates_with_violations) {
for (odb::dbTechLayer* layer : violation_layers) {
// when repair antenna is running, calculate number of diodes
if (layer_info->getRoutingLevel() != 0
&& pin_added[layer_info].find(gate_iter.first)
== pin_added[layer_info].end()) {
if (layer->getRoutingLevel() != 0
&& pin_added[layer].find(gate) == pin_added[layer].end()) {
double diode_diff_area = 0.0;
if (diode_mterm) {
diode_diff_area = diffArea(diode_mterm);
}
NodeInfo violation_info = gate_info[gate_iter.first][layer_info];
NodeInfo violation_info = gate_info[gate][layer];
std::vector<odb::dbITerm*> gates = violation_info.iterms;
odb::dbTechLayer* violation_layer = layer_info;
odb::dbTechLayer* violation_layer = layer;
int diode_count_per_gate = 0;
// check violations only PAR & PSR
auto par_violation = checkPAR(
Expand Down Expand Up @@ -926,7 +919,23 @@ int AntennaChecker::checkGates(odb::dbNet* db_net,
// save antenna violation
if (violated) {
antenna_violations.push_back(
{layer_info->getRoutingLevel(), gates, diode_count_per_gate});
{layer->getRoutingLevel(), gates, diode_count_per_gate});
}

bool car_violation = checkCAR(
violation_layer, violation_info, false, false, report_file);
bool csr_violation = checkCSR(
violation_layer, violation_info, false, false, report_file);

// naive approach for cumulative area violations. here, all the pins
// of the net are included, and placing one diode per pin is not the
// best approach. as a first implementation, insert one diode per net.
// TODO: implement a proper approach for CAR violations
if (car_violation || csr_violation) {
std::vector<odb::dbITerm*> gates_for_violation;
gates_for_violation.push_back(gates[0]);
antenna_violations.push_back(
{layer->getRoutingLevel(), gates_for_violation, 1});
}
}
}
Expand All @@ -936,8 +945,7 @@ int AntennaChecker::checkGates(odb::dbNet* db_net,
}

void AntennaChecker::buildLayerMaps(odb::dbNet* db_net,
LayerToGraphNodes& node_by_layer_map,
GateToLayerToNodeInfo& gate_info)
LayerToGraphNodes& node_by_layer_map)
{
odb::dbWire* wires = db_net->getWire();

Expand Down Expand Up @@ -1023,7 +1031,7 @@ void AntennaChecker::checkNet(odb::dbNet* db_net,
if (wire) {
LayerToGraphNodes node_by_layer_map;
GateToLayerToNodeInfo gate_info;
buildLayerMaps(db_net, node_by_layer_map, gate_info);
buildLayerMaps(db_net, node_by_layer_map);

calculateAreas(node_by_layer_map, gate_info);

Expand Down
Loading
Loading