From 945b9a24fa982836aec2357a785423331bcf83d8 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Wed, 9 Dec 2020 00:05:52 +0100 Subject: [PATCH] Fix I/O Pad ring 45 degree corners where off the foundry grid. * New: In CRL/hepers, new function onFGrid() to ensure a DbU is on the foundry grid. Rounding is always done to the inferior integer. * New: In CRL/GdsDriver, added a set of isOnGrid() functions to check that all coordinates of various objects are on the foundry grid. Use isOnGrid() in most objects processed in GdsStream::operator<<(Cell*). * Bug: In cumulus/plugins.chip.pads.Corner, correctly round the coordinates of the 45 degree segments so they are still on the foundry grid. --- crlcore/python/helpers/__init__.py | 7 ++ crlcore/src/ccore/gds/GdsDriver.cpp | 117 ++++++++++++++++++++++++- cumulus/src/plugins/alpha/chip/pads.py | 10 +-- 3 files changed, 128 insertions(+), 6 deletions(-) diff --git a/crlcore/python/helpers/__init__.py b/crlcore/python/helpers/__init__.py index 4a28ef5d..682e1132 100644 --- a/crlcore/python/helpers/__init__.py +++ b/crlcore/python/helpers/__init__.py @@ -262,6 +262,13 @@ def u ( value ): return Hurricane.DbU.fromPhysical( value, Hurricane.DbU.UnitPow def n ( value ): return Hurricane.DbU.fromPhysical( value, Hurricane.DbU.UnitPowerNano ) +def onFGrid ( u ): + oneGrid = Hurricane.DbU.fromGrid( 1.0 ) + if u % oneGrid: + u -= (u % oneGrid) + return u + + def initTechno ( argQuiet ): global quiet global ndaDir diff --git a/crlcore/src/ccore/gds/GdsDriver.cpp b/crlcore/src/ccore/gds/GdsDriver.cpp index 9e0db2d1..71e13f45 100644 --- a/crlcore/src/ccore/gds/GdsDriver.cpp +++ b/crlcore/src/ccore/gds/GdsDriver.cpp @@ -68,6 +68,115 @@ namespace { } + bool isOnGrid ( Instance* instance ) + { + bool error = false; + DbU::Unit oneGrid = DbU::fromGrid( 1.0 ); + Point position = instance->getTransformation().getTranslation(); + if (position.getX() % oneGrid) { + error = true; + cerr << Error( "isOnGrid(): On %s of %s,\n" + " Tx %s is not on grid (%s)" + , getString(instance).c_str() + , getString(instance->getCell()).c_str() + , DbU::getValueString(position.getX()).c_str() + , DbU::getValueString(oneGrid).c_str() + ) << endl; + } + if (position.getY() % oneGrid) { + error = true; + cerr << Error( "isOnGrid(): On %s of %s,\n" + " Ty %s is not on grid (%s)" + , getString(instance).c_str() + , getString(instance->getCell()).c_str() + , DbU::getValueString(position.getY()).c_str() + , DbU::getValueString(oneGrid).c_str() + ) << endl; + } + return error; + } + + + bool isOnGrid ( Component* component, const Box& bb ) + { + bool error = false; + DbU::Unit oneGrid = DbU::fromGrid( 1.0 ); + if (bb.getXMin() % oneGrid) { + error = true; + cerr << Error( "isOnGrid(): On %s of %s,\n" + " X-Min %s is not on grid (%s)" + , getString(component).c_str() + , getString(component->getCell()).c_str() + , DbU::getValueString(bb.getXMin()).c_str() + , DbU::getValueString(oneGrid).c_str() + ) << endl; + } + if (bb.getXMax() % oneGrid) { + error = true; + cerr << Error( "isOnGrid(): On %s of %s,\n" + " X-Max %s is not on grid (%s)" + , getString(component).c_str() + , getString(component->getCell()).c_str() + , DbU::getValueString(bb.getXMax()).c_str() + , DbU::getValueString(oneGrid).c_str() + ) << endl; + } + if (bb.getYMin() % oneGrid) { + error = true; + cerr << Error( "isOnGrid(): On %s of %s,\n" + " Y-Min %s is not on grid (%s)" + , getString(component).c_str() + , getString(component->getCell()).c_str() + , DbU::getValueString(bb.getYMin()).c_str() + , DbU::getValueString(oneGrid).c_str() + ) << endl; + } + if (bb.getYMax() % oneGrid) { + error = true; + cerr << Error( "isOnGrid(): On %s of %s,\n" + " Y-Max %s is not on grid (%s)" + , getString(component).c_str() + , getString(component->getCell()).c_str() + , DbU::getValueString(bb.getYMax()).c_str() + , DbU::getValueString(oneGrid).c_str() + ) << endl; + } + return error; + } + + + bool isOnGrid ( Component* component, const vector& points ) + { + bool error = false; + DbU::Unit oneGrid = DbU::fromGrid( 1.0 ); + for ( size_t i=0 ; igetCell()).c_str() + , i + , DbU::getValueString(points[i].getX()).c_str() + , DbU::getValueString(oneGrid).c_str() + ) << endl; + } + if (points[i].getY() % oneGrid) { + error = true; + cerr << Error( "isOnGrid(): On %s of %s,\n" + " Point [%d] Y %s is not on grid (%s)" + , getString(component).c_str() + , getString(component->getCell()).c_str() + , i + , DbU::getValueString(points[i].getY()).c_str() + , DbU::getValueString(oneGrid).c_str() + ) << endl; + } + } + return error; + } + + // ------------------------------------------------------------------- // Class : "::DepthOrder". @@ -598,6 +707,7 @@ namespace { (*this) << SNAME( instance->getMasterCell()->getName() ); (*this) << instance->getTransformation(); (*this) << ENDEL; + isOnGrid( instance ); } for ( Net* net : cell->getNets() ) { @@ -623,6 +733,7 @@ namespace { (*this) << layer; (*this) << rectilinear->getPoints(); (*this) << ENDEL; + isOnGrid( component, rectilinear->getPoints() ); } } else { Diagonal* diagonal = dynamic_cast(component); @@ -638,10 +749,14 @@ namespace { or dynamic_cast(component) or dynamic_cast(component)) { for ( const BasicLayer* layer : component->getLayer()->getBasicLayers() ) { + Box bb = component->getBoundingBox(layer); + if ((bb.getWidth() == 0) or (bb.getHeight() == 0)) + continue; (*this) << BOUNDARY; (*this) << layer; - (*this) << component->getBoundingBox(layer); + (*this) << bb; (*this) << ENDEL; + isOnGrid( component, bb ); } } } diff --git a/cumulus/src/plugins/alpha/chip/pads.py b/cumulus/src/plugins/alpha/chip/pads.py index 6c1a638a..47dfded9 100644 --- a/cumulus/src/plugins/alpha/chip/pads.py +++ b/cumulus/src/plugins/alpha/chip/pads.py @@ -25,7 +25,7 @@ from Hurricane import DbU, Point, Transformation, Interval, Box, \ import CRL from CRL import RoutingLayerGauge import helpers -from helpers import trace, l, u, n +from helpers import trace, l, u, n, onFGrid from helpers.io import ErrorMessage, WarningMessage from helpers.overlay import UpdateSession import plugins.alpha.chip @@ -58,28 +58,28 @@ class Corner ( object ): yCorner = self.conf.chipAb.getYMin() + axis xBb = self.conf.chipAb.getXMin() + self.conf.ioPadHeight yBb = self.conf.chipAb.getYMin() + self.conf.ioPadHeight - xExtend = - long( 0.5 * float(self.conf.ioPadHeight - axis) ) + xExtend = - onFGrid( long( 0.5 * float(self.conf.ioPadHeight - axis) ) ) yExtend = xExtend elif self.type == SouthEast: xCorner = self.conf.chipAb.getXMax() - axis yCorner = self.conf.chipAb.getYMin() + axis xBb = self.conf.chipAb.getXMax() - self.conf.ioPadHeight yBb = self.conf.chipAb.getYMin() + self.conf.ioPadHeight - xExtend = long( 0.5 * float(self.conf.ioPadHeight - axis) ) + xExtend = onFGrid( long( 0.5 * float(self.conf.ioPadHeight - axis) ) ) yExtend = - xExtend elif self.type == NorthEast: xCorner = self.conf.chipAb.getXMax() - axis yCorner = self.conf.chipAb.getYMax() - axis xBb = self.conf.chipAb.getXMax() - self.conf.ioPadHeight yBb = self.conf.chipAb.getYMax() - self.conf.ioPadHeight - xExtend = long( 0.5 * float(self.conf.ioPadHeight - axis) ) + xExtend = onFGrid( long( 0.5 * float(self.conf.ioPadHeight - axis) ) ) yExtend = xExtend elif self.type == NorthWest: xCorner = self.conf.chipAb.getXMin() + axis yCorner = self.conf.chipAb.getYMax() - axis xBb = self.conf.chipAb.getXMin() + self.conf.ioPadHeight yBb = self.conf.chipAb.getYMax() - self.conf.ioPadHeight - xExtend = - long( 0.5 * float(self.conf.ioPadHeight - axis) ) + xExtend = - onFGrid( long( 0.5 * float(self.conf.ioPadHeight - axis) ) ) yExtend = - xExtend return xCorner, yCorner, xBb, yBb, xExtend, yExtend