Better handling of GDS sub-models, now put into separate library.

In order to better handle colliding cell names coming from multiple
GDS files, now, if a topCell is defined, create a sub-library with
the name of that top cell and put any other model from *that* GDS
file into it. This way, only the top cell will be shown in the
library and sub-cells with common names will be separateds.
Work needed for loading GF180MCU I/O pads.

* New: In Gds::setTopCellname(), specify the name of the top cell
    we specifically wants to load from the GDS file.
* New: In GdsStream::getCell(), function to find/create a Cell in
    the current library and, if any, the "top cell" dedicated
    sub-library.
* Change: In GdsStream::readTextBody(), if the layer material of
    the label is "other", do not create a Net with the name of
    the label. This should be a pure text label. Use the new
    Hurricane::Text Go for that.
      Compute the text box in a approximative way. Have to make
    it smarter in the future.
* Change: In LefImport::_macroForeignCbk(), change of policy for
    loading associated GDS. First, we look if a cell with the
    right name exists, in which case we use it. If not, *only*
    then, do we try to load from GDS.
      This allows to load by ourselves, in a separate way the
    GDS. This is more flexible when there are naming issues.
* New: Hurricane::Text Go class, to display text label without the
    need of a Net.
* New: In Hurricane::CellWidget, add support to display
    Hurricane::Text. Add a new mode to drawDisplayText() : FillBox
    so the text is resized to exactly fill the box it is in
    (in width).
This commit is contained in:
Jean-Paul Chaput 2023-08-31 16:12:56 +02:00
parent 9846330b91
commit c21afeef8b
10 changed files with 463 additions and 111 deletions

View File

@ -34,10 +34,17 @@ namespace CRL {
static const uint32_t NoGdsPrefix = (1<<0);
static const uint32_t Layer_0_IsBoundary = (1<<1);
static const uint32_t NoBlockages = (1<<2);
static std::string _topCellName;
public:
static bool save ( Cell* );
static bool load ( Library*, std::string gdsPath, uint32_t flags=0 );
inline static void setTopCellName ( std::string );
inline static std::string getTopCellName ();
};
inline void Gds::setTopCellName ( std::string topCellName ) { _topCellName=topCellName; }
inline std::string Gds::getTopCellName () { return _topCellName; }
} // CRL namespace.

View File

@ -37,6 +37,7 @@ using namespace std;
#include "hurricane/Diagonal.h"
#include "hurricane/Rectilinear.h"
#include "hurricane/Pad.h"
#include "hurricane/Text.h"
#include "hurricane/Net.h"
#include "hurricane/Cell.h"
#include "hurricane/Library.h"
@ -649,6 +650,7 @@ namespace {
public:
static void _staticInit ();
GdsStream ( string gdsPath, uint32_t flags );
Cell* getCell ( string cellName, bool create=false );
inline bool useGdsPrefix () const;
inline bool useLayer0AsBoundary () const;
inline bool isValidSyntax () const;
@ -800,6 +802,34 @@ namespace {
}
Cell* GdsStream::getCell ( string cellName, bool create )
{
if (not _library) return nullptr;
Library* workLibrary = _library;
Cell* cell = workLibrary->getCell( cellName );
if (cell) return cell;
if (not Gds::getTopCellName().empty() and (cellName != Gds::getTopCellName())) {
workLibrary = _library->getLibrary( Gds::getTopCellName() );
if (workLibrary) {
cell = workLibrary->getCell( cellName );
if (cell) return cell;
} else {
if (not create) return nullptr;
workLibrary = Library::create( _library, Gds::getTopCellName() );
}
}
if (not create) return nullptr;
cparanoid << Warning( "GdsStream::readStructure(): No Cell named \"%s\" in Library \"%s\" (created)."
, cellName.c_str()
, getString(_library).c_str()
) << endl;
return Cell::create( workLibrary, cellName );
}
bool GdsStream::misplacedRecord ()
{
cerr << Error( "GdsStream: Misplaced record %s.\n"
@ -900,18 +930,10 @@ namespace {
if (_record.isSTRNAME()) {
if (_library) {
string cellName = _record.getName();
if (useGdsPrefix()) cellName.insert( 0, "gds_" );
_cell = _library->getCell( cellName );
if (not _cell) {
cparanoid << Warning( "GdsStream::readStructure(): No Cell named \"%s\" in Library \"%s\" (created)."
, cellName.c_str()
, getString(_library).c_str()
) << endl;
_cell = Cell::create( _library, cellName );
}
}
_cell = getCell( cellName, true );
_stream >> _record;
}
}
if (_record.isSTRCLASS()) { _stream >> _record; }
@ -1075,6 +1097,7 @@ namespace {
}
if (not _text.empty()) {
if (static_cast<const BasicLayer*>(layer)->getMaterial() != BasicLayer::Material::other) {
Net* net = _cell->getNet( _text );
if (not net) {
net = Net::create( _cell, _text );
@ -1084,6 +1107,15 @@ namespace {
if (_text[ _text.size()-1 ] == '!') net->setGlobal( true );
}
addNetReference( net, layer, xpos, ypos );
} else {
DbU::Unit textHeight = _scale * 500;
DbU::Unit textWidth = _scale * 500 * _text.size();
Text::create( _cell, layer, Box( xpos
, ypos
, xpos + textWidth
, ypos + textHeight
), _text );
}
}
cdebug_log(101,-1) << "GdsStream::readTextbody() - return:" << _validSyntax << endl;
@ -1260,7 +1292,6 @@ namespace {
// << " XR:" << _xReflection << " angle:" << _angle
// << " " << Transformation(xpos,ypos,orient)
// << " in " << _cell << endl;
if (useGdsPrefix()) masterName.insert( 0, "gds_" );
_delayedInstances.push_back( DelayedInstance( _cell
, masterName
, Transformation(xpos,ypos,orient)) );
@ -1698,7 +1729,7 @@ namespace {
cdebug_log(101,1) << "GdsStream::makeInstances(): " << endl;
for ( const DelayedInstance& di : _delayedInstances ) {
Cell* masterCell = _library->getCell( di._masterName );
Cell* masterCell = getCell( di._masterName );
if (masterCell) {
string insName = "sref_" + getString(_SREFCount++);
@ -1710,6 +1741,9 @@ namespace {
, Instance::PlacementStatus::FIXED
);
cdebug_log(101,0) << "| " << instance << " @" << di._transformation << " in " << di._owner << endl;
} else {
cerr << Error( "GdsStream::makeInstances(): Delayed sub-model (STRUCTURE) \"%s\" not found."
, di._masterName.c_str() ) << endl;
}
}
cdebug_tabw(101,-1);
@ -1840,6 +1874,10 @@ namespace CRL {
// -------------------------------------------------------------------
// Class : "CRL::Gds".
std::string Gds::_topCellName = "";
bool Gds::load ( Library* library, string gdsPath, uint32_t flags )
{
//DebugSession::open( 101, 110 );
@ -1856,6 +1894,7 @@ namespace CRL {
Contact::enableCheckMinSize();
UpdateSession::close();
Gds::setTopCellName( "" );
//DebugSession::close();
return true;

View File

@ -357,6 +357,8 @@ namespace {
if (not _cell) {
if (name.empty())
name = "EarlyLEFCell";
_cell = getLibrary(true)->getCell( name );
if (not _cell)
_cell = Cell::create( getLibrary(true), name );
}
return _cell;
@ -533,6 +535,9 @@ namespace {
{
LefParser* parser = (LefParser*)ud;
Cell* cell = parser->earlyGetCell( foreign->cellName() );
if (cell->getName() == "EarlyLEFCell") {
if (_gdsForeignDirectory.empty()) {
cerr << Warning( "LefParser::_macroForeignCbk(): GDS directory *not* set, ignoring FOREIGN statement." ) << endl;
return 0;
@ -540,13 +545,15 @@ namespace {
string gdsPath = _gdsForeignDirectory + "/" + foreign->cellName() + ".gds";
parser->setForeignPath( gdsPath );
Gds::setTopCellName( foreign->cellName() );
Gds::load( parser->getLibrary(), parser->getForeignPath()
, Gds::NoBlockages|Gds::Layer_0_IsBoundary);
}
parser->setForeignPosition( Point( parser->fromUnitsMicrons( foreign->px() )
, parser->fromUnitsMicrons( foreign->px() )));
Cell* cell = parser->earlyGetCell( foreign->cellName() );
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 );

View File

@ -63,7 +63,6 @@ extern "C" {
static PyObject* PyGds_save ( PyObject*, PyObject* args )
{
cdebug_log(30,0) << "PyGds_save()" << endl;
HTRY
PyObject* pyCell = NULL;
if (PyArg_ParseTuple( args, "O:Gds.save", &pyCell )) {
@ -78,7 +77,6 @@ extern "C" {
return NULL;
}
HCATCH
Py_RETURN_NONE;
}
@ -86,10 +84,8 @@ extern "C" {
static PyObject* PyGds_load ( PyObject*, PyObject* args )
{
cdebug_log(30,0) << "PyGds_load()" << endl;
char* path = NULL;
uint32_t flags = 0;
HTRY
PyObject* pyLibrary = NULL;
if (PyArg_ParseTuple( args, "Os|I:Gds.load", &pyLibrary, &path, &flags )) {
@ -104,7 +100,23 @@ extern "C" {
return NULL;
}
HCATCH
Py_RETURN_NONE;
}
static PyObject* PyGds_setTopCellName ( PyObject*, PyObject* args )
{
cdebug_log(30,0) << "PyGds_setTopCellName()" << endl;
char* topCellName = NULL;
HTRY
PyObject* pyLibrary = NULL;
if (PyArg_ParseTuple( args, "s:Gds.setTopCellName", &topCellName )) {
Gds::setTopCellName( string(topCellName) );
} else {
PyErr_SetString( ConstructorError, "Gds.setTopCellName(): Takes *one* str argument only." );
return NULL;
}
HCATCH
Py_RETURN_NONE;
}
@ -117,6 +129,8 @@ extern "C" {
, "Save a complete Gds design." }
, { "load" , (PyCFunction)PyGds_load , METH_VARARGS|METH_STATIC
, "Load a Gds layout inside a Cell (cumulative)." }
, { "setTopCellName" , (PyCFunction)PyGds_setTopCellName, METH_VARARGS|METH_STATIC
, "The name of the main cell from the GDS (not to be renamed)." }
, {NULL, NULL, 0, NULL} /* sentinel */
};
@ -140,6 +154,7 @@ extern "C" {
{
PyObject* constant;
LoadObjectConstant(PyTypeGds.tp_dict,Gds::NoGdsPrefix ,"NoGdsPrefix");
LoadObjectConstant(PyTypeGds.tp_dict,Gds::NoBlockages ,"NoBlockages");
LoadObjectConstant(PyTypeGds.tp_dict,Gds::Layer_0_IsBoundary,"Layer_0_IsBoundary");
}

View File

@ -44,6 +44,7 @@
hurricane/Filter.h
hurricane/Go.h hurricane/Gos.h
hurricane/ExtensionGo.h hurricane/ExtensionGos.h
hurricane/Text.h
hurricane/Hook.h hurricane/Hooks.h
hurricane/Horizontal.h hurricane/Horizontals.h
hurricane/HyperNet.h
@ -163,6 +164,7 @@
DeepNet.cpp
HyperNet.cpp
Go.cpp
Text.cpp
ExtensionGo.cpp
Hook.cpp
Instance.cpp

View File

@ -204,7 +204,7 @@ Instance::Instance(Cell* cell, const Name& name, Cell* masterCell, const Transfo
throw Error("Instance::Instance(): Can't create " + _TName("Instance") + ", empty name");
if (_cell->getInstance(_name))
throw Error("Instance::Instance(): Can't create " + _TName("Instance") + " " + getString(_name) + ", already exists");
throw Error("Instance::Instance(): Can't create " + _TName("Instance") + " " + getString(_name) + ", already exists in " + getString(cell) );
if (!_masterCell)
throw Error("Instance::Instance(): Can't create " + _TName("Instance") + ", NULL master cell");

View File

@ -0,0 +1,169 @@
// -*- C++ -*-
//
// Copyright (c) BULL S.A. 2018-2018, All Rights Reserved
//
// This file is part of Hurricane.
//
// Hurricane is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// Hurricane is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN-
// TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU
// General Public License for more details.
//
// You should have received a copy of the Lesser GNU General Public
// License along with Hurricane. If not, see
// <http://www.gnu.org/licenses/>.
//
// +-----------------------------------------------------------------+
// | H U R R I C A N E |
// | V L S I B a c k e n d D a t a - B a s e |
// | |
// | Authors : Jean-Paul Chaput |
// | E-mail : Jean-Paul.Chaput@lip6.fr |
// | =============================================================== |
// | C++ Module : "./Text.cpp" |
// +-----------------------------------------------------------------+
#include "hurricane/DataBase.h"
#include "hurricane/Technology.h"
#include "hurricane/Slice.h"
#include "hurricane/Text.h"
#include "hurricane/Net.h"
#include "hurricane/BasicLayer.h"
#include "hurricane/Layer.h"
#include "hurricane/Cell.h"
#include "hurricane/Error.h"
#include "hurricane/Warning.h"
namespace Hurricane {
// -------------------------------------------------------------------
// Class : "Text".
Text::Text ( Cell* cell, const Layer* layer, const Box& boundingBox, std::string text )
: Super ()
, _cell (cell)
, _layer (layer)
, _boundingBox(boundingBox)
, _text (text)
{ }
Text* Text::create ( Cell* cell, const Layer* layer, const Box& boundingBox, std::string text )
{
if (not layer)
throw Error( "Text::create(): Can't create, NULL layer" );
Text* goText = new Text ( cell, layer, boundingBox, text );
goText->_postCreate();
return goText;
}
Cell* Text::getCell () const { return _cell; }
const Layer* Text::getLayer () const { return _layer; }
DbU::Unit Text::getX () const { return getBoundingBox().getCenter().getX(); }
DbU::Unit Text::getY () const { return getBoundingBox().getCenter().getY(); }
Box Text::getBoundingBox() const
{ return _boundingBox; }
Box Text::getBoundingBox ( const BasicLayer* basicLayer ) const
{
if (not _layer->contains(basicLayer)) return Box();
return getBoundingBox();
}
void Text::translate ( const DbU::Unit& dx, const DbU::Unit& dy )
{
if ( (dx != 0) or (dy != 0) ) {
invalidate( true );
_boundingBox.translate( dx, dy );
}
}
void Text::setLayer ( const Layer* layer )
{
if (not layer) throw Error( "Text::setLayer(): Can't set layer, NULL layer" );
if (layer != _layer) {
invalidate( false );
_layer = layer;
}
}
void Text::materialize()
{
cdebug_log(18,0) << "Text::materialize() - " << this << endl;
if (isMaterialized()) return;
Cell* cell = getCell();
const Layer* layer = getLayer();
if (not cell or not layer) return;
Slice* slice = cell->getSlice( layer );
if (not slice) slice = Slice::_create( cell, layer );
QuadTree* quadTree = slice->_getQuadTree();
quadTree->insert( this );
cell->_fit( quadTree->getBoundingBox() );
}
void Text::unmaterialize()
{
cdebug_log(18,0) << "Text::unmaterialize() " << this << endl;
if (not isMaterialized()) return;
Cell* cell = getCell();
Slice* slice = cell->getSlice(getLayer());
if (not slice) return;
cell->_unfit(getBoundingBox());
slice->_getQuadTree()->remove(this);
if (slice->isEmpty()) slice->_destroy();
}
string Text::_getTypeName () const
{ return _TName( "Text" ); }
string Text::_getString () const
{
string s = Super::_getString();
s.insert( s.length() - 1, " " + getString(_layer->getName()) );
s.insert( s.length() - 1, " \"" + _text + "\"" );
s.insert( s.length() - 1, " @" + getString(_boundingBox) );
return s;
}
Record* Text::_getRecord () const
{
Record* record = Super::_getRecord();
if (record) {
record->add( getSlot("_cell" , _cell ) );
record->add( getSlot("_layer" , _layer ) );
record->add( getSlot("_boundinBox", &_boundingBox) );
record->add( getSlot("_text" , _text ) );
}
return record;
}
} // Hurricane namespace.

View File

@ -0,0 +1,83 @@
// -*- C++ -*-
//
// Copyright (c) BULL S.A. 2018-2023, All Rights Reserved
//
// This file is part of Hurricane.
//
// Hurricane is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// Hurricane is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN-
// TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU
// General Public License for more details.
//
// You should have received a copy of the Lesser GNU General Public
// License along with Hurricane. If not, see
// <http://www.gnu.org/licenses/>.
//
// +-----------------------------------------------------------------+
// | H U R R I C A N E |
// | V L S I B a c k e n d D a t a - B a s e |
// | |
// | Authors : Jean-Paul Chaput |
// | E-mail : Jean-Paul.Chaput@lip6.fr |
// | =============================================================== |
// | C++ Header : "./hurricane/Text.h" |
// +-----------------------------------------------------------------+
#pragma once
#include "hurricane/Component.h"
namespace Hurricane {
class Layer;
// -------------------------------------------------------------------
// Class : "Text".
class Text : public Go {
public:
typedef Go Super;
public:
static Text* create ( Cell*, const Layer*, const Box&, std::string );
// Accessors.
virtual Cell* getCell () const;
virtual DbU::Unit getX () const;
virtual DbU::Unit getY () const;
virtual Box getBoundingBox () const;
virtual Box getBoundingBox ( const BasicLayer* ) const;
inline std::string getText () const;
// Mutators.
void setLayer ( const Layer* );
const Layer* getLayer () const;
virtual void translate ( const DbU::Unit& dx, const DbU::Unit& dy );
virtual void materialize ();
virtual void unmaterialize ();
// Hurricane management.
virtual string _getTypeName () const;
virtual string _getString () const;
virtual Record* _getRecord () const;
protected:
Text ( Cell*, const Layer*, const Box&, std::string );
private:
Cell* _cell;
const Layer* _layer;
Box _boundingBox;
std::string _text;
};
inline std::string Text::getText () const { return _text; }
} // Hurricane namespace.
INSPECTOR_P_SUPPORT(Hurricane::Text);

View File

@ -45,6 +45,7 @@
#include "hurricane/Polygon.h"
#include "hurricane/RoutingPad.h"
#include "hurricane/ExtensionGo.h"
#include "hurricane/Text.h"
#include "hurricane/viewer/Graphics.h"
#include "hurricane/viewer/PaletteItem.h"
@ -721,6 +722,18 @@ namespace Hurricane {
_cellWidget->drawDisplayText( rectangle, netName, BigFont|Bold|Center|Frame );
}
}
return;
}
const Text* text = dynamic_cast<const Text*>(go);
if (text) {
_goCount++;
Box bb = transformation.getBox(text->getBoundingBox(basicLayer));
rectangle = _cellWidget->dbuToScreenRect( bb );
if ((rectangle.width() < 5) or (rectangle.height() < 5))
return;
_cellWidget->drawDisplayText( rectangle, text->getText().c_str(), FillBox|Left );
}
}
@ -1388,7 +1401,6 @@ namespace Hurricane {
for ( BasicLayer* layer : _technology->getBasicLayers() ) {
_drawingPlanes.setPen ( Graphics::getPen (layer->getName(),getDarkening()) );
_drawingPlanes.setBrush( Graphics::getBrush(layer->getName(),getDarkening()) );
if ( isDrawable(layer->getName()) ) {
_drawingQuery.setBasicLayer( layer );
_drawingQuery.setFilter ( getQueryFilter().unset(Query::DoMasterCells
@ -1698,11 +1710,19 @@ namespace Hurricane {
void CellWidget::drawDisplayText ( const QRect& box, const char* text, unsigned int flags )
{
QFont font = Graphics::getNormalFont(flags&Bold);
shared_ptr<QFont> font = shared_ptr<QFont>( new QFont( Graphics::getNormalFont( flags&Bold )));
if ( flags & BigFont ) font.setPointSize ( Graphics::isHighDpi() ? 7 : 18 );
if (flags & BigFont)
font->setPointSize( Graphics::isHighDpi() ? 7 : 18 );
if (flags & FillBox) {
QFontMetrics metrics = QFontMetrics( *font );
float width = (float)metrics.width( text );
float ptSize = font->pointSizeF();
ptSize *= ((float)box.width() / width);
font->setPointSizeF( ptSize );
}
QFontMetrics metrics = QFontMetrics(font);
QFontMetrics metrics = QFontMetrics( *font );
int width = metrics.width( text );
//int height = metrics.height();
int angle = 0;
@ -1710,23 +1730,32 @@ namespace Hurricane {
if ( (width > box.width()) and (box.height() > 2*box.width()) )
angle = -90;
drawDisplayText ( box.center(), text, flags, angle );
QPoint textBL ( box.center() );
if (flags & Top) {
textBL.ry() += box.height() / 2;
}
if (flags & Left) {
textBL.rx() -= box.width() / 2;
}
drawDisplayText( textBL, text, flags, angle, font );
}
void CellWidget::drawDisplayText ( const QPoint& point, const char* text, unsigned int flags, int angle )
void CellWidget::drawDisplayText ( const QPoint& point, const char* text, unsigned int flags, int angle, shared_ptr<QFont> font )
{
QPainter& painter = _drawingPlanes.painter();
QPen pen = painter.pen();
QBrush brush = painter.brush();
QFont font = Graphics::getNormalFont(flags&Bold);
if (not font.get())
font = shared_ptr<QFont>( new QFont( Graphics::getNormalFont( flags&Bold )));
painter.save();
if (flags & Reverse) painter.setPen( Graphics::getPen("background") );
if (flags & Reverse) painter.setBackgroundMode( Qt::OpaqueMode );
if ( flags & BigFont ) font.setPointSize ( Graphics::isHighDpi() ? 7 : 18 );
QFontMetrics metrics = QFontMetrics(font);
QFontMetrics metrics = QFontMetrics ( *font );
int width = metrics.width ( text );
int height = metrics.height();
@ -1737,7 +1766,7 @@ namespace Hurricane {
painter.setPen ( pen );
painter.setBrush ( brush );
painter.setFont ( font );
painter.setFont ( *font );
painter.translate( point );
painter.rotate ( angle );

View File

@ -104,6 +104,7 @@ namespace Hurricane {
, Left =0x0040
, Right =0x0080
, Top =0x0100
, FillBox =0x0200
};
enum Flag { NoFlags =0x0000
, NoResetCommands=0x0001
@ -193,7 +194,7 @@ namespace Hurricane {
void drawRuler ( shared_ptr<Ruler> );
void drawRulers ( QRect );
void drawDisplayText ( const QRect& , const char*, unsigned int flags=0 );
void drawDisplayText ( const QPoint&, const char*, unsigned int flags=0, int angle=0 );
void drawDisplayText ( const QPoint&, const char*, unsigned int flags=0, int angle=0, std::shared_ptr<QFont> font=std::shared_ptr<QFont>() );
void drawScreenPolygon ( const QPoint*, int count, size_t plane=PlaneId::Working );
void drawScreenPolygon ( const QPolygon&, size_t plane=PlaneId::Working );
void drawScreenLine ( const QPoint&, const QPoint&, size_t plane=PlaneId::Working, bool mode=true );