-- File: DJExtract.mesa
-- Circuit extractor for disjoint
-- Written by Martin Newell/Dan Fitzpatrick June 1981
-- Last edited: 13-Aug-81 14:42:21

DIREC
TORY

CIFU
tilitiesDefs: FROM "CIFUtilitiesDefs" USING [ClearClipRectangle],
DisjointAllocDefs: FROM "DisjointAllocDefs" USING [EnumerateSymbols],
DisjointPropDefs: FROM "DisjointPropDefs" USING [GetProp, GetLongProp, AllocPropID,
PutProp,PutLongProp, RemoveProp],
DisjointTypes: FROM "DisjointTypes" USING [Instance, Rectangle, RectangleRecord, Symbol,
Geometry,PropID],
DJExtDefs: FROM "DJExtDefs",
DJExtractDefs: FROM "DJExtractDefs",
DJExtAllocDefs: FROM "DJExtAllocDefs" USING [MakeHEdge, MakeVEdge, FreeEdge,
AllocateSegment,AllocateBox, AllocateActualParameter, MakeNodeLocation],
DJExtCapDefs: FROM "DJExtCapDefs" USING [SelectCap, RenumberCap,CopyCap,AddCapPerim],
DJExtCombineDefs: FROM "DJExtCombineDefs" USING [AttachNode,FindNode],
DJExtDebugDefs: FROM "DJExtDebugDefs" USING [Debug],
DJExtGeomDefs: FROM "DJExtGeomDefs" USING [ExtractGeometry],
DJExtGraphicsDefs: FROM "DJExtGraphicsDefs" USING [DrawSymbol, DrawSegment],
DJExtMergeDefs: FROM "DJExtMergeDefs" USING [InitMerge, GenNodeNumber, FinishMerge,
ReserveNodeNumbers,LookSmall,GetSmall],
DJExtSegDefs: FROM "DJExtSegDefs" USING [SegBucketSort, SegListSort],
DJExtSortDefs: FROM "DJExtSortDefs" USING [InitSorter, SortBox],
DJExtTransDefs: FROM "DJExtTransDefs" USING [SelectTransistors, RenumberTrans,CopyTrans],
DJExtTypes: FROM "DJExtTypes" USING [Edge, NodeLocation, NodeNumber, Position, Segment,
Box,ActualParameter, APLimit, poly, diff, metal, gate, Node],
IODefs: FROM "IODefs" USING [WriteString,WriteLine],
Real: FROM "Real" USING [FixI];

DJExtr
act: PROGRAM
IMPORTS CIFUtilitiesDefs, DisjointAllocDefs, DisjointPropDefs, DJExtAllocDefs, DJExtCapDefs, DJExtCombineDefs, DJExtDebugDefs, DJExtGeomDefs, DJExtGraphicsDefs, DJExtMergeDefs, DJExtSegDefs, DJExtSortDefs, DJExtTransDefs, IODefs, Real
EXPORTS DJExtDefs, DJExtractDefs =
BEGIN
OPEN CIFUtilitiesDefs, DisjointAllocDefs, DisjointTypes, DisjointPropDefs, DJExtAllocDefs, DJExtCapDefs, DJExtCombineDefs, DJExtDebugDefs, DJExtGeomDefs, DJExtGraphicsDefs, DJExtMergeDefs, DJExtSegDefs, DJExtSortDefs, DJExtTransDefs, DJExtTypes, IODefs, Real;

Interr
upt: PUBLIC SIGNAL = CODE;

Extract: PUBLIC PROCEDURE[s
ymbol: Symbol] =
BEGIN
ENABLE Interrupt => {
WriteLine["Interrupt!"];
CONTINUE;
};

Mark:
PROC[s:Symbol] RETURNS[BOOLEAN] =
BEGIN
PutProp[@s.prop,extractID,0];
RETURN[FALSE];
END;

RemoveMark: PROC[s:Symbol] RETURNS[BOOLEAN] =
BEGIN
RemoveProp[s.prop,extractID];
RETURN[FALSE];
END;

debug ← Debug[];
[] ← EnumerateSymbols[Mark];
ExtractSymbol[symbol];
CleanUp[symbol];
[] ← EnumerateSymbols[RemoveMark];
IF NOT debug THEN WriteLine[""];
END;

CleanUp: PROCEDURE[symbol: Symbol] =
-- since this is the out most symbol remove external references
BEGIN
next:Node;
intTrans:Node ← GetLongProp[symbol.prop,intID];
intCap:Node ← GetLongProp[symbol.prop,intCapID];
FOR ptr:Node ← GetLongProp[symbol.prop,extID], next UNTIL ptr = NIL DO
next ← ptr.next;
ptr.next ← intTrans;
intTrans ← ptr;
ENDLOOP;
PutLongProp[@symbol.prop,intID,intTrans];

FOR ptr:Node ← GetLongProp[symbol.prop,extCapID], next UNTIL ptr = NIL DO
next ← ptr.next;
ptr.next ← intCap;
intCap ← ptr;
ENDLOOP;
PutLongProp[@symbol.prop,intCapID,intCap];
END;

ExtractSymbol: PROCEDURE[
symbol: Symbol] =
BEGIN
-- for each callee of symbol see if it has been extracted, if not extract it
-- only one extraction can take place at a time so we can have only one merge table &
-- one element list
-- symbol.geom ← Strip[symbol.geom];
FOR in: Instance ← symbol.insts,in.next UNTIL in = NIL DO
IF GetProp[in.symbol.prop,extractID] # 1 THEN ExtractSymbol[in.symbol];
ENDLOOP;
-- start extraction of symbol
InitExtractSymbol[symbol];
-- enter each window of symbol
FOR w:Rectangle ← symbol.windows,w.next UNTIL w = NIL DO
EnterWindow[w];
ENDLOOP;
-- for each callee of symbol sort its set of external segments into the ElementList
FOR in: Instance ← symbol.insts,in.next UNTIL in = NIL DO
GetInstance[in];
ENDLOOP;
-- enter geometry of symbol into the ElementList
FOR g:Geometry ← symbol.geom,g.next UNTIL g = NIL DO
EnterGeometry[g];
ENDLOOP;
-- find trans regions of diffusion segments
SortSegments[];
-- extract the conectivity of the geometry
ExtractGeometry[];
FinishExtractSymbol[symbol];
-- output an upper bound on the node numbers of this symbol
PutLongProp[@symbol.prop,nNodesID,GetSmall[]];
-- mark symbol as checked
PutProp[@symbol.prop,extractID,1];
IF NOT debug THEN WriteString["."];
END;

InitExtractSymbol: PROCEDURE[symbol: Symbol] =
BEGI
N
InitMerge[];
--WindowList ← NIL;
--GeomList ← NIL;
firstActual ← lastActual ← NIL;
Offset ← 0;
NodeLocList ← NIL;
-- compute bounding box of current symbol
SetBBox[@bbox,symbol.windows];
FOR w:Rectangle ← symbol.windows.next,w.next UNTIL w = NIL DO
ExpandBBox[@bbox,w];
ENDLOOP;
InitSorter[@bbox];
ClearClipRectangle[];
IF debug THEN DrawSymbol[symbol,FALSE,1];
END;

FinishExtractSymbol: PROCEDURE[symbol: Symbol] =
BEGIN
enext: Edge;
snext: Segment;
segList: Segment ← NIL;
intTrans,extTrans: Node;
intCap,extCap: Node;
i:INTEGER;

-- put all segments on one long list
FOR i IN [0..32) DO
FOR e: Edge ← LeftWindowBin[i],enext UNTIL e = NIL DO
enext ← e.next;
FOR s: Segment ← e.segment,snext UNTIL s = NIL DO
snext ← s.next;
s.next ← segList;
s.node ← LookSmall[s.node];
segList ← s;
ENDLOOP;
FreeEdge[e];
ENDLOOP;
FOR e: Edge ← BotWindowBin[i],enext UNTIL e = NIL DO
enext ← e.next;
FOR s: Segment ← e.segment,snext UNTIL s = NIL DO
snext ← s.next;
s.next ← segList;
s.node ← LookSmall[s.node];
segList ← s;
ENDLOOP;
FreeEdge[e];
ENDLOOP;
FOR e: Edge ← RightWindowBin[i],enext UNTIL e = NIL DO
enext ← e.next;
FOR s: Segment ← e.segment,snext UNTIL s = NIL DO
snext ← s.next;
s.next ← segList;
s.node ← LookSmall[s.node];
segList ← s;
ENDLOOP;
FreeEdge[e];
ENDLOOP;
FOR e: Edge ← TopWindowBin[i],enext UNTIL e = NIL DO
enext ← e.next;
FOR s: Segment ← e.segment,snext UNTIL s = NIL DO
snext ← s.next;
s.next ← segList;
s.node ← LookSmall[s.node];
segList ← s;
ENDLOOP;
FreeEdge[e];
ENDLOOP;
ENDLOOP;
[intTrans,extTrans] ← SelectTransistors[];
[intCap,extCap] ← SelectCap[];
RenumberTrans[extTrans];
RenumberCap[extCap];
PutLongProp[@symbol.prop,extID,extTrans];-- hang external trans on cell
PutLongProp[@symbol.prop,extCapID,extCap];-- hang external caps on cell
-- output an upper bound on the external segments of this symbol
PutLongProp[@symbol.prop,nParamID,GetSmall[]];
RenumberTrans[intTrans];
RenumberCap[intCap];
PutLongProp[@symbol.prop,intID,intTrans];-- hang internal trans on cell
PutLongProp[@symbol.prop,intCapID,intCap];-- hang internal caps on cell

FOR a: ActualParameter ← firstActual,a.next UNTIL a = NIL DO
FOR i: CARDINAL IN [0..a.count) DO
a.node[i] ← LookSmall[a.node[i]];
ENDLOOP;
ENDLOOP;
-- output node numbers of parameters of this symbol
PutLongProp[@symbol.prop,paramID,firstActual];
BotWindowBin ← ALL[NIL];
TopWindowBin ← ALL[NIL];
LeftWindowBin ← ALL[NIL];
RightWindowBin ← ALL[NIL];
-- renumber all the nodes so that we get a minimum number description
ReNumber[];
-- attach parameter list to symbol
PutLongProp[@symbol.prop,segmentID,segList];
-- attach node locations to symbol
PutLongProp[@symbol.prop,nodeLocID,NodeLocList];
FinishMerge[];
END;

EnterWindow: PROCEDURE[window:Rectangle]
=
--
each window of the current symbol is broken into its four components, left, bottom, right, & top
-- each component is placed in a bucket table, for later comparison against geometry & segments
-- as each component is enter it is compare
d against other members of the bucket to see if it is
-- a continuation of any edges already entered.
BEGIN
h,v: Edge;
n: INTEGER;
-- bottom edge
h ← MakeHEdge[window.b,window.l,window.r];
n ← SelectHBin[window.b];
EnterHWindowEdge[h,@BotWindowBin[n]];
-- top edge
h ← MakeHEdge[window.t,window.l,window.r];
n ← SelectHBin[window.t];
EnterHWindowEdge[h,@TopWindowBin[n]];
-- left edge
v ← MakeVEdge[window.l,window.b,window.t];
n ← SelectVBin[window.l];
EnterVWindowEdge[v,@LeftWindowBin[n]];
-- right edge
v ← MakeVEdge[window.r,window.b,window.t];
n ← SelectVBin[window.r];
EnterVWindowEdge[v,@RightWindowBin[n]];
END;

GetInstance: PROCEDURE[in:In
stance] =
BEGIN
tmp: ActualParameter;
n: LONG CARDINAL ← GetLongProp[in.symbol.prop,nParamID];-- number of params in this symbol
-- reserve n node numbers
ReserveNodeNumbers[n];
FOR trans: Node ← GetLongProp[in.symbol.prop,extID],trans.next UNTIL trans = NIL DO
AttachNode[trans.node+Offset,CopyTrans[trans,Offset]];
ENDLOOP;
FOR cap: Node ← GetLongProp[in.symbol.prop,extCapID],cap.next UNTIL cap = NIL DO
AttachNode[cap.node+Offset,CopyCap[cap,Offset]];
ENDLOOP;
FOR seg: Segment ← GetLongProp[in.symbol.prop,segmentID],seg.next UNTIL seg = NIL DO
EnterSegment[seg,seg.node+Offset,in.xOffset,in.yOffset];
ENDLOOP;
-- make note of node numbers assigned to this instance
-- this loop causes: Offset ← Offset + n;
FOR i: LONG CARDINAL IN [0..n) DO
IF lastActual = NIL OR lastActual.count = APLimit THEN {
tmp ← AllocateActualParameter[];
IF lastActual = NIL THEN firstActual ← tmp
ELSE lastActual.next ← tmp;
lastActual ← tmp;
lastActual.count ← 0;
lastActual.next ← NIL;
};
lastActual.node[lastActual.count] ← Offset ← Offset + 1;
lastActual.count ← lastActual.count + 1;
ENDLOOP;
END;

EnterSegment: PROCEDURE[segment:Segment, node:NodeNumb
er, x,y:REAL] =
-- Each segment creates a zero width (or height) geometry cell with given
node number
-- It is recorded that this node number was given to this segment by adding a record to paramList
-- The segment is checked against the window edges to see if is a p
arameter to the outside world
-- if so a new (outside) segment is created with the given node number
BEGIN
box: Box ← AllocateBox[];
box.l ← segment.bx + x;
box.b ← segment.by + y;
box.r ← segment.tx + x;
box.t ← segment.ty + y;
box.layer ← segment.layer;
box.node ← node;
AddCapPerim[FindNode[node,box.layer,box.l,box.b],box.layer, 2*(box.l+box.b-box.r-box.t)];
SELECT segment.pos FROM
Top => CheckTop[box];
Bottom => CheckBottom[box];
Left => CheckLeft[box];
Right => CheckRight[box];
ENDCASE;
SortBox[box];
END;

EnterGeometry: PROCEDURE[geom:G
eometry] =
-- Each piece of geometry is checked ag
ainst the windows to see if it is to be a parameter
-- if it is, it is given
a node number and added segList
-- the geometry is then added to the list of geometry to be extracted
BEGIN
box: Box ← AllocateBox[];
box.l ← geom.l;
box.b ← geom.b;
box.r ← geom.r;
box.t ← geom.t;
box.layer ← geom.layer;
box.node ← 0;
IF Active[box.layer] THEN {
CheckLeft[box];
CheckRight[box];
CheckBottom[box];
CheckTop[box];
};
SortBox[box];
END;

ReNumber: PROCEDURE =
BEGIN
FOR p:NodeLocation ← NodeLocList, p.next UNTIL p = NIL DO
p.node ← LookSmall[p.node];
ENDLOOP;
END;

CheckLeft: PROCEDURE[box:Box] =
BEGIN
n: INTEGER ← SelectVBin[box.l];
FOR ptr: Edge ← LeftWindowBin[n],ptr.next UNTIL ptr = NIL DO
IF box.l = ptr.bx AND ptr.by < box.t AND box.b < ptr.ty THEN {
box.node ← AddSegment[@ptr.segment,box.l,box.b,box.t,box.node,Left,box.layer];
ptr.count ← ptr.count + 1;
RETURN;
}
ENDLOOP;
END;

CheckRight: PROCEDURE[box:Box] =
BEGIN
n: INTEGER ← SelectVBin[box.r];
FOR ptr: Edge ← RightWindowBin[n],ptr.next UNTIL ptr = NIL DO
IF box.r = ptr.bx AND ptr.by < box.t AND box.b < ptr.ty THEN {
box.node ← AddSegment[@ptr.segment,box.r,box.b,box.t,box.node,Right,box.layer];
ptr.count ← ptr.count + 1;
RETURN;
}
ENDLOOP;
END;

CheckBottom: PROCEDURE[box:Box] =
BEGIN
n: INTEGER ← SelectHBin[box.b];
FOR ptr: Edge ← BotWindowBin[n],ptr.next UNTIL ptr = NIL DO
IF box.b = ptr.by AND ptr.bx < box.r AND box.l < ptr.tx THEN {
box.node ← AddSegment[@ptr.segment,box.b,box.l,box.r,box.node,Bottom,box.layer];
ptr.count ← ptr.count + 1;
RETURN;
}
ENDLOOP;
END;

CheckTop: PROCEDURE[box:Box] =
BEGIN
n: INTEGER ← SelectHBin[box.t];
FOR ptr: Edge ← TopWindowBin[n],ptr.next UNTIL ptr = NIL DO
IF box.t = ptr.by AND ptr.bx < box.r AND box.l < ptr.tx THEN {
box.node ← AddSegment[@ptr.segment,box.t,box.l,box.r,box.node,Top,box.layer];
ptr.count ← ptr.count + 1;
RETURN;
}
ENDLOOP;
END;

AddSegment: PROCEDURE[list:LONG POINTER TO Seg
ment, a,low,high:REAL, node:NodeNumber, pos:Position,
layer:INTEGER] RETURNS[NodeNumber] =
-- Add a segment from high to low ont
o the segment list of e
-- if there already is a segment which overlaps this new segment combine them
BEGIN
seg: Segment;

SELECT pos FROM
Top,Bottom => {
IF debug THEN DrawSegment[low,a,high,a];
seg ← AllocateSegment[];
seg.pos ← pos;
seg.by ← seg.ty ← a;
seg.bx ← low;
seg.tx ← high;
seg.layer ← layer;
seg.node ← node;
seg.next ← list↑;
list↑ ← seg;
-- remember diffusion isn’t a conductor
IF seg.layer # diff AND seg.node = 0 THEN {
seg.node ← GenNodeNumber[];
RecordNodeLoc[seg.node,(seg.bx+seg.tx)/2,(seg.by+seg.ty)/2];
};
RETURN[seg.node];
};
Left,Right => {
IF debug THEN DrawSegment[a,low,a,high];
seg ← AllocateSegment[];
seg.pos ← pos;
seg.bx ← seg.tx ← a;
seg.by ← low;
seg.ty ← high;
seg.layer ← layer;
seg.node ← node;
seg.next ← list↑;
list↑ ← seg;
-- remember diffusion isn’t a conductor
IF seg.layer # diff AND seg.node = 0 THEN {
seg.node ← GenNodeNumber[];
RecordNodeLoc[seg.node,(seg.bx+seg.tx)/2,(seg.by+seg.ty)/2];
};
RETURN[seg.node];
};
ENDCASE;
RETURN[0];-- we never reach this statement but it keeps the compiler happy
END;

SortSegments: PROCEDURE =
BEGIN
i:INTEGER;

FOR i IN [0..32) DO
FOR e: Edge ← LeftWindowBin[i],e.next UNTIL e = NIL DO
IF e.count > nBreak THEN e.segment ← SegBucketSort[e.segment,e.count,e.by,e.ty,Left]
ELSE e.segment ← SegListSort[e.segment,Left];
ENDLOOP;
FOR e: Edge ← BotWindowBin[i],e.next UNTIL e = NIL DO
IF e.count > nBreak THEN e.segment ← SegBucketSort[e.segment,e.count,e.bx,e.tx,Bottom]
ELSE e.segment ← SegListSort[e.segment,Bottom];
ENDLOOP;
FOR e: Edge ← RightWindowBin[i],e.next UNTIL e = NIL DO
IF e.count > nBreak THEN e.segment ← SegBucketSort[e.segment,e.count,e.by,e.ty,Right]
ELSE e.segment ← SegListSort[e.segment,Right];
ENDLOOP;
FOR e: Edge ← TopWindowBin[i],e.next UNTIL e = NIL DO
IF e.count > nBreak THEN e.segment ← SegBucketSort[e.segment,e.count,e.bx,e.tx,Top]
ELSE e.segment ← SegListSort[e.segment,Top];
ENDLOOP;
ENDLOOP;
END;

EnterHWindowEdge: PROCEDURE [e:Edge, list: LONG POINTER TO Edge] =
BEGIN
next: Edge;
tmp: Edge ← NIL;
FOR ptr: Edge ← list↑,next UNTIL ptr = NIL DO
next ← ptr.next;
IF e.by = ptr.by AND ptr.bx <= e.tx AND e.bx <= ptr.bx THEN {
e.bx ← MIN[e.bx,ptr.bx];
e.tx ← MAX[e.tx,ptr.tx];
FreeEdge[ptr];
LOOP;
};
ptr.next ← tmp;
tmp ← ptr;
ENDLOOP;
e.next ← tmp;
list↑ ← e;
END;

EnterVWindowEdge: PROCEDURE [e:Edge, list: LONG POINTER TO Edge] =
BEGIN
next: Edge;
tmp: Edge ← NIL;
FOR ptr: Edge ← list↑,next UNTIL ptr = NIL DO
next ← ptr.next;
IF e.bx = ptr.bx AND ptr.by <= e.ty AND e.by <= ptr.by THEN {
e.by ← MIN[e.by,ptr.by];
e.ty ← MAX[e.ty,ptr.ty];
FreeEdge[ptr];
LOOP;
};
ptr.next ← tmp;
tmp ← ptr;
ENDLOOP;
e.next ← tmp;
list↑ ← e;
END;

SelectHBin: PROCE
DURE [y: REAL] RETURNS [n: INTEGER] =
BEGIN
n ← FixI[32*(y - bbox.b)/(bbox.t - bbox.b + 1)];
END;

SelectVBin: PROCE
DURE [x: REAL] RETURNS [n: INTEGER] =
BEGIN
n ← FixI[32*(x - bbox.l)/(bbox.r - bbox.l + 1)];
END;

SetBBox: PROCEDURE
[bb1,bb2: Rectangle] =
BEGIN
bb1.l ← bb2.l;
bb1.b ← bb2.b;
bb1.r ← bb2.r;
bb1.t ← bb2.t;
END;

ExpandBBox: PROCEDURE [bb1,bb2: Rectangle] =
BEGIN
IF bb2.l < bb1.l THEN bb1.l ← bb2.l;
IF bb2.b < bb1.b THEN bb1.b ← bb2.b;
IF bb1.r < bb2.r THEN bb1.r ← bb2.r;
IF bb1.t < bb2.t THEN bb1.t ← bb2.t;
END;

GetSegmentList: PUBLIC PROCEDURE[sym
bol: Symbol] RETURNS[segList: Segment] =
BEGIN
segList ← GetLongProp[symbol.prop,segmentID];
END;

Strip: PUBLIC PROCEDURE[in: Geometry] RETURNS[out: Geometry] =
BEGIN
geom: Geometry;
out ← NIL;
UNTIL in = NIL DO
geom ← in;
in ← in.next;
IF geom.layer = 2 THEN {
geom.next ← out;
out ← geom;
};
ENDLOOP;
END;

RecordNodeLoc: PUBLIC PROCEDURE[node: NodeNumber, x,y:REAL] =
BEGIN
tmp: NodeLocation ← MakeNodeLocation[node,x,y];
tmp.next ← NodeLocList;
NodeLocList ← tmp;
END;

GetNodeLocID: PUBLIC PROCEDURE RETURNS[PropID] =
BEGIN
RETURN[nodeLocID];
END;

GetNodesID: PUBLIC PROCEDURE RETURNS[PropID] =
BEGIN
RETURN[nNodesID];
END;

GetSegmentID: PUBLIC PROCEDURE RETURNS[PropID] =
BEGIN
RETURN[segmentID];
END;

GetParamID: PUBLIC PROCEDURE RETURNS[PropID] =
BEGIN
RETURN[paramID];
END;

GetNParamID: PUBLIC PROCEDURE RETURNS[PropID] =
BEGIN
RETURN[nParamID];
END;

GetIntTransID: PUBLIC PROCEDURE RETURNS[PropID] =
BEGIN
RETURN[intID];
END;

GetExtTransID: PUBLIC PROCEDURE RETURNS[PropID] =
BEGIN
RETURN[extID];
END;

GetIntCapID: PUBLIC PROCEDURE RETURNS[PropID] =
BEGIN
RETURN[intCapID];
END;

GetExt
CapID: PUBLIC PROCEDURE RETURNS[PropID] =
BE
GIN
RETURN[extCapID];
END;

debug:BOOLEAN ← TRUE;-- debugging flag

bbox: RectangleRecord;
-- bounding box of current symbol

firstActual:
ActualParameter;
lastActual: Ac
tualParameter;
Offset: LONG CARDINAL;
NodeLocList: NodeLocation;
-- loaction of nodes in this symbol

BotWindowBin: ARRAY [0..32) OF Edge ← ALL[NIL];
TopWindowBin: ARRAY [0..32) OF Edge ← ALL[NIL];
LeftWindowBin: ARRAY [0..32) OF Edge
← ALL[NIL];
RightWindowBin: ARRAY [0..32) OF Edge ← ALL[NI
L];

extractID: PropID ← AllocPropID[];
-- tag which marks whether the sub-circuit has been extracted
segmentID: PropI
D ← AllocPropID[];-- tag to get the segments of the sub-circuit
paramID: PropID ← AllocPr
opID[];-- tag to get list of parameter numbers for this symbol
nPa
ramID: PropID ← AllocPropID[];-- tag to get number of segments
nNodesID: PropID
← AllocPropID[];-- tag to get number of nodes in sub-circuit
nodeLocID: Pro
pID ← AllocPropID[];-- tag to get node locations for sub-circuit
e
xtID: PropID ← AllocPropID[];-- tag to get external transistors
int
ID: PropID ← AllocPropID[];-- tag to get internal transistors
extCapID: PropID ← All
ocPropID[];-- tag to get external caps
intCapID: PropID ← AllocPropID[];
-- tag to get internal caps

nBreak: CARDINAL = 8;
MaxLayer: CARDINAL = 16;
Active: ARRAY [0..MaxLayer) OF BOOLEAN ← ALL[FALSE];
Active[poly] ← Active[diff] ← Active[metal] ← Active[gate] ← TRUE;

END.