PWCImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Louis Monier May 17, 1986 1:35:25 pm PDT
Bertrand Serlet August 11, 1986 8:06:03 pm PDT
Barth, April 22, 1986 7:30:28 pm PST
Spreitzer, April 11, 1986 10:52:25 am PST
Curry, October 8, 1986 7:46:14 am PDT
Don Curry November 3, 1986 4:18:37 pm PST
DIRECTORY
Atom, Basics, CD, CDBasics, CDCells, CDDirectory, CDInstances, CDOrient, CDProperties, CDRects,
Commander,
Core, CoreClasses, CoreGeometry, CoreIO, CoreOps, CoreProperties,
CMosB,
HashTable, IO,
PW, PWObjects, PWC, PWPins,
Rope, Sinix, SinixOps;
PWCImpl: CEDAR PROGRAM
IMPORTS Atom, Basics, CD, CDBasics, CDCells, CDDirectory, CDInstances, CDProperties, CDRects, CoreClasses, CoreGeometry, CoreIO, CoreOps, CoreProperties, HashTable, IO, PW, PWObjects, Rope, Sinix, SinixOps
EXPORTS PWC
SHARES CDCells, CDDirectory =
BEGIN OPEN PWC;
VisitAtomicPairs: PROC [wire1, wire2: Wire, eachPair: PROC [Wire, Wire]] = {
VisitInternal: PROC [wire1, wire2: Wire] = {
IF wire1.size#wire2.size THEN ERROR;
IF wire1.size=0
THEN eachPair[wire1, wire2]
ELSE FOR i: NAT IN [0 .. wire1.size) DO VisitInternal[wire1[i], wire2[i]] ENDLOOP};
IF wire1.size#wire2.size THEN ERROR;
FOR i: NAT IN [0 .. wire1.size) DO VisitInternal[wire1[i], wire2[i]] ENDLOOP};
Exceptions
Error: PUBLIC ERROR [type: ATOM, message: ROPE, cellType: CellType] = CODE;
GeometryCorrespondingToSeveralPublics: PUBLIC SIGNAL [cellType: CellType, obj: Object, publics: Wires, geometry: LIST OF CD.Instance] = CODE;
NoGeometryOnAtomicPublics: PUBLIC SIGNAL [cellType: CellType, obj: Object, publics: Wires, message: ROPENIL] = CODE;
LayoutAtomsTable
layoutAtomsTable:  HashTable.Table ← HashTable.Create[];
LayoutAtomData:  TYPE = REF LayoutAtomDataRec;
LayoutAtomDataRec: TYPE = RECORD [layoutProc: LayoutProc, decorateProc: DecorateProc];
RegisterLayoutAtom: PUBLIC PROC [layoutAtom: ATOM, layoutProc: LayoutProc, decorateProc: DecorateProc] RETURNS [sameAtom: ATOM] = {
sameAtom ← layoutAtom;
IF ~HashTable.Store[layoutAtomsTable, layoutAtom, NEW [LayoutAtomDataRec ← [layoutProc: layoutProc, decorateProc: decorateProc]]]
THEN PW.WriteF["LayoutProc and DecorateProc for %g overwritten\n", IO.atom[layoutAtom]]};
Layout primitives
layoutAtomProp: PUBLIC ATOM ← CoreProperties.RegisterProperty[$Layout];
GetLayoutAtom: PUBLIC PROC [cellType: CellType] RETURNS [layoutAtom: ATOMNIL] = {
layoutAtom ← NARROW [CoreProperties.GetCellTypeProp[cellType, layoutAtomProp]];
IF layoutAtom#NIL THEN RETURN;
layoutAtom ← NARROW [CoreProperties.GetCellClassProp[cellType.class, layoutAtomProp]]};
Cache on CellTypes and Objects
layoutProp: PRIVATE ATOM ← CoreProperties.RegisterProperty[$PWCLayout];
FakeExtract: Sinix.ExtractProc = {result ← CDProperties.GetObjectProp[obj, $PWCCellType]};
SetExtractCell: PUBLIC PROC [obj: CD.Object, cellType: CellType] = {
CDProperties.PutObjectProp[obj, $PWCCellType, cellType];
CDProperties.PutObjectProp[obj, extractMode.extractProcProp, $FakeExtract]};
SetLayoutObj: PUBLIC PROC [cellType: CellType, obj: CD.Object] =
{CoreProperties.PutCellTypeProp[cellType, layoutProp, obj]};
{SetLayout[cellType, $ValueNoDecorate, $PWCValue, obj]};
Layout: PUBLIC PROC [cellType: CellType] RETURNS [obj: Object] = {
obj ← NARROW [CoreProperties.GetCellTypeProp[cellType, layoutProp]];
IF obj#NIL THEN RETURN;
BEGIN
CopyDecorations: PROC [wire1, wire2: Wire] = {
SourcePinsFromExtracted[cellType, obj, wire2, wire1]};
publicsWithoutPin: Wires;
layoutAtom:   ATOM ← GetLayoutAtom[cellType];
layoutAtomData:  LayoutAtomData;
layoutData:   LayoutData;
layoutCellType:  CellType;
IF layoutAtom=NIL THEN Error[$NoLayoutAtom,
"Impossible to find a layoutAtom for this cellType", cellType];
layoutAtomData ← NARROW [HashTable.Fetch[layoutAtomsTable, layoutAtom].value];
IF layoutAtomData=NIL THEN Error[$NoRegistration,
IO.PutFR["LayoutAtom %g has not been registered", IO.atom[layoutAtom]], cellType];
obj ← layoutAtomData.layoutProc[cellType];
layoutData ← NEW [LayoutDataRec ← [cellType: cellType, obj: obj, mode: extractMode]];
layoutCellType ← CoreOps.CreateCellType[class: layoutClass, public: CoreOps.CopyWire[cellType.public], data: layoutData];
Now we decorate the source cellType
IF layoutAtomData.decorateProc#NIL THEN layoutAtomData.decorateProc[cellType, obj];
IF NOT CoreGeometry.HasIR[extractMode.decoration, cellType]
THEN ERROR;
We make a simple check to see if the public was correctly decorated
publicsWithoutPin ← AtomicWithoutPin[cellType.public];
IF publicsWithoutPin#NIL
THEN NoGeometryOnAtomicPublics[cellType, obj, publicsWithoutPin];
We decorate layoutCellType with the same decorations
VisitAtomicPairs[cellType.public, layoutCellType.public, CopyDecorations];
Indirect object to allow the same layout to be returned on 2 different calls of Layout
obj ← PWObjects.CreateIndirect[obj];
SetExtractCell[obj, cellType];
SetLayoutObj[cellType, obj];
IF CoreOps.GetCellTypeName[cellType]#NIL AND CDDirectory.Name[obj]=NIL THEN SetObjName[obj, CoreOps.GetCellTypeName[cellType]];
Consistency check
IF Sinix.Extract[obj, extractMode].result#cellType
THEN Error[$InternalBug, "Internal invariant failed", cellType];
IF CorrespondingCellType[obj]#cellType
THEN Error[$InternalBug, "Internal invariant failed", cellType];
END };
SetObjName: PUBLIC PROC [obj: CD.Object, name: ROPE] = {
NARROW[obj.class.directoryProcs, REF CDDirectory.DirectoryProcs].setName[obj, name]};
CountTransistors: PUBLIC PROC[cell: CellType] RETURNS[count: INT ← 0] = {
refInt: REF INT;
IF cell=NIL THEN RETURN[0];
refInt ← NARROW[CoreProperties.GetCellTypeProp[cell, transistorCount].value];
IF refInt#NIL THEN RETURN[refInt^];
SELECT cell.class FROM
CoreClasses.sequenceCellClass  => {
data: CoreClasses.SequenceCellType ← NARROW[cell.data];
count ← data.count*CountTransistors[data.base]};
CoreClasses.recordCellClass  => {
data: CoreClasses.RecordCellType ← NARROW[cell.data];
FOR child: NAT IN [0..data.size) DO
count ← count + CountTransistors[ data.instances[child].type ] ENDLOOP };
CoreClasses.transistorCellClass => RETURN[1];
rotatedCellClass => count ← CountTransistors[NARROW[cell.data]];
CoreIO.importCellClass => {
PW.WriteF["\nSkipping Imported Transistors: %g\n",
IO.rope[CoreOps.GetCellTypeName[cell] ] ]};
ENDCASE       => IF ISTYPE[cell.data, CellType]
THEN count ← CountTransistors[NARROW[cell.data]]
ELSE PW.WriteF["\nSkipping transistor count: %g\n",
IO.rope[CoreOps.GetCellTypeName[cell] ] ];
CoreProperties.PutCellTypeProp[cell, transistorCount, NEW[INT ← count]] };
transistorCount: PUBLIC ATOM ← CoreIO.RegisterProperty[
CoreProperties.RegisterProperty[
$TransistorCount,
CoreProperties.Props[
[CoreProperties.propPrint,  NEW[CoreProperties.PropPrintProc  ← PrintTCnt ]] ] ],
WriteTCnt,
ReadTCnt ];
WriteTCnt: CoreIO.PropWriteProc = {CoreIO.WriteInt[h, NARROW[value, REF INT]^]};
ReadTCnt: CoreIO.PropReadProc = {RETURN[ NEW[INT ← CoreIO.ReadInt[h] ] ]};
PrintTCnt: CoreProperties.PropPrintProc =
{to.PutF[" Transistor Count: %g", IO.int[NARROW[val, REF INT]^]]};
InterestRect: PUBLIC PROC [cellType: CellType] RETURNS [ir: CD.Rect] = {
IF NOT CoreGeometry.HasIR[extractMode.decoration, cellType] THEN [] ← Layout[cellType];
ir ← CoreGeometry.GetIR[extractMode.decoration, cellType]};
InterestSize: PUBLIC PROC [cellType: CellType] RETURNS [size: CD.Position] =
{RETURN[ CDBasics.SizeOfRect[ InterestRect[ cellType]]]};
Extract: PUBLIC PROC [obj: Object] RETURNS [cellType: CellType] = {
cellType ← NARROW [Sinix.Extract[obj, extractMode].result];
SetLayoutObj[cellType, obj]};
Global Variable
extractMode: PUBLIC Sinix.Mode ← SinixOps.GetExtractMode[$cmosB];
StoringPins
AtomicWithoutPin: PROC [public: Wire] RETURNS [publicsWithoutPin: Wires ← NIL] = {
CheckPinsNonNil: PROC [wire: Wire] = {
IF CoreGeometry.GetPins[extractMode.decoration, wire]=NIL
THEN publicsWithoutPin ← CONS [wire, publicsWithoutPin]};
FOR i: NAT IN [0 .. public.size)
DO CoreOps.VisitRootAtomics[public[i], CheckPinsNonNil] ENDLOOP};
IndirectGetPins: PROC [mode: Sinix.Mode, wire: Wire, ir: CD.Rect, data: REF]
RETURNS [pins: LIST OF CD.Instance ← NIL] = {
Check for simple loops that should never occur
IF data=wire THEN Error[$InternalBug, "Internal invariant failed", NIL];
pins ← Sinix.GetPinsProp[mode, NARROW [data]]};
Should be called only when source.size=extracted.size=0
SourcePinsFromExtracted: PROC
[cellType: CellType, obj: Object, source, extracted: Wire] = {
IF NOT CoreGeometry.HasPins[extractMode.decoration, extracted] THEN NoGeometryOnAtomicPublics[cellType, obj, LIST [source]];
CoreGeometry.AddIndirectLazyPins[extractMode.decoration, source, extracted]};
$Get, $GetAndFlatten, $Value and $ValueNoDecorate
maskSuffix: PUBLIC ROPE ← ".mask";
GetAndAddSuffix: PROC [source: CD.Design, name: ROPE] RETURNS [obj: Object] = {
obj ← PW.Get[source, IO.PutR[IO.rope[name], IO.rope[maskSuffix]]]};
Get: LayoutProc = {
source: CD.Design ← NARROW [CoreProperties.GetCellTypeProp[cellType, $PWCSourceDesign]];
obj ← GetAndAddSuffix[source, CoreOps.GetCellTypeName[cellType]]};
GetAndFlatten: LayoutProc = {
source: CD.Design ← NARROW [CoreProperties.GetCellTypeProp[cellType, $PWCSourceDesign]];
obj ← PW.Flatten[GetAndAddSuffix[source, CoreOps.GetCellTypeName[cellType]]]};
Value: LayoutProc = {
obj ← NARROW [CoreProperties.GetCellTypeProp[cellType, $PWCValue]]};
NoDecorate: DecorateProc = {};
DecorateValue: PUBLIC DecorateProc = {
extractedCT: CellType ← NARROW [Sinix.Extract[obj, extractMode].result];
extractedToSource: HashTable.Table ← HashTable.Create[extractedCT.public.size];
FindInExtractedPublic: CoreOps.EachWireProc = {
FOR names: LIST OF ROPE ← CoreOps.GetFullWireNames[cellType.public, wire], names.rest WHILE names#NIL DO
name: ROPE ← names.first;
extractedWire: Wire ← CoreOps.FindWire[extractedCT.public, name];
previousSourceWire: Wire ← NARROW [HashTable.Fetch[extractedToSource, extractedWire].value];
IF extractedWire=NIL OR extractedWire.size#0 THEN LOOP;
IF previousSourceWire#NIL AND previousSourceWire#wire THEN GeometryCorrespondingToSeveralPublics[cellType, obj, LIST [previousSourceWire, wire], CoreGeometry.GetPins[extractMode.decoration, extractedWire]];
SourcePinsFromExtracted[cellType, obj, wire, extractedWire];
[] ← HashTable.Store[extractedToSource, extractedWire, wire];
ENDLOOP };
CoreGeometry.PutIR[extractMode.decoration, cellType, CD.InterestRect[obj]];
[] ← CoreOps.VisitWire[cellType.public, FindInExtractedPublic] };
Abuts, Arrays and Recast
AbutX: LayoutProc = {
data: CoreClasses.RecordCellType ← NARROW [cellType.data];
subObjects: LIST OF Object ← NIL;
FOR i: NAT DECREASING IN [0 .. data.size) DO
subObjects ← CONS [Layout[data[i].type], subObjects];
ENDLOOP;
obj ← PW.AbutListX[subObjects]};
AbutY: LayoutProc = {
data: CoreClasses.RecordCellType ← NARROW [cellType.data];
subObjects: LIST OF Object ← NIL;
FOR i: NAT DECREASING IN [0 .. data.size) DO
subObjects ← CONS [Layout[data[i].type], subObjects];
ENDLOOP;
obj ← PW.AbutListY[subObjects]};
ReverseAbutX: LayoutProc = {
data: CoreClasses.RecordCellType ← NARROW [cellType.data];
subObjects: LIST OF Object ← NIL;
FOR i: NAT IN [0 .. data.size) DO
subObjects ← CONS [Layout[data[i].type], subObjects];
ENDLOOP;
obj ← PW.AbutListX[subObjects]};
ReverseAbutY: LayoutProc = {
data: CoreClasses.RecordCellType ← NARROW [cellType.data];
subObjects: LIST OF Object ← NIL;
FOR i: NAT IN [0 .. data.size) DO
subObjects ← CONS [Layout[data[i].type], subObjects];
ENDLOOP;
obj ← PW.AbutListY[subObjects]};
ArrayX: LayoutProc = {
recasted: CellType ← CoreOps.Recast[cellType];
SetLayout[recasted, $AbutX]; obj ← Layout[recasted]};
ArrayY: LayoutProc = {
recasted: CellType ← CoreOps.Recast[cellType];
SetLayout[recasted, $AbutY]; obj ← Layout[recasted]};
ReverseArrayX: LayoutProc = {
recasted: CellType ← CoreOps.Recast[cellType];
SetLayout[recasted, $ReverseAbutX]; obj ← Layout[recasted]};
ReverseArrayY: LayoutProc = {
recasted: CellType ← CoreOps.Recast[cellType];
SetLayout[recasted, $ReverseAbutY]; obj ← Layout[recasted]};
Recast: LayoutProc = {
obj ← PWObjects.CreateIndirect[Layout[CoreOps.Recast[cellType]]]};
DecorateAbut: PUBLIC PROC [cellType: CellType, obj: Object, sort: SortProc] = {
InsertInOrder: PROC [element: CD.Instance, sorted: LIST OF CD.Instance] RETURNS [new: LIST OF CD.Instance] = {
IF element.orientation#0 THEN Error[$CallerBug, "DecorateAbut is only applicable for CD Cells without rotations", cellType];
IF sorted=NIL THEN RETURN [LIST [element]];
IF sort[CDBasics.BaseOfRect[CDInstances.InstRectO[element]], CDBasics.BaseOfRect[CDInstances.InstRectO[sorted.first]]] THEN RETURN [CONS [element, sorted]];
RETURN [CONS [sorted.first, InsertInOrder[element, sorted.rest]]]};
SetLazyPins: PROC [wire: Wire] = {CoreGeometry.PutRecordLazyPins[extractMode.decoration, wire, cellType]};
instances: LIST OF CD.Instance;
recordData: CoreClasses.RecordCellType ← NARROW [cellType.data];
WHILE obj.class#CDCells.cellClass DO obj ← CDDirectory.Expand[obj].new ENDLOOP;
CoreGeometry.PutIR[extractMode.decoration, cellType, CD.InterestRect[obj]];
FOR list: LIST OF CD.Instance ← NARROW [obj.specificRef, CD.CellPtr].contents, list.rest WHILE list#NIL DO
instances ← InsertInOrder[list.first, instances];
ENDLOOP;
We decorate each instance with the appropriate extractMode.instanceProp, so that the Lazy GetPins can find the location
FOR i: NAT IN [0 .. recordData.size) DO
CoreGeometry.PutTransf[extractMode.decoration, recordData[i], instances.first];
instances ← instances.rest;
ENDLOOP;
IF instances#NIL THEN Error[$CallerBug, "DecorateAbut assumption not valid: CD cell has more instances than record CellType", cellType];
FOR i: NAT IN [0 .. cellType.public.size) DO CoreOps.VisitRootAtomics[cellType.public[i], SetLazyPins] ENDLOOP };
DecorateAbutX: PUBLIC DecorateProc =
{DecorateAbut[cellType, obj, SortInX] };
DecorateAbutY: PUBLIC DecorateProc =
{DecorateAbut[cellType, obj, SortInY] };
DecorateReverseAbutX: PUBLIC DecorateProc =
{DecorateAbut[cellType, obj, ReverseSortInX] };
DecorateReverseAbutY: PUBLIC DecorateProc =
{DecorateAbut[cellType, obj, ReverseSortInY]};
SmashPins: PROC [wire: Wire] = {CoreGeometry.PutPins[extractMode.decoration, wire, NIL]};
DecorateRecasted: PUBLIC DecorateProc = {
recastedCT: CellType ← CoreOps.Recast[cellType];
CopySourcePinsFromRecasted: PROC [wire1, wire2: Wire] = {
SourcePinsFromExtracted[cellType, obj, wire1, wire2]};
We check that the public of the source and the public of the recasted layout are similar, and we copy properties from one to the other
CoreOps.VisitRootAtomics[cellType.public, SmashPins];
CoreGeometry.PutIR[extractMode.decoration, cellType, CD.InterestRect[obj]];
VisitAtomicPairs[cellType.public, recastedCT.public, CopySourcePinsFromRecasted]};
Rotations
rotatedCellClass: PUBLIC Core.CellClass ← CoreOps.SetClassPrintProc
[NEW [Core.CellClassRec ← [name: "Rotated", recast: RecastRotated, layersProps: FALSE]], PrintRotated];
RecastRotated: Core.RecastProc = {RETURN[ NARROW[me.data, CellType] ]};
PrintRotated: CoreOps.PrintClassProc = {
CoreOps.PrintIndent[indent, out];
out.PutF["Rotation of: %g", IO.rope[CoreOps.GetCellTypeName[NARROW [data, CellType]]]]};
RotateCellType: PUBLIC PROC[cellType: CellType, orientation: ATOM]
RETURNS [rotatedCellType: CellType] = {
name: ROPE ← Rope.Cat
[Atom.GetPName[orientation], "-", CoreOps.GetCellTypeName[cellType]];
rotatedCellType ← CoreOps.CreateCellType[
class: rotatedCellClass,
public: CoreOps.CopyWire[cellType.public],
data: cellType,
name: name];
SetLayout[rotatedCellType, orientation]};
AtomOrientation: PROC[atom: ATOM] RETURNS[orientation: CDOrient.Orientation] = {
RETURN[SELECT atom FROM
$Rot0   => CDOrient.original,
$Rot0X  => CDOrient.mirrorX,
$Rot90  => CDOrient.rotate90,
$Rot90X  => CDOrient.rotate90X,
$Rot180  => CDOrient.rotate180,
$Rot180X  => CDOrient.rotate180X,
$Rot270  => CDOrient.rotate270,
$Rot270X  => CDOrient.rotate270X,
$FlipX  => CDOrient.mirrorX,
$FlipY  => CDOrient.mirrorY,
ENDCASE  => ERROR]};
Rotate: LayoutProc = {
layoutAtom: ATOM ← GetLayoutAtom[cellType];
orientation: CDOrient.Orientation ← AtomOrientation[layoutAtom];
IF cellType.class#rotatedCellClass THEN
Error[$CallerBug, "Rotated CellType expected", cellType];
obj ← PW.ChangeOrientation[Layout[NARROW [cellType.data]], orientation]};
DecorateRotated: PUBLIC DecorateProc = {
recastedCT: CellType ← CoreOps.Recast[cellType];
transf: CD.Instance;
CopyPinsFromRotated: PROC [wire1, wire2: Wire] = {
CoreGeometry.PutTransfWireIRLazyPins[
decoration: extractMode.decoration, public: wire1, indirect: wire2, transf: transf, ir: ir]};
instances: LIST OF CD.Instance;
ir: CD.Rect = CD.InterestRect[obj];
WHILE obj.class#CDCells.cellClass DO obj ← CDDirectory.Expand[obj].new ENDLOOP;
CoreGeometry.PutIR[extractMode.decoration, cellType, ir];
instances ← NARROW [obj.specificRef, CD.CellPtr].contents;
IF instances=NIL OR instances.rest#NIL THEN ERROR Error[$CallerBug, "DecorateRotated is not supposed to be called with an obj that does not expand into a one instance cell", cellType];
transf ← instances.first;
We check that the public of the source and the public of the recasted layout are similar, and we copy pins from one to the other
VisitAtomicPairs[cellType.public, recastedCT.public, CopyPinsFromRotated];
};
Help for writing DecorateProcs
SortInX: PUBLIC PROC [pos1, pos2: CD.Position] RETURNS [BOOL] = {RETURN [pos1.x<pos2.x]};
SortInY: PUBLIC PROC [pos1, pos2: CD.Position] RETURNS [BOOL] = {RETURN [pos1.y<pos2.y]};
ReverseSortInX: PUBLIC PROC [pos1, pos2: CD.Position] RETURNS [BOOL] = {RETURN [pos1.x>pos2.x]};
ReverseSortInY: PUBLIC PROC [pos1, pos2: CD.Position] RETURNS [BOOL] = {RETURN [pos1.y>pos2.y]};
Short cut
SetLayout: PUBLIC PROC [cellType: CellType, layoutAtom: ATOM, userDataProp: ATOMNIL, userData: REFNIL] = {
CoreProperties.PutCellTypeProp[cellType, layoutAtomProp, layoutAtom];
IF userDataProp#NIL THEN
CoreProperties.PutCellTypeProp[cellType, userDataProp, userData]};
Tentative help for regular structures
AbutList: PUBLIC PROC [cellTypes: LIST OF CellType, inX: BOOL] RETURNS [recordCell: CellType] = {
lobj: LIST OF CD.Object ← NIL;
WHILE cellTypes#NIL DO
ct: CellType ← cellTypes.first;
obj: CD.Object ← CDCells.CreateEmptyCell[];
CDCells.SetInterestRect[obj, InterestRect[ct]];
CDProperties.PutObjectProp[obj, $PWCCellType, ct];
CDProperties.PutObjectProp[obj, extractMode.extractProcProp, $FakeExtract];
lobj ← CONS [obj, lobj];
cellTypes ← cellTypes.rest;
ENDLOOP;
recordCell ← NARROW [Sinix.Extract[(IF inX THEN PW.AbutListX ELSE PW.AbutListY)[PW.Reverse[lobj]], extractMode].result];
SetLayout[recordCell, IF inX THEN $AbutListXNoDecorate ELSE $AbutListYNoDecorate]};
CellShell: PUBLIC PROC[cell: CellType] RETURNS[shell: CD.Object] = {
iSize:  CD.Position ← InterestSize[cell];
list:  LIST OF NWMML;
minW: INT = CMosB.lambda;
shell ← CDCells.CreateEmptyCell[];
FOR side: Side IN Side DO
FOR list ← SidePinList[cell, side], list.rest WHILE list#NIL DO
wireName: ROPE ← CoreOps.GetFullWireName[cell.public, list.first.wire];
pos: CD.Position ← SELECT side FROM
left  => [0,     list.first.min],
right  => [iSize.x-minW, list.first.min],
top  => [list.first.min,  iSize.y-minW],
bottom => [list.first.min,  0],
ENDCASE => ERROR;
size: CD.Position ← SELECT side FROM
top, bottom => [list.first.max - list.first.min, minW]
ENDCASE  => [minW, list.first.max - list.first.min];
inst: CD.Instance ← PW.IncludeInCell[shell, CDRects.CreateRect[size, list.first.layer], pos];
IF wireName.Length[]=0 THEN ERROR;
CDProperties.PutInstanceProp[inst, $InstanceName, wireName];
ENDLOOP;
ENDLOOP;
PW.SetInterestRect[shell, iSize];
PW.RepositionCell[shell]};
SidePinList: PUBLIC PROC [cellType: CellType, side: Side]
RETURNS [list: LIST OF NWMMLNIL] = {
thisSide: Side ← side;
EachWirePin: CoreGeometry.EachWirePinProc = {
name: ROPE ← CoreOps.GetShortWireName[wire];
IF side#thisSide THEN RETURN;
IF name=NIL THEN RETURN;
list ← AddMergeNWMMLs[[name, wire, min, max, layer], list]};
[] ← CoreGeometry.EnumerateWireSides[extractMode.decoration, cellType, EachWirePin];
PosSortNWMMLs[list]};
Add sorted by name, wire, layer, min, max - - - merge overlaps
AddMergeNWMMLs: PUBLIC PROC[item: NWMML, lst: LIST OF NWMML]
RETURNS[LIST OF NWMML] = {
NameCompare: PROC[item1, item2: NWMML] RETURNS[comp: Basics.Comparison] = {
IV: PROC[w: Core.Wire] RETURNS[int: INT] = {int ← LOOPHOLE[w]};
comp ← IF item1.name=NIL AND item2.name = NIL
THEN Basics.CompareINT[IV[ item1.wire], IV[ item2.wire]]
ELSE Rope.Compare[   item1.name,   item2.name]};
dummy: NWMML ← [];
head:  LIST OF NWMML ← CONS[dummy, lst];
l:   LIST OF NWMML ← head;
IF lst=NIL THEN RETURN[CONS[item, NIL]];
WHILE l.rest#NIL DO
SELECT NameCompare[l.rest.first, item] FROM
greater  => EXIT;
equal   => IF
l.rest.first.layer   =  item.layer AND
l.rest.first.max  >=  item.min AND
l.rest.first.min  <=  item.max THEN {
item.max ← MAX[ l.rest.first.max, item.max];
item.min ← MIN[ l.rest.first.min, item.min];
l.rest ← l.rest.rest; LOOP};
ENDCASE;
l ← l.rest;
ENDLOOP;
lhead;
FOR l ← l, l.rest WHILE l.rest#NIL DO
cpr: Basics.Comparison ← NameCompare[l.rest.first, item];
IF cpr  = greater OR
cpr = equal AND (
l.rest.first.layer   >  item.layer OR
l.rest.first.layer  =  item.layer AND
l.rest.first.min  >  item.max) THEN {l.rest ← CONS[item, l.rest]; EXIT};
REPEAT FINISHED => l.rest ← CONS[item, NIL] ENDLOOP;
RETURN[head.rest]};
PosSortNWMMLs: PUBLIC PROC[lst: LIST OF NWMML] = {
DO
ok: BOOLTRUE;
FOR l: LIST OF NWMML ← lst, l.rest WHILE l#NIL AND l.rest#NIL DO
IF l.first.min > l.rest.first.min OR
l.first.min = l.rest.first.min AND l.first.max > l.rest.first.max THEN
{temp: NWMML ← l.first; l.first ← l.rest.first; l.rest.first ← temp; ok ← FALSE}
ENDLOOP;
IF ok THEN EXIT;
ENDLOOP};
Registering layoutAtoms
Sinix.RegisterExtractProc[$FakeExtract, FakeExtract];
[] ← RegisterLayoutAtom[$Get, Get, DecorateValue];
[] ← RegisterLayoutAtom[$GetAndFlatten, GetAndFlatten, DecorateValue];
[] ← RegisterLayoutAtom[$Value, Value, DecorateValue];
[] ← RegisterLayoutAtom[$ValueNoDecorate, Value, NoDecorate];
[] ← RegisterLayoutAtom[$AbutListXNoDecorate, AbutX, NoDecorate];
[] ← RegisterLayoutAtom[$AbutListYNoDecorate, AbutY, NoDecorate];
[] ← RegisterLayoutAtom[$AbutX, AbutX, DecorateAbutX];
[] ← RegisterLayoutAtom[$AbutY, AbutY, DecorateAbutY];
[] ← RegisterLayoutAtom[$ReverseAbutX, ReverseAbutX, DecorateReverseAbutX];
[] ← RegisterLayoutAtom[$ReverseAbutY, ReverseAbutY, DecorateReverseAbutY];
[] ← RegisterLayoutAtom[$ArrayX, ArrayX, DecorateRecasted];
[] ← RegisterLayoutAtom[$ArrayY, ArrayY, DecorateRecasted];
[] ← RegisterLayoutAtom[$ReverseArrayX, ReverseArrayX, DecorateRecasted];
[] ← RegisterLayoutAtom[$ReverseArrayY, ReverseArrayY, DecorateRecasted];
[] ← RegisterLayoutAtom[$Recast, Recast, DecorateRecasted];
[] ← RegisterLayoutAtom[$FlipX,  Rotate, DecorateRotated];
[] ← RegisterLayoutAtom[$FlipY,  Rotate, DecorateRotated];
[] ← RegisterLayoutAtom[$Rot0,  Rotate, DecorateRotated];
[] ← RegisterLayoutAtom[$Rot0X,  Rotate, DecorateRotated];
[] ← RegisterLayoutAtom[$Rot90,  Rotate, DecorateRotated];
[] ← RegisterLayoutAtom[$Rot90X, Rotate, DecorateRotated];
[] ← RegisterLayoutAtom[$Rot180,  Rotate, DecorateRotated];
[] ← RegisterLayoutAtom[$Rot180X, Rotate, DecorateRotated];
[] ← RegisterLayoutAtom[$Rot270,  Rotate, DecorateRotated];
[] ← RegisterLayoutAtom[$Rot270X, Rotate, DecorateRotated];
CoreProperties.PutCellClassProp[CoreClasses.identityCellClass, layoutAtomProp, $Recast];
END.