| /*============================================================================== |
| File: S130fet12vPcell.il |
| Purpose: Pcell code for layout setup for 12v mosfet (DE) |
| devices for Skywater S130 Pcells |
| |
| Created: May 30, 2020 Madek Graham |
| Description: Pcell code to create the 12V mosfet (DE) devices |
| |
| Devices/views: nmos_de_v12 / layout |
| pmos_de_v12 / layout |
| |
| ------------------------------------------------------------ |
| Modifications: |
| - Jun 27, 2020 MSG |
| Changed hvi layer to thkox to accomodate change in PDK |
| - Jul 18, 2020 MSG |
| Fixed top/bottom tap spacing to nwell for nmos devices |
| - Sep 05, 2020 MSG |
| Changed tap to default to bot, added fixed cdf params for w & l for discrete |
| device sizes |
| |
| ==============================================================================*/ |
| |
| let( ( libName ) |
| |
| libName = "S130" |
| |
| ;; techData will be loaded in by the tech library's libInit.il |
| |
| foreach( device fet12vDevices |
| |
| printf("Creating device %s in %s library\n" device->deviceName libName ) |
| |
| ;=========================================================== |
| ;***** Define Layout Pcell ***** |
| ;=========================================================== |
| |
| pcDefinePCell( list( ddGetObj(libName) device->deviceName "layout" ) |
| ; formal parameters name value pairs |
| ( |
| ( devInfo "ilList" device ) |
| ( rules "ilList" designRules ) |
| ( grid "float" techGetMfgGridResolution(techGetTechFile(ddGetObj(libName))) ) |
| ( fw "float" device->defW ) ; finger width |
| ( l "float" device->defL ) |
| ( nf "int" 1 ) |
| ( gateCnt "string" "none") ; choices: none, Top, Bottom, Both |
| ( gateCntExt "float" 0.0) |
| ( tapTop "boolean" nil) |
| ( tapTopCnt "boolean" t) |
| ( tapBottom "boolean" t) |
| ( tapBottomCnt "boolean" t) |
| ( tapRight "boolean" nil) |
| ( tapRightCnt "boolean" t) |
| ( tapLeft "boolean" nil) |
| ( tapLeftCnt "boolean" t) |
| ) |
| |
| let(( actImp activeBotEdge activeLftEdge activeRhtEdge activeTopEdge |
| activeTotalL activeTotalW allActiveShapes allDiffShapes cv |
| diffBotEdge diffLftEdge diffRhtEdge diffTopEdge drainImpPoints |
| drainPoints drnBevW endCapExt fdrnSP fsrcSP |
| gateCntL gateCntMetL gateCntMetW gateCntW gateNumCnts |
| gateSPgateCnt gateX hvBot hvLft hvOLbot |
| hvOLlft hvOLrht hvOLtop hvRht hvTop |
| impOLsrc minDrnW nwellBevW nwellBot nwellEndPoints |
| nwellL nwellLayer nwellLft nwellOLbot nwellOLlft |
| nwellOLrht nwellOLtop nwellPoints nwellRht nwellShapes |
| nwellTop nwellW nwellWend pinAdj polyWidth |
| srcDrnLength srcDrnNumConts tapBotAdjL tapBotAdjR tapBotEncPath |
| tapBotL tapBotSubRect tapEncPath tapEncPathWithCnt tapImp |
| tapImpOLtap tapLftAdjB tapLftAdjT tapLftEncPath tapLftL |
| tapLftSubRect tapMetOLcont tapOLcont tapRhtAdjB tapRhtAdjT |
| tapRhtEncPath tapRhtL tapRhtSubRect tapSubRect tapSubRectWithCnt |
| tapTopAdjL tapTopAdjR tapTopEncPath tapTopL tapTopSubRect |
| tapW tapbSP taplSP taprSP taptSP ) |
| |
| cv = pcCellView |
| if( rexMatchp("^pmos" devInfo->deviceName) then |
| dbReplaceProp(cv "instNamePrefix" "string" "MP") |
| actImp = rules->psdm |
| tapImp = rules->nsdm |
| else |
| dbReplaceProp(cv "instNamePrefix" "string" "MN") |
| actImp = rules->nsdm |
| tapImp = rules->psdm |
| ) |
| |
| ; poly width (gate l + overlaps) |
| polyWidth = l + devInfo->rules->srcOLnwell + rules->poly->minOLdiff |
| ; figure out the finger spacing |
| fsrcSP = 2*(rules->licon1->minW + rules->licon1->minDcontSPpoly) + rules->licon1->minSP |
| fdrnSP = devInfo->rules->minDrnW + 2*(devInfo->rules->drnBevW + devInfo->rules->srcDrnSP - rules->poly->minOLdiff) |
| ; calculate li1 Length |
| srcDrnNumConts = 1 + fix( (fw - 2*devInfo->rules->drnBevW - rules->licon1->minW - |
| 2*max(rules->diff->minOLSlicon1,rules->li1->minOLSlicon1))/ |
| (rules->licon1->minW + rules->licon1->minSP) ) |
| srcDrnLength = rules->licon1->minW + 2*rules->li1->minOLSlicon1 + |
| (srcDrnNumConts - 1)*(rules->licon1->minW + rules->licon1->minSP) |
| |
| ; create the gates |
| ;----------------------------- |
| gateX = 0.0 |
| |
| for( finger 1 nf |
| rodCreateRect( |
| ?cvId cv |
| ?name sprintf( nil "gate%d" finger ) |
| ?layer rules->poly->layer |
| ?width polyWidth |
| ?length fw + 2*rules->poly->minOLdiff |
| ?origin gateX : -rules->poly->minOLdiff |
| ) |
| if( oddp(finger) then |
| gateX = gateX + fdrnSP + polyWidth |
| else |
| gateX = gateX + fsrcSP + polyWidth |
| ); if odd finger |
| ); for 1 to nf |
| |
| ; create sources & implants |
| ;----------------------------- |
| rodCreateRect( |
| ?cvId cv |
| ?name "active1" |
| ?layer rules->diff->layer |
| ?width (polyWidth - rules->poly->minOLdiff) + rules->licon1->minW + 2*rules->licon1->minDcontSPpoly |
| ?length fw |
| ?origin 0.0 - (rules->licon1->minW + 2*rules->licon1->minDcontSPpoly) : 0.00 |
| ) |
| rodCreateRect( |
| ?cvId cv |
| ?name "implant1" |
| ?layer actImp->layer |
| ?fromObj rodGetObj("active1" cv) |
| ?size devInfo->rules->impOLsrc |
| ) |
| ; create the srcContact |
| rodCreatePath( |
| ?cvId cv |
| ?name "srcCont1" |
| ?layer rules->li1->layer |
| ?termName "s" |
| ?termIOType "inputOutput" |
| ?width rules->licon1->minW + 2*max(rules->li1->minOLLlicon1 rules->li1->minOLLmcon) |
| ?pts list(0:0 0:srcDrnLength) |
| ?subRect list( list( |
| ?layer rules->licon1->layer |
| ?length rules->licon1->minW |
| ?width rules->licon1->minW |
| ?space rules->licon1->minSP |
| ?gap "minimum" |
| ?endOffset -rules->li1->minOLSlicon1 |
| ?beginOffset -rules->li1->minOLSlicon1 |
| )) |
| ) |
| rodAlign( |
| ?alignObj rodGetObj("srcCont1" cv) |
| ?alignHandle "lowerLeft" |
| ?refObj rodGetObj("active1" cv) |
| ?refHandle "lowerLeft" |
| ?xSep rules->licon1->minDcontSPpoly - max(rules->li1->minOLLlicon1 rules->li1->minOLLmcon) |
| ?ySep round((0.5*(fw-srcDrnLength))/grid)*grid |
| ) |
| rodCreateRect( |
| ?cvId cv |
| ?name "srcPin1" |
| ?layer list( rules->li1->pinlayer rules->li1->pinpurpose ) |
| ?width rodGetObj("srcCont1" cv)->width |
| ?length rodGetObj("srcCont1" cv)->length |
| ?netName "s" |
| ?termName "s" |
| ?termIOType "inputOutput" |
| ?pin t |
| ?pinLabel t |
| ?pinLabelHeight round(0.25*rodGetObj("srcCont1" cv)->width/grid)*grid |
| ?pinLabelLayer list( rules->li1->layer "label") |
| ?pinLabelFont "stick" |
| ) |
| rodAlign( |
| ?alignObj rodGetObj("srcPin1" cv) |
| ?alignHandle "lowerLeft" |
| ?refObj rodGetObj("srcCont1" cv) |
| ?refHandle "lowerLeft" |
| ) |
| |
| when( nf > 2 |
| for( finger 2 nf-1 |
| when( evenp(finger) |
| rodCreateRect( |
| ?cvId cv |
| ?name sprintf( nil "active%d" finger ) |
| ?layer rules->diff->layer |
| ?width 2*(polyWidth - rules->poly->minOLdiff) + |
| 2*(rules->licon1->minW + rules->licon1->minDcontSPpoly) + rules->licon1->minSP |
| ?length fw |
| ) |
| rodAlign( |
| ?alignObj rodGetObj(sprintf( nil "active%d" finger ) cv) |
| ?alignHandle "lowerLeft" |
| ?refObj rodGetObj(sprintf( nil "gate%d" finger ) cv) |
| ?refHandle "lowerLeft" |
| ?xSep rules->poly->minOLdiff |
| ?ySep rules->poly->minOLdiff |
| ) |
| rodCreateRect( |
| ?cvId cv |
| ?name sprintf( nil "implant%d" finger ) |
| ?layer actImp->layer |
| ?fromObj rodGetObj(sprintf( nil "active%d" finger ) cv) |
| ?size devInfo->rules->impOLsrc |
| ) |
| ; create the srcContact |
| rodCreatePath( |
| ?cvId cv |
| ?name sprintf( nil "srcCont%d" finger ) |
| ?layer rules->li1->layer |
| ?termName "s" |
| ?termIOType "inputOutput" |
| ?width 2*rules->licon1->minW + rules->licon1->minSP + 2*max(rules->li1->minOLLlicon1 rules->li1->minOLLmcon) |
| ?pts list(0:0 0:srcDrnLength) |
| ?subRect list( |
| list( |
| ?layer rules->licon1->layer |
| ?length rules->licon1->minW |
| ?width rules->licon1->minW |
| ?space rules->licon1->minSP |
| ?gap "minimum" |
| ?sep -0.5*(rules->licon1->minW + rules->licon1->minSP) |
| ?endOffset -rules->li1->minOLSlicon1 |
| ?beginOffset -rules->li1->minOLSlicon1 |
| ) |
| list( |
| ?layer rules->licon1->layer |
| ?length rules->licon1->minW |
| ?width rules->licon1->minW |
| ?space rules->licon1->minSP |
| ?gap "minimum" |
| ?sep 0.5*(rules->licon1->minW + rules->licon1->minSP) |
| ?endOffset -rules->li1->minOLSlicon1 |
| ?beginOffset -rules->li1->minOLSlicon1 |
| ) |
| ) |
| ) |
| rodAlign( |
| ?alignObj rodGetObj(sprintf(nil "srcCont%d" finger) cv) |
| ?alignHandle "lowerLeft" |
| ?refObj rodGetObj(sprintf(nil "active%d" finger) cv) |
| ?refHandle "lowerLeft" |
| ?xSep polyWidth - rules->poly->minOLdiff + rules->licon1->minDcontSPpoly - max(rules->li1->minOLLlicon1 rules->li1->minOLLmcon) |
| ?ySep round((0.5*(fw-srcDrnLength))/grid)*grid |
| ) |
| rodCreateRect( |
| ?cvId cv |
| ?name sprintf( nil "srcPin%d" finger ) |
| ?layer list( rules->li1->pinlayer rules->li1->pinpurpose ) |
| ?width rodGetObj(sprintf(nil "srcCont%d" finger) cv)->width |
| ?length rodGetObj(sprintf(nil "srcCont%d" finger) cv)->length |
| ?netName "s" |
| ?termName "s" |
| ?termIOType "inputOutput" |
| ?pin t |
| ?pinLabel t |
| ?pinLabelHeight round(0.25*rodGetObj(sprintf(nil "srcCont%d" finger) cv)->width/grid)*grid |
| ?pinLabelLayer list( rules->li1->layer "label") |
| ?pinLabelFont "stick" |
| ) |
| rodAlign( |
| ?alignObj rodGetObj(sprintf( nil "srcPin%d" finger ) cv) |
| ?alignHandle "lowerLeft" |
| ?refObj rodGetObj(sprintf(nil "srcCont%d" finger) cv) |
| ?refHandle "lowerLeft" |
| ) |
| ); when even finger |
| ); for finger 2 to nf-1 |
| ); when nf > 2 |
| when( evenp(nf) |
| rodCreateRect( |
| ?cvId cv |
| ?name sprintf( nil "active%d" nf ) |
| ?layer rules->diff->layer |
| ?width (polyWidth - rules->poly->minOLdiff) + rules->licon1->minW + 2*rules->licon1->minDcontSPpoly |
| ?length fw |
| ) |
| rodAlign( |
| ?alignObj rodGetObj(sprintf( nil "active%d" nf ) cv) |
| ?alignHandle "lowerLeft" |
| ?refObj rodGetObj(sprintf( nil "gate%d" nf ) cv) |
| ?refHandle "lowerLeft" |
| ?xSep rules->poly->minOLdiff |
| ?ySep rules->poly->minOLdiff |
| ) |
| rodCreateRect( |
| ?cvId cv |
| ?name sprintf( nil "implant%d" nf ) |
| ?layer actImp->layer |
| ?fromObj rodGetObj(sprintf( nil "active%d" nf ) cv) |
| ?size devInfo->rules->impOLsrc |
| ) |
| ; create the srcContact |
| rodCreatePath( |
| ?cvId cv |
| ?name sprintf( nil "srcCont%d" nf ) |
| ?layer rules->li1->layer |
| ?termName "s" |
| ?termIOType "inputOutput" |
| ?width rules->licon1->minW + 2*max(rules->li1->minOLLlicon1 rules->li1->minOLLmcon) |
| ?pts list(0:0 0:srcDrnLength) |
| ?subRect list( list( |
| ?layer rules->licon1->layer |
| ?length rules->licon1->minW |
| ?width rules->licon1->minW |
| ?space rules->licon1->minSP |
| ?gap "minimum" |
| ?endOffset -rules->li1->minOLSlicon1 |
| ?beginOffset -rules->li1->minOLSlicon1 |
| )) |
| ) |
| rodAlign( |
| ?alignObj rodGetObj(sprintf( nil "srcCont%d" nf ) cv) |
| ?alignHandle "lowerRight" |
| ?refObj rodGetObj(sprintf( nil "active%d" nf ) cv) |
| ?refHandle "lowerRight" |
| ?xSep -(rules->licon1->minDcontSPpoly - max(rules->li1->minOLLlicon1 rules->li1->minOLLmcon)) |
| ?ySep round((0.5*(fw-srcDrnLength))/grid)*grid |
| ) |
| rodCreateRect( |
| ?cvId cv |
| ?name sprintf( nil "srcPin%d" nf ) |
| ?layer list( rules->li1->pinlayer rules->li1->pinpurpose ) |
| ?width rodGetObj(sprintf( nil "srcCont%d" nf ) cv)->width |
| ?length rodGetObj(sprintf( nil "srcCont%d" nf ) cv)->length |
| ?netName "s" |
| ?termName "s" |
| ?termIOType "inputOutput" |
| ?pin t |
| ?pinLabel t |
| ?pinLabelHeight round(0.25*rodGetObj(sprintf( nil "srcCont%d" nf ) cv)->width/grid)*grid |
| ?pinLabelLayer list( rules->li1->layer "label") |
| ?pinLabelFont "stick" |
| ) |
| rodAlign( |
| ?alignObj rodGetObj(sprintf( nil "srcPin%d" nf ) cv) |
| ?alignHandle "lowerLeft" |
| ?refObj rodGetObj(sprintf( nil "srcCont%d" nf ) cv) |
| ?refHandle "lowerLeft" |
| ) |
| ); when even nf |
| |
| ; create drains, implants, & nwells |
| ;----------------------------- |
| ; drain points based at lowerCenter |
| minDrnW = devInfo->rules->minDrnW |
| drnBevW = devInfo->rules->drnBevW |
| impOLsrc = devInfo->rules->impOLsrc |
| drainPoints = list(0:0 |
| 0.5*minDrnW:0 |
| 0.5*minDrnW + drnBevW:drnBevW |
| 0.5*minDrnW + drnBevW:fw - drnBevW |
| 0.5*minDrnW:fw |
| -0.5*minDrnW:fw |
| -0.5*minDrnW - drnBevW:fw - drnBevW |
| -0.5*minDrnW - drnBevW:drnBevW |
| -0.5*minDrnW:0 |
| ) |
| drainImpPoints = list(0:0 |
| 0.5*minDrnW + impOLsrc:0 |
| 0.5*minDrnW + impOLsrc + drnBevW:drnBevW |
| 0.5*minDrnW + impOLsrc + drnBevW:fw + 2*impOLsrc - drnBevW |
| 0.5*minDrnW + impOLsrc:fw + 2*impOLsrc |
| -0.5*minDrnW - impOLsrc:fw + 2*impOLsrc |
| -0.5*minDrnW - impOLsrc - drnBevW:fw + 2*impOLsrc - drnBevW |
| -0.5*minDrnW - impOLsrc - drnBevW:drnBevW |
| -0.5*minDrnW - impOLsrc:0 |
| ) |
| nwellBevW = devInfo->rules->nwellBevW |
| nwellW = 2*(devInfo->rules->srcOLnwell + devInfo->rules->srcDrnSP - nwellBevW) + minDrnW + 2*drnBevW |
| nwellWend = devInfo->rules->srcOLnwell + devInfo->rules->srcDrnSP - 2*nwellBevW + minDrnW + 2*drnBevW + devInfo->rules->wellOLdrn |
| nwellL = fw + 2*devInfo->rules->wellOLdrn |
| nwellPoints = list(0:0 |
| 0.5*nwellW:0 |
| 0.5*nwellW + nwellBevW:nwellBevW |
| 0.5*nwellW + nwellBevW:nwellL - nwellBevW |
| 0.5*nwellW:nwellL |
| -0.5*nwellW:nwellL |
| -0.5*nwellW - nwellBevW:nwellL - nwellBevW |
| -0.5*nwellW - nwellBevW:nwellBevW |
| -0.5*nwellW:0 |
| ) |
| nwellEndPoints = list(0:0 |
| 0.5*nwellWend:0 |
| 0.5*nwellWend + nwellBevW:nwellBevW |
| 0.5*nwellWend + nwellBevW:nwellL - nwellBevW |
| 0.5*nwellWend:nwellL |
| -0.5*nwellWend:nwellL |
| -0.5*nwellWend - nwellBevW:nwellL - nwellBevW |
| -0.5*nwellWend - nwellBevW:nwellBevW |
| -0.5*nwellWend:0 |
| ) |
| for( finger 1 nf |
| when( oddp(finger) |
| rodCreatePolygon( |
| ?cvId cv |
| ?name sprintf(nil "drain%d" finger) |
| ?layer rules->diff->layer |
| ?pts drainPoints |
| ) |
| rodAlign( |
| ?alignObj rodGetObj(sprintf(nil "drain%d" finger) cv) |
| ?alignHandle "lowerLeft" |
| ?refObj rodGetObj(sprintf( nil "active%d" finger) cv)||rodGetObj(sprintf( nil "active%d" finger-1) cv) |
| ?refHandle "lowerRight" |
| ?xSep devInfo->rules->srcDrnSP |
| ) |
| rodCreatePolygon( |
| ?cvId cv |
| ?name sprintf( nil "drainImp%d" finger ) |
| ?layer actImp->layer |
| ?pts drainImpPoints |
| ) |
| rodAlign( |
| ?alignObj rodGetObj(sprintf(nil "drainImp%d" finger) cv) |
| ?alignHandle "centerCenter" |
| ?refObj rodGetObj(sprintf(nil "drain%d" finger) cv) |
| ?refHandle "centerCenter" |
| ) |
| ; create the srcContact |
| rodCreatePath( |
| ?cvId cv |
| ?name sprintf( nil "drnCont%d" finger ) |
| ?layer rules->li1->layer |
| ?termName "d" |
| ?termIOType "inputOutput" |
| ?width rules->licon1->minW + 2*max(rules->li1->minOLLlicon1 rules->li1->minOLLmcon) |
| ?pts list(0:0 0:srcDrnLength) |
| ?subRect list( list( |
| ?layer rules->licon1->layer |
| ?length rules->licon1->minW |
| ?width rules->licon1->minW |
| ?space rules->licon1->minSP |
| ?gap "minimum" |
| ?endOffset -rules->li1->minOLSlicon1 |
| ?beginOffset -rules->li1->minOLSlicon1 |
| )) |
| ) |
| rodAlign( |
| ?alignObj rodGetObj(sprintf( nil "drnCont%d" finger ) cv) |
| ?alignHandle "lowerCenter" |
| ?refObj rodGetObj(sprintf( nil "drain%d" finger ) cv) |
| ?refHandle "lowerCenter" |
| ?ySep round((0.5*(fw-srcDrnLength))/grid)*grid |
| ) |
| rodCreateRect( |
| ?cvId cv |
| ?name sprintf( nil "drnPin%d" finger ) |
| ?layer list( rules->li1->pinlayer rules->li1->pinpurpose ) |
| ?width rodGetObj(sprintf( nil "drnCont%d" finger ) cv)->width |
| ?length rodGetObj(sprintf( nil "drnCont%d" finger ) cv)->length |
| ?netName "d" |
| ?termName "d" |
| ?termIOType "inputOutput" |
| ?pin t |
| ?pinLabel t |
| ?pinLabelHeight round(0.25*rodGetObj(sprintf( nil "drnCont%d" finger ) cv)->width/grid)*grid |
| ?pinLabelLayer list( rules->li1->layer "label") |
| ?pinLabelFont "stick" |
| ) |
| rodAlign( |
| ?alignObj rodGetObj(sprintf( nil "drnPin%d" finger ) cv) |
| ?alignHandle "lowerLeft" |
| ?refObj rodGetObj(sprintf( nil "drnCont%d" finger ) cv) |
| ?refHandle "lowerLeft" |
| ) |
| |
| if( finger < nf then |
| rodCreatePolygon( |
| ?cvId cv |
| ?name sprintf( nil "drainNwell%d" finger ) |
| ?layer rules->nwell->layer |
| ?pts nwellPoints |
| ) |
| rodAlign( |
| ?alignObj rodGetObj(sprintf(nil "drainNwell%d" finger) cv) |
| ?alignHandle "centerCenter" |
| ?refObj rodGetObj(sprintf(nil "drain%d" finger) cv) |
| ?refHandle "centerCenter" |
| ) |
| else |
| rodCreatePolygon( |
| ?cvId cv |
| ?name sprintf( nil "drainNwell%d" finger ) |
| ?layer rules->nwell->layer |
| ?pts nwellEndPoints |
| ) |
| rodAlign( |
| ?alignObj rodGetObj(sprintf(nil "drainNwell%d" finger) cv) |
| ?alignHandle "centerRight" |
| ?refObj rodGetObj(sprintf(nil "drain%d" finger) cv) |
| ?refHandle "centerRight" |
| ?xSep devInfo->rules->wellOLdrn |
| ) |
| ); if finger < nf |
| ); when odd finger |
| ); for fingers |
| |
| ; create marking layer (ext drain) |
| ;----------------------------- |
| ; get the edges of the active diff |
| allActiveShapes = setof( shape cv->shapes shape->layerName == rules->diff->layer ) |
| activeTopEdge = topEdge( car(allActiveShapes)->bBox ) |
| activeLftEdge = leftEdge( car(allActiveShapes)->bBox ) |
| activeBotEdge = bottomEdge( car(allActiveShapes)->bBox ) |
| activeRhtEdge = rightEdge( car(allActiveShapes)->bBox ) |
| foreach( activeShape allActiveShapes |
| activeTopEdge = max(activeTopEdge topEdge( activeShape->bBox )) |
| activeLftEdge = min(activeLftEdge leftEdge( activeShape->bBox )) |
| activeBotEdge = min(activeBotEdge bottomEdge( activeShape->bBox )) |
| activeRhtEdge = max(activeRhtEdge rightEdge( activeShape->bBox )) |
| ); foreach activeShape |
| |
| activeTotalW = activeRhtEdge - activeLftEdge |
| activeTotalL = activeTopEdge - activeBotEdge |
| rodCreateRect( |
| ?cvId cv |
| ?name "extDrain" |
| ?layer devInfo->mrkLay |
| ?width activeTotalW |
| ?length activeTotalL |
| ) |
| rodAlign( |
| ?alignObj rodGetObj("extDrain" cv) |
| ?alignHandle "lowerLeft" |
| ?refObj rodGetObj("active1" cv) |
| ?refHandle "lowerLeft" |
| ) |
| |
| ; create 12V marking layer (only over active as the body might want to be a diff potential) |
| ;----------------------------- |
| rodCreateRect( |
| ?cvId cv |
| ?name "hvMarker" |
| ?layer rules->vhvi->layer |
| ?width activeTotalW |
| ?length activeTotalL |
| ) |
| rodAlign( |
| ?alignObj rodGetObj("hvMarker" cv) |
| ?alignHandle "lowerLeft" |
| ?refObj rodGetObj("active1" cv) |
| ?refHandle "lowerLeft" |
| ) |
| |
| ; create gate contacts |
| ;----------------------------- |
| unless( gateCnt == "none" |
| |
| ; calculate poly (gateCnt) for gate contacts |
| gateCntL = max( 2*rules->poly->minOLSlicon1 + rules->licon1->minW, |
| polyWidth ) |
| gateCntW = 2*rules->poly->minOLLlicon1 + rules->licon1->minW |
| ; calculate number of gate contacts and metal length |
| ; want to keep li1 within the gate cont poly |
| gateNumCnts = 1 + fix( (gateCntL - 2*max(rules->poly->minOLSlicon1,rules->li1->minOLSlicon1) - |
| rules->licon1->minW) / (rules->licon1->minW + rules->licon1->minSP)) |
| gateCntMetL = 2*rules->li1->minOLSlicon1 + rules->licon1->minW + |
| (gateNumCnts-1)*(rules->licon1->minW + rules->licon1->minSP) |
| gateCntMetW = 2*rules->li1->minOLLlicon1 + rules->licon1->minW |
| gateSPgateCnt = gateCntExt + max( rules->poly->minSPdiff, |
| rules->npc->minSPgate + (rules->npc->minOLpcont - rules->poly->minOLLlicon1) |
| rules->licon1->minPcontSPdiff - rules->poly->minOLLlicon1 |
| max(actImp->minOLdiff devInfo->rules->impOLsrc) + (rules->licon1->minPcontSPpsdm - rules->poly->minOLLlicon1) ) |
| |
| ; extension of gate endcap (if needed) |
| endCapExt = 0.0 |
| if( gateSPgateCnt > rules->poly->minOLdiff then |
| endCapExt = gateSPgateCnt - rules->poly->minOLdiff |
| ); if gateSPgateCnt > endcap |
| |
| when( gateCnt == "Top" || gateCnt == "Both" |
| for( finger 1 nf |
| rodCreateRect( |
| ?cvId cv |
| ?name sprintf(nil "gateTopCntPoly%d" finger) |
| ?layer rules->poly->layer |
| ?width gateCntL |
| ?length gateCntW |
| ) |
| rodAlign( |
| ?alignObj rodGetObj(sprintf(nil "gateTopCntPoly%d" finger) cv) |
| ?alignHandle "lowerLeft" |
| ?refObj rodGetObj(sprintf(nil "gate%d" finger) cv ) |
| ?refHandle "upperLeft" |
| ?ySep -rules->poly->minOLdiff + gateSPgateCnt |
| ) |
| rodCreateRect( |
| ?cvId cv |
| ?name sprintf(nil "gateTopCntImp%d" finger) |
| ?layer rules->npc->layer |
| ?width 2*(rules->npc->minOLpcont - rules->poly->minOLLlicon1) + gateCntL |
| ?length 2*(rules->npc->minOLpcont - rules->poly->minOLLlicon1) + gateCntW |
| ) |
| rodAlign( |
| ?alignObj rodGetObj(sprintf( nil "gateTopCntImp%d" finger) cv) |
| ?alignHandle "centerCenter" |
| ?refObj rodGetObj(sprintf( nil "gateTopCntPoly%d" finger) cv) |
| ?refHandle "centerCenter" |
| ) |
| when( endCapExt > 0.0 |
| rodCreateRect( |
| ?cvId cv |
| ?name sprintf(nil "gateTopExt%d" finger) |
| ?layer rules->poly->layer |
| ?width polyWidth |
| ?length endCapExt |
| ) |
| rodAlign( |
| ?alignObj rodGetObj( sprintf(nil "gateTopExt%d" finger) cv ) |
| ?alignHandle "lowerLeft" |
| ?refObj rodGetObj( sprintf(nil "gate%d" finger) cv ) |
| ?refHandle "upperLeft" |
| ) |
| ); when endCapExt > 0 |
| |
| rodCreatePath( |
| ?cvId cv |
| ?name sprintf(nil "gateTopMetCnt%d" finger) |
| ?layer rules->li1->layer |
| ?width gateCntMetW |
| ?pts list(0:0 gateCntMetL:0) |
| ?subRect list( list( |
| ?layer rules->licon1->layer |
| ?length rules->licon1->minW |
| ?width rules->licon1->minW |
| ?space rules->licon1->minSP |
| ?gap "minimum" |
| ?endOffset -rules->li1->minOLSlicon1 |
| ?beginOffset -rules->li1->minOLSlicon1 |
| )) |
| ) |
| rodAlign( |
| ?alignObj rodGetObj( sprintf(nil "gateTopMetCnt%d" finger) cv ) |
| ?alignHandle "centerLeft" |
| ?refObj rodGetObj(sprintf( nil "gateTopCntPoly%d" finger) cv) |
| ?refHandle "centerLeft" |
| ?xSep round((0.5*(gateCntL - gateCntMetL))/grid)*grid |
| ) |
| rodCreateRect( |
| ?cvId cv |
| ?name sprintf(nil "gateTopPin%d" finger) |
| ?layer list( rules->li1->pinlayer rules->li1->pinpurpose ) |
| ?width rodGetObj(sprintf( nil "gateTopMetCnt%d" finger) cv)->width |
| ?length rodGetObj(sprintf( nil "gateTopMetCnt%d" finger) cv)->length |
| ?netName "g" |
| ?termName "g" |
| ?termIOType "input" |
| ?pin t |
| ?pinLabel t |
| ?pinLabelHeight round(0.25*gateCntMetW/grid)*grid |
| ?pinLabelLayer list( rules->li1->layer "label") |
| ?pinLabelFont "stick" |
| ) |
| rodAlign( |
| ?alignObj rodGetObj( sprintf(nil "gateTopPin%d" finger) cv ) |
| ?alignHandle "lowerLeft" |
| ?refObj rodGetObj( sprintf(nil "gateTopMetCnt%d" finger) cv ) |
| ?refHandle "lowerLeft" |
| ) |
| |
| ); for each finger |
| ); when gateCnt Top |
| |
| when( gateCnt == "Bottom" || gateCnt == "Both" |
| for( finger 1 nf |
| rodCreateRect( |
| ?cvId cv |
| ?name sprintf(nil "gateBotCntPoly%d" finger) |
| ?layer rules->poly->layer |
| ?width gateCntL |
| ?length gateCntW |
| ) |
| rodAlign( |
| ?alignObj rodGetObj(sprintf(nil "gateBotCntPoly%d" finger) cv) |
| ?alignHandle "upperLeft" |
| ?refObj rodGetObj(sprintf(nil "gate%d" finger) cv ) |
| ?refHandle "lowerLeft" |
| ?ySep rules->poly->minOLdiff - gateSPgateCnt |
| ) |
| rodCreateRect( |
| ?cvId cv |
| ?name sprintf(nil "gateBotCntImp%d" finger) |
| ?layer rules->npc->layer |
| ?width 2*(rules->npc->minOLpcont - rules->poly->minOLLlicon1) + gateCntL |
| ?length 2*(rules->npc->minOLpcont - rules->poly->minOLLlicon1) + gateCntW |
| ) |
| rodAlign( |
| ?alignObj rodGetObj(sprintf( nil "gateBotCntImp%d" finger) cv) |
| ?alignHandle "centerCenter" |
| ?refObj rodGetObj(sprintf( nil "gateBotCntPoly%d" finger) cv) |
| ?refHandle "centerCenter" |
| ) |
| when( endCapExt > 0.0 |
| rodCreateRect( |
| ?cvId cv |
| ?name sprintf(nil "gateBotExt%d" finger) |
| ?layer rules->poly->layer |
| ?width polyWidth |
| ?length endCapExt |
| ) |
| rodAlign( |
| ?alignObj rodGetObj( sprintf(nil "gateBotExt%d" finger) cv ) |
| ?alignHandle "upperLeft" |
| ?refObj rodGetObj( sprintf(nil "gate%d" finger) cv ) |
| ?refHandle "lowerLeft" |
| ) |
| ); when endCapExt > 0 |
| |
| rodCreatePath( |
| ?cvId cv |
| ?name sprintf(nil "gateBotMetCnt%d" finger) |
| ?layer rules->li1->layer |
| ?width gateCntMetW |
| ?pts list(0:0 gateCntMetL:0) |
| ?subRect list( list( |
| ?layer rules->licon1->layer |
| ?length rules->licon1->minW |
| ?width rules->licon1->minW |
| ?space rules->licon1->minSP |
| ?gap "minimum" |
| ?endOffset -rules->li1->minOLSlicon1 |
| ?beginOffset -rules->li1->minOLSlicon1 |
| )) |
| ) |
| rodAlign( |
| ?alignObj rodGetObj( sprintf(nil "gateBotMetCnt%d" finger) cv ) |
| ?alignHandle "centerLeft" |
| ?refObj rodGetObj(sprintf( nil "gateBotCntPoly%d" finger) cv) |
| ?refHandle "centerLeft" |
| ?xSep round((0.5*(gateCntL - gateCntMetL))/grid)*grid |
| ) |
| rodCreateRect( |
| ?cvId cv |
| ?name sprintf(nil "gateBotPin%d" finger) |
| ?layer list( rules->li1->pinlayer rules->li1->pinpurpose ) |
| ?width rodGetObj(sprintf( nil "gateBotMetCnt%d" finger) cv)->width |
| ?length rodGetObj(sprintf( nil "gateBotMetCnt%d" finger) cv)->length |
| ?netName "g" |
| ?termName "g" |
| ?termIOType "input" |
| ?pin t |
| ?pinLabel t |
| ?pinLabelHeight round(0.25*gateCntMetW/grid)*grid |
| ?pinLabelLayer list( rules->li1->layer "label") |
| ?pinLabelFont "stick" |
| ) |
| rodAlign( |
| ?alignObj rodGetObj( sprintf(nil "gateBotPin%d" finger) cv ) |
| ?alignHandle "lowerLeft" |
| ?refObj rodGetObj( sprintf(nil "gateBotMetCnt%d" finger) cv ) |
| ?refHandle "lowerLeft" |
| ) |
| |
| ); for each finger |
| ); when gateCnt Bot |
| |
| ); unless gateCnt none |
| |
| ; create gate pins when no gate contact |
| ;----------------------------- |
| when( gateCnt == "none" |
| for( finger 1 nf |
| rodCreateRect( |
| ?cvId cv |
| ?name sprintf(nil "gateTopPin%d" finger) |
| ?layer list( rules->poly->pinlayer rules->poly->pinpurpose ) |
| ?width polyWidth |
| ?length rules->poly->minOLdiff |
| ?netName "g" |
| ?termName "g" |
| ?termIOType "input" |
| ?pin t |
| ?pinLabel t |
| ?pinLabelHeight round(0.25*rules->poly->minOLdiff/grid)*grid |
| ?pinLabelLayer list( rules->poly->layer "label") |
| ?pinLabelFont "stick" |
| ) |
| rodAlign( |
| ?alignObj rodGetObj( sprintf(nil "gateTopPin%d" finger) cv ) |
| ?alignHandle "upperLeft" |
| ?refObj rodGetObj( sprintf(nil "gate%d" finger) cv) |
| ?refHandle "upperLeft" |
| ) |
| rodCreateRect( |
| ?cvId cv |
| ?name sprintf(nil "gateBotPin%d" finger) |
| ?layer list( rules->poly->pinlayer rules->poly->pinpurpose ) |
| ?width polyWidth |
| ?length rules->poly->minOLdiff |
| ?netName "g" |
| ?termName "g" |
| ?termIOType "input" |
| ?pin t |
| ?pinLabel t |
| ?pinLabelHeight round(0.25*rules->poly->minOLdiff/grid)*grid |
| ?pinLabelLayer list( rules->poly->layer "label") |
| ?pinLabelFont "stick" |
| ) |
| rodAlign( |
| ?alignObj rodGetObj( sprintf(nil "gateBotPin%d" finger) cv ) |
| ?alignHandle "lowerLeft" |
| ?refObj rodGetObj( sprintf(nil "gate%d" finger) cv) |
| ?refHandle "lowerLeft" |
| ) |
| ); for nf |
| ); when no gateCnt |
| |
| ; create the taps |
| ;----------------------------- |
| tapImpOLtap = tapImp->minOLtap |
| |
| ; best to go with max overlap contact so the corners will line up |
| tapOLcont = max(rules->tap->minOLLisoTapLicon1 rules->tap->minOLSisoTapLicon1) |
| tapMetOLcont = max(rules->li1->minOLLlicon1 rules->li1->minOLSlicon1) |
| tapW = max(rules->tap->minW 2*tapOLcont + rules->licon1->minW ) |
| |
| ; do some basic calculations for the tap |
| |
| ; for left & right taps, the spacing will be from the mos diff or nwell |
| taplSP = max( rules->diff->minSPhvtap |
| actImp->minOLdiff + actImp->minSPdiff |
| tapImp->minOLtap + actImp->minSPdiff ) |
| if( evenp(nf) then |
| taprSP = max( rules->diff->minSPhvtap |
| actImp->minOLdiff + actImp->minSPdiff |
| tapImp->minOLtap + actImp->minSPdiff ) |
| else |
| if( rexMatchp("^pmos" devInfo->deviceName) then |
| taprSP = max( rules->nwell->minOLhvtap + devInfo->rules->wellOLdrn |
| devInfo->rules->wellSPtap + devInfo->rules->wellOLdrn |
| actImp->minOLdiff + actImp->minSPdiff |
| tapImp->minOLtap + actImp->minSPdiff ) |
| else |
| taprSP = max( rules->tap->minSPnwell + devInfo->rules->wellOLdrn |
| actImp->minOLdiff + actImp->minSPdiff |
| tapImp->minOLtap + actImp->minSPdiff ) |
| ); if pmos |
| ); if even nf |
| |
| ; for top & bottom taps, the spacing could be from the mos diff, gates, or poly cont |
| ; in the end, the spacing will be from mos diff to tap edge |
| taptSP = tapbSP = max( rules->diff->minSPhvtap |
| if( rexMatchp("^pmos" devInfo->deviceName) then |
| max( rules->nwell->minOLhvtap + devInfo->rules->wellOLdrn |
| devInfo->rules->wellSPtap + devInfo->rules->wellOLdrn ) |
| else |
| rules->tap->minSPnwell + devInfo->rules->wellOLdrn |
| devInfo->rules->wellSPtap + devInfo->rules->wellOLdrn |
| ) |
| actImp->minOLdiff + actImp->minSPdiff |
| tapImp->minOLtap + actImp->minSPdiff |
| rules->tap->minSPpoly + rules->poly->minOLdiff |
| rules->licon1->minDcontSPpoly - rules->tap->minOLSisoTapLicon1 + rules->poly->minOLdiff ) |
| |
| when( gateCnt == "Top" || gateCnt == "Both" |
| taptSP = max( taptSP gateSPgateCnt + gateCntW + rules->tap->minSPpoly ) |
| when( tapTopCnt |
| taptSP = max( taptSP |
| gateSPgateCnt + gateCntW - 0.5*(gateCntW - gateCntMetW) + rules->li1->minSP + (tapMetOLcont - tapOLcont) |
| gateSPgateCnt + gateCntW + (rules->npc->minOLpcont - rules->poly->minOLLlicon1) + |
| rules->licon1->taplicon1SPnpc - rules->tap->minOLSisoTapLicon1 |
| gateSPgateCnt + gateCntW - 0.5*(gateCntW - gateCntMetW) + rules->licon1->minPcontSPdiff |
| gateSPgateCnt + gateCntW - 0.5*(gateCntW - gateCntMetW) + rules->licon1->minPcontSPpsdm + tapImp->minOLtap ) |
| ) |
| ); when top gateCnt |
| when( gateCnt == "Bottom" || gateCnt == "Both" |
| tapbSP = max( tapbSP gateSPgateCnt + gateCntW + rules->tap->minSPpoly ) |
| when( tapBottomCnt |
| tapbSP = max( tapbSP |
| gateSPgateCnt + gateCntW - 0.5*(gateCntW - gateCntMetW) + rules->li1->minSP + (tapMetOLcont - tapOLcont) |
| gateSPgateCnt + gateCntW + (rules->npc->minOLpcont - rules->poly->minOLLlicon1) + |
| rules->licon1->taplicon1SPnpc - rules->tap->minOLSisoTapLicon1 |
| gateSPgateCnt + gateCntW - 0.5*(gateCntW - gateCntMetW) + rules->licon1->minPcontSPdiff |
| gateSPgateCnt + gateCntW - 0.5*(gateCntW - gateCntMetW) + rules->licon1->minPcontSPpsdm + tapImp->minOLtap ) |
| ) |
| ); when bottom gateCnt |
| |
| if( tapTop then tapRhtAdjT = tapLftAdjT = tapW + taptSP else tapRhtAdjT = tapLftAdjT = 0.0 ) |
| if( tapLeft then tapTopAdjL = tapBotAdjL = tapW + taplSP else tapTopAdjL = tapBotAdjL = 0.0 ) |
| if( tapBottom then tapRhtAdjB = tapLftAdjB = tapW + tapbSP else tapRhtAdjB = tapLftAdjB = 0.0 ) |
| if( tapRight then tapTopAdjR = tapBotAdjR = tapW + taprSP else tapTopAdjR = tapBotAdjR = 0.0 ) |
| |
| tapTopL = activeTotalW + tapTopAdjL + tapTopAdjR |
| tapLftL = activeTotalL + tapLftAdjT + tapLftAdjB |
| tapBotL = activeTotalW + tapBotAdjL + tapBotAdjR |
| tapRhtL = activeTotalL + tapRhtAdjT + tapRhtAdjB |
| |
| tapEncPath = list( list( ?layer tapImp->layer ?enclosure -tapImpOLtap ) ) |
| tapSubRect = list( ) |
| tapEncPathWithCnt = list( |
| ?layer rules->li1->layer |
| ?enclosure -(tapMetOLcont - tapOLcont) |
| ) |
| tapSubRectWithCnt = list( |
| ?layer rules->licon1->layer |
| ?length rules->licon1->minW |
| ?width rules->licon1->minW |
| ?space rules->licon1->minSP |
| ?endOffset -tapOLcont |
| ?beginOffset -tapOLcont |
| ) |
| |
| ; create top tap |
| if( tapTop then |
| if( tapTopCnt then |
| tapTopEncPath = append1( tapEncPath tapEncPathWithCnt ) |
| tapTopSubRect = append1( tapSubRect tapSubRectWithCnt ) |
| else |
| tapTopEncPath = tapEncPath |
| tapTopSubRect = tapSubRect |
| ); end when tapTopCnt |
| rodCreatePath( |
| ?cvId cv |
| ?name "tapTopPath" |
| ?layer rules->tap->layer |
| ?width tapW |
| ?pts list( |
| activeLftEdge-tapTopAdjL : activeTopEdge+taptSP+0.5*tapW |
| activeRhtEdge+tapTopAdjR : activeTopEdge+taptSP+0.5*tapW |
| ) |
| ?netName "b" |
| ?termName "b" |
| ?termIOType "inputOutput" |
| ?pin t |
| ?encSubPath tapTopEncPath |
| ?subRect tapTopSubRect |
| ); end rodCreatePath tapTopPath |
| |
| ; create pin |
| when( tapTopCnt |
| pinAdj = tapMetOLcont - tapOLcont |
| rodCreateRect( |
| ?cvId cv |
| ?name "tapTopPin" |
| ?layer list( rules->li1->pinlayer rules->li1->pinpurpose ) |
| ?bBox list( |
| rodAddToY(rodAddToX(rodGetObj("tapTopPath" cv)->lowerLeft -pinAdj) -pinAdj) |
| rodAddToY(rodAddToX(rodGetObj("tapTopPath" cv)->upperRight pinAdj) pinAdj) |
| ) |
| ?netName "b" |
| ?termName "b" |
| ?termIOType "inputOutput" |
| ?pin t |
| ?pinLabel t |
| ?pinLabelHeight 0.5*tapW |
| ?pinLabelLayer list( rules->li1->layer "label") |
| ?pinLabelFont "stick" |
| ) |
| ) |
| ); end if tapTop |
| |
| ; create right tap |
| if( tapRight then |
| if( tapRightCnt then |
| tapRhtEncPath = append1( tapEncPath tapEncPathWithCnt ) |
| tapRhtSubRect = append1( tapSubRect tapSubRectWithCnt ) |
| else |
| tapRhtEncPath = tapEncPath |
| tapRhtSubRect = tapSubRect |
| ); end when tapRightCnt |
| rodCreatePath( |
| ?cvId cv |
| ?name "tapRhtPath" |
| ?layer rules->tap->layer |
| ?width tapW |
| ?pts list( |
| activeRhtEdge+taprSP+0.5*tapW : activeBotEdge-tapRhtAdjB |
| activeRhtEdge+taprSP+0.5*tapW : activeTopEdge+tapRhtAdjT |
| ) |
| ?netName "b" |
| ?termName "b" |
| ?termIOType "inputOutput" |
| ?pin t |
| ?encSubPath tapRhtEncPath |
| ?subRect tapRhtSubRect |
| ); end rodCreatePath tapRhtPath |
| |
| when( tapRightCnt |
| pinAdj = tapMetOLcont - tapOLcont |
| rodCreateRect( |
| ?cvId cv |
| ?name "tapRhtPin" |
| ?layer list( rules->li1->pinlayer rules->li1->pinpurpose ) |
| ?bBox list( |
| rodAddToY(rodAddToX(rodGetObj("tapRhtPath" cv)->lowerLeft -pinAdj) -pinAdj) |
| rodAddToY(rodAddToX(rodGetObj("tapRhtPath" cv)->upperRight pinAdj) pinAdj) |
| ) |
| ?netName "b" |
| ?termName "b" |
| ?termIOType "inputOutput" |
| ?pin t |
| ?pinLabel t |
| ?pinLabelHeight 0.5*tapW |
| ?pinLabelLayer list( rules->li1->layer "label") |
| ?pinLabelFont "stick" |
| ) |
| ) |
| ); end if tapRight |
| |
| ; create bottom tap |
| if( tapBottom then |
| if( tapBottomCnt then |
| tapBotEncPath = append1( tapEncPath tapEncPathWithCnt ) |
| tapBotSubRect = append1( tapSubRect tapSubRectWithCnt ) |
| else |
| tapBotEncPath = tapEncPath |
| tapBotSubRect = tapSubRect |
| ); end when tapBottomCnt |
| rodCreatePath( |
| ?cvId cv |
| ?name "tapBotPath" |
| ?layer rules->tap->layer |
| ?width tapW |
| ?pts list( |
| activeLftEdge-tapBotAdjL : activeBotEdge-tapbSP-0.5*tapW |
| activeRhtEdge+tapBotAdjR : activeBotEdge-tapbSP-0.5*tapW |
| ) |
| ?netName "b" |
| ?termName "b" |
| ?termIOType "inputOutput" |
| ?pin t |
| ?encSubPath tapBotEncPath |
| ?subRect tapBotSubRect |
| ); end rodCreatePath tapBotPath |
| |
| when( tapBottomCnt |
| pinAdj = tapMetOLcont - tapOLcont |
| rodCreateRect( |
| ?cvId cv |
| ?name "tapBotPin" |
| ?layer list( rules->li1->pinlayer rules->li1->pinpurpose ) |
| ?bBox list( |
| rodAddToY(rodAddToX(rodGetObj("tapBotPath" cv)->lowerLeft -pinAdj) -pinAdj) |
| rodAddToY(rodAddToX(rodGetObj("tapBotPath" cv)->upperRight pinAdj) pinAdj) |
| ) |
| ?netName "b" |
| ?termName "b" |
| ?termIOType "inputOutput" |
| ?pin t |
| ?pinLabel t |
| ?pinLabelHeight 0.5*tapW |
| ?pinLabelLayer list( rules->li1->layer "label") |
| ?pinLabelFont "stick" |
| ) |
| ) |
| ); end if tapBottom |
| |
| ; create left tap |
| if( tapLeft then |
| if( tapLeftCnt then |
| tapLftEncPath = append1( tapEncPath tapEncPathWithCnt ) |
| tapLftSubRect = append1( tapSubRect tapSubRectWithCnt ) |
| else |
| tapLftEncPath = tapEncPath |
| tapLftSubRect = tapSubRect |
| ); end when tapLeftCnt |
| rodCreatePath( |
| ?cvId cv |
| ?name "tapLftPath" |
| ?layer rules->tap->layer |
| ?width tapW |
| ?pts list( |
| activeLftEdge-taplSP-0.5*tapW : activeBotEdge-tapLftAdjB |
| activeLftEdge-taplSP-0.5*tapW : activeTopEdge+tapLftAdjT |
| ) |
| ?netName "b" |
| ?termName "b" |
| ?termIOType "inputOutput" |
| ?pin t |
| ?encSubPath tapLftEncPath |
| ?subRect tapLftSubRect |
| ); end rodCreatePath tapLftPath |
| |
| when( tapLeftCnt |
| pinAdj = tapMetOLcont - tapOLcont |
| rodCreateRect( |
| ?cvId cv |
| ?name "tapLftPin" |
| ?layer list( rules->li1->pinlayer rules->li1->pinpurpose ) |
| ?bBox list( |
| rodAddToY(rodAddToX(rodGetObj("tapLftPath" cv)->lowerLeft -pinAdj) -pinAdj) |
| rodAddToY(rodAddToX(rodGetObj("tapLftPath" cv)->upperRight pinAdj) pinAdj) |
| ) |
| ?netName "b" |
| ?termName "b" |
| ?termIOType "inputOutput" |
| ?pin t |
| ?pinLabel t |
| ?pinLabelHeight 0.5*tapW |
| ?pinLabelLayer list( rules->li1->layer "label") |
| ?pinLabelFont "stick" |
| ) |
| ) |
| ); end if tapLeft |
| |
| ; calculations for thick ox (tkkox/v5), nwell, and dnwell layers |
| ;----------------------------- |
| allDiffShapes = setof( shape cv->shapes (shape->objType != "label" && shape->lpp == list("diff" "drawing"))) |
| diffTopEdge = topEdge( car(allDiffShapes)->bBox ) |
| diffLftEdge = leftEdge( car(allDiffShapes)->bBox ) |
| diffBotEdge = bottomEdge( car(allDiffShapes)->bBox ) |
| diffRhtEdge = rightEdge( car(allDiffShapes)->bBox ) |
| foreach( diffShape allDiffShapes |
| diffTopEdge = max(diffTopEdge topEdge( diffShape->bBox )) |
| diffLftEdge = min(diffLftEdge leftEdge( diffShape->bBox )) |
| diffBotEdge = min(diffBotEdge bottomEdge( diffShape->bBox )) |
| diffRhtEdge = max(diffRhtEdge rightEdge( diffShape->bBox )) |
| ); foreach diffShape |
| |
| if( tapTop then |
| if( rexMatchp("^pmos" devInfo->deviceName) then |
| hvOLtop = nwellOLtop = max( rules->nwell->minOLhvtap rules->nwell->minOLdnwell |
| rules->nwell->minOLdnwell + rules->dnwell->minOLipw - (rules->nwell->minOLhvtap + tapW) ) |
| else |
| hvOLtop = rules->thkox->minOLtap |
| nwellOLtop = rules->nwell->minOLhvtap |
| ) |
| else |
| if( rexMatchp("^pmos" devInfo->deviceName) then |
| hvOLtop = nwellOLtop = max( rules->nwell->minOLhvdiff rules->nwell->minOLdnwell |
| devInfo->rules->wellOLdrn + rules->dnwell->minOLipw + rules->nwell->minOLdnwell |
| devInfo->rules->wellOLdrn + rules->nwell->minW ) |
| else |
| hvOLtop = max( rules->thkox->minOLdiff rules->nwell->minOLhvdiff devInfo->rules->wellOLdrn ) |
| nwellOLtop = rules->nwell->minOLhvdiff |
| ) |
| ); if tapTop |
| hvTop = diffTopEdge + hvOLtop |
| nwellTop = diffTopEdge + nwellOLtop |
| |
| if( tapBottom then |
| if( rexMatchp("^pmos" devInfo->deviceName) then |
| hvOLbot = nwellOLbot = max( rules->nwell->minOLhvtap rules->nwell->minOLdnwell |
| rules->nwell->minOLdnwell + rules->dnwell->minOLipw - (rules->nwell->minOLhvtap + tapW) ) |
| else |
| hvOLbot = rules->thkox->minOLtap |
| nwellOLbot = max( rules->nwell->minOLhvtap rules->nwell->minOLdnwell ) |
| ) |
| else |
| if( rexMatchp("^pmos" devInfo->deviceName) then |
| hvOLbot = nwellOLbot = max( rules->nwell->minOLhvdiff rules->nwell->minOLdnwell |
| devInfo->rules->wellOLdrn + rules->dnwell->minOLipw + rules->nwell->minOLdnwell |
| devInfo->rules->wellOLdrn + rules->nwell->minW ) |
| else |
| hvOLbot = max( rules->thkox->minOLdiff rules->nwell->minOLhvdiff devInfo->rules->wellOLdrn ) |
| nwellOLbot = rules->nwell->minOLhvdiff |
| ) |
| ); if tapBottom |
| hvBot = diffBotEdge - hvOLbot |
| nwellBot = diffBotEdge - nwellOLbot |
| |
| if( tapRight then |
| if( rexMatchp("^pmos" devInfo->deviceName) then |
| hvOLrht = nwellOLrht = max( rules->nwell->minOLhvtap rules->nwell->minOLdnwell ) |
| ;rules->nwell->minOLdnwell + rules->dnwell->minOLipw - (rules->nwell->minOLhvtap + tapW) ) |
| else |
| hvOLrht = rules->thkox->minOLtap |
| nwellOLrht = 0.0 |
| ) |
| else |
| if( evenp(nf) then |
| if( rexMatchp("^pmos" devInfo->deviceName) then |
| hvOLrht = nwellOLrht = max( rules->nwell->minOLhvdiff rules->nwell->minOLdnwell |
| rules->nwell->minOLdnwell + rules->dnwell->minOLipw - |
| (rodGetObj("active1" cv)->width - devInfo->rules->srcOLnwell)) |
| else |
| hvOLrht = rules->thkox->minOLdiff |
| nwellOLrht = 0.0 |
| ) |
| else |
| if( rexMatchp("^pmos" devInfo->deviceName) then |
| hvOLrht = nwellOLrht = max( rules->nwell->minOLhvdiff rules->nwell->minOLdnwell |
| devInfo->rules->wellOLdrn + rules->dnwell->minOLipw + rules->nwell->minOLdnwell |
| devInfo->rules->wellOLdrn + rules->nwell->minW ) |
| else |
| hvOLrht = max( rules->thkox->minOLdiff rules->nwell->minOLhvdiff devInfo->rules->wellOLdrn ) |
| nwellOLrht = 0.0 |
| ) |
| ); if even nf |
| ); if tapRight |
| hvRht = diffRhtEdge + hvOLrht |
| nwellRht = diffRhtEdge + nwellOLrht |
| |
| if( tapLeft then |
| if( rexMatchp("^pmos" devInfo->deviceName) then |
| hvOLlft = nwellOLlft = max( rules->nwell->minOLhvtap rules->nwell->minOLdnwell ) |
| else |
| hvOLlft = rules->thkox->minOLtap |
| nwellOLlft = 0.0 |
| ) |
| else |
| if( rexMatchp("^pmos" devInfo->deviceName) then |
| hvOLlft = nwellOLlft = max( rules->nwell->minOLhvdiff rules->nwell->minOLdnwell ) |
| hvOLlft = nwellOLlft = max( rules->nwell->minOLhvdiff rules->nwell->minOLdnwell |
| rules->nwell->minOLdnwell + rules->dnwell->minOLipw - |
| (rodGetObj("active1" cv)->width - devInfo->rules->srcOLnwell)) |
| else |
| hvOLlft = rules->thkox->minOLdiff |
| nwellOLlft = 0.0 |
| ) |
| ); if tapLeft |
| hvLft = diffLftEdge - hvOLlft |
| nwellLft = diffLftEdge - nwellOLlft |
| |
| ; create thkox layer |
| ;----------------------------- |
| rodCreateRect( |
| ?cvId cv |
| ?name "thickOxLayer" |
| ?layer rules->thkox->layer |
| ?bBox list( hvLft:hvBot hvRht:hvTop ) |
| ) |
| |
| ; create nwell and dnwell layers |
| ;----------------------------- |
| when( rexMatchp("^pmos" devInfo->deviceName) |
| nwellShapes = setof( shape cv->shapes shape->layerName == rules->nwell->layer ) |
| rodCreateRect( |
| ?cvId cv |
| ?name "nwellLayer" |
| ?layer rules->nwell->layer |
| ?bBox list( nwellLft:nwellBot nwellRht:nwellTop ) |
| ) |
| rodCreateRect( |
| ?cvId cv |
| ?name "dnwellLayer" |
| ?layer rules->dnwell->layer |
| ?fromObj rodGetObj( "nwellLayer" cv) |
| ?size -rules->nwell->minOLdnwell |
| ) |
| ; need to remove the nwells that are place holders for the iso pwells |
| nwellLayer = dbLayerAndNot( cv rules->nwell->layer list( rodGetObj("nwellLayer" cv)->dbId ) nwellShapes ) |
| foreach( nw nwellShapes dbDeleteObject(nw)) |
| dbDeleteObject(rodGetObj("nwellLayer" cv)->dbId) |
| ); when pmos |
| |
| ; create body pin if no taps exist |
| unless( tapTop || tapLeft || tapBottom || tapRight |
| if( rexMatchp("^pmos" devInfo->deviceName) then |
| rodCreateRect( |
| ?cvId cv |
| ?name "wellPin" |
| ?layer list( "nwell" "pin" ) |
| ?fromObj rodGetObj( "srcPin1" cv ) |
| ?netName "b" |
| ?termName "b" |
| ?termIOType "inputOutput" |
| ?pin t |
| ?pinLabel t |
| ?pinLabelHeight 0.3 |
| ?pinLabelLayer list( "nwell" "label") |
| ?pinLabelFont "stick" |
| ) |
| else |
| rodCreateRect( |
| ?cvId cv |
| ?name "wellPin" |
| ?layer list( "pwell" "pin" ) |
| ?fromObj rodGetObj( "srcPin1" cv ) |
| ?netName "b" |
| ?termName "b" |
| ?termIOType "inputOutput" |
| ?pin t |
| ?pinLabel t |
| ?pinLabelHeight 0.3 |
| ?pinLabelLayer list( "pwell" "label") |
| ?pinLabelFont "stick" |
| ) |
| ); if pmos |
| ); unless any taps |
| |
| ); let |
| ); pcDefinePCell layout |
| |
| ); foreach device |
| |
| ); let |
| |
| /*================================== EOF ===================================*/ |