From 892661ca2a9b90bdbff0d72c58a5aff979fee597 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Wed, 19 Jul 2023 16:06:43 +0200 Subject: [PATCH] Support of the FOREIGN directive in LEF files (using GDS view). * New: In LefImport, add setGdsForeignDirectory() to point out from where to load the extra GDS file in case a FOREIGN directory is present in MACRO. Also add support for merging the supply nets. It may happens that the supply nets have different names in the GDS ("vdd!") and LEF files ("pvdd"), in that case, the LEF name supersede the GDS one. The GDS file will be loaded *first* then completed by the LEF contents. Blockage in the GDS file are *not* loaded. * Change: In GdsParser, perform an early recognition of supply nets. For now it's hardwired to names starting by "vdd" and "gnd", but should be parametrized in the future. Needed for the LefImport to merge, if needed, the power supplies. In GdsStream::xyToComponent(), skip the blockage if required. --- crlcore/src/ccore/crlcore/Gds.h | 1 + crlcore/src/ccore/crlcore/LefImport.h | 7 +- crlcore/src/ccore/gds/GdsParser.cpp | 11 +- crlcore/src/ccore/lefdef/LefImport.cpp | 154 ++++++++++++++++++++----- crlcore/src/pyCRL/PyLefImport.cpp | 36 ++++-- 5 files changed, 164 insertions(+), 45 deletions(-) diff --git a/crlcore/src/ccore/crlcore/Gds.h b/crlcore/src/ccore/crlcore/Gds.h index 959ba926..f5a24f6e 100644 --- a/crlcore/src/ccore/crlcore/Gds.h +++ b/crlcore/src/ccore/crlcore/Gds.h @@ -33,6 +33,7 @@ namespace CRL { public: static const uint32_t NoGdsPrefix = (1<<0); static const uint32_t Layer_0_IsBoundary = (1<<1); + static const uint32_t NoBlockages = (1<<2); public: static bool save ( Cell* ); static bool load ( Library*, std::string gdsPath, uint32_t flags=0 ); diff --git a/crlcore/src/ccore/crlcore/LefImport.h b/crlcore/src/ccore/crlcore/LefImport.h index c55d0f6e..d0ecd844 100644 --- a/crlcore/src/ccore/crlcore/LefImport.h +++ b/crlcore/src/ccore/crlcore/LefImport.h @@ -29,9 +29,10 @@ namespace CRL { class LefImport { public: - static void reset (); - static Hurricane::Library* load ( std::string fileName ); - static void setMergeLibrary ( Hurricane::Library* ); + static void reset (); + static Hurricane::Library* load ( std::string fileName ); + static void setMergeLibrary ( Hurricane::Library* ); + static void setGdsForeignDirectory ( std::string path ); }; diff --git a/crlcore/src/ccore/gds/GdsParser.cpp b/crlcore/src/ccore/gds/GdsParser.cpp index 772673a7..3e518c1c 100644 --- a/crlcore/src/ccore/gds/GdsParser.cpp +++ b/crlcore/src/ccore/gds/GdsParser.cpp @@ -1079,6 +1079,9 @@ namespace { if (not net) { net = Net::create( _cell, _text ); net->setExternal( true ); + if (_text.substr(0,3) == "vdd") net->setType ( Net::Type::POWER ); + if (_text.substr(0,3) == "gnd") net->setType ( Net::Type::GROUND ); + if (_text[ _text.size()-1 ] == '!') net->setGlobal( true ); } addNetReference( net, layer, xpos, ypos ); } @@ -1513,13 +1516,19 @@ namespace { if (not net) { net = Net::create( _cell, _text ); net->setExternal( true ); + if (_text.substr(0,3) == "vdd") net->setType ( Net::Type::POWER ); + if (_text.substr(0,3) == "gnd") net->setType ( Net::Type::GROUND ); + if (_text[ _text.size()-1 ] == '!') net->setGlobal( true ); } } } else _skipENDEL = true; - if (not net) net = fusedNet(); + if (layer->isBlockage() and (_flags & Gds::NoBlockages)) + return; + if (not net) net = fusedNet(); + if (points.size() > 2) { bool isRectilinear = true; for ( size_t i=1 ; i LefParser::_layerLut; DbU::Unit LefParser::_coreSiteX = 0; @@ -187,6 +212,10 @@ namespace { { _mergeLibrary = library; } + void LefParser::setGdsForeignDirectory ( string path ) + { _gdsForeignDirectory = path; } + + void LefParser::reset () { _layerLut.clear(); @@ -226,9 +255,13 @@ namespace { LefParser::LefParser ( string file, string libraryName ) : _file (file) , _libraryName (libraryName) - , _library (NULL) - , _cell (NULL) - , _net (NULL) + , _library (nullptr) + , _foreignPath () + , _foreignPosition (Point(0,0)) + , _gdsPower (nullptr) + , _gdsGround (nullptr) + , _cell (nullptr) + , _net (nullptr) , _busBits ("()") , _unitsMicrons (0.01) , _unmatchedLayers () @@ -236,8 +269,8 @@ namespace { , _nthMetal (0) , _nthCut (0) , _nthRouting (0) - , _routingGauge (NULL) - , _cellGauge (NULL) + , _routingGauge (nullptr) + , _cellGauge (nullptr) , _minTerminalWidth(DbU::fromPhysical(Cfg::getParamDouble("lefImport.minTerminalWidth",0.0)->asDouble(),DbU::UnitPower::Micro)) { _routingGauge = AllianceFramework::get()->getRoutingGauge(); @@ -262,13 +295,14 @@ namespace { } lefrInit(); - lefrSetUnitsCbk ( _unitsCbk ); - lefrSetLayerCbk ( _layerCbk ); - lefrSetSiteCbk ( _siteCbk ); - lefrSetObstructionCbk( _obstructionCbk ); - lefrSetMacroCbk ( _macroCbk ); - lefrSetMacroSiteCbk ( _macroSiteCbk ); - lefrSetPinCbk ( _pinCbk ); + lefrSetUnitsCbk ( _unitsCbk ); + lefrSetLayerCbk ( _layerCbk ); + lefrSetSiteCbk ( _siteCbk ); + lefrSetObstructionCbk ( _obstructionCbk ); + lefrSetMacroCbk ( _macroCbk ); + lefrSetMacroSiteCbk ( _macroSiteCbk ); + lefrSetMacroForeignCbk( _macroForeignCbk ); + lefrSetPinCbk ( _pinCbk ); } @@ -458,6 +492,20 @@ namespace { return 0; } + int LefParser::_macroForeignCbk ( lefrCallbackType_e c, const lefiMacroForeign* foreign, lefiUserData ud ) + { + LefParser* parser = (LefParser*)ud; + AllianceFramework* af = AllianceFramework::get(); + + if (_gdsForeignDirectory.empty()) return 0; + + string gdsPath = _gdsForeignDirectory + "/" + foreign->cellName() + ".gds"; + parser->setForeignPath( gdsPath ); + parser->setForeignPosition( Point( parser->fromUnitsMicrons( foreign->px() ) + , parser->fromUnitsMicrons( foreign->px() ))); + + return 0; + } int LefParser::_obstructionCbk ( lefrCallbackType_e c, lefiObstruction* obstruction, lefiUserData ud ) { @@ -550,6 +598,21 @@ namespace { parser->setCell( cell ); } + if (not parser->getForeignPath().empty()) { + Gds::load( parser->getLibrary(), parser->getForeignPath() + , Gds::NoGdsPrefix|Gds::NoBlockages|Gds::Layer_0_IsBoundary); + for ( Net* net : cell->getNets() ) { + if (net->isPower ()) parser->setGdsPower ( net ); + if (net->isGround()) parser->setGdsGround( net ); + if (parser->getForeignPosition() != Point(0,0)) { + for ( Component* component : net->getComponents() ) { + component->translate( parser->getForeignPosition().getX() + , parser->getForeignPosition().getY() ); + } + } + } + } + if (macro->hasSize()) { width = parser->fromUnitsMicrons( macro->sizeX() ); height = parser->fromUnitsMicrons( macro->sizeY() ); @@ -581,7 +644,7 @@ namespace { else parser->_pinPadPostProcess(); parser->clearPinComponents(); - cerr << " - " << cellName + cerr << " o " << cellName << " " << DbU::getValueString(width) << " " << DbU::getValueString(height) << " " << gaugeName; if (isPad) cerr << " (PAD)"; @@ -612,8 +675,38 @@ namespace { if (not parser->getCell()) parser->setCell( Cell::create( parser->getLibrary(true), "LefImportTmpCell" ) ); - Net* net = Net::create( parser->getCell(), pin->name() ); + Net* net = nullptr; + Net::Type netType = Net::Type::UNDEFINED; + if (pin->hasUse()) { + string lefUse = pin->use(); + boost::to_upper( lefUse ); + + if (lefUse == "SIGNAL") netType = Net::Type::LOGICAL; + //if (lefUse == "ANALOG") netType = Net::Type::ANALOG; + if (lefUse == "CLOCK" ) netType = Net::Type::CLOCK; + if (lefUse == "POWER" ) netType = Net::Type::POWER; + if (lefUse == "GROUND") netType = Net::Type::GROUND; + } + + if ((netType == Net::Type::POWER) and parser->getGdsPower()) { + net = parser->getGdsPower(); + cerr << " - Renaming GDS power net \"" << net->getName() << "\"" + << " to LEF name \"" << pin->name() << "\"." << endl; + net->setName( pin->name() ); + parser->setGdsPower( nullptr ); + } else { + if ((netType == Net::Type::GROUND) and parser->getGdsGround()) { + net = parser->getGdsGround(); + cerr << " - Renaming GDS ground net \"" << net->getName() << "\"" + << " to LEF name \"" << pin->name() << "\"." << endl; + net->setName( pin->name() ); + parser->setGdsGround( nullptr ); + } else { + net = Net::create( parser->getCell(), pin->name() ); + } + } net->setExternal( true ); + net->setType ( netType ); if (pin->hasDirection()) { string lefDir = pin->direction(); @@ -624,17 +717,6 @@ namespace { if (lefDir == "OUTPUT TRISTATE") net->setDirection( Net::Direction::TRISTATE ); if (lefDir == "INOUT" ) net->setDirection( Net::Direction::INOUT ); } - - if (pin->hasUse()) { - string lefUse = pin->use(); - boost::to_upper( lefUse ); - - if (lefUse == "SIGNAL") net->setType( Net::Type::LOGICAL ); - //if (lefUse == "ANALOG") net->setType( Net::Type::ANALOG ); - if (lefUse == "CLOCK" ) net->setType( Net::Type::CLOCK ); - if (lefUse == "POWER" ) net->setType( Net::Type::POWER ); - if (lefUse == "GROUND") net->setType( Net::Type::GROUND ); - } if (net->isSupply()) net->setGlobal( true ); if (pin->name()[ strlen(pin->name())-1 ] == '!') net->setGlobal( true ); @@ -1072,4 +1154,12 @@ namespace CRL { } + void LefImport::setGdsForeignDirectory ( string path ) + { +#if defined(HAVE_LEFDEF) + LefParser::setGdsForeignDirectory( path ); +#endif + } + + } // End of CRL namespace. diff --git a/crlcore/src/pyCRL/PyLefImport.cpp b/crlcore/src/pyCRL/PyLefImport.cpp index 623e361c..0986d5db 100644 --- a/crlcore/src/pyCRL/PyLefImport.cpp +++ b/crlcore/src/pyCRL/PyLefImport.cpp @@ -109,19 +109,37 @@ extern "C" { } + static PyObject* PyLefImport_setGdsForeignDirectory ( PyObject*, PyObject* args ) + { + cdebug_log(30,0) << "PyLefImport_setGdsForeignDirectory()" << endl; + HTRY + char* path = NULL; + if (PyArg_ParseTuple( args, "s:LefImport.setGdsForeignDirectory", &path )) { + LefImport::setGdsForeignDirectory( path ); + } else { + PyErr_SetString ( ConstructorError, "LefImport.setGdsForeignDirectory(): Bad type or bad number of parameters." ); + return NULL; + } + HCATCH + Py_RETURN_NONE; + } + + // Standart Destroy (Attribute). PyMethodDef PyLefImport_Methods[] = - { { "load" , (PyCFunction)PyLefImport_load , METH_VARARGS|METH_STATIC - , "Load a complete Cadence LEF library." } - , { "reset" , (PyCFunction)PyLefImport_reset , METH_NOARGS|METH_STATIC - , "Reset the Cadence LEF parser (clear technology)." } - , { "setMergeLibrary" , (PyCFunction)PyLefImport_setMergeLibrary, METH_VARARGS|METH_STATIC - , "Merge into this library instead of creating a new one." } - //, { "destroy" , (PyCFunction)PyLefImport_destroy , METH_VARARGS - // , "Destroy the associated hurricane object. The python object remains." } - , {NULL, NULL, 0, NULL} /* sentinel */ + { { "load" , (PyCFunction)PyLefImport_load , METH_VARARGS|METH_STATIC + , "Load a complete Cadence LEF library." } + , { "reset" , (PyCFunction)PyLefImport_reset , METH_NOARGS|METH_STATIC + , "Reset the Cadence LEF parser (clear technology)." } + , { "setMergeLibrary" , (PyCFunction)PyLefImport_setMergeLibrary , METH_VARARGS|METH_STATIC + , "Merge into this library instead of creating a new one." } + , { "setGdsForeignDirectory", (PyCFunction)PyLefImport_setGdsForeignDirectory, METH_VARARGS|METH_STATIC + , "Set the directory where to find FOREIGN GDS files." } + //, { "destroy" , (PyCFunction)PyLefImport_destroy , METH_VARARGS + // , "Destroy the associated hurricane object. The python object remains." } + , {NULL, NULL, 0, NULL} /* sentinel */ };