Improvements & bugs corrections in the LEF/DEF importer/exporter.
* Bug: In Hurricane, In NetAlias::removeAlias(), perform the isMaster() check on the *current* hook, not the *this* one... Was preventing the removal of most aliases. * New: In CRL Core, in DefExport, perform a virtual flatten before exporting a design. Replace the hard-wired "sxlib" gauge by the current default one. More secure management of flattened instance and net names (removal of all potentially special characters). In net names, correct management of vectorized names (do not systematically add "_net" at the end). In DefImport, manage the BUSBITS property and revectorize accordingly the net names. When loading nets, systematically remove the alias of the temporary net "__prebuild__" (a bug in NetAlias was preventing it). In LefExport, the right value of MANUFACTURINGGRID in pseudo symbolic mode is 0.5 (expressed in lamba). That way all length are even multiples of it. Note that there is still the order bug of the 5.7 drivers that puts that entry *before* UNITS in the LEF file (bad bad Cadence).
This commit is contained in:
parent
25ba4ad3d4
commit
fcb4acadad
|
@ -26,6 +26,7 @@
|
|||
#include "hurricane/Technology.h"
|
||||
#include "hurricane/Net.h"
|
||||
#include "hurricane/NetExternalComponents.h"
|
||||
#include "hurricane/RoutingPad.h"
|
||||
#include "hurricane/Horizontal.h"
|
||||
#include "hurricane/Vertical.h"
|
||||
#include "hurricane/Cell.h"
|
||||
|
@ -36,6 +37,7 @@
|
|||
#include "crlcore/RoutingGauge.h"
|
||||
#include "crlcore/RoutingLayerGauge.h"
|
||||
#include "crlcore/AllianceFramework.h"
|
||||
#include "crlcore/CellGauge.h"
|
||||
#include "crlcore/LefExport.h"
|
||||
#include "crlcore/DefExport.h"
|
||||
|
||||
|
@ -63,6 +65,39 @@ namespace {
|
|||
}
|
||||
|
||||
|
||||
string toDefName ( string name )
|
||||
{
|
||||
if (name.empty()) return name;
|
||||
|
||||
if (name[0] == '<') name.erase ( 0, 1 );
|
||||
if (name[name.size()-1] == '>') name.erase ( name.size()-1 );
|
||||
for ( size_t i=0 ; i<name.size() ; ++i ) {
|
||||
switch ( name[i] ) {
|
||||
case ':':
|
||||
case '.': name[i] = '_'; break;
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
string extractInstanceName ( const RoutingPad* rp )
|
||||
{
|
||||
ostringstream name;
|
||||
|
||||
Occurrence occurrence = rp->getOccurrence();
|
||||
|
||||
name << getString(occurrence.getOwnerCell()->getName()) << '.';
|
||||
|
||||
if (not rp->getOccurrence().getPath().getHeadPath().isEmpty())
|
||||
name << getString(rp->getOccurrence().getPath().getHeadPath().getName()) << ".";
|
||||
|
||||
name << "I." << getString(rp->getOccurrence().getPath().getTailInstance()->getName());
|
||||
|
||||
return toDefName(name.str());
|
||||
}
|
||||
|
||||
|
||||
#define CHECK_STATUS_CBK(status) if ((status) != 0) return driver->checkStatus(status);
|
||||
#define CHECK_STATUS_DRV(status) if ((status) != 0) return checkStatus(status);
|
||||
#define RETURN_CHECK_STATUS_CBK(status) return driver->checkStatus(status);
|
||||
|
@ -75,7 +110,7 @@ namespace {
|
|||
static int getUnits ();
|
||||
static int toDefUnits ( DbU::Unit );
|
||||
static int toDefOrient ( Transformation::Orientation );
|
||||
static void toDefCoordinates ( Instance*, int& statusX, int& statusY, int& statusOrient );
|
||||
static void toDefCoordinates ( Instance*, Transformation, int& statusX, int& statusY, int& statusOrient );
|
||||
static DbU::Unit getSliceHeight ();
|
||||
static DbU::Unit getPitchWidth ();
|
||||
~DefDriver ();
|
||||
|
@ -155,9 +190,9 @@ namespace {
|
|||
}
|
||||
|
||||
|
||||
void DefDriver::toDefCoordinates ( Instance* instance, int& statusX, int& statusY, int& statusOrient )
|
||||
void DefDriver::toDefCoordinates ( Instance* instance, Transformation transf, int& statusX, int& statusY, int& statusOrient )
|
||||
{
|
||||
const Transformation& transf = instance->getTransformation();
|
||||
instance->getTransformation().applyOn( transf );
|
||||
statusX = toDefUnits ( transf.getTx() );
|
||||
statusY = toDefUnits ( transf.getTy() );
|
||||
statusOrient = toDefOrient( transf.getOrientation() );
|
||||
|
@ -192,8 +227,11 @@ namespace {
|
|||
, _flags (flags)
|
||||
, _status (0)
|
||||
{
|
||||
_sliceHeight = DbU::lambda(50.0);
|
||||
_pitchWidth = DbU::lambda( 5.0);
|
||||
AllianceFramework* framework = AllianceFramework::get ();
|
||||
CellGauge* cg = framework->getCellGauge();
|
||||
|
||||
_sliceHeight = cg->getSliceHeight ();
|
||||
_pitchWidth = cg->getPitch ();
|
||||
|
||||
_status = defwInitCbk ( _defStream );
|
||||
if ( _status != 0 ) return;
|
||||
|
@ -230,6 +268,7 @@ namespace {
|
|||
|
||||
int DefDriver::write ()
|
||||
{
|
||||
_cell->flattenNets( Cell::Flags::NoFlags );
|
||||
return checkStatus ( defwWrite(_defStream,_designName.c_str(),(void*)this) );
|
||||
}
|
||||
|
||||
|
@ -238,7 +277,9 @@ namespace {
|
|||
{
|
||||
if ( (_status=status) != 0 ) {
|
||||
defwPrintError ( _status );
|
||||
cerr << Error("DefDriver::drive(): Error occured while driving <%s>.",_designName.c_str()) << endl;
|
||||
ostringstream message;
|
||||
message << "DefDriver::drive(): Error occured while driving <" << _designName << ">.";
|
||||
cerr << Error(message.str()) << endl;
|
||||
}
|
||||
return _status;
|
||||
}
|
||||
|
@ -346,6 +387,8 @@ namespace {
|
|||
Cell* cell = driver->getCell();
|
||||
Box abutmentBox ( cell->getAbutmentBox() );
|
||||
|
||||
if (abutmentBox.isEmpty()) return 0;
|
||||
|
||||
int origY = (int)( toDefUnits(abutmentBox.getYMin()) );
|
||||
int origX = (int)( toDefUnits(abutmentBox.getXMin()) );
|
||||
int stepY = (int)( toDefUnits(DefDriver::getSliceHeight()) );
|
||||
|
@ -390,6 +433,8 @@ namespace {
|
|||
Cell* cell = driver->getCell();
|
||||
Box abutmentBox ( cell->getAbutmentBox() );
|
||||
|
||||
if (abutmentBox.isEmpty()) return 0;
|
||||
|
||||
const vector<RoutingLayerGauge*>& rg
|
||||
= AllianceFramework::get()->getRoutingGauge()->getLayerGauges();
|
||||
|
||||
|
@ -487,27 +532,33 @@ namespace {
|
|||
status = defwNewLine ();
|
||||
CHECK_STATUS_CBK(status);
|
||||
|
||||
status = defwStartComponents ( cell->getInstances().getSize() );
|
||||
status = defwStartComponents ( cell->getLeafInstanceOccurrences().getSize() );
|
||||
CHECK_STATUS_CBK(status);
|
||||
|
||||
forEach ( Instance*, iinstance, cell->getInstances() ) {
|
||||
string insname = getString((*iinstance)->getName());
|
||||
for ( Occurrence occurrence : cell->getLeafInstanceOccurrences() ) {
|
||||
Instance* instance = static_cast<Instance*>(occurrence.getEntity());
|
||||
string insname = toDefName(occurrence.getCompactString());
|
||||
const char* source = NULL;
|
||||
const char* statusS = "UNPLACED";
|
||||
int statusX = 0;
|
||||
int statusY = 0;
|
||||
int statusOrient = 0;
|
||||
|
||||
if (CatalogExtension::isFeed((*iinstance)->getMasterCell())) source = "DIST";
|
||||
Box instanceAb = instance->getMasterCell()->getAbutmentBox();
|
||||
Transformation instanceTransf = instance->getTransformation();
|
||||
occurrence.getPath().getTransformation().applyOn( instanceTransf );
|
||||
instanceTransf.applyOn( instanceAb );
|
||||
|
||||
if ((*iinstance)->getPlacementStatus() == Instance::PlacementStatus::PLACED) statusS = "PLACED";
|
||||
if ((*iinstance)->getPlacementStatus() == Instance::PlacementStatus::FIXED ) statusS = "FIXED";
|
||||
if (CatalogExtension::isFeed(instance->getMasterCell())) source = "DIST";
|
||||
|
||||
if (instance->getPlacementStatus() == Instance::PlacementStatus::PLACED) statusS = "PLACED";
|
||||
if (instance->getPlacementStatus() == Instance::PlacementStatus::FIXED ) statusS = "FIXED";
|
||||
if (statusS[0] != 'U') {
|
||||
toDefCoordinates( *iinstance, statusX, statusY, statusOrient );
|
||||
toDefCoordinates( instance, occurrence.getPath().getTransformation(), statusX, statusY, statusOrient );
|
||||
}
|
||||
|
||||
status = defwComponent ( insname.c_str()
|
||||
, getString((*iinstance)->getMasterCell()->getName()).c_str()
|
||||
, getString((instance)->getMasterCell()->getName()).c_str()
|
||||
, 0 // numNetNames (disabled).
|
||||
, NULL // netNames (disabled).
|
||||
, NULL // eeq (electrical equivalence).
|
||||
|
@ -541,24 +592,30 @@ namespace {
|
|||
Cell* cell = driver->getCell();
|
||||
int netsNb = 0;
|
||||
|
||||
forEach ( Net*, inet, cell->getNets() ) {
|
||||
if ( (*inet)->isSupply() or (*inet)->isClock() ) continue;
|
||||
for ( Net* net : cell->getNets() ) {
|
||||
if ( net->isSupply() or net->isClock() ) continue;
|
||||
++netsNb;
|
||||
}
|
||||
|
||||
status = defwStartNets ( netsNb );
|
||||
if ( status != 0 ) return driver->checkStatus(status);
|
||||
|
||||
forEach ( Net*, inet, cell->getNets() ) {
|
||||
if ( (*inet)->isSupply() or (*inet)->isClock() ) continue;
|
||||
for ( Net* net : cell->getNets() ) {
|
||||
if ( net->isSupply() or net->isClock() ) continue;
|
||||
|
||||
size_t pos = string::npos;
|
||||
string netName = getString( net->getName() );
|
||||
if (netName[netName.size()-1] == ')') pos = netName.rfind('(');
|
||||
if (pos == string::npos) pos = netName.size();
|
||||
netName.insert( pos, "_net" );
|
||||
netName = toDefName( netName );
|
||||
|
||||
string netName = getString((*inet)->getName()) + "_net";
|
||||
status = defwNet ( netName.c_str() );
|
||||
if ( status != 0 ) return driver->checkStatus(status);
|
||||
|
||||
forEach ( Plug*, iplug, (*inet)->getPlugs() ) {
|
||||
status = defwNetConnection ( getString((*iplug)->getInstance ()->getName()).c_str()
|
||||
, getString((*iplug)->getMasterNet()->getName()).c_str()
|
||||
for ( RoutingPad* rp : net->getRoutingPads() ) {
|
||||
status = defwNetConnection ( extractInstanceName(rp).c_str()
|
||||
, getString(static_cast<Plug*>(rp->getPlugOccurrence().getEntity())->getMasterNet()->getName()).c_str()
|
||||
, 0
|
||||
);
|
||||
if ( status != 0 ) return driver->checkStatus(status);
|
||||
|
|
|
@ -83,7 +83,8 @@ namespace {
|
|||
inline size_t getPitchs () const;
|
||||
inline size_t getSlices () const;
|
||||
inline const Box& getFitOnCellsDieArea () const;
|
||||
inline Net* getPrebuildNet () const;
|
||||
inline Net* getPrebuildNet () const;
|
||||
inline string getBusBits () const;
|
||||
Net* lookupNet ( const string& );
|
||||
inline vector<string>& getErrors ();
|
||||
inline void pushError ( const string& );
|
||||
|
@ -91,10 +92,13 @@ namespace {
|
|||
inline void clearErrors ();
|
||||
inline void setPitchs ( size_t );
|
||||
inline void setSlices ( size_t );
|
||||
inline void setPrebuildNet ( Net* );
|
||||
inline void setPrebuildNet ( Net* );
|
||||
inline void setBusBits ( string );
|
||||
void addNetLookup ( const string& netName, Net* );
|
||||
void toHurricaneName ( string& );
|
||||
inline void mergeToFitOnCellsDieArea ( const Box& );
|
||||
private:
|
||||
static int _busBitCbk ( defrCallbackType_e, const char* , defiUserData );
|
||||
static int _designEndCbk ( defrCallbackType_e, void* , defiUserData );
|
||||
static int _dieAreaCbk ( defrCallbackType_e, defiBox* , defiUserData );
|
||||
static int _pinCbk ( defrCallbackType_e, defiPin* , defiUserData );
|
||||
|
@ -110,6 +114,7 @@ namespace {
|
|||
string _file;
|
||||
unsigned int _flags;
|
||||
AllianceLibrary* _library;
|
||||
string _busBits;
|
||||
Cell* _cell;
|
||||
size_t _pitchs;
|
||||
size_t _slices;
|
||||
|
@ -128,6 +133,7 @@ namespace {
|
|||
: _file (file)
|
||||
, _flags (flags)
|
||||
, _library (library)
|
||||
, _busBits ("()")
|
||||
, _cell (NULL)
|
||||
, _pitchs (0)
|
||||
, _slices (0)
|
||||
|
@ -137,6 +143,7 @@ namespace {
|
|||
, _errors ()
|
||||
{
|
||||
defrInit ();
|
||||
defrSetBusBitCbk ( _busBitCbk );
|
||||
defrSetDesignEndCbk ( _designEndCbk );
|
||||
defrSetDieAreaCbk ( _dieAreaCbk );
|
||||
defrSetPinCbk ( _pinCbk );
|
||||
|
@ -158,6 +165,7 @@ namespace {
|
|||
inline DbU::Unit DefParser::fromDefUnits ( int u ) { return DbU::lambda(_defUnits*(double)u); }
|
||||
inline bool DefParser::hasErrors () { return not _errors.empty(); }
|
||||
inline unsigned int DefParser::getFlags () const { return _flags; }
|
||||
inline string DefParser::getBusBits () const { return _busBits; }
|
||||
inline AllianceLibrary* DefParser::getLibrary () { return _library; }
|
||||
inline Cell* DefParser::getCell () { return _cell; }
|
||||
inline size_t DefParser::getPitchs () const { return _pitchs; }
|
||||
|
@ -170,6 +178,7 @@ namespace {
|
|||
inline void DefParser::setPitchs ( size_t pitchs ) { _pitchs=pitchs; }
|
||||
inline void DefParser::setSlices ( size_t slices ) { _slices=slices; }
|
||||
inline void DefParser::setPrebuildNet ( Net* net ) { _prebuildNet=net; }
|
||||
inline void DefParser::setBusBits ( string busbits ) { _busBits = busbits; }
|
||||
inline void DefParser::mergeToFitOnCellsDieArea ( const Box& box ) { _fitOnCellsDieArea.merge(box); }
|
||||
|
||||
|
||||
|
@ -192,6 +201,20 @@ namespace {
|
|||
}
|
||||
|
||||
|
||||
void DefParser::toHurricaneName ( string& defName )
|
||||
{
|
||||
if (_busBits != "()") {
|
||||
if (defName[defName.size()-1] == _busBits[1]) {
|
||||
size_t pos = defName.rfind( _busBits[0] );
|
||||
if (pos != string::npos) {
|
||||
defName[pos] = '(';
|
||||
defName[defName.size()-1] = ')';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Transformation DefParser::getTransformation ( const Box& abox
|
||||
, DbU::Unit x
|
||||
, DbU::Unit y
|
||||
|
@ -250,6 +273,22 @@ namespace {
|
|||
}
|
||||
|
||||
|
||||
int DefParser::_busBitCbk ( defrCallbackType_e c, const char* busbits, lefiUserData ud )
|
||||
{
|
||||
DefParser* parser = (DefParser*)ud;
|
||||
|
||||
if (strlen(busbits) == 2) {
|
||||
parser->setBusBits( busbits );
|
||||
} else {
|
||||
ostringstream message;
|
||||
message << "BUSBITCHARS is not two character long (" << busbits << ")";
|
||||
parser->pushError( message.str() );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int DefParser::_designEndCbk ( defrCallbackType_e c, void*, lefiUserData ud )
|
||||
{
|
||||
DefParser* parser = (DefParser*)ud;
|
||||
|
@ -283,11 +322,14 @@ namespace {
|
|||
|
||||
//cout << " - Pin " << pin->pinName() << ":" << pin->netName() << endl;
|
||||
|
||||
Net* hnet = parser->getCell()->getNet ( pin->netName() );
|
||||
string netName = pin->netName();
|
||||
parser->toHurricaneName( netName );
|
||||
|
||||
Net* hnet = parser->getCell()->getNet ( netName );
|
||||
if ( hnet == NULL ) {
|
||||
hnet = Net::create ( parser->getCell(), pin->netName() );
|
||||
parser->addNetLookup ( pin->netName(), hnet );
|
||||
if ( string(pin->netName()).compare(pin->pinName()) != 0 )
|
||||
hnet = Net::create ( parser->getCell(), netName );
|
||||
parser->addNetLookup ( netName, hnet );
|
||||
if ( netName.compare(pin->pinName()) != 0 )
|
||||
parser->addNetLookup ( pin->pinName(), hnet );
|
||||
}
|
||||
|
||||
|
@ -351,19 +393,33 @@ namespace {
|
|||
DefParser* parser = (DefParser*)ud;
|
||||
|
||||
//cout << " - Net " << net->name() << endl;
|
||||
|
||||
string name = net->name();
|
||||
parser->toHurricaneName( name );
|
||||
|
||||
Net* hnet = parser->lookupNet ( net->name() );
|
||||
Net* hnet = parser->lookupNet ( name );
|
||||
if ( hnet == NULL )
|
||||
hnet = Net::create ( parser->getCell(), net->name() );
|
||||
hnet = Net::create ( parser->getCell(), name );
|
||||
|
||||
if ( parser->getPrebuildNet() != NULL ) {
|
||||
Name prebuildAlias = parser->getPrebuildNet()->getName();
|
||||
hnet->merge ( parser->getPrebuildNet() );
|
||||
hnet->removeAlias ( prebuildAlias );
|
||||
parser->setPrebuildNet ( NULL );
|
||||
}
|
||||
|
||||
if (name.size() > 78) {
|
||||
name.erase ( 0, name.size()-75 );
|
||||
name.insert( 0, 3, '.' );
|
||||
}
|
||||
name.insert( 0, "<" );
|
||||
name.insert( name.size(), ">" );
|
||||
if (name.size() < 80) name.insert( name.size(), 80-name.size(), ' ' );
|
||||
|
||||
if (tty::enabled()) {
|
||||
cmess2 << " " << tty::bold << setw(7) << setfill('0') << ++netCount << ":" << setfill(' ')
|
||||
<< tty::reset << setw(40) << "<" << net->name() << "> " << tty::cr;
|
||||
cmess2 << " "
|
||||
<< tty::bold << setw(7) << setfill('0') << ++netCount << ":" << setfill(' ')
|
||||
<< tty::reset << setw(80) << name << tty::cr;
|
||||
cmess2.flush ();
|
||||
}
|
||||
|
||||
|
@ -374,6 +430,7 @@ namespace {
|
|||
|
||||
// Connect to an external pin.
|
||||
if ( instanceName.compare("PIN") == 0 ) continue;
|
||||
parser->toHurricaneName( pinName );
|
||||
|
||||
Instance* instance = parser->getCell()->getInstance ( instanceName );
|
||||
if ( instance == NULL ) {
|
||||
|
@ -402,6 +459,7 @@ namespace {
|
|||
int DefParser::_netEndCbk ( defrCallbackType_e c, void*, lefiUserData ud )
|
||||
{
|
||||
DefParser* parser = (DefParser*)ud;
|
||||
if (tty::enabled()) cmess2 << endl;
|
||||
return parser->flushErrors ();
|
||||
}
|
||||
|
||||
|
|
|
@ -580,7 +580,7 @@ namespace {
|
|||
// The driver puts it before UNITS, which seems to displease Cadence Encounter.
|
||||
// So, as long as it doesn't prevent Encounter to works, disable it.
|
||||
LefDriver* driver = (LefDriver*)udata;
|
||||
return driver->checkStatus ( lefwManufacturingGrid ( LefDriver::getUnits()/10.0 ) );
|
||||
return driver->checkStatus ( lefwManufacturingGrid ( LefDriver::toLefUnits(DbU::fromLambda(0.5)) ) );
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
|
@ -724,8 +724,9 @@ namespace CRL {
|
|||
if ( cell != NULL ) {
|
||||
libraryName = getString(cell->getName()) + "_export";
|
||||
|
||||
forEach ( Instance*, iinstance, cell->getInstances() ) {
|
||||
cells.insert ( (*iinstance)->getMasterCell() );
|
||||
for ( Occurrence occurrence : cell->getLeafInstanceOccurrences() ) {
|
||||
Instance* instance = static_cast<Instance*>(occurrence.getEntity());
|
||||
cells.insert ( instance->getMasterCell() );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -59,8 +59,9 @@ namespace Hurricane {
|
|||
{
|
||||
const NetAliasHook* current = this;
|
||||
do {
|
||||
if ( not isMaster() and (current->getName() == name) )
|
||||
if ( not current->isMaster() and (current->getName() == name) ) {
|
||||
return const_cast<NetAliasName*>( dynamic_cast<const NetAliasName*>(current) );
|
||||
}
|
||||
|
||||
current = current->_next;
|
||||
} while ( current != this );
|
||||
|
|
Loading…
Reference in New Issue