348 lines
12 KiB
C++
348 lines
12 KiB
C++
#include "hurricane/DataBase.h"
|
|
#include "hurricane/Technology.h"
|
|
#include "hurricane/UpdateSession.h"
|
|
#include "hurricane/Pad.h"
|
|
using namespace Hurricane;
|
|
|
|
#include "AEnv.h"
|
|
#include "ATechnology.h"
|
|
#include "Transistor.h"
|
|
|
|
namespace {
|
|
|
|
Layer* getLayer(Technology* technology, const string& layerStr) {
|
|
Layer* layer = technology->getLayer(layerStr);
|
|
if (!layer) {
|
|
throw Error("Unknown Layer : " + layerStr);
|
|
}
|
|
return layer;
|
|
}
|
|
|
|
Pad* createPad(Technology* technology, Net* net, const string& layerName) {
|
|
static Box emptyBox(0, 0, 0, 0);
|
|
Layer* layer = getLayer(technology, layerName);
|
|
Pad* pad = Pad::create(net, layer, emptyBox);
|
|
return pad;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
const Name Transistor::DrainName("DRAIN");
|
|
const Name Transistor::SourceName("SOURCE");
|
|
const Name Transistor::GridName("GRID");
|
|
const Name Transistor::BulkName("BULK");
|
|
const Name Transistor::AnonymousName("ANONYMOUS");
|
|
|
|
Transistor::Type::Type(const Code& code):
|
|
_code(code)
|
|
{}
|
|
|
|
Transistor::Type::Type(const Type& type):
|
|
_code(type._code)
|
|
{}
|
|
|
|
Transistor::Type& Transistor::Type::operator=(const Type& type) {
|
|
_code = type._code;
|
|
return *this;
|
|
}
|
|
|
|
Transistor::Transistor(Library* library, const Name& name):
|
|
AnalogComponent(library, name),
|
|
_drain(NULL),
|
|
_source(NULL),
|
|
_grid(NULL),
|
|
_bulk(NULL),
|
|
_anonymous(NULL),
|
|
_type(),
|
|
_l(0),
|
|
_w(0),
|
|
//_source20(NULL),
|
|
_source22(NULL),
|
|
//_drain40(NULL),
|
|
_drain42(NULL),
|
|
_grid00(NULL), _grid01(NULL), _grid30(NULL), _grid31(NULL),
|
|
_anonymous10(NULL), _anonymous11(NULL), _anonymous12(NULL), _anonymous50(NULL)
|
|
{}
|
|
|
|
|
|
Transistor* Transistor::create(Library* library, const Name& name) {
|
|
Transistor* transistor = new Transistor(library, name);
|
|
|
|
transistor->_postCreate();
|
|
|
|
return transistor;
|
|
}
|
|
|
|
void Transistor::_postCreate() {
|
|
Inherit::_postCreate();
|
|
|
|
//ChoiceParameter<Transistor>::Choices choices;
|
|
//choices.push_back(string("N"));
|
|
//choices.push_back(string("P"));
|
|
//addParameter(ChoiceParameter<Transistor>("type", choices, 0, new CallBack<Transistor>(this, &Transistor::updateType)));
|
|
|
|
DataBase* db = DataBase::getDB();
|
|
Technology* technology = db->getTechnology();
|
|
_drain = Net::create(this, DrainName);
|
|
_drain->setExternal(true);
|
|
_source = Net::create(this, SourceName);
|
|
_source->setExternal(true);
|
|
_grid = Net::create(this, GridName);
|
|
_grid->setExternal(true);
|
|
_bulk = Net::create(this, BulkName);
|
|
_bulk->setExternal(true);
|
|
_anonymous = Net::create(this, AnonymousName);
|
|
//_source20 = createPad(technology, _source, "cut0");
|
|
_source22 = createPad(technology, _source, "cut1");
|
|
//_drain40 = createPad(technology, _drain, "cut0");
|
|
_drain42 = createPad(technology, _drain, "cut1");
|
|
_grid00 = createPad(technology, _grid, "poly");
|
|
_grid01 = createPad(technology, _grid, "poly");
|
|
_grid30 = createPad(technology, _grid, "cut0");
|
|
_grid31 = createPad(technology, _grid, "metal1");
|
|
_anonymous10 = createPad(technology, _anonymous, "active");
|
|
if (_type == Type::NMOS) {
|
|
_anonymous11 = createPad(technology, _anonymous, "nImplant");
|
|
_anonymous12 = createPad(technology, _anonymous, "nImplant");
|
|
} else {
|
|
_anonymous11 = createPad(technology, _anonymous, "pImplant");
|
|
_anonymous12 = createPad(technology, _anonymous, "pImplant");
|
|
}
|
|
setTerminal(false);
|
|
}
|
|
|
|
void Transistor::setType(Type type) {
|
|
UpdateSession::open();
|
|
if (type != _type) {
|
|
_type = type;
|
|
DataBase* db = DataBase::getDB();
|
|
Technology* technology = db->getTechnology();
|
|
if (_type == Type::NMOS) {
|
|
_anonymous11->setLayer(getLayer(technology, "nImplant"));
|
|
_anonymous12->setLayer(getLayer(technology, "nImplant"));
|
|
} else {
|
|
_anonymous11->setLayer(getLayer(technology, "pImplant"));
|
|
_anonymous12->setLayer(getLayer(technology, "pImplant"));
|
|
}
|
|
updateLayout();
|
|
}
|
|
UpdateSession::close();
|
|
}
|
|
|
|
void Transistor::updateLayout() {
|
|
DataBase* db = DataBase::getDB();
|
|
if (!db) {
|
|
throw Error("Error : no DataBase");
|
|
}
|
|
Technology* techno = db->getTechnology();
|
|
if (!techno) {
|
|
throw Error("Error : no Technology");
|
|
}
|
|
ATechnology* atechno = AEnv::getATechnology();
|
|
|
|
DbU::Unit widthCut0 = atechno->getPhysicalRule("minWidth", getLayer(techno, "cut0"))->getValue();
|
|
DbU::Unit spacingCut0 = atechno->getPhysicalRule("minSpacing", getLayer(techno, "cut0"))->getValue();
|
|
DbU::Unit extGateActive = atechno->getPhysicalRule("minExtension",
|
|
getLayer(techno, "poly"), getLayer(techno, "active"))->getValue();
|
|
DbU::Unit extPolyCut0 = atechno->getPhysicalRule("minExtension",
|
|
getLayer(techno, "poly"), getLayer(techno, "cut0"))->getValue();
|
|
DbU::Unit spacingActiveCut0 = atechno->getPhysicalRule("minSpacing",
|
|
getLayer(techno, "active"), getLayer(techno, "cut0"))->getValue();
|
|
DbU::Unit spacingGateCut0 = atechno->getPhysicalRule("minGateSpacing",
|
|
getLayer(techno, "cut0"), getLayer(techno, "active"))->getValue();
|
|
DbU::Unit spacingActivePoly = atechno->getPhysicalRule("minSpacing",
|
|
getLayer(techno, "active"), getLayer(techno, "poly"))->getValue();
|
|
DbU::Unit sourceDrainWidth = atechno->getPhysicalRule("minExtension",
|
|
getLayer(techno, "active"), getLayer(techno, "poly"))->getValue();
|
|
DbU::Unit extActiveCut0 = atechno->getPhysicalRule("minExtension",
|
|
getLayer(techno, "active"), getLayer(techno, "cut0"))->getValue();
|
|
DbU::Unit enclosurePPlusActive = atechno->getPhysicalRule("minEnclosure",
|
|
getLayer(techno, "nWell"), getLayer(techno, "active"))->getValue();
|
|
DbU::Unit enclosureImplantPoly = 0;
|
|
DbU::Unit enclosureGateImplant = 0;
|
|
DbU::Unit extImplantActive = 0;
|
|
DbU::Unit extImplantCut0 = 0;
|
|
|
|
if (_type == Type::NMOS) {
|
|
enclosureImplantPoly = atechno->getPhysicalRule("minEnclosure",
|
|
getLayer(techno, "nImplant"), getLayer(techno, "poly"))->getValue();
|
|
enclosureGateImplant = atechno->getPhysicalRule("minGateEnclosure",
|
|
getLayer(techno, "nImplant"), getLayer(techno, "poly"))->getValue();
|
|
extImplantActive = atechno->getPhysicalRule("minExtension",
|
|
getLayer(techno, "nImplant"), getLayer(techno, "active"))->getValue();
|
|
extImplantCut0 = atechno->getPhysicalRule("minExtension",
|
|
getLayer(techno, "nImplant"), getLayer(techno, "cut0"))->getValue();
|
|
} else {
|
|
enclosureImplantPoly = atechno->getPhysicalRule("minEnclosure",
|
|
getLayer(techno, "pImplant"), getLayer(techno, "poly"))->getValue();
|
|
enclosureGateImplant = atechno->getPhysicalRule("minGateEnclosure",
|
|
getLayer(techno, "nImplant"), getLayer(techno, "poly"))->getValue();
|
|
extImplantActive = atechno->getPhysicalRule("minExtension",
|
|
getLayer(techno, "pImplant"), getLayer(techno, "active"))->getValue();
|
|
extImplantCut0 = atechno->getPhysicalRule("minExtension",
|
|
getLayer(techno, "pImplant"), getLayer(techno, "cut0"))->getValue();
|
|
}
|
|
|
|
UpdateSession::open();
|
|
DbU::setStringMode(1);
|
|
|
|
//grid 00
|
|
DbU::Unit x00 = 0;
|
|
DbU::Unit y00 = -extGateActive;
|
|
DbU::Unit dx00 = _l;
|
|
DbU::Unit dy00 = _w + extGateActive;
|
|
Box box00(x00, y00, x00 + dx00, y00 + dy00);
|
|
_grid00->setBoundingBox(box00);
|
|
|
|
//grid30
|
|
DbU::Unit maxValue = widthCut0 + 2*extPolyCut0;
|
|
DbU::Unit x30 = 0, dx30 = 0, y30 = 0, dy30 = 0;
|
|
if (maxValue > _l) {
|
|
dx30 = widthCut0;
|
|
dy30 = dx30;
|
|
y30 = _w + max(spacingActiveCut0, spacingActivePoly + extPolyCut0);
|
|
} else {
|
|
dx30 = dx00 - 2*extPolyCut0;
|
|
dy30 = widthCut0;
|
|
y30 = _w + spacingActiveCut0;
|
|
}
|
|
x30 = x00 + dx00/2 - dx30/2;
|
|
Box box30(x30, y30, x30 + dx30, y30 + dy30);
|
|
_grid30->setBoundingBox(box30);
|
|
|
|
//grid31
|
|
DbU::Unit dx31 = dx30 + 2*extPolyCut0;
|
|
DbU::Unit dy31 = dy30 + 2*extPolyCut0;
|
|
DbU::Unit x31 = x30 - extPolyCut0;
|
|
DbU::Unit y31 = y30 - extPolyCut0;
|
|
Box box31(x31, y31, x31 + dx31, y31 + dy31);
|
|
_grid31->setBoundingBox(box31);
|
|
|
|
//grid01
|
|
DbU::Unit x01 = 0, y01 = 0, dx01 = 0, dy01 = 0;
|
|
if (y31 <= y00+dy00) {
|
|
x01 = 0; y01 = 0; dx01 = 0; dy01 = 0;
|
|
} else {
|
|
x01 = x00;
|
|
y01 = y00 + dy00;
|
|
dx01 = dx00;
|
|
dy01 = y31 - (y00 + dy00);
|
|
}
|
|
Box box01(x01, y01, x01 + dx01, y01 + dy01);
|
|
_grid01->setBoundingBox(box01);
|
|
|
|
//anonymous12
|
|
DbU::Unit x12 = min(x31, x00) - enclosureImplantPoly;
|
|
DbU::Unit y12 = min(0 - extImplantActive, y00 - enclosureImplantPoly);
|
|
DbU::Unit dx12 = max(dx31, dx00) + 2 * enclosureImplantPoly;
|
|
DbU::Unit yMax = max( max(y30 + dy30 + extImplantCut0, max(y31 + dy31, y00 + dy00) + enclosureImplantPoly), _w + extImplantActive);
|
|
DbU::Unit dy12 = yMax - y12;
|
|
|
|
Box box12(x12, y12, x12 + dx12, y12 + dy12);
|
|
_anonymous12->setBoundingBox(box12);
|
|
|
|
////_source20
|
|
DbU::Unit y20 = extActiveCut0;
|
|
DbU::Unit dy20 = _w - 2 * extActiveCut0;
|
|
unsigned sourceColumnNumber = 1;
|
|
DbU::Unit dx20 = sourceColumnNumber * widthCut0 + (sourceColumnNumber - 1) * spacingCut0;
|
|
DbU::Unit x20 = -(dx20 + spacingGateCut0);
|
|
//Box box20(x20, y20, x20 + dx20, y20 + dy20);
|
|
////_source20->setBoundingBox(box20);
|
|
|
|
////_drain40
|
|
//DbU::Unit y40 = y20;
|
|
DbU::Unit x40 = x00 + dx00 + spacingGateCut0;
|
|
unsigned drainColumnNumber = 1;
|
|
DbU::Unit dx40 = drainColumnNumber * widthCut0 + (drainColumnNumber - 1) * (spacingCut0);
|
|
//DbU::Unit dy40 = dy20;
|
|
|
|
//Box box40(x40, y40, x40 + dx40, y40 + dy40);
|
|
//_drain40->setBoundingBox(box40);
|
|
|
|
//_anonymous10
|
|
DbU::Unit y10 = 0;
|
|
DbU::Unit x10 = min(x20 - spacingActiveCut0, sourceDrainWidth);
|
|
DbU::Unit dy10 = _w;
|
|
DbU::Unit extension10 = max(x40 + dx40 + spacingActiveCut0, dx00 + sourceDrainWidth);
|
|
DbU::Unit dx10 = -x10 + extension10;
|
|
|
|
Box box10(x10, y10, x10 + dx10, y10 + dy10);
|
|
_anonymous10->setBoundingBox(box10);
|
|
|
|
//Rectangle 23
|
|
DbU::Unit x23 = x10;
|
|
DbU::Unit y23 = y10;
|
|
DbU::Unit dx23 = x10;
|
|
DbU::Unit dy23 = _w;
|
|
|
|
|
|
//_anonymous11
|
|
DbU::Unit extension11_1 = enclosureGateImplant;
|
|
DbU::Unit extension11_2 = extImplantCut0 - x20;
|
|
DbU::Unit extension11_3 = extImplantActive - x10;
|
|
|
|
DbU::Unit extension11_4 = max(max(extension11_1, extension11_2), extension11_3);
|
|
|
|
DbU::Unit x11 = -extension11_4;
|
|
|
|
extension11_1 = enclosureGateImplant + x00 + dx00;
|
|
extension11_2 = extImplantCut0 + x40 + dx40;
|
|
extension11_3 = extImplantActive + x10 + dx10;
|
|
|
|
extension11_4 = max(max(extension11_1, extension11_2), extension11_3);
|
|
|
|
DbU::Unit dx11 = -x11 + extension11_4;
|
|
|
|
DbU::Unit y11 = min(y20 - extImplantCut0, y23 - extImplantActive);
|
|
DbU::Unit dy11 = max(y20 + dy20 + extImplantCut0, y23 + dy23 + extImplantActive) - y11;
|
|
|
|
Box box11(x11, y11, x11 + dx11, y11 + dy11);
|
|
_anonymous11->setBoundingBox(box11);
|
|
|
|
if (_type == Type::PMOS) {
|
|
DbU::Unit x50 = x10 - enclosurePPlusActive;
|
|
DbU::Unit y50 = y10 - enclosurePPlusActive;
|
|
DbU::Unit dx50 = dx10 + 2 * enclosurePPlusActive;
|
|
DbU::Unit dy50 = dy10 + 2 * enclosurePPlusActive;
|
|
Box box50(x50, y50, x50 + dx50, y50 + dy50);
|
|
if (!_anonymous50) {
|
|
_anonymous50 = createPad(techno, _anonymous, "nWell");
|
|
}
|
|
_anonymous50->setBoundingBox(box50);
|
|
} else {
|
|
if (_anonymous50) {
|
|
_anonymous50->destroy();
|
|
_anonymous50 = NULL;
|
|
}
|
|
}
|
|
|
|
setAbutmentBox(box12);
|
|
UpdateSession::close();
|
|
}
|
|
|
|
Record* Transistor::_getRecord() const {
|
|
Record* record = Inherit::_getRecord();
|
|
if (record) {
|
|
record->add(getSlot("Drain", _drain));
|
|
record->add(getSlot("Source", _source));
|
|
record->add(getSlot("Grid", _grid));
|
|
record->add(getSlot("Bulk", _bulk));
|
|
record->add(getSlot("L", &_l));
|
|
record->add(getSlot("W", &_w));
|
|
//record->add(getSlot("Source20", _source20));
|
|
record->add(getSlot("Source22", _source22));
|
|
//record->add(getSlot("Drain40", _drain40));
|
|
record->add(getSlot("Drain42", _drain42));
|
|
record->add(getSlot("Grid00", _grid00));
|
|
record->add(getSlot("Grid01", _grid01));
|
|
record->add(getSlot("Grid30", _grid30));
|
|
record->add(getSlot("Grid31", _grid31));
|
|
record->add(getSlot("10", _anonymous10));
|
|
record->add(getSlot("11", _anonymous11));
|
|
record->add(getSlot("12", _anonymous12));
|
|
}
|
|
return record;
|
|
}
|