690 lines
22 KiB
C++
690 lines
22 KiB
C++
// ****************************************************************************************************
|
|
// File: TrMos.cpp
|
|
// Authors: Wu YiFei
|
|
// Date : 21/12/2006
|
|
// ****************************************************************************************************
|
|
|
|
|
|
#include "TrMos.h"
|
|
|
|
#include "Instances.h"
|
|
#include "MetaTransistor.h"
|
|
#include "Net.h"
|
|
#include "Transistors.h"
|
|
#include "Box.h"
|
|
#include "UpdateSession.h"
|
|
#include "HyperNet.h"
|
|
#include "DataBase.h"
|
|
#include "Technology.h"
|
|
#include "Vertical.h"
|
|
#include "Horizontal.h"
|
|
#include "Pin.h"
|
|
|
|
#include "RdsUnit.h"
|
|
#include "Transistor.h"
|
|
#include "DtrAccess.h"
|
|
using namespace Hurricane;
|
|
|
|
|
|
|
|
#include "DeviceUtil.h"
|
|
|
|
|
|
namespace DEVICE{
|
|
|
|
|
|
// ****************************************************************************************************
|
|
// TrMos implementation
|
|
// ****************************************************************************************************
|
|
void TrMos::_PlaceAndRoute()
|
|
// *************************
|
|
{
|
|
|
|
// get Dtr Rules And Calculate the Size of AbutmentBox of Device.
|
|
// **************************************************************
|
|
DtrAccess * dtraccess = DtrAccess::Instance();
|
|
|
|
char type;
|
|
if(_type == 'P') type = 'N';
|
|
else type = 'P';
|
|
|
|
long minImpWidth = dtraccess->getSingleRdsRuleByLabel("RW_", getString(type), "IMP");
|
|
long minContWidth = dtraccess->getSingleRdsRuleByLabel(string("RW_CONT"));
|
|
long minAlu1Width = dtraccess->getSingleRdsRuleByLabel(string("RW_ALU1"));
|
|
long minVia1Width = dtraccess->getSingleRdsRuleByLabel(string("RW_VIA1"));
|
|
|
|
long rdImp = dtraccess->getSingleRdsRuleByLabel(string("RD_NIMP"));
|
|
long rdActive = dtraccess->getSingleRdsRuleByLabel(string("RD_ACTI"));
|
|
long rdAlu2 = dtraccess->getSingleRdsRuleByLabel(string("RD_ALU1"));
|
|
|
|
long reImpActi = dtraccess->getSingleRdsRuleByLabel("RE_", getString(type), "IMP_CONT");
|
|
long reActiContact = dtraccess->getSingleRdsRuleByLabel("RE_ACTI_CONT");
|
|
long reAlu1Contact = dtraccess->getSingleRdsRuleByLabel("RE_ALU1_CONT");
|
|
long reAlu1Via1 = dtraccess->getSingleRdsRuleByLabel("RE_ALU1_VIA1");
|
|
|
|
long minActiWidth = 2*reActiContact + minContWidth;
|
|
|
|
long widthOfSourceWire = ConvertRealToRdsUnit(_widthOfSourceWire);
|
|
long widthOfDrainWire = ConvertRealToRdsUnit(_widthOfDrainWire);
|
|
|
|
long widthOfActive = MAX_INTEGER(minActiWidth, minContWidth + 2*reActiContact);
|
|
long widthOfImp = MAX_INTEGER(widthOfActive + 2*reImpActi, minImpWidth);
|
|
|
|
|
|
// **************************************************************
|
|
// Placing .
|
|
// **************************************************************
|
|
|
|
Transformation::Orientation::Code internalTransCode = Transformation::Orientation::ID;
|
|
|
|
Unit horizontalMargin = 0; // the horizontal margin of trmos.
|
|
Unit verticalLowMargin = 0; // the vertical low margin of trmos.
|
|
Unit verticalHighMargin = 0; // the vertical high margin of trmos.
|
|
|
|
Unit fingerHeight = 0; // the height of trmos.
|
|
Instance * leftins = NULL;
|
|
Instance * rightins = NULL;
|
|
|
|
OccurrenceLocator locator = getLeafInstanceOccurrences().getLocator();
|
|
Instance * instance = dynamic_cast<Instance*>(locator.getElement().getEntity());;
|
|
fingerHeight = instance->getCell()->getBoundingBox().getHeight();
|
|
horizontalMargin = getUnit(RETURN_EVEN((long)(getValue(fingerHeight))/4));
|
|
verticalLowMargin = getUnit(RETURN_EVEN((long)(getValue(fingerHeight))/2));
|
|
verticalHighMargin = getUnit(RETURN_EVEN((long)(getValue(fingerHeight))/2));
|
|
|
|
|
|
verticalLowMargin = MAX_INTEGER(verticalLowMargin, getUnit(RETURN_EVEN(rdImp + widthOfImp/2 + widthOfSourceWire
|
|
+ rdAlu2 + widthOfActive + rdActive)) );
|
|
|
|
verticalHighMargin = MAX_INTEGER(verticalHighMargin, horizontalMargin + getUnit(2*rdAlu2 + 2*widthOfDrainWire) );
|
|
horizontalMargin = MAX_INTEGER(horizontalMargin, getUnit(RETURN_EVEN(rdImp + widthOfImp/2)) );
|
|
|
|
OpenUpdateSession();
|
|
|
|
if(_m == 1 ) { // If there is only one finger.
|
|
_Place( instance, Transformation::Orientation::ID, Point( horizontalMargin, verticalLowMargin ) );
|
|
//CloseUpdateSession();
|
|
//return;
|
|
|
|
}
|
|
else {
|
|
// get instance who's model's abutment type is Left or Right.
|
|
// ************************************************************
|
|
for_each_occurrence(occurrence, getLeafInstanceOccurrences())
|
|
instance = dynamic_cast<Instance*>(occurrence.getEntity());
|
|
Transistor * trans = dynamic_cast<Transistor*>(instance->getMasterCell());
|
|
|
|
if ( _sourceIsFirst ) {
|
|
if(trans->IsLeft() && !leftins)
|
|
leftins = instance;
|
|
else if ( trans->IsLeft() && leftins)
|
|
rightins = instance;
|
|
else if ( trans->IsRight())
|
|
rightins = instance;
|
|
}
|
|
else {
|
|
if(trans->IsRight() && !leftins)
|
|
leftins = instance;
|
|
else if (trans->IsRight() && leftins )
|
|
rightins = instance;
|
|
else if (trans->IsLeft())
|
|
rightins = instance;
|
|
}
|
|
end_for
|
|
|
|
// You must place this first instance who's model is left finger in a point who's
|
|
// x, y are all pair.
|
|
// Because if you do this, you can be sure that all rectangle of this instance are
|
|
// correctly in the grille of fondor.
|
|
// ***********************************************************************************
|
|
|
|
if(_sourceIsFirst)
|
|
_Place( leftins, Transformation::Orientation::ID, Point(horizontalMargin, verticalLowMargin) );
|
|
else
|
|
_Place( leftins, Transformation::Orientation::MX, Point(horizontalMargin, verticalLowMargin) );
|
|
|
|
_setRefIns(leftins);
|
|
|
|
if(_sourceIsFirst) // internal Finger's transformation.
|
|
internalTransCode = Transformation::Orientation::MX;
|
|
else
|
|
internalTransCode = Transformation::Orientation::ID;
|
|
|
|
// Place internal finger.
|
|
// *********************
|
|
for_each_occurrence(occurrence, getLeafInstanceOccurrences())
|
|
|
|
Instance * instance = dynamic_cast<Instance*>(occurrence.getEntity());
|
|
|
|
if(instance==leftins || instance==rightins )
|
|
continue;
|
|
|
|
_PlaceRight( instance, internalTransCode);
|
|
|
|
if(internalTransCode == Transformation::Orientation::MX)
|
|
internalTransCode = Transformation::Orientation::ID;
|
|
else
|
|
internalTransCode = Transformation::Orientation::MX;
|
|
|
|
end_for
|
|
|
|
// Place the last finger.
|
|
// **********************
|
|
Transistor * trans = dynamic_cast<Transistor*>(rightins->getMasterCell());
|
|
|
|
if( trans->IsRight())
|
|
_PlaceRight( rightins, Transformation::Orientation::ID);
|
|
else
|
|
_PlaceRight( rightins, Transformation::Orientation::MX);
|
|
|
|
}
|
|
|
|
CloseUpdateSession();
|
|
|
|
|
|
|
|
// Set AbutmentBox.
|
|
// ****************
|
|
for_each_instance(instance, getInstances())
|
|
instance->unmaterialize();
|
|
instance->materialize();
|
|
end_for
|
|
|
|
OpenUpdateSession();
|
|
|
|
|
|
cout <<"Bounding box of TrMos is "<<getString(getBoundingBox())<<endl;
|
|
|
|
setAbutmentBox(Box(0, 0,
|
|
getBoundingBox().getWidth() + 2*horizontalMargin,
|
|
getBoundingBox().getHeight() + verticalLowMargin + verticalHighMargin
|
|
)
|
|
);
|
|
|
|
|
|
// **************************************************************
|
|
// Routing .
|
|
// **************************************************************
|
|
|
|
Unit expectedInterval = getUnit(RETURN_EVEN((long)(getValue(horizontalMargin))/2));
|
|
Unit interval = 0;
|
|
Unit initialPosition = verticalLowMargin + fingerHeight + getUnit(rdAlu2 + widthOfDrainWire/2);
|
|
|
|
map<string, Unit> netName2PositionOfConnectorMap;
|
|
list<Box> routingZoneList;
|
|
list<Unit> sourcePositionList;
|
|
list<Unit> drainPositionList;
|
|
Unit sourceRoutingZoneWidth;
|
|
Unit drainRoutingZoneWidth;
|
|
|
|
DataBase * db = getDataBase();
|
|
if(!db) throw Error("Can't launch Trmos::PlaceAndRoute for " + getString(this) + " : can't find DataBase");
|
|
|
|
Layer * layerAlu1 = db->getTechnology()->getLayer(Name("ALU1"));
|
|
Layer * layerAlu2 = db->getTechnology()->getLayer(Name("ALU2"));
|
|
|
|
Layer * layerVia1 = db->getTechnology()->getLayer(Name("VIA1"));
|
|
Layer * layerActive = db->getTechnology()->getLayer(Name("ACTIVE"));
|
|
|
|
Layer * layerVia01 = db->getTechnology()->getLayer(Name("via01"));
|
|
Layer * layerVia12 = db->getTechnology()->getLayer(Name("via12"));
|
|
|
|
Layer * layerPoly = db->getTechnology()->getLayer(Name("POLY"));
|
|
Layer * layerNwell = db->getTechnology()->getLayer(Name("NWELL"));
|
|
Layer * layerCont = db->getTechnology()->getLayer(Name("CONT"));
|
|
|
|
Layer * layerImp = NULL;
|
|
|
|
if(_type == 'P')
|
|
layerImp = db->getTechnology()->getLayer(Name("NIMP"));
|
|
else
|
|
layerImp = db->getTechnology()->getLayer(Name("PIMP"));
|
|
|
|
Pin * pin = NULL; // For get the adresse of Created Pins.
|
|
|
|
long connectorPosition = 0;
|
|
|
|
|
|
cout << " Begin routage " << endl;
|
|
|
|
|
|
// Set position of four connectors.
|
|
// ********************************
|
|
vector<PinName>::iterator i = _highPinOrder.begin(),
|
|
j = _highPinOrder.end();
|
|
|
|
while(i!=j) {
|
|
if(*i == D)
|
|
netName2PositionOfConnectorMap[string("drain")] = initialPosition;
|
|
if(*i == G)
|
|
netName2PositionOfConnectorMap[string("grid")] = initialPosition;
|
|
|
|
interval = MAX_INTEGER(expectedInterval, getUnit(widthOfDrainWire + rdAlu2));
|
|
|
|
// initialPosition += horizontalMargin/2;
|
|
initialPosition += interval;
|
|
i++;
|
|
}
|
|
|
|
vector<PinName>::iterator m = _lowPinOrder.begin(),
|
|
n = _lowPinOrder.end();
|
|
|
|
//initialPosition = verticalMargin - horizontalMargin/2;
|
|
//initialPosition = verticalLowMargin - MAX_INTEGER(expectedInterval, getUnit(rdImp + widthOfImp/2));
|
|
initialPosition = verticalLowMargin - getUnit(rdImp + widthOfImp/2);
|
|
|
|
while(m!=n) {
|
|
if(*m == S)
|
|
netName2PositionOfConnectorMap[string("source")] = initialPosition;
|
|
if(*m == B)
|
|
netName2PositionOfConnectorMap[string("bulk")] = initialPosition;
|
|
|
|
interval = MAX_INTEGER(expectedInterval, getUnit(rdAlu2 + widthOfSourceWire));
|
|
|
|
initialPosition -= interval;
|
|
m++;
|
|
}
|
|
|
|
cout << " Main loop "<< endl;
|
|
|
|
// Main Routing Algorithm.
|
|
// ***********************
|
|
|
|
// Main Loop.
|
|
// **********
|
|
for_each_net(net, getNets()) // For all hypernets.
|
|
|
|
if(getString(net->getName())=="bulk" || getString(net->getName())=="BULK" )
|
|
continue;
|
|
|
|
// get Routing Zone.
|
|
// *****************
|
|
HyperNet hyperNet(Occurrence(net, Path()));
|
|
for_each_occurrence(occurrence, hyperNet.getNetOccurrences()) // For all net occurrences.
|
|
Net * net = dynamic_cast<Net*>(occurrence.getEntity());
|
|
Box routingZone;
|
|
|
|
if(net->getCell()->isLeaf()) {
|
|
Transistor * trans = dynamic_cast<Transistor*>(net->getCell());
|
|
if ( !trans )
|
|
throw Error("Can't launch Trmos::PlaceAndRoute for " + getString(this)
|
|
+ ", it is not a Transistor");
|
|
|
|
cout << getString(occurrence) << endl;
|
|
cout << getString(occurrence.getPath().getTransformation()) <<endl;
|
|
cout << getString((*(trans->_getMapNet2Box()))[net]) << endl;
|
|
|
|
// get Routing Zone.
|
|
// *****************
|
|
routingZone = occurrence.getPath().getTransformation().getBox((*(trans->_getMapNet2Box()))[net]);
|
|
routingZoneList.push_back(routingZone);
|
|
|
|
if(getString(net->getName())=="SOURCE") {
|
|
sourcePositionList.push_back(routingZone.getXCenter());
|
|
sourceRoutingZoneWidth = routingZone.getWidth();
|
|
}
|
|
else if (getString(net->getName())=="DRAIN") {
|
|
drainPositionList.push_back(routingZone.getXCenter());
|
|
drainRoutingZoneWidth = routingZone.getWidth();
|
|
}
|
|
}
|
|
|
|
end_for
|
|
|
|
|
|
cout <<"Print routing zone for " <<getString(net)<<endl;
|
|
|
|
list<Box>::iterator it_begin_listbox = routingZoneList.begin(),
|
|
it_end_listbox = routingZoneList.end();
|
|
|
|
while(it_begin_listbox != it_end_listbox)
|
|
{
|
|
cout<< getString(*it_begin_listbox) <<endl;
|
|
it_begin_listbox++;
|
|
}
|
|
|
|
cout <<"End Print Routing Zone for "<<getString(net)<<endl;
|
|
|
|
// Create routing line.
|
|
// ********************
|
|
list<Box>::iterator routingzonelist_begin_it = routingZoneList.begin(),
|
|
routingzonelist_end_it = routingZoneList.end();
|
|
|
|
connectorPosition = netName2PositionOfConnectorMap[getString(net->getName())];
|
|
cout << "Connector Position is " << netName2PositionOfConnectorMap[getString(net)] << endl;
|
|
|
|
while(routingzonelist_begin_it!=routingzonelist_end_it) {
|
|
|
|
Box routingZoneBox = *routingzonelist_begin_it;
|
|
|
|
// Create vertical line and Contact.
|
|
// ********************************
|
|
if(connectorPosition > routingZoneBox.getYMin()) {
|
|
Vertical::create(net, layerAlu1, routingZoneBox.getXCenter()
|
|
, routingZoneBox.getWidth() + getUnit(2*reAlu1Contact)
|
|
, routingZoneBox.getYMin() - getUnit(reAlu1Contact)
|
|
, connectorPosition);
|
|
}
|
|
else {
|
|
Vertical::create(net, layerAlu1, routingZoneBox.getXCenter()
|
|
, routingZoneBox.getWidth() + getUnit(2*reAlu1Contact)
|
|
, connectorPosition
|
|
, routingZoneBox.getYMax() + getUnit(reAlu1Contact) ) ;
|
|
}
|
|
|
|
Contact::create(net, layerVia12, routingZoneBox.getXCenter()
|
|
, connectorPosition
|
|
, getUnit(minVia1Width)
|
|
, getUnit(minVia1Width)
|
|
);
|
|
|
|
routingzonelist_begin_it ++ ;
|
|
}
|
|
|
|
// Create horizontal line.
|
|
// ***********************
|
|
long widthOfWire = 0;
|
|
|
|
if(getString(net->getName())=="source")
|
|
widthOfWire = widthOfSourceWire;
|
|
else if(getString(net->getName())=="drain")
|
|
widthOfWire = widthOfDrainWire;
|
|
else
|
|
widthOfWire = widthOfDrainWire;
|
|
|
|
|
|
Horizontal::create(net, layerAlu2, connectorPosition
|
|
, getUnit(widthOfWire)
|
|
, 0
|
|
, getAbutmentBox().getXMax()
|
|
);
|
|
|
|
// Create Two Pins.
|
|
// ****************
|
|
pin = Pin::create(net
|
|
, Name(getString(net->getName())+"_west")
|
|
, Pin::AccessDirection(Pin::AccessDirection::WEST)
|
|
, Pin::PlacementStatus(Pin::PlacementStatus::PLACED)
|
|
, layerAlu2
|
|
, getAbutmentBox().getXMin()
|
|
, connectorPosition
|
|
, getUnit(widthOfWire)
|
|
, getUnit(widthOfWire)
|
|
);
|
|
|
|
_mapNetToPinBoxInLeftSide[net] = pin;
|
|
|
|
pin = Pin::create(net
|
|
, Name(getString(net->getName())+"_east")
|
|
, Pin::AccessDirection(Pin::AccessDirection::EAST)
|
|
, Pin::PlacementStatus(Pin::PlacementStatus::PLACED)
|
|
, layerAlu2
|
|
, getAbutmentBox().getXMax()
|
|
, connectorPosition
|
|
, getUnit(widthOfWire)
|
|
, getUnit(widthOfWire)
|
|
);
|
|
|
|
_mapNetToPinBoxInRightSide[net] = pin;
|
|
|
|
routingZoneList.clear();
|
|
|
|
// End Of Main Loop.
|
|
// *****************
|
|
end_for
|
|
|
|
// Route Net Bulk.
|
|
// ***************
|
|
connectorPosition = netName2PositionOfConnectorMap[string("bulk")];
|
|
|
|
Net * netBulk = getNet(Name("bulk"));
|
|
|
|
if(!netBulk) // bulk and source are connected.
|
|
netBulk = getNet(Name("source"));
|
|
|
|
// Calculate the width of Contact Alu1.
|
|
// ************************************
|
|
long widthOfAlu1 = MAX_INTEGER( MAX_INTEGER(minAlu1Width, 2*reAlu1Contact + minContWidth), 2*reAlu1Via1 + minVia1Width);
|
|
|
|
Unit bulkPosition = netName2PositionOfConnectorMap[string("bulk")];
|
|
Unit sourcePosition = netName2PositionOfConnectorMap[string("source")];
|
|
|
|
Horizontal::create( netBulk
|
|
, layerImp
|
|
, bulkPosition
|
|
, getUnit(widthOfImp)
|
|
, 0 - getUnit(reImpActi)
|
|
, getAbutmentBox().getXMax() + getUnit(reImpActi)
|
|
);
|
|
|
|
Horizontal::create( netBulk
|
|
, layerActive
|
|
, bulkPosition
|
|
, getUnit(widthOfActive)
|
|
, 0
|
|
, getAbutmentBox().getXMax()
|
|
);
|
|
|
|
Horizontal::create( netBulk
|
|
, layerAlu2
|
|
, bulkPosition
|
|
, getUnit(widthOfSourceWire)
|
|
, 0
|
|
, getAbutmentBox().getXMax()
|
|
);
|
|
|
|
// Create Two Pins For Net bulk.
|
|
// *****************************
|
|
if(!_isBsConnected) {
|
|
|
|
pin = Pin::create(netBulk
|
|
, Name(getString(netBulk->getName())+"_west")
|
|
, Pin::AccessDirection(Pin::AccessDirection::WEST)
|
|
, Pin::PlacementStatus(Pin::PlacementStatus::PLACED)
|
|
, layerAlu2
|
|
, getAbutmentBox().getXMin()
|
|
, bulkPosition
|
|
, getUnit(widthOfSourceWire)
|
|
, getUnit(widthOfSourceWire)
|
|
);
|
|
|
|
_mapNetToPinBoxInLeftSide[netBulk] = pin;
|
|
|
|
pin = Pin::create(netBulk
|
|
, Name(getString(netBulk->getName())+"_east")
|
|
, Pin::AccessDirection(Pin::AccessDirection::EAST)
|
|
, Pin::PlacementStatus(Pin::PlacementStatus::PLACED)
|
|
, layerAlu2
|
|
, getAbutmentBox().getXMax()
|
|
, bulkPosition
|
|
, getUnit(widthOfSourceWire)
|
|
, getUnit(widthOfSourceWire)
|
|
);
|
|
|
|
_mapNetToPinBoxInRightSide[netBulk] = pin;
|
|
}
|
|
|
|
|
|
if( netName2PositionOfConnectorMap[string("source")] > netName2PositionOfConnectorMap[string("bulk")] ) {
|
|
// Source Is Upper Than Bulk.
|
|
|
|
cout << " Source is Upper Than Bulk" << endl;
|
|
|
|
list<Unit>::iterator i = sourcePositionList.begin(), j = sourcePositionList.end();
|
|
|
|
while(i!=j) {
|
|
|
|
cout << " ######### Create Contact ###########" <<endl;
|
|
|
|
Contact::create(netBulk, layerVia01, *i
|
|
, bulkPosition
|
|
, getUnit(minContWidth)
|
|
, getUnit(minContWidth)
|
|
);
|
|
|
|
Contact::create(netBulk, layerAlu1, *i
|
|
, bulkPosition
|
|
, getUnit(widthOfAlu1)
|
|
, getUnit(widthOfAlu1)
|
|
);
|
|
|
|
Contact::create(netBulk, layerVia12, *i
|
|
, bulkPosition
|
|
, getUnit(minVia1Width)
|
|
, getUnit(minVia1Width)
|
|
);
|
|
|
|
if( _isBsConnected ) { // If bulk and Source are connected.
|
|
|
|
cout << " B S is connected in " << *i << endl;
|
|
|
|
Vertical::create(netBulk, layerAlu1, *i
|
|
, sourceRoutingZoneWidth
|
|
, bulkPosition
|
|
, sourcePosition);
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
} else {
|
|
|
|
list<Unit>::iterator i , j;
|
|
|
|
|
|
if( _isBsConnected ) { // If bulk and Source are connected.
|
|
i = sourcePositionList.begin();
|
|
j = sourcePositionList.end();
|
|
}
|
|
else {
|
|
i = drainPositionList.begin();
|
|
j = drainPositionList.end();
|
|
}
|
|
|
|
while(i!=j) {
|
|
|
|
cout << " ######### Create Contact ###########" <<endl;
|
|
|
|
Contact::create(netBulk, layerVia01, *i
|
|
, bulkPosition
|
|
, getUnit(minContWidth)
|
|
, getUnit(minContWidth)
|
|
);
|
|
|
|
Contact::create(netBulk, layerAlu1, *i
|
|
, bulkPosition
|
|
, getUnit(widthOfAlu1)
|
|
, getUnit(widthOfAlu1)
|
|
);
|
|
|
|
Contact::create(netBulk, layerVia12, *i
|
|
, bulkPosition
|
|
, getUnit(minVia1Width)
|
|
, getUnit(minVia1Width)
|
|
);
|
|
|
|
i++;
|
|
}
|
|
}
|
|
|
|
|
|
// Create Ring.
|
|
// ************
|
|
if( _hasRing ) {
|
|
widthOfImp = MAX_INTEGER(minImpWidth, minActiWidth + 2*reImpActi);
|
|
|
|
Net * netRing = Net::create(this, Name("RING"));
|
|
|
|
|
|
// Create rectangle in IMPLANT.
|
|
// ***************************
|
|
Horizontal::create( netRing
|
|
, layerImp
|
|
, getAbutmentBox().getYMax()
|
|
, getUnit(widthOfImp)
|
|
, getAbutmentBox().getXMin() - getUnit(widthOfImp/2)
|
|
, getAbutmentBox().getXMax() + getUnit(widthOfImp/2)
|
|
);
|
|
|
|
Horizontal::create( netRing
|
|
, layerImp
|
|
, getAbutmentBox().getYMin()
|
|
, getUnit(widthOfImp)
|
|
, getAbutmentBox().getXMin() - getUnit(widthOfImp/2)
|
|
, getAbutmentBox().getXMax() + getUnit(widthOfImp/2)
|
|
);
|
|
|
|
Vertical::create(netRing
|
|
, layerImp
|
|
, getAbutmentBox().getXMin()
|
|
, getUnit(widthOfImp)
|
|
, getAbutmentBox().getYMin()
|
|
, getAbutmentBox().getYMax()
|
|
);
|
|
|
|
Vertical::create(netRing
|
|
, layerImp
|
|
, getAbutmentBox().getXMax()
|
|
, getUnit(widthOfImp)
|
|
, getAbutmentBox().getYMin()
|
|
, getAbutmentBox().getYMax()
|
|
);
|
|
|
|
|
|
// Create rectangle in Active.
|
|
// ***************************
|
|
Horizontal::create( netRing
|
|
, layerActive
|
|
, getAbutmentBox().getYMax()
|
|
, getUnit(minActiWidth)
|
|
, getAbutmentBox().getXMin() - getUnit(minActiWidth/2)
|
|
, getAbutmentBox().getXMax() + getUnit(minActiWidth/2)
|
|
);
|
|
|
|
Horizontal::create( netRing
|
|
, layerActive
|
|
, getAbutmentBox().getYMin()
|
|
, getUnit(minActiWidth)
|
|
, getAbutmentBox().getXMin() - getUnit(minActiWidth/2)
|
|
, getAbutmentBox().getXMax() + getUnit(minActiWidth/2)
|
|
);
|
|
|
|
|
|
Vertical::create(netRing
|
|
, layerActive
|
|
, getAbutmentBox().getXMin()
|
|
, getUnit(minActiWidth)
|
|
, getAbutmentBox().getYMin()
|
|
, getAbutmentBox().getYMax()
|
|
);
|
|
|
|
Vertical::create(netRing
|
|
, layerActive
|
|
, getAbutmentBox().getXMax()
|
|
, getUnit(minActiWidth)
|
|
, getAbutmentBox().getYMin()
|
|
, getAbutmentBox().getYMax()
|
|
);
|
|
|
|
}
|
|
|
|
// Create Caission NWELL if this is a PMOS.
|
|
// ****************************************
|
|
if(_type == 'P') {
|
|
Net * netCaisson = Net::create(this, Name("CAISSON"));
|
|
Contact::create(netCaisson, layerNwell
|
|
, getAbutmentBox().getXCenter()
|
|
, getAbutmentBox().getYCenter()
|
|
, getAbutmentBox().getWidth()
|
|
, getAbutmentBox().getHeight()
|
|
);
|
|
}
|
|
|
|
CloseUpdateSession();
|
|
|
|
}
|
|
|
|
|
|
|
|
} // END OF NAMESPACE DEVICE
|