PWCoreImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Louis Monier May 17, 1986 1:35:25 pm PDT
Bertrand Serlet June 9, 1986 2:47:03 pm PDT
Barth, April 22, 1986 7:30:28 pm PST
Spreitzer, April 11, 1986 10:52:25 am PST
DIRECTORY
CD, CDBasics, CDCells, CDDirectory, CDInstances, CDOrient, CDProperties, CDSymbolicObjects,
Commander,
Core, CoreClasses, CoreCreate, CoreFlat, CoreOps, CoreProperties,
HashTable, IO, ProcessProps,
PW, PWCore, PWObjects,
Rope,
Sinix, SinixCMos, CoreStructuralComparison;
PWCoreImpl: CEDAR PROGRAM
IMPORTS CD, CDBasics, CDCells, CDDirectory, CDInstances, CDProperties, CDSymbolicObjects, CoreClasses, CoreCreate, CoreFlat, CoreOps, CoreProperties, HashTable, IO, ProcessProps, PW, PWObjects, Sinix, SinixCMos, CoreStructuralComparison
EXPORTS PWCore
SHARES CDCells, CDDirectory =
BEGIN OPEN PWCore;
Test for Lichen
Signal: PUBLIC SIGNAL = 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]];
};
Global Variables
testLichen: PUBLIC BOOLFALSE;
checkAbuts: PUBLIC BOOLFALSE;
extractMode: PUBLIC Sinix.Mode ← SinixCMos.extractBMode;
maskSuffix: PUBLIC ROPE ← ".mask";
Layout primitives
layoutAtomProp: PUBLIC ATOM ← CoreProperties.RegisterProperty[$Layout, CoreProperties.Props[[CoreProperties.propCopy, CoreProperties.PropDoCopy]]];
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];
};
layoutProp: PRIVATE ATOM ← CoreProperties.RegisterProperty[$PWCoreLayout]; -- cache on CellTypes
HasLayout: PUBLIC PROC [cellType: CellType] RETURNS [BOOL] = {
RETURN [CoreProperties.GetCellTypeProp[cellType, layoutProp]#NIL];
};
CancelLayout: PUBLIC PROC [cellType: CellType] = {
CoreProperties.PutCellTypeProp[cellType, layoutProp, NIL];
};
Layout: PUBLIC PROC [cellType: CellType] RETURNS [obj: Object] = {
obj ← NARROW [CoreProperties.GetCellTypeProp[cellType, layoutProp]];
IF obj#NIL THEN RETURN;
BEGIN
CheckPinsNonNil: PROC [public: Wire] = {
IF Sinix.GetPinsProp[extractMode, public]=NIL THEN Signal[];
};
layoutAtom: ATOMNARROW [CoreProperties.GetCellTypeProp[cellType, layoutAtomProp]];
layoutAtomData: LayoutAtomData;
IF layoutAtom=NIL THEN layoutAtom ← NARROW [CoreProperties.GetCellClassProp[cellType.class, layoutAtomProp]];
IF layoutAtom=NIL THEN {
PW.WriteF["*** Impossible to find a layoutAtom for this cellType\n"];
Signal[];
};
layoutAtomData ← NARROW [HashTable.Fetch[layoutAtomsTable, layoutAtom].value];
IF layoutAtomData=NIL THEN {
PW.WriteF["*** LayoutAtom %g has not been registered\n", IO.atom[layoutAtom]];
Signal[];
};
obj ← layoutAtomData.layoutProc[cellType];
Now we decorate the source cellType
layoutAtomData.decorateProc[cellType, obj];
We make a simple check to see if the public was correctly decorated
CoreOps.VisitAtomicWires[cellType.public, CheckPinsNonNil];
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, extractMode.cacheProp, cellType];
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#cellType THEN Signal[]; -- internal Bug of PWCore
END;
};
GetAndAddSuffix: PROC [source: CD.Design, name: ROPE] RETURNS [obj: CD.Object] = {
obj ← PW.Get[source, IO.PutR[IO.rope[name], IO.rope[maskSuffix]]];
};
Checks that each sourcePublic corresponds to some extractedPublic, and decorates the sourcePublic.
DecorateCorrespondingPublic: PROC [sourcePublic, extractedPublic: Wire] RETURNS [extractedToSource: HashTable.Table] = {
FindInExtractedPublic: CoreOps.EachWireProc = {
xwire: Wire ← wire; -- to avoid name clash
names: LIST OF ROPE ← CoreOps.GetFullWireNames[sourcePublic, wire];
name: ROPE;
FindInExtractedPublicInternal: CoreOps.EachWireProc = {
source: Wire;
IF ~CoreOps.IsFullWireName[extractedPublic, wire, name] THEN RETURN;
source ← NARROW [HashTable.Fetch[extractedToSource, wire].value];
IF source=xwire THEN RETURN;
IF source#NIL THEN Signal[]; -- extracted wire corresponds to 2 source publics
[] ← HashTable.Store[extractedToSource, wire, xwire];
IF wire.size=0 THEN SourcePinsFromExtracted[xwire, wire, TRUE];
};
IF names=NIL OR names.rest#NIL
THEN IF xwire.size#0 THEN RETURN ELSE Signal[]; -- more than one full name
name ← names.first;
[] ← CoreOps.VisitWire[extractedPublic, FindInExtractedPublicInternal];
IF xwire.size=0 AND Sinix.GetPinsProp[extractMode, xwire]=NIL THEN Signal[]; -- source public not found
};
extractedToSource ← HashTable.Create[extractedPublic.size];
[] ← CoreOps.VisitWire[sourcePublic, FindInExtractedPublic];
};
FromLayout: PUBLIC PROC [public: Wire, obj: CD.Object] RETURNS [cellType: CellType] = {
CreateActual: PROC [extractedPublic: Wire] RETURNS [actual: Wire] = {
sourceWire: Wire ← NARROW [HashTable.Fetch[extractedToSource, extractedPublic].value];
IF sourceWire#NIL THEN RETURN [sourceWire];
sourceWire ← CoreOps.CreateWires[size: extractedPublic.size];
[] ← HashTable.Store[extractedToSource, extractedPublic, sourceWire];
FOR i: NAT IN [0 .. extractedPublic.size) DO
sourceWire[i] ← CreateActual[extractedPublic[i]];
ENDLOOP;
RETURN [sourceWire];
};
actual: Wire;
extractedToSource: HashTable.Table;
extractedCellType: CellType ← NARROW [Sinix.Extract[obj, extractMode].result];
extractedToSource ← DecorateCorrespondingPublic[public, extractedCellType.public];
actual ← CreateActual[extractedCellType.public];
cellType ← CoreClasses.CreateRecordCell[public, CoreOps.CreateWire[LIST[public, actual]], LIST [CoreClasses.CreateInstance[actual: CreateActual[extractedCellType.public], type: extractedCellType]]];
CDProperties.PutObjectProp[obj, extractMode.cacheProp, cellType];
CoreProperties.PutCellTypeProp[cellType, layoutProp, obj];
};
FromLayoutWithoutPublic: PUBLIC PROC [obj: CD.Object] RETURNS [cellType: CellType] = {
cellType ← NARROW [Sinix.Extract[obj, extractMode].result];
CoreProperties.PutCellTypeProp[cellType, layoutProp, obj];
};
StoringPins
IndirectGetPins: PROC [mode: Sinix.Mode, wire: Wire, ir: CD.Rect, data: REF] RETURNS [pins: LIST OF CD.Instance ← NIL] = {
pins ← Sinix.GetPinsProp[mode, NARROW [data]];
};
Should be called only when source.size=extracted.size=0
SourcePinsFromExtracted: PROC [source, extracted: Wire, checkPins: BOOL] = {
pins: LIST OF CD.Instance ← Sinix.GetPinsProp[extractMode, extracted];
IF pins=NIL THEN IF checkPins THEN Signal[] ELSE RETURN;
IF Sinix.GetPinsProp[extractMode, source]=NIL
THEN Sinix.PutLazyPinsProp[extractMode, source, NEW [Sinix.LazyPinsDataRec ← [ir: CDBasics.empty, data: extracted, getLazyPins: IndirectGetPins]]] -- anything would do for ir, since it is not checked by IndirectGetPins
ELSE Sinix.AppendPinsProp[extractMode, source, pins];
};
Predefined layoutAtoms and their associated procs
Get: PUBLIC LayoutProc = {
source: CD.Design ← NARROW [CoreProperties.GetCellTypeProp[cellType, $PWCoreSourceDesign]];
obj ← GetAndAddSuffix[source, CoreOps.GetCellTypeName[cellType]];
};
GetAndFlatten: PUBLIC LayoutProc = {
source: CD.Design ← NARROW [CoreProperties.GetCellTypeProp[cellType, $PWCoreSourceDesign]];
obj ← PW.Flatten[GetAndAddSuffix[source, CoreOps.GetCellTypeName[cellType]]];
};
AbutX: PUBLIC LayoutProc = {
data: CoreClasses.RecordCellType ← NARROW [cellType.data];
subObjects: LIST OF CD.Object ← NIL;
FOR i: NAT DECREASING IN [0 .. data.size) DO
subObjects ← CONS [Layout[data[i].type], subObjects];
ENDLOOP;
obj ← PW.AbutListX[subObjects];
};
AbutY: PUBLIC LayoutProc = {
data: CoreClasses.RecordCellType ← NARROW [cellType.data];
subObjects: LIST OF CD.Object ← NIL;
FOR i: NAT DECREASING IN [0 .. data.size) DO
subObjects ← CONS [Layout[data[i].type], subObjects];
ENDLOOP;
obj ← PW.AbutListY[subObjects];
};
ReverseAbutX: PUBLIC LayoutProc = {
data: CoreClasses.RecordCellType ← NARROW [cellType.data];
subObjects: LIST OF CD.Object ← NIL;
FOR i: NAT IN [0 .. data.size) DO
subObjects ← CONS [Layout[data[i].type], subObjects];
ENDLOOP;
obj ← PW.AbutListX[subObjects];
};
ReverseAbutY: PUBLIC LayoutProc = {
data: CoreClasses.RecordCellType ← NARROW [cellType.data];
subObjects: LIST OF CD.Object ← NIL;
FOR i: NAT IN [0 .. data.size) DO
subObjects ← CONS [Layout[data[i].type], subObjects];
ENDLOOP;
obj ← PW.AbutListY[subObjects];
};
ArrayX: PUBLIC LayoutProc = {
recasted: CellType ← CoreOps.Recast[cellType];
SetLayout[recasted, $AbutX]; obj ← Layout[recasted];
};
ArrayY: PUBLIC LayoutProc = {
recasted: CellType ← CoreOps.Recast[cellType];
SetLayout[recasted, $AbutY]; obj ← Layout[recasted];
};
ReverseArrayX: PUBLIC LayoutProc = {
recasted: CellType ← CoreOps.Recast[cellType];
SetLayout[recasted, $ReverseAbutX]; obj ← Layout[recasted];
};
ReverseArrayY: PUBLIC LayoutProc = {
recasted: CellType ← CoreOps.Recast[cellType];
SetLayout[recasted, $ReverseAbutY]; obj ← Layout[recasted];
};
FlipX: PUBLIC LayoutProc = {
IF cellType.class#CoreClasses.identityCellClass THEN Signal[];
obj ← PW.FlipX[Layout[NARROW [cellType.data]]];
};
FlipY: PUBLIC LayoutProc = {
IF cellType.class#CoreClasses.identityCellClass THEN Signal[];
obj ← PW.FlipY[Layout[NARROW [cellType.data]]];
};
Rot90: PUBLIC LayoutProc = {
IF cellType.class#CoreClasses.identityCellClass THEN Signal[];
obj ← PW.Rot90[Layout[NARROW [cellType.data]]];
};
Rot180: PUBLIC LayoutProc = {
IF cellType.class#CoreClasses.identityCellClass THEN Signal[];
obj ← PW.Rot180[Layout[NARROW [cellType.data]]];
};
Rot270: PUBLIC LayoutProc = {
IF cellType.class#CoreClasses.identityCellClass THEN Signal[];
obj ← PW.Rot270[Layout[NARROW [cellType.data]]];
};
Recast: LayoutProc = {
obj ← Layout[CoreOps.Recast[cellType]];
};
StructureWarnings: TYPE = RECORD [
kind: CoreStructuralComparison.WarningKind,
fromA, fromB: LIST OF REF];
FuseTransistors: PROC [recordCell: CellType] RETURNS [new: CellType] = {
oldData, newData, data: CoreClasses.RecordCellType;
nb, fused: NAT ← 0;
IF recordCell.class#CoreClasses.recordCellClass THEN RETURN [recordCell];
oldData ← NARROW [recordCell.data];
data ← NEW [CoreClasses.RecordCellTypeRec[oldData.size]];
data.internal ← oldData.internal;
FOR i: NAT IN [0 .. data.size) DO data[i] ← oldData[i] ENDLOOP;
FOR i: NAT IN [0 .. data.size) DO
IF data[i]=NIL THEN LOOP;
data[i].type ← FuseTransistors[data[i].type];
IF data[i].type.class#CoreClasses.transistorCellClass THEN LOOP;
FOR j: NAT IN [0 .. i) DO
IF data[j]=NIL THEN LOOP;
IF data[j].type.class#CoreClasses.transistorCellClass THEN LOOP;
IF data[i].actual[0]=data[j].actual[0] AND ((data[i].actual[1]=data[j].actual[1] AND data[i].actual[2]=data[j].actual[2]) OR (data[i].actual[2]=data[j].actual[1] AND data[i].actual[1]=data[j].actual[2])) THEN {
t1: CoreClasses.Transistor ← NARROW [data[i].type.data];
t2: CoreClasses.Transistor ← NARROW [data[j].type.data];
IF t1.type=t2.type AND t1.length=t2.length THEN {
data[i] ← CoreClasses.CreateInstance[
actual: data[i].actual,
type: CoreClasses.CreateTransistor[
args: [type: t1.type, length: t1.length, width: t1.width + t2.width],
props: data[i].type.properties
],
props: data[i].properties
];
data[j] ← NIL;
fused ← fused + 1;
};
};
ENDLOOP;
ENDLOOP;
IF fused=0 THEN RETURN [recordCell];
PW.WriteF["*** Lichen for PWCore.Get: fused %g transistors.\n", IO.int[fused]];
new ← CoreOps.CreateCellType[CoreClasses.recordCellClass, recordCell.public, NEW [CoreClasses.RecordCellTypeRec[data.size-fused]], NIL, recordCell.properties];
newData ← NARROW [new.data];
newData.internal ← data.internal;
FOR i: NAT IN [0 .. data.size) DO
IF data[i]=NIL THEN LOOP;
newData[nb] ← data[i]; nb ← nb + 1;
ENDLOOP;
};
DecorateGet: PUBLIC DecorateProc = {
extractedCT: CellType ← NARROW [Sinix.Extract[obj, extractMode].result];
InsertHint: PROC [key, value: REF ANY] RETURNS [quit: BOOLFALSE] = {
sourceWire: CoreFlat.FlatWire ← NEW [CoreFlat.FlatWireRec ← [path: CoreFlat.NullPath, wire: NARROW [value]]];
extractedWire: CoreFlat.FlatWire ← NEW [CoreFlat.FlatWireRec ← [path: CoreFlat.NullPath, wire: NARROW [key]]];
IF NOT HashTable.Insert[table: wireHints, key: sourceWire, value: extractedWire] THEN ERROR;
};
extractedToSource: HashTable.Table ← DecorateCorrespondingPublic[cellType.public, extractedCT.public];
wireHints: HashTable.Table ← HashTable.Create[];
warnings: LIST OF StructureWarnings ← NIL;
IF testLichen THEN {
[] ← HashTable.Pairs[table: extractedToSource, action: InsertHint];
extractedCT ← FuseTransistors[extractedCT];
IF ~CoreStructuralComparison.FlattenAndCompare[ctA: cellType, ctB: extractedCT, wireHints: wireHints, instanceHints: HashTable.Create[] ! CoreStructuralComparison.Warning => {warnings ← CONS[[kind, fromA, fromB], warnings]; RESUME}] THEN {PrintWarnings[cellType, extractedCT, warnings, TerminalIO.TOS[]]; Signal[]};
};
};
PrintWarnings: PROC [cellType: Core.CellType, extractedCT: Core.CellType, warnings: LIST OF StructureWarnings, out: Core.STREAMNIL] = {
PrintDescendants: PROC [descendants: LIST OF REF, root: Core.CellType] = {
FOR descendants ← descendants, descendants.rest UNTIL descendants=NIL DO
WITH descendants.first SELECT FROM
in: CoreFlat.FlatInstance => {
IO.PutRope[out, CoreFlat.InstancePathRope[root, in^]];
IO.PutRope[out, "/"];
IO.PutRope[out, "?"];
};
wire: CoreFlat.FlatWire => {
IO.PutRope[out, CoreFlat.WirePathRope[root, wire^]];
};
ENDCASE => ERROR;
IO.PutRope[out, " "];
ENDLOOP;
};
IF out=NIL THEN out ← NARROW[ProcessProps.GetProp[$CommanderHandle], Commander.Handle].out;
FOR warns: LIST OF StructureWarnings ← warnings, warns.rest UNTIL warns=NIL DO
warning: StructureWarnings ← warns.first;
IO.PutRope[out, IF warning.kind=stuck THEN "stuck " ELSE "difference "];
IO.PutRope[out, "\n fromA: "];
PrintDescendants[warning.fromA, cellType];
IO.PutRope[out, "\n fromB: "];
PrintDescendants[warning.fromB, extractedCT];
IO.PutRope[out, "\n"];
ENDLOOP;
};
EqualCellType: PROC [cellType1, cellType2: CellType] RETURNS [equal: BOOL] = {
equal ← SELECT TRUE FROM
cellType1=cellType2
=> TRUE,
cellType1.class=CoreClasses.identityCellClass
=> EqualCellType[NARROW [cellType1.data], cellType2],
cellType2.class=CoreClasses.identityCellClass
=> EqualCellType[cellType1, NARROW [cellType2.data]],
ENDCASE
=> FALSE;
};
UncheckedDecorateAbut: PROC [cellType: CellType, obj: CD.Object, inOrder: OrderProc] = {
lazyPinsData: Sinix.LazyPinsData ← NEW [Sinix.LazyPinsDataRec ← [ir: CD.InterestRect[obj], getLazyPins: Sinix.RecordGetLazyPins, data: cellType]];
InsertInOrder: PROC [element: CD.Instance, sorted: LIST OF CD.Instance] RETURNS [new: LIST OF CD.Instance] = {
IF sorted=NIL THEN RETURN [LIST [element]];
IF inOrder[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] = {Sinix.PutLazyPinsProp[extractMode, wire, lazyPinsData]};
instances: LIST OF CD.Instance;
recordData: CoreClasses.RecordCellType ← NARROW [cellType.data];
WHILE obj.class#CDCells.cellClass DO obj ← CDDirectory.Expand[obj].new ENDLOOP;
FOR list: LIST OF CD.Instance ← NARROW [obj.specificRef, CD.CellPtr].contents, list.rest WHILE list#NIL DO
instances ← InsertInOrder[list.first, instances];
ENDLOOP;
FOR i: NAT IN [0 .. recordData.size) DO
CoreProperties.PutCellInstanceProp[recordData[i], extractMode.instanceProp, instances.first];
instances ← instances.rest;
ENDLOOP;
IF instances#NIL THEN Signal[];
CoreOps.VisitAtomicWires[cellType.public, SetLazyPins];
};
InternalDecorateAbutX: PUBLIC DecorateProc = {
IF checkAbuts
THEN DecorateAbutX[cellType, obj]
ELSE UncheckedDecorateAbut[cellType, obj, SortInX];
};
InternalDecorateAbutY: PUBLIC DecorateProc = {
IF checkAbuts
THEN DecorateAbutY[cellType, obj]
ELSE UncheckedDecorateAbut[cellType, obj, SortInY];
};
InternalDecorateReverseAbutX: PUBLIC DecorateProc = {
IF checkAbuts
THEN DecorateReverseAbutX[cellType, obj]
ELSE UncheckedDecorateAbut[cellType, obj, ReverseSortInX];
};
InternalDecorateReverseAbutY: PUBLIC DecorateProc = {
IF checkAbuts
THEN DecorateReverseAbutY[cellType, obj]
ELSE UncheckedDecorateAbut[cellType, obj, ReverseSortInY];
};
DecorateAbutX: PUBLIC DecorateProc = {
DecorateFlatten[cellType, obj, SortInX];
};
DecorateAbutY: PUBLIC DecorateProc = {
DecorateFlatten[cellType, obj, SortInY];
};
DecorateReverseAbutX: PUBLIC DecorateProc = {
DecorateFlatten[cellType, obj, ReverseSortInX];
};
DecorateReverseAbutY: PUBLIC DecorateProc = {
DecorateFlatten[cellType, obj, ReverseSortInY];
};
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]};
PositionnedInstance: TYPE = REF PositionnedInstanceRec;
PositionnedInstanceRec: TYPE = RECORD [
instance: CoreClasses.CellInstance,
bindings: HashTable.Table,
transf: CD.Instance
];
PositionnedWire: TYPE = REF PositionnedWireRec;
PositionnedWireRec: TYPE = RECORD [
wire: Wire,
bindings: HashTable.Table,
transf: 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 [obj: CD.Object, inOrder: OrderProc] RETURNS [positionnedInstances: LIST OF PositionnedInstance ← NIL, positionnedWires: LIST OF PositionnedWire ← NIL] = {
transfs: LIST OF CD.Instance ← LIST [CDInstances.NewInst[obj]];
extractedCT: CellType ← NARROW [Sinix.Extract[obj, extractMode].result];
InsertInOrdered: PROC [element: PositionnedInstance, sorted: LIST OF PositionnedInstance] RETURNS [new: LIST OF PositionnedInstance] = {
IF sorted=NIL THEN RETURN [LIST [element]];
IF inOrder[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]]];
};
EachInstance: CoreFlat.EachInstanceProc = {
transf: CD.Instance ← Sinix.Transform[transfs.first, InstanceTransf[instance]];
flatten ← NOT HasLayout[instance.type];
IF flatten THEN {transfs ← CONS [transf, transfs]; RETURN};
positionnedInstances ← InsertInOrdered [
NEW [PositionnedInstanceRec ← [instance: instance, bindings: bindings, transf: transf]],
positionnedInstances];
};
RecordGeometry: CoreFlat.EachCellTypeProc = {
recordCellData: CoreClasses.RecordCellType ← NARROW [cellType.data];
RecordWireGeometry: PROC [wire: Wire] = {
IF Sinix.GetWireGeometryProp[extractMode, wire]=NIL THEN RETURN;
positionnedWires ← CONS [
NEW [PositionnedWireRec ← [wire: wire, bindings: bindings, transf: transfs.first]],
positionnedWires];
};
CoreOps.VisitAtomicWires[recordCellData.internal, RecordWireGeometry];
};
PopTransf: CoreFlat.EachCellTypeProc = {transfs ← transfs.rest};
CoreFlat.EnumerateLeaves[extractedCT, EachInstance, RecordGeometry, RecordGeometry, PopTransf];
};
DecorateFlatten: PUBLIC PROC [cellType: CellType, obj: CD.Object, inOrder: 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]];
extractedCTData: CoreClasses.RecordCellType ← NARROW [extractedCT.data];
cellTypeData: CoreClasses.RecordCellType ← NARROW [cellType.data];
DecorateActual: PROC [bindings: HashTable.Table, sourceActual, deepActual: Wire] = {
wireBind: CoreFlat.WireBind ← NARROW [HashTable.Fetch[bindings, deepActual].value];
extractedActual: Wire;
wire: Wire;
FOR i: NAT IN [0 .. sourceActual.size) DO DecorateActual[bindings, sourceActual[i], deepActual[i]] ENDLOOP;
IF deepActual.size#0 THEN RETURN;
IF wireBind=NIL THEN Signal[]; -- something is really wrong!
IF wireBind.path.length#0 THEN Signal[]; -- a deep internal wire
extractedActual ← wireBind.wire;
IF sourceActual.size#extractedActual.size THEN Signal[];
wire ← NARROW [HashTable.Fetch[extractedToSource, extractedActual].value];
IF wire=sourceActual THEN RETURN;
IF wire#NIL THEN {
PW.WriteF[
"*** Mismatch between extracted layout and source description: atomic extracted wire '%g' corresponds to 2 different atomic source wires '%g' and '%g'\n",
IO.rope[CoreOps.GetFullWireNames[extractedCTData.internal, extractedActual].first],
IO.rope[CoreOps.GetFullWireNames[cellType.public, wire].first],
IO.rope[CoreOps.GetFullWireNames[cellType.public, sourceActual].first]
];
Signal[];
};
SourcePinsFromExtracted[sourceActual, extractedActual, FALSE];
[] ← HashTable.Insert[extractedToSource, extractedActual, sourceActual];
};
positionnedInstances: LIST OF PositionnedInstance;
positionnedWires: LIST OF PositionnedWire;
length: INT ← 0;
[positionnedInstances, positionnedWires] ← GetPositionnedInstances[obj, inOrder];
FOR list: LIST OF PositionnedInstance ← positionnedInstances, list.rest WHILE list#NIL DO length ← length+1 ENDLOOP;
IF cellTypeData.size#length THEN {
PW.WriteF["*** Mismatch between extracted layout (%g instances) and source description (%g instances)\n", IO.int[length], IO.int[cellTypeData.size]];
Signal[];
};
FOR i: NAT IN [0 .. cellTypeData.size) DO
positionnedInstance: PositionnedInstance ← positionnedInstances.first;
positionnedInstances ← positionnedInstances.rest;
IF NOT EqualCellType[cellTypeData[i].type, positionnedInstance.instance.type] THEN {
PW.WriteF["*** Mismatch between the %gth instance of the extracted layout and the %gth instance of the source description: cellTypes are different\n", IO.int[i], IO.int[i]];
Signal[];
};
CoreProperties.PutCellInstanceProp[cellTypeData[i], extractMode.instanceProp, positionnedInstance.transf];
IF ~ CoreOps.Conform[cellTypeData[i].actual, positionnedInstance.instance.actual] THEN Signal[];
FOR j: NAT IN [0 .. positionnedInstance.instance.actual.size) DO
DecorateActual[positionnedInstance.bindings, cellTypeData[i].actual[j], positionnedInstance.instance.actual[j]];
ENDLOOP;
ENDLOOP;
We copy the pinsProp and wireGeometryProp for all positionnedWires. For now, we only do it for wires which have the same name as some internal of cellType.
WHILE positionnedWires#NIL DO
positionnedWire: PositionnedWire ← positionnedWires.first;
wireBind: CoreFlat.WireBind;
name: ROPE ← CoreOps.GetShortWireName[positionnedWire.wire];
source: Wire;
geometry: LIST OF CD.Instance ← Sinix.GetWireGeometryProp[extractMode, positionnedWire.wire];
wireBind ← NARROW [HashTable.Fetch[positionnedWire.bindings, positionnedWire.wire].value];
IF wireBind=NIL THEN Signal[]; -- internal bug!
IF wireBind.path#CoreFlat.NullPath THEN Signal[]; -- not yet implemented if it is not part of the internal of extractedCT
source ← NARROW [HashTable.Fetch[extractedToSource, wireBind.wire].value];
All this code stinks ....
IF source=NIL THEN source ← CoreOps.FindWire[cellTypeData.internal, name];
IF source=NIL THEN Signal[];
geometry ← Sinix.TransformList[positionnedWire.transf, geometry];
Sinix.AppendWireGeometryProp[extractMode, source, geometry];
FOR pins: LIST OF CD.Instance ← geometry, pins.rest WHILE pins#NIL DO
pin: CD.Instance ← pins.first;
IF ~CDBasics.Inside[CDInstances.InstRectO[pin], CDBasics.Extend[ir, -1]]
THEN Sinix.AddPinsProp[extractMode, source, pin];
ENDLOOP;
positionnedWires ← positionnedWires.rest;
ENDLOOP;
};
DecorateRotated: PUBLIC DecorateProc = {
extractedCT: CellType ← NARROW [Sinix.Extract[obj, extractMode].result];
extractedToSource: HashTable.Table ← HashTable.Create[CoreOps.WireBits[extractedCT.public]];
DecorateActual: PROC [sourceActual, extractedActual: Wire] = {
wire: Wire ← NARROW [HashTable.Fetch[extractedToSource, extractedActual].value];
IF sourceActual.size#extractedActual.size THEN Signal[];
FOR i: NAT IN [0 .. sourceActual.size) DO DecorateActual[sourceActual[i], extractedActual[i]] ENDLOOP;
IF sourceActual.size#0 THEN RETURN;
IF wire=sourceActual THEN RETURN;
IF wire#NIL THEN {
PW.WriteF[
"*** Mismatch between extracted layout and source description: atomic extracted wire '%g' corresponds to 2 different atomic source wires '%g' and '%g'\n",
IO.rope[CoreOps.GetFullWireNames[extractedCTData.internal, extractedActual].first],
IO.rope[CoreOps.GetFullWireNames[cellType.public, wire].first],
IO.rope[CoreOps.GetFullWireNames[cellType.public, sourceActual].first]
];
Signal[];
};
SourcePinsFromExtracted[sourceActual, extractedActual, FALSE];
[] ← HashTable.Insert[extractedToSource, extractedActual, sourceActual];
};
extractedCTData: CoreClasses.RecordCellType ← NARROW [extractedCT.data];
IF cellType.class#CoreClasses.identityCellClass OR extractedCTData.size#1 THEN {
PW.WriteF["*** Mismatch between extracted layout (%g instances) and source description (%g)\n", IO.int[extractedCTData.size], IO.rope[cellType.class.name]];
Signal[];
};
DecorateActual[cellType.public, extractedCTData[0].actual];
};
DecorateRecasted: PUBLIC DecorateProc = {
extractedCT: CellType ← NARROW [Sinix.Extract[obj, extractMode].result];
CopyPinsFromExtractedToSourceProp: CoreOps.EachWirePairProc = {
IF publicWire.size#0 THEN RETURN;
SourcePinsFromExtracted[publicWire, actualWire, TRUE];
};
We check that the public of the source and the public of the extracted layout are similar, and we copy properties from one to the other
IF CoreOps.VisitBinding[extractedCT.public, cellType.public, CopyPinsFromExtractedToSourceProp] THEN Signal[];
};
InstanceTransf: PROC [cellInst: CoreClasses.CellInstance] RETURNS [transf: CD.Instance] = {
transf ← NARROW [CoreProperties.GetCellInstanceProp[cellInst, extractMode.instanceProp]];
};
InstanceLocation: PROC [cellInst: CoreClasses.CellInstance] RETURNS [location: CD.Position] = {
location ← CDBasics.BaseOfRect[CDInstances.InstRectO[InstanceTransf[cellInst]]];
};
SortInstances: PUBLIC PROC [cellType: CellType, inOrder: PROC [CD.Position, CD.Position] RETURNS [BOOL]] = {
data: CoreClasses.RecordCellType ← NARROW [cellType.data];
FOR i: NAT IN [0 .. data.size-1) DO
FOR j: NAT IN (i .. data.size) DO
IF ~inOrder[InstanceLocation[data[i]], InstanceLocation[data[j]]] THEN {
w: CoreClasses.CellInstance ← data[i];
data[i] ← data[j]; data[j] ← w;
};
ENDLOOP;
ENDLOOP;
};
Tentative help for regular structures
AbutCell: PUBLIC PROC [public: Wire, abutInstances: LIST OF AbutInstance, inX: BOOL, shared: BOOLFALSE, name: ROPENIL, props: Properties ← NIL] RETURNS [recordCell: CellType] = {
positionnedInstances: LIST OF PositionnedInstance ← NIL;
ObjectsFromAbutInstances: PROC [abutInstances: LIST OF AbutInstance] RETURNS [LIST OF CD.Object] = {
IF abutInstances=NIL THEN RETURN [NIL];
BEGIN
obj: CD.Object ← abutInstances.first.object; -- to allow 2 instances of the same object to have different bindings
ct: CellType ← FromLayoutWithoutPublic[obj];
RETURN [CONS [obj, ObjectsFromAbutInstances[abutInstances.rest]]];
END;
};
AnalyzePositionnedInstances: PROC = {
FOR abuts: LIST OF AbutInstance ← abutInstances, abuts.rest WHILE abuts#NIL DO
positionnedInstance: PositionnedInstance ← positionnedInstances.first;
instance: CoreClasses.CellInstance ← positionnedInstance.instance;
IF abuts.first.object#Layout[instance.type] THEN Signal[];
FOR pas: LIST OF CoreCreate.PA ← abuts.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];
wireBind: CoreFlat.WireBind ← NARROW [HashTable.Fetch[positionnedInstance.bindings, CoreClasses.CorrespondingActual[instance, pub]].value];
IF pub=NIL OR act=NIL THEN Signal[];
IF wireBind.path.length#0 THEN Signal[]; -- a deep internal wire
IF ~CoreOps.RecursiveMember[extractedCT.public, wireBind.wire] THEN Signal[]; -- corresponding wire does not end up being public
RegisterExtractedToSource[wireBind.wire, act, TRUE];
ENDLOOP;
positionnedInstances ← positionnedInstances.rest;
ENDLOOP;
IF positionnedInstances#NIL THEN Signal[];
};
RegisterExtractedToSource: PROC [extracted, source: Wire, checkPins: BOOL] = {
pins: LIST OF CD.Instance ← Sinix.GetPinsProp[extractMode, extracted];
prevAct: Wire ← NARROW [HashTable.Fetch[extractedToSource, extracted].value];
IF extracted.size#source.size THEN Signal[]; -- extracted wire and truth public do not have same structure!
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[]; -- extracted wire connected to 2 parts of the public
[] ← HashTable.Store[extractedToSource, extracted, source];
IF source.size=0 THEN SourcePinsFromExtracted[source, extracted, checkPins]; -- sub-public should have pins!
};
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];
};
CheckHasPins: PROC [wire: Wire] = {
pins: LIST OF CD.Instance ← Sinix.GetPinsProp[extractMode, wire];
IF pins#NIL THEN RETURN;
PW.WriteF["Public %g does not have have any pins. Probably because you forgot to specify in each abutInstance the sub-public bound to it\n", IO.rope[CoreOps.GetFullWireNames[public, wire].first]];
Signal[];
};
internals: LIST OF Wire ← LIST [public];
i: NAT ← 0;
instances: LIST OF CoreClasses.CellInstance;
obj: CD.Object ← IF shared
THEN IF abutInstances=NIL OR abutInstances.rest=NIL
THEN PW.AbutListX[ObjectsFromAbutInstances[abutInstances]]
ELSE (IF inX THEN PW.SharedAbutListX ELSE PW.SharedAbutListY)[ObjectsFromAbutInstances[abutInstances]] -- the last level of abutting is for the case of only one abutInstances
ELSE (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]];
positionnedWires: LIST OF PositionnedWire;
[positionnedInstances, positionnedWires] ← GetPositionnedInstances[obj, IF inX THEN SortInX ELSE SortInY];
IF positionnedWires#NIL THEN Signal[]; -- They were not really abuts ?
AnalyzePositionnedInstances[];
We check now that every atomic public has pins
CoreOps.VisitAtomicWires[public, CheckHasPins];
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];
CoreProperties.PutCellTypeProp[recordCell, layoutProp, obj]; -- The truth is the layout!
CDProperties.PutObjectProp[obj, extractMode.cacheProp, recordCell]; -- Fake the extraction!
IF Sinix.Extract[Layout[recordCell], extractMode].result#recordCell THEN Signal[]; -- invariant failed
};
Help for writing routers
EnumerateWirePins: PUBLIC PROC [cellType: CellType, eachWirePin: EachWirePinProc] RETURNS [quit: BOOL] = {
EachWire: CoreOps.EachWireProc = {
EachPin: EachPinProc = {
quit ← eachWirePin[wire, instance, min, max, side, layer];
};
IF wire.size#0 THEN RETURN;
quit ← EnumeratePins[cellType, wire, EachPin];
};
quit ← CoreOps.VisitWire[cellType.public, EachWire];
};
WIMMSL: TYPE = RECORD [wire: Wire, instance: CD.Instance, min, max: INT, side: Side, layer: CD.Layer];
EnumerateNonOverlappingWirePins: PUBLIC PROC [cellType: CellType, eachWirePin: EachWirePinProc] RETURNS [quit: BOOL] = {
list: LIST OF WIMMSLNIL;
InsertInList: PROC [wimmsl: WIMMSL, list: LIST OF WIMMSL] RETURNS [newList: LIST OF WIMMSL] = {
WHILE list#NIL DO
if Overlap then Union else strore in newList
IF wimmsl.wire=list.first.wire AND wimmsl.layer=list.first.layer AND wimmsl.side=list.first.side AND wimmsl.min<=list.first.max AND list.first.min<=wimmsl.max
THEN {wimmsl.min ← MIN [wimmsl.min, list.first.min]; wimmsl.max ← MAX [wimmsl.max, list.first.max]}
ELSE newList ← CONS [list.first, newList];
list ← list.rest;
ENDLOOP;
newList ← CONS [wimmsl, newList];
};
EachWirePin: EachWirePinProc = {
list ← InsertInList [[wire, instance, min, max, side, layer], list];
};
[] ← EnumerateWirePins[cellType, EachWirePin];
WHILE list#NIL DO
quit ← eachWirePin[list.first.wire, list.first.instance, list.first.min, list.first.max, list.first.side, list.first.layer];
IF quit THEN EXIT;
list ← list.rest;
ENDLOOP;
};
EnumeratePins: PUBLIC PROC [cellType: CellType, wire: Wire, eachPin: EachPinProc] RETURNS [quit: BOOLFALSE] = {
obj: CD.Object ← Layout[cellType];
objSize: CD.Position ← CD.InterestSize[obj];
FOR pins: LIST OF CD.Instance ← Sinix.GetPinsProp[extractMode, wire], pins.rest WHILE pins#NIL DO
pin: CD.Instance ← pins.first;
side: Side; min, max: INT ← 0;
sides: ARRAY Side OF BOOLALL [FALSE];
pinRect: CD.Rect ← CDBasics.MoveRect[CDInstances.InstRectO[pin], CDBasics.SubPoints[[0, 0], CDBasics.BaseOfRect[CD.InterestRect[obj]]]]; -- bbox of the pin in the obj coordinate system of the outer
layer: CD.Layer ← IF CDSymbolicObjects.IsSymbolicOb[pin.ob]
THEN CDSymbolicObjects.GetLayer[pin]
ELSE pin.ob.layer;
sides[top] ← CDBasics.Intersect[pinRect, [0, objSize.y-1, objSize.x, objSize.y]];
sides[bottom] ← CDBasics.Intersect[pinRect, [0, 0, objSize.x, 1]];
sides[left] ← CDBasics.Intersect[pinRect, [0, 0, 1, objSize.y]];
sides[right] ← CDBasics.Intersect[pinRect, [objSize.x-1, 0, objSize.x, objSize.y]];
FOR s: Side IN Side DO
IF ~sides[s] THEN LOOP;
side ← s;
IF side=top OR side=bottom THEN {min ← pinRect.x1; max ← pinRect.x2};
IF side=left OR side=right THEN {min ← pinRect.y1; max ← pinRect.y2};
IF (quit ← eachPin[pin, min, max, side, layer]) THEN RETURN;
ENDLOOP;
ENDLOOP;
};
EnumerateSortedPins: PUBLIC PROC [cellType: CellType, side: Side, eachSortedPin: EachSortedPinProc] RETURNS [quit: BOOL] = {
thisSide: Side ← side;
list: LIST OF WIMMSLNIL;
InsertInList: PROC [wimmsl: WIMMSL, list: LIST OF WIMMSL] RETURNS [LIST OF WIMMSL] = {
IF list=NIL THEN RETURN [LIST [wimmsl]];
RETURN [IF list.first.min<wimmsl.min
THEN CONS [list.first, InsertInList[wimmsl, list.rest]] ELSE CONS [wimmsl, list]];
};
EachWirePin: EachWirePinProc = {
IF side=thisSide THEN list ← InsertInList [[wire, instance, min, max, side, layer], list];
};
[] ← EnumerateWirePins[cellType, EachWirePin];
WHILE list#NIL DO
quit ← eachSortedPin[list.first.wire, list.first.instance, list.first.min, list.first.max, list.first.layer];
IF quit THEN EXIT;
list ← list.rest;
ENDLOOP;
};
Registering layoutAtoms
[] ← RegisterLayoutAtom[$Get, Get, DecorateGet];
[] ← RegisterLayoutAtom[$GetAndFlatten, GetAndFlatten, DecorateGet];
[] ← RegisterLayoutAtom[$AbutX, AbutX, InternalDecorateAbutX];
[] ← RegisterLayoutAtom[$AbutY, AbutY, InternalDecorateAbutY];
[] ← RegisterLayoutAtom[$ReverseAbutX, ReverseAbutX, InternalDecorateReverseAbutX];
[] ← RegisterLayoutAtom[$ReverseAbutY, ReverseAbutY, InternalDecorateReverseAbutY];
[] ← RegisterLayoutAtom[$ArrayX, ArrayX, DecorateRecasted];
[] ← RegisterLayoutAtom[$ArrayY, ArrayY, DecorateRecasted];
[] ← RegisterLayoutAtom[$ReverseArrayX, ReverseArrayX, DecorateRecasted];
[] ← RegisterLayoutAtom[$ReverseArrayY, ReverseArrayY, DecorateRecasted];
[] ← RegisterLayoutAtom[$FlipX, FlipX, DecorateRotated];
[] ← RegisterLayoutAtom[$FlipY, FlipY, DecorateRotated];
[] ← RegisterLayoutAtom[$Rot90, Rot90, DecorateRotated];
[] ← RegisterLayoutAtom[$Rot180, Rot180, DecorateRotated];
[] ← RegisterLayoutAtom[$Rot270, Rot270, DecorateRotated];
[] ← RegisterLayoutAtom[$Recast, Recast, DecorateRecasted];
CoreProperties.PutCellClassProp[CoreClasses.identityCellClass, layoutAtomProp, $Recast];
END.