PWCoreImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Louis Monier May 17, 1986 1:35:25 pm PDT
Bertrand Serlet November 7, 1986 5:22:24 pm PST
Barth, April 22, 1986 7:30:28 pm PST
Spreitzer, April 11, 1986 10:52:25 am PST
Last Edited by: Louis Monier October 20, 1986 3:30:17 pm PDT
DIRECTORY
CD, CDBasics, CDCells, CDDirectory, CDInstances, CDOrient, CDProperties,
Commander,
Core, CoreClasses, CoreCreate, CoreFlat, CoreOps, CoreProperties,
CoreGeometry,
GList, HashTable, IO,
PW, PWCore, PWObjects,
Rope,
Sinix, SinixOps, Sisyph;
PWCoreImpl: CEDAR PROGRAM
IMPORTS CD, CDBasics, CDCells, CDDirectory, CDInstances, CDProperties, CoreClasses, CoreCreate, CoreOps, CoreProperties, CoreGeometry, GList, HashTable, IO, PW, PWObjects, Rope, Sinix, SinixOps, Sisyph
EXPORTS PWCore
SHARES CDCells, CDDirectory =
BEGIN OPEN PWCore;
Soon in Core ?
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;
};
SmashProps: CoreOps.EachWireProc = {
name: ROPE = CoreOps.GetShortWireName[wire];
wire.properties ← NIL;
[] ← CoreOps.SetShortWireName[wire, name];
};
CopyWire: PROC [old: Wire] RETURNS [new: Wire] = {
new ← CoreOps.CopyWire[old];
[] ← CoreOps.VisitWire[new, SmashProps];
};
Exceptions
Signal: PUBLIC SIGNAL [cellType: CellType] = CODE;
Error: PUBLIC ERROR [type: ATOM, message: ROPE, cellType: CellType] = CODE;
PinsCorrespondingToSeveralPublics: PUBLIC SIGNAL [cellType: CellType, obj: Object, publics: Wires, geometry: LIST OF CD.Instance] = CODE;
NoPinsOnAtomicPublic: PUBLIC SIGNAL [cellType: CellType, obj: Object, public: Wire, message: ROPENIL] = CODE;
NoInterestRectDecoration: PUBLIC SIGNAL [cellType: CellType, obj: Object] = CODE;
LayoutAtomsTable
layoutAtomsTable: HashTable.Table ← HashTable.Create[];
LayoutAtomData: TYPE = REF LayoutAtomDataRec;
LayoutAtomDataRec: TYPE = RECORD [layoutProc: LayoutProc, decorateProc: DecorateProc, attributesProc: AttributesProc ← NIL];
RegisterLayoutAtom: PUBLIC PROC [layoutAtom: ATOM, layoutProc: LayoutProc, decorateProc: DecorateProc ← NIL, attributesProc: AttributesProc ← NIL] RETURNS [sameAtom: ATOM] = {
sameAtom ← layoutAtom;
IF ~HashTable.Store[layoutAtomsTable, layoutAtom, NEW [LayoutAtomDataRec ← [layoutProc: layoutProc, decorateProc: decorateProc, attributesProc: attributesProc]]]
THEN PW.WriteF["LayoutProc and DecorateProc for %g overwritten\n", IO.atom[layoutAtom]];
};
GetLayoutAtomRegistration: PUBLIC PROC [layoutAtom: ATOM] RETURNS [layoutProc: LayoutProc ← NIL, decorateProc: DecorateProc ← NIL, attributesProc: AttributesProc ← NIL] = {
layoutAtomData: LayoutAtomData ← NARROW [HashTable.Fetch[layoutAtomsTable, layoutAtom].value];
IF layoutAtomData=NIL THEN RETURN;
layoutProc ← layoutAtomData.layoutProc;
decorateProc ← layoutAtomData.decorateProc;
attributesProc ← layoutAtomData.attributesProc;
};
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]];
};
layoutProp: PRIVATE ATOM ← CoreProperties.RegisterProperty[$PWCoreLayout]; -- cache on CellTypes
FakeExtract: Sinix.ExtractProc = {result ← CDProperties.GetObjectProp[obj, $PWCoreCellType]};
SmashPins: PROC [wire: Wire] = {CoreGeometry.PutPins[extractMode.decoration, wire, NIL]};
copies decorations from from to to
CopyDecorations: PROC [to, from: CellType, obj: Object] = {
CopyPins: PROC [toWire, fromWire: Wire] = {
IF NOT CoreGeometry.HasPins[extractMode.decoration, fromWire]
THEN SIGNAL NoPinsOnAtomicPublic[from, obj, fromWire, CoreOps.GetFullWireName[from.public, fromWire]];
CoreGeometry.AddIndirectLazyPins[extractMode.decoration, toWire, fromWire];
};
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[to.public, SmashPins];
CoreGeometry.PutIR[extractMode.decoration, to, CD.InterestRect[obj]];
VisitAtomicPairs[to.public, from.public, CopyPins];
};
Layout: PUBLIC PROC [cellType: CellType] RETURNS [obj: Object] = {
obj ← NARROW [CoreProperties.GetCellTypeProp[cellType, layoutProp]];
IF obj#NIL THEN RETURN;
BEGIN
layoutAtom: ATOM ← GetLayoutAtom[cellType];
layoutAtomData: LayoutAtomData;
layoutData: LayoutData;
layoutCellType: CellType;
IF layoutAtom=NIL
THEN IF cellType.class.recast=NIL
THEN ERROR Error[$NoLayoutAtom, "Impossible to find a layoutAtom for this cellType", cellType]
ELSE {
recasted: CellType = CoreOps.Recast[cellType];
obj ← Layout[recasted];
CopyDecorations[cellType, recasted, obj];
RETURN;
};
layoutAtomData ← NARROW [HashTable.Fetch[layoutAtomsTable, layoutAtom].value];
IF layoutAtomData=NIL THEN ERROR Error[$NoRegistration, IO.PutFR["LayoutAtom %g has not been registered", IO.atom[layoutAtom]], cellType];
We compute the attributes (if any)
IF layoutAtomData.attributesProc#NIL THEN layoutAtomData.attributesProc[cellType];
Now the layout
obj ← layoutAtomData.layoutProc[cellType];
layoutData ← NEW [LayoutDataRec ← [cellType: cellType, obj: obj, mode: extractMode]];
layoutCellType ← CoreOps.CreateCellType[class: layoutClass, public: CopyWire[cellType.public], data: layoutData];
Now we decorate the source cellType
IF layoutAtomData.decorateProc#NIL THEN layoutAtomData.decorateProc[cellType, obj];
We decorate layoutCellType with the same decorations, and on the way check those decorations
IF NOT CoreGeometry.HasIR[extractMode.decoration, cellType] OR CoreGeometry.GetIR[extractMode.decoration, cellType]#CD.InterestRect[obj] THEN SIGNAL NoInterestRectDecoration[cellType, obj];
CopyDecorations[layoutCellType, cellType, obj];
We make an indirect object to allow the same layout to be returned on 2 different calls of Layout
obj ← PWObjects.CreateIndirect[obj];
CDProperties.PutObjectProp[obj, $PWCoreCellType, layoutCellType];
CDProperties.PutObjectProp[obj, extractMode.extractProcProp, $FakeExtract];
CoreProperties.PutCellTypeProp[cellType, layoutProp, obj];
IF CoreOps.GetCellTypeName[cellType]#NIL AND CDDirectory.Name[obj]=NIL THEN NARROW [obj.class.directoryProcs, REF CDDirectory.DirectoryProcs].setName[obj, CoreOps.GetCellTypeName[cellType]];
Consistency check
IF Sinix.Extract[obj, extractMode].result#layoutCellType THEN ERROR Error[$InternalBug, "Internal invariant failed", cellType];
IF CorrespondingCellType[obj]#layoutCellType THEN ERROR Error[$InternalBug, "Internal invariant failed", cellType];
END;
};
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];
};
FromLayoutWithoutPublic: PUBLIC PROC [obj: Object] RETURNS [cellType: CellType] = {
cellType ← NARROW [Sinix.Extract[obj, extractMode].result];
SetLayoutAndDecoration[cellType, obj];
};
Global Variable
extractMode: PUBLIC Sinix.Mode ← SinixOps.GetExtractMode[$cmosB];
$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, $PWCoreSourceDesign]];
obj ← GetAndAddSuffix[source, CoreOps.GetCellTypeName[cellType]];
};
GetAndFlatten: LayoutProc = {
source: CD.Design ← NARROW [CoreProperties.GetCellTypeProp[cellType, $PWCoreSourceDesign]];
obj ← PW.Flatten[GetAndAddSuffix[source, CoreOps.GetCellTypeName[cellType]]];
};
Value: LayoutProc = {
obj ← NARROW [CoreProperties.GetCellTypeProp[cellType, $PWCoreValue]];
};
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 SIGNAL PinsCorrespondingToSeveralPublics[cellType, obj, LIST [previousSourceWire, wire], CoreGeometry.GetPins[extractMode.decoration, extractedWire]];
IF NOT CoreGeometry.HasPins[extractMode.decoration, extractedWire]
THEN SIGNAL NoPinsOnAtomicPublic[cellType, obj, extractedWire, name];
CoreGeometry.AddIndirectLazyPins[extractMode.decoration, wire, extractedWire];
[] ← HashTable.Store[extractedToSource, extractedWire, wire];
ENDLOOP;
};
CoreOps.VisitRootAtomics[cellType.public, SmashPins];
CoreGeometry.PutIR[extractMode.decoration, cellType, CD.InterestRect[obj]];
[] ← CoreOps.VisitWire[cellType.public, FindInExtractedPublic];
};
Abuts, Arrays and Recast
AttributeX: AttributesProc = {SortInstances[Sisyph.mode.decoration, cellType, SortInX]};
AttributeY: AttributesProc = {SortInstances[Sisyph.mode.decoration, cellType, SortInY]};
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, $RawAbutX]; obj ← Layout[recasted];
};
ArrayY: LayoutProc = {
recasted: CellType ← CoreOps.Recast[cellType];
SetLayout[recasted, $RawAbutY]; obj ← Layout[recasted];
};
ReverseArrayX: LayoutProc = {
recasted: CellType ← CoreOps.Recast[cellType];
SetLayout[recasted, $RawReverseAbutX]; obj ← Layout[recasted];
};
ReverseArrayY: LayoutProc = {
recasted: CellType ← CoreOps.Recast[cellType];
SetLayout[recasted, $RawReverseAbutY]; obj ← Layout[recasted];
};
Recast: LayoutProc = {
obj ← 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 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 transf, 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 Error[$CallerBug, "DecorateAbut assumption not valid: CD cell has more instances than record CellType", cellType];
CoreOps.VisitRootAtomics[cellType.public, SetLazyPins];
};
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];
};
DecorateRecasted: PUBLIC DecorateProc = {
CopyDecorations[cellType, CoreOps.Recast[cellType], obj];
};
Rotations
Rotated: PROC [cellType: CellType] RETURNS [rotatedCT: CellType] = {
rct: CoreClasses.RecordCellType;
IF cellType.class#CoreClasses.recordCellClass THEN ERROR Error[$CallerBug, "Rotation CellType expected [RecordCell with one instance]", cellType];
rct ← NARROW [cellType.data];
IF rct.size#1 THEN ERROR Error[$CallerBug, "Rotation CellType expected [RecordCell with one instance]", cellType];
rotatedCT ← rct[0].type;
IF NOT CoreOps.CorrectConform[cellType.public, rotatedCT.public] THEN ERROR Error[$CallerBug, "Rotation CellType expected [RecordCell with one instance]", cellType];
};
FlipX: LayoutProc = {obj ← PW.FlipX[Layout[Rotated[cellType]]]};
FlipY: LayoutProc = {obj ← PW.FlipY[Layout[Rotated[cellType]]]};
Rot90: LayoutProc = {obj ← PW.Rot90[Layout[Rotated[cellType]]]};
Rot180: LayoutProc = {obj ← PW.Rot180[Layout[Rotated[cellType]]]};
Rot270: LayoutProc = {obj ← PW.Rot270[Layout[Rotated[cellType]]]};
DecorateRotated: PUBLIC DecorateProc = {
rotatedCT: CellType = Rotated[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 properties from one to the other
VisitAtomicPairs[cellType.public, rotatedCT.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]};
InstanceLocation: PROC [decoration: CoreGeometry.Decoration, cellInst: CoreClasses.CellInstance] RETURNS [location: CD.Position] = {
location ← CDBasics.BaseOfRect[CDInstances.InstRectO[CoreGeometry.GetTransf[decoration, cellInst]]];
};
SortInstances: PUBLIC PROC [decoration: CoreGeometry.Decoration, cellType: CellType, sort: SortProc] = {
data: CoreClasses.RecordCellType ← NARROW [cellType.data];
FOR i: NAT IN [0 .. data.size-1) DO
FOR j: NAT IN (i .. data.size) DO
IF ~sort[InstanceLocation[decoration, data[i]], InstanceLocation[decoration, data[j]]] THEN {
w: CoreClasses.CellInstance ← data[i];
data[i] ← data[j]; data[j] ← w;
};
ENDLOOP;
ENDLOOP;
};
DecorateFlatten: PUBLIC PROC [cellType: CellType, obj: Object, sort: PROC [CD.Position, CD.Position] RETURNS [BOOL]] = {
ir: CD.Rect ← CD.InterestRect[obj];
extractedCT: CellType ← NARROW [Sinix.Extract[obj, extractMode].result];
extractedToSource: HashTable.Table ← HashTable.Create[CoreOps.WireBits[extractedCT.public]]; -- table of publics of extracted to publics of source
extractedCTData: CoreClasses.RecordCellType ← NARROW [extractedCT.data];
cellTypeData: CoreClasses.RecordCellType ← NARROW [cellType.data];
positionnedInstances: LIST OF PositionnedInstance;
positionnedWires: LIST OF PositionnedWire;
DecorateActual: PROC [bindings: HashTable.Table, sourceActual, deepPublic: Wire] = {
wireBind: CoreFlat.FlatWire ← NARROW [HashTable.Fetch[bindings, deepPublic].value]; -- bindings=NIL would mean that extractedCT is a leaf, which is impossible
extractedActual: Wire;
wire: Wire;
FOR i: NAT IN [0 .. sourceActual.size) DO DecorateActual[bindings, sourceActual[i], deepPublic[i]] ENDLOOP;
IF deepPublic.size#0 THEN RETURN;
IF wireBind=NIL THEN ERROR Error[$InternalBug, "Internal invariant failed", cellType]; -- something is really wrong!
IF wireBind.flatCell#[] THEN ERROR Error[$InternalBug, "Internal invariant failed", cellType]; -- a deep internal wire
extractedActual ← wireBind.wire;
IF sourceActual.size#extractedActual.size THEN ERROR Error[$InternalBug, "Internal invariant failed", cellType];
wire ← NARROW [HashTable.Fetch[extractedToSource, extractedActual].value];
IF wire=sourceActual THEN RETURN;
IF wire#NIL THEN SIGNAL PinsCorrespondingToSeveralPublics[cellType, obj, LIST [wire, sourceActual], CoreGeometry.GetPins[extractMode.decoration, extractedActual]];
CoreGeometry.AddIndirectLazyPins[extractMode.decoration, sourceActual, extractedActual];
[] ← HashTable.Insert[extractedToSource, extractedActual, sourceActual];
};
[positionnedInstances, positionnedWires] ← GetPositionnedInstances[extractedCT, sort];
CoreGeometry.PutIR[extractMode.decoration, cellType, CD.InterestRect[obj]];
IF cellTypeData.size#GList.Length[positionnedInstances] THEN ERROR Error[$CallerBug, IO.PutFR["Mismatch between extracted layout (%g instances) and source description (%g instances)", IO.int[GList.Length[positionnedInstances]], IO.int[cellTypeData.size]], cellType];
CoreOps.VisitRootAtomics[cellType.public, SmashPins];
FOR i: NAT IN [0 .. cellTypeData.size) DO
positionnedInstance: PositionnedInstance = positionnedInstances.first;
cell: CellType = positionnedInstance.cell;
sourceCellType: CellType = NARROW [cell.data, LayoutData].cellType;
IF Layout[cellTypeData[i].type]#Layout[sourceCellType] THEN ERROR Error[$CallerBug, IO.PutFR["Mismatch between the %gth instance of the extracted layout and the %gth instance of the source description: cellTypes are different", IO.int[i], IO.int[i]], cellType];
CoreGeometry.PutTransf[extractMode.decoration, cellTypeData[i], positionnedInstance.transf];
IF ~ CoreOps.CorrectConform[cellTypeData[i].actual, cell.public] THEN ERROR Error[$InternalBug, "Call Implementor!", cellType];
FOR j: NAT IN [0 .. cell.public.size) DO
DecorateActual[positionnedInstance.bindings, cellTypeData[i].actual[j], cell.public[j]];
ENDLOOP;
positionnedInstances ← positionnedInstances.rest;
ENDLOOP;
We copy the pins for all publics. For now, we only do it for wires which have the same name as some internal of cellType.
All this code stinks ....
WHILE positionnedWires#NIL DO
positionnedWire: PositionnedWire = positionnedWires.first;
wire: Wire = positionnedWire.wire;
flatWire: CoreFlat.FlatWireRec = positionnedWire.flatWire;
name: ROPE = CoreOps.GetShortWireName[wire];
source: Wire ← NARROW [HashTable.Fetch[extractedToSource, flatWire.wire].value];
IF flatWire.flatCell#[] THEN ERROR Error[$InternalBug, "Call implementor!", cellType]; -- not yet implemented if it is not part of the internal of extractedCT
The following line is to pass PWCoreRoute test
All this code stinks ....
IF source=NIL THEN source ← CoreOps.FindWire[cellTypeData.internal, name];
If source is NIL, crash!
IF source=NIL THEN SIGNAL Signal[cellType];
If it is an internal only, let's forget it!
IF source#NIL AND CoreOps.RecursiveMember[cellType.public, source] THEN FOR list: LIST OF CD.Instance ← positionnedWire.geometry, list.rest WHILE list#NIL DO
IF NOT CoreGeometry.AtEdge[ir, list.first] THEN LOOP;
CoreGeometry.PutPins[
extractMode.decoration, source,
CONS [list.first, CoreGeometry.GetPins[extractMode.decoration, source]]
];
ENDLOOP;
positionnedWires ← positionnedWires.rest;
ENDLOOP;
};
PositionnedInstance: TYPE = REF PositionnedInstanceRec;
PositionnedInstanceRec: TYPE = RECORD [
cell: CellType,   -- flat CT (of class layoutClass)
flatCell: CoreFlat.FlatCellTypeRec,
bindings: CoreFlat.Bindings,  -- [public of cellType -> CoreFlat.WireBind]
transf: CD.Instance
];
PositionnedWire: TYPE = REF PositionnedWireRec;
PositionnedWireRec: TYPE = RECORD [
wire: Wire,
flatWire: CoreFlat.FlatWireRec,
geometry: LIST OF CD.Instance
];
positionnedInstances is the sorted list of all instances that have associated layout.
positionnedWires is the list of all wires having their own geometry.
GetPositionnedInstances: PROC [extractedCT: CellType, sort: SortProc] RETURNS [positionnedInstances: LIST OF PositionnedInstance ← NIL, positionnedWires: LIST OF PositionnedWire ← NIL] = {
InsertInOrdered: PROC [element: PositionnedInstance, sorted: LIST OF PositionnedInstance] RETURNS [new: LIST OF PositionnedInstance] = {
IF sorted=NIL THEN RETURN [LIST [element]];
IF sort[CDBasics.BaseOfRect[CDInstances.InstRectO[element.transf]], CDBasics.BaseOfRect[CDInstances.InstRectO[sorted.first.transf]]] THEN RETURN [CONS [element, sorted]];
RETURN [CONS [sorted.first, InsertInOrdered[element, sorted.rest]]];
};
Leaf: CoreGeometry.LeafProc = {RETURN [cellType.class=layoutClass]};
EachFlatWire: CoreGeometry.EachFlatWireProc = {
positionnedWires ← CONS [
NEW [PositionnedWireRec ← [wire: wire, flatWire: flatWire, geometry: geometry]],
positionnedWires];
};
EachFlatCell: CoreGeometry.EachFlatCellProc = {
positionnedInstances ← CONS [
NEW [PositionnedInstanceRec ← [
cell: cell, flatCell: flatCell, bindings: bindings, transf: transf
]],
positionnedInstances];
};
Compare: GList.CompareProc = {
pi1: PositionnedInstance = NARROW [ref1];
pi2: PositionnedInstance = NARROW [ref2];
RETURN [IF sort[CDBasics.BaseOfRect[CDInstances.InstRectO[pi1.transf]], CDBasics.BaseOfRect[CDInstances.InstRectO[pi2.transf]]] THEN less ELSE greater];
};
CoreGeometry.EnumerateFlatGeometry[decoration: extractMode.decoration, root: extractedCT, leafProc: Leaf, eachFlatWire: EachFlatWire, eachFlatCell: EachFlatCell];
positionnedInstances ← NARROW [GList.Sort[positionnedInstances, Compare]];
};
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];
};
SetLayoutAndDecoration: PUBLIC PROC [cellType: CellType, layout: CD.Object] = {
SetLayout[cellType, $ValueNoDecorate, $PWCoreValue, layout];
};
RotateCellType: PUBLIC PROC [rotatedCellType: CellType, orientation: ATOM] RETURNS [cellType: CellType] = {
public: Wire = CoreOps.CreateWires[size: rotatedCellType.public.size];
internal: Wire = CoreOps.CreateWires[size: rotatedCellType.public.size];
FOR i: NAT IN [0 .. rotatedCellType.public.size) DO
new: Wire = CopyWire[rotatedCellType.public[i]];
public[i] ← internal[i] ← new;
ENDLOOP;
cellType ← CoreClasses.CreateRecordCell[public: public, internal: internal, instances: LIST [CoreClasses.CreateInstance[actual: internal, type: rotatedCellType]]];
SetLayout[cellType, orientation];
};
Tentative help for regular structures
AbutCell: PUBLIC PROC [public: Wire, abutInstances: LIST OF AbutInstance, inX: BOOL, name: ROPENIL, props: Properties ← NIL] RETURNS [recordCell: CellType] = {
positionnedInstances: LIST OF PositionnedInstance ← NIL;
ObjectsFromAbutInstances: PROC [abutInstances: LIST OF AbutInstance] RETURNS [LIST OF Object] = {
IF abutInstances=NIL THEN RETURN [NIL];
BEGIN
obj: Object ← abutInstances.first.object; -- to allow 2 instances of the same object to have different bindings
ct: CellType ← FromLayoutWithoutPublic[obj];
RETURN [CONS [Layout[ct], ObjectsFromAbutInstances[abutInstances.rest]]];
END;
};
RegisterExtractedToSource: PROC [extracted, source: Wire, checkPins: BOOL] = {
prevAct: Wire ← NARROW [HashTable.Fetch[extractedToSource, extracted].value];
IF extracted.size#source.size THEN ERROR Error[$CallerBug, "Extracted wire and truth public do not have same structure. You may call implementor for help!", extractedCT];
FOR i: NAT IN [0 .. extracted.size) DO RegisterExtractedToSource[extracted[i], source[i], checkPins] ENDLOOP;
IF prevAct=source THEN RETURN;
IF prevAct#NIL THEN SIGNAL PinsCorrespondingToSeveralPublics[extractedCT, obj, LIST [prevAct, source], CoreGeometry.GetPins[extractMode.decoration, extracted]];
[] ← HashTable.Store[extractedToSource, extracted, source];
IF source.size#0 THEN RETURN;
IF checkPins AND NOT CoreGeometry.HasPins[extractMode.decoration, extracted]
THEN IF checkPins THEN SIGNAL NoPinsOnAtomicPublic[extractedCT, obj, extracted] ELSE RETURN; -- sub-public should have pins!
CoreGeometry.AddIndirectLazyPins[extractMode.decoration, source, extracted];
};
Replace: PROC [extractedWire: Wire] RETURNS [wire: Wire] = {
wire ← NARROW [HashTable.Fetch[extractedToSource, extractedWire].value];
IF wire#NIL THEN RETURN;
wire ← CoreOps.CreateWires[size: extractedWire.size];
internals ← CONS [wire, internals];
FOR i: NAT IN [0 .. extractedWire.size) DO
wire[i] ← Replace[extractedWire[i]];
ENDLOOP;
RegisterExtractedToSource[extractedWire, wire, FALSE];
};
CheckPinsNonNil: PROC [wire: Wire] = {
IF NOT CoreGeometry.HasPins[extractMode.decoration, wire]
THEN SIGNAL NoPinsOnAtomicPublic[extractedCT, obj, wire, "Some atomic publics have no associated geometry, probably because you forgot to specify in each abutInstance the sub-public bound to it."];
};
internals: Wires ← LIST [public];
instances: LIST OF CoreClasses.CellInstance;
obj: Object ← (IF inX THEN PW.AbutListX ELSE PW.AbutListY)[ObjectsFromAbutInstances[abutInstances]];
extractedCT: CellType ← NARROW [Sinix.Extract[obj, extractMode].result];
extractedData: CoreClasses.RecordCellType ← NARROW [extractedCT.data];
extractedToSource: HashTable.Table ← HashTable.Create[CoreOps.WireBits[public]];
i: NAT ← 0;
CoreOps.VisitRootAtomics[public, SmashPins];
SortInstances[extractMode.decoration, extractedCT, IF inX THEN SortInX ELSE SortInY];
FOR list: LIST OF AbutInstance ← abutInstances, list.rest WHILE list#NIL DO
instance: CoreClasses.CellInstance = extractedData[i];
FOR pas: LIST OF CoreCreate.PA ← list.first.pas, pas.rest WHILE pas#NIL DO
pub: Wire = CoreCreate.FindWire[instance.type.public, pas.first.public];
act: Wire = CoreCreate.FindWire[public, pas.first.actual];
IF pub=NIL THEN ERROR Error[$CallerBug, "Some public specified in some PA in your call to AbutCell is not really a public of the cellTYpe. You may call the maintainor of this package for help!", extractedCT];
IF act=NIL THEN ERROR Error[$CallerBug, "Call implementor for help!", extractedCT];
RegisterExtractedToSource[CoreClasses.CorrespondingActual[instance, pub], act, TRUE];
ENDLOOP;
i ← i + 1;
ENDLOOP;
IF i#extractedData.size THEN Error[$CallerBug, "Call implementor for help!", extractedCT];
We check now that every atomic public has pins
CoreOps.VisitRootAtomics[public, CheckPinsNonNil];
We replace the actuals
FOR i: NAT DECREASING IN [0 .. extractedData.size) DO
actual: Wire ← CoreOps.CreateWires[size: extractedData[i].actual.size];
FOR j: NAT IN [0 .. extractedData[i].actual.size) DO
actual[j] ← Replace[extractedData[i].actual[j]];
ENDLOOP;
instances ← CONS [CoreClasses.CreateInstance[actual: actual, type: extractedData[i].type, props: extractedData[i].properties], instances];
ENDLOOP;
recordCell ← CoreClasses.CreateRecordCell[public, CoreOps.CreateWire[internals], instances, name, props];
CoreGeometry.PutIR[extractMode.decoration, recordCell, CD.InterestRect[obj]];
SetLayoutAndDecoration[recordCell, obj];
};
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, $PWCoreCellType, 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];
};
Backdoor for clients such as PWCoreLichen
layoutClass: PUBLIC Core.CellClass ← NEW [Core.CellClassRec ← [name: "Layout", recast: RecastLayout]];
RecastLayout: Core.RecastProc = {
FillTable: PROC [extractedWire: Wire] = {
FillTableInternal: PROC [sourcePublic, newPublic: Wire] = {
prevSource: Wire;
sourcePins: LIST OF CD.Instance ← CoreGeometry.GetPins[data.mode.decoration, sourcePublic];
CoreGeometry.PutPins[data.mode.decoration, sourcePublic, sourcePins]; -- to avoid all that lazyness
IF NOT CoreGeometry.TouchListList[sourcePins, extractedPins] THEN RETURN;
prevSource ← NARROW [HashTable.Fetch[table, extractedWire].value];
IF prevSource#NIL AND prevSource#newPublic THEN SIGNAL PinsCorrespondingToSeveralPublics[data.cellType, data.obj, LIST [prevSource, sourcePublic], extractedPins];
[] ← HashTable.Store[table, extractedWire, newPublic];
[] ← HashTable.Store[extractedToSource, extractedWire, sourcePublic];
};
extractedPins: LIST OF CD.Instance ← CoreGeometry.GetPins[data.mode.decoration, extractedWire];
VisitAtomicPairs[data.cellType.public, public, FillTableInternal];
};
recordData: CoreClasses.RecordCellType;
data: LayoutData ← NARROW [me.data];
extractedCT: CellType ← NARROW [Sinix.Extract[data.obj, data.mode].result];
public: Wire = CopyWire[me.public];
table: HashTable.Table ← HashTable.Create[];
extractedToSource: HashTable.Table ← HashTable.Create[];
CoreOps.VisitRootAtomics[extractedCT.public, FillTable];
new ← CoreClasses.CreatePermutedRecordCell[iconPublic: public, schCell: extractedCT, table: table, name: Rope.Cat["LayoutRecastOf", CoreOps.GetCellTypeName[data.cellType]]];
recordData ← NARROW [new.data];
IF recordData.size#1 THEN ERROR Error[$InternalBug, "Internal invariant failed", data.cellType];
CoreProperties.PutCellTypeProp[extractedCT, $ExtractedToSource, extractedToSource];
CoreGeometry.PutTransf[data.mode.decoration, recordData[0], CDInstances.NewInst[data.obj]];
};
LayoutCellTypeInfo: PUBLIC PROC [layoutCellType: CellType] RETURNS [obj: Object, sourceCellType, extractedCellType: CellType, extractedToSource: HashTable.Table] = {
data: LayoutData ← NARROW [layoutCellType.data];
obj ← data.obj;
sourceCellType ← data.cellType;
extractedCellType ← NARROW [CoreOps.Recast[layoutCellType].data, CoreClasses.RecordCellType][0].type;
extractedToSource ← NARROW [CoreProperties.GetCellTypeProp[extractedCellType, $ExtractedToSource]];
};
CorrespondingCellType: PUBLIC PROC [obj: Object] RETURNS [layoutCellType: CellType ← NIL] = {
IF CDProperties.GetObjectProp[obj, extractMode.extractProcProp]=$FakeExtract THEN layoutCellType ← NARROW [CDProperties.GetObjectProp[obj, $PWCoreCellType]];
};
Registering layoutAtoms
Sinix.RegisterExtractProc[$FakeExtract, FakeExtract];
[] ← RegisterLayoutAtom[$Get, Get, DecorateValue];
[] ← RegisterLayoutAtom[$GetAndFlatten, GetAndFlatten, DecorateValue];
[] ← RegisterLayoutAtom[$Value, Value, DecorateValue];
[] ← RegisterLayoutAtom[$ValueNoDecorate, Value];
[] ← RegisterLayoutAtom[$AbutListXNoDecorate, AbutX];
[] ← RegisterLayoutAtom[$AbutListYNoDecorate, AbutY];
[] ← RegisterLayoutAtom[$RawAbutX, AbutX, DecorateAbutX];
[] ← RegisterLayoutAtom[$RawAbutY, AbutY, DecorateAbutY];
[] ← RegisterLayoutAtom[$RawReverseAbutX, ReverseAbutX, DecorateReverseAbutX];
[] ← RegisterLayoutAtom[$RawReverseAbutY, ReverseAbutY, DecorateReverseAbutY];
[] ← RegisterLayoutAtom[$AbutX, AbutX, DecorateAbutX, AttributeX];
[] ← RegisterLayoutAtom[$AbutY, AbutY, DecorateAbutY, AttributeY];
[] ← RegisterLayoutAtom[$ReverseAbutX, ReverseAbutX, DecorateReverseAbutX, AttributeX];
[] ← RegisterLayoutAtom[$ReverseAbutY, ReverseAbutY, DecorateReverseAbutY, AttributeY];
[] ← RegisterLayoutAtom[$ArrayX, ArrayX, DecorateRecasted];
[] ← RegisterLayoutAtom[$ArrayY, ArrayY, DecorateRecasted];
[] ← RegisterLayoutAtom[$ReverseArrayX, ReverseArrayX, DecorateRecasted];
[] ← RegisterLayoutAtom[$ReverseArrayY, ReverseArrayY, DecorateRecasted];
[] ← RegisterLayoutAtom[$Recast, Recast, DecorateRecasted];
[] ← RegisterLayoutAtom[$FlipX, FlipX, DecorateRotated];
[] ← RegisterLayoutAtom[$FlipY, FlipY, DecorateRotated];
[] ← RegisterLayoutAtom[$Rot90, Rot90, DecorateRotated];
[] ← RegisterLayoutAtom[$Rot180, Rot180, DecorateRotated];
[] ← RegisterLayoutAtom[$Rot270, Rot270, DecorateRotated];
END.