TimValuesImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reversed.
Created by Bertrand Serlet September 11, 1985 11:09:10 am PDT
Bertrand Serlet September 11, 1985 12:00:30 pm PDT
ToDo:
ERROR -> Signals;
Name of the atoms for CD.FetchObjectClass $Transistor
Use instanceName property and SignalName (???)
non connected actualWire (that is a problem for transistors)
Commenting object PROCS
Speed Hack for Rect
Naming wires to avoid problems when printing name: "Bidon"
DIRECTORY
CD, CDBasics, CDDirectory, CDErrors, CDObjectProcs, CDOrient, CDPinObjects, CDProperties, CDRects,
Core, CoreOps, CoreProperties, CoreRecord,
PWPins,
RefTab, Rope,
Sinix, SinixBridge;
TimValuesImpl: CEDAR PROGRAM
IMPORTS CD, CDBasics, CDDirectory, CDErrors, CDObjectProcs, CDOrient, CDPinObjects, CDProperties, CDRects, Core, CoreOps, CoreProperties, CoreRecord, PWPins, RefTab, Rope, SinixBridge
EXPORTS Sinix =
BEGIN OPEN Sinix;
Utilities
debug: BOOLTRUE;
Utilities
MakeInterval: PUBLIC PROC [min, max: INT] RETURNS [interval: Interval] = {
interval ← NEW [IntervalRec ← [min, max]];
};
MakeCutValue: PUBLIC PROC [tcut: INT, before, after: Value] RETURNS [cutValue: CutValue] = {
cutValue ← NEW [CutValueRec ← [tcut, before, after]];
};
Usual Operations
Add: PUBLIC PROC [value1, value2: Value] RETURNS [result: VALUE] = {
WITH value1 SELECT FROM
refInt1: Interval   => WITH value2 SELECT FROM
refInt2: Interval   => RETURN [MakeInterval[refInt1.min+refInt2.min, refInt1.max+refInt2.max]];
cutValue2: CutValue => RETURN [MakeCutValue[cutValue2.tcut, Add[value1, cutValue2.before], Add[value1, cutValue2.after]]];
ENDCASE     => ERROR;
cutValue1: CutValue => WITH value2 SELECT FROM
refInt2: Interval   => RETURN [MakeCutValue[cutValue1.tcut, Add[value2, cutValue1.before], Add[value2, cutValue1.after]]];
cutValue2: CutValue => IF cutValue1.tcut=cutValue2.tcut THEN RETURN [MakeCutValue[cutValue1.tcut, Add[cutValue1.before, cutValue2.before], Add[cutValue1.after, cutValue2.after]]] ELSE IF cutValue1.tcut<cutValue2.tcut THEN RETURN [MakeCutValue[cutValue1.tcut, Add[cutValue1.before, cutValue2.before], Add[cutValue1.after, value2]]] ELSE RETURN [MakeCutValue[cutValue2.tcut, Add[cutValue1.before, cutValue2.before], Add[cutValue2.after, value1]]];
ENDCASE     => ERROR;
ENDCASE     => ERROR;
};
TouchProcs are put on property on each class of object that does not use the default (default is expand). It is also possible to have that properties on an object. The callable function Touch is soforth programmed in an Object Oriented manner.
touchProcProp: ATOM;
Touch: TouchProc;
Operations for an easy management of those properties
PutObjectPropOnCellType: PUBLIC PROC [cellType: Core.CellType, obj: CD.Object] = {
cellType.properties ← CoreProperties.PutProp[cellType.properties, sinixObjectProp, obj];
};
GetObjectPropFromCellType: PUBLIC PROC [cellType: Core.CellType] RETURNS [obj: CD.Object] = {
obj ← NARROW [CoreProperties.GetProp[cellType.properties, sinixObjectProp]];
};
AppendWireGeometryPropOnWire: PUBLIC PROC [wire: Core.Wire, geometry: LIST OF CD.Instance] = {
WHILE geometry#NIL DO
AddWireGeometryPropOnWire[wire, geometry.first];
geometry ← geometry.rest;
ENDLOOP;
};
AddWireGeometryPropOnWire: PUBLIC PROC [wire: Core.Wire, cdInstance: CD.Instance] = {
PutWireGeometryPropOnWire[wire, CONS [cdInstance, GetWireGeometryPropFromWire[wire]]];
};
PutWireGeometryPropOnWire: PUBLIC PROC [wire: Core.Wire, geometry: LIST OF CD.Instance] = {
wire.properties ← CoreProperties.PutProp[wire.properties, sinixWireGeometryProp, geometry];
};
GetWireGeometryPropFromWire: PUBLIC PROC [wire: Core.Wire] RETURNS [geometry: LIST OF CD.Instance] = {
geometry ← NARROW[CoreProperties.GetProp[wire.properties, sinixWireGeometryProp]];
};
PutInstancePropOnInstance: PUBLIC PROC [cellInstance: CoreRecord.CellInstance, cdInstance: CD.Instance] = {
cellInstance.properties ← CoreProperties.PutProp[cellInstance.properties, sinixInstanceProp, cdInstance];
};
GetInstancePropFromInstance: PUBLIC PROC [cellInstance: CoreRecord.CellInstance] RETURNS [cdInstance: CD.Instance] = {
cdInstance ← NARROW [CoreProperties.GetProp[cellInstance.properties, sinixInstanceProp]];
};
Internal utilities
The following PROC implements Fisher-Galler fusion, not for efficiency, but for simplicity
Root: PROC [table: RefTab.Ref, wire: Core.Wire] RETURNS [newWire: Core.Wire] = {
newWire ← NARROW [RefTab.Fetch[table, wire].val];
IF newWire=NIL THEN RETURN[wire];
newWire ← Root[table, newWire];
[] ← RefTab.Replace[table, wire, newWire];
};
Fusion: PROC [table: RefTab.Ref, wire: Core.Wire] = {
geometry: LIST OF CD.Instance ← GetWireGeometryPropFromWire[wire];
EachWire: RefTab.EachPairAction = {
[key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOLEAN]
rootWire: Core.Wire ← Root[table, NARROW[key]];
rootGeometry: LIST OF CD.Instance ← GetWireGeometryPropFromWire[rootWire];
quit ← FALSE;
IF rootWire=wire OR ~TouchInstances[rootGeometry, geometry] THEN RETURN;
AppendWireGeometryPropOnWire[wire, rootGeometry];
SELECT TRUE FROM
rootWire.name=NIL       => {};
wire.name=NIL        => wire.name ← rootWire.name;
Rope.Equal[rootWire.name, wire.name] => {};
ENDCASE          => ERROR; -- different names on the same net (probably 2 pins of different nets connected together)
[] ← RefTab.Store[table, rootWire, wire];
};
[] ← RefTab.Pairs[table, EachWire];
[] ← RefTab.Store[table, wire, NIL];
};
TableToWire: PROC [table: RefTab.Ref] RETURNS [wire: Core.Wire] = {
EachWire: RefTab.EachPairAction = {
[key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOLEAN]
quit ← FALSE;
wire.elements[index] ← NARROW[key];
index ← index + 1;
};
size: NAT ← RefTab.GetSize[table];
index: NAT ← 0;
wire ← NEW [Core.WireRec ← [name: "Bidon", structure: record, elements: NEW [Core.WireSequenceRec[size]]]];
[] ← RefTab.Pairs[table, EachWire];
};
Member: PROC [wires: LIST OF Core.Wire, wire: Core.Wire] RETURNS [BOOL] = {
WHILE wires#NIL DO IF wires.first=wire THEN RETURN [TRUE]; wires ← wires.rest ENDLOOP;
RETURN [FALSE];
};
Extraction
extractObjProcProp: PUBLIC ATOM ← $ExtractObjProc;
ExtractObj: PUBLIC ExtractObjProc = {
refProc: REF ExtractObjProc;
name: ROPE ← CDDirectory.Name[obj];
IF name#NIL THEN cellType ← CoreOps.FetchCellType[coreDesign, name];
IF cellType#NIL THEN RETURN;
refProc ← NARROW [CDProperties.GetPropFromObject[obj, extractObjProcProp]];
IF refProc=NIL THEN refProc ← NARROW [CDObjectProcs.FetchFurther[obj.class, extractObjProcProp]];
[cellType, nbErrors] ← (IF refProc=NIL THEN DefaultExtractObj ELSE refProc^)[coreDesign, cdDesign, obj];
IF cellType=NIL THEN RETURN;
cellType.name ← name;
cellType.properties ← CoreProperties.PutProp[cellType.properties, sinixObjectProp, obj];
IF name#NIL AND CDDirectory.Fetch[cdDesign, name].found THEN CoreOps.InsertCellType[coreDesign, cellType];
};
DefaultExtractObj: PUBLIC ExtractObjProc = {
obj ← CDDirectory.ExpandHard[obj, NIL, NIL];
IF obj=NIL THEN ERROR;
RETURN ExtractObj[coreDesign, cdDesign, obj];
};
AtomicExtractObj: PUBLIC ExtractObjProc = {
subWire: Core.Wire ← NEW [Core.WireRec];
wire: Core.Wire ← NEW [Core.WireRec ← [structure: record, elements: NEW [Core.WireSequenceRec[1]]]];
AddWireGeometryPropOnWire[subWire, NEW [CD.InstanceRep ← [ob: obj]]];
wire.elements[0] ← subWire;
cellType ← NEW[Core.CellTypeRec ← [class: CoreRecord.recordCellClass, publicWire: wire, data: NEW[CoreRecord.RecordCellTypeRec ← [internalWire: wire]]]];
};
PinExtractObj: ExtractObjProc = {
RETURN [NIL];
};
CellExtractObj: ExtractObjProc = {
cellPtr: CD.CellPtr ← NARROW [obj.specificRef];
currentWires: RefTab.Ref ← RefTab.Create[];
realPublicWire: RefTab.Ref ← RefTab.Create[];
realInternalWires: RefTab.Ref ← RefTab.Create[];
currentInstances: LIST OF CoreRecord.CellInstance ← NIL;
cellTypeData: CoreRecord.RecordCellType;
FOR instances: LIST OF CD.Instance ← cellPtr.contents, instances.rest WHILE instances#NIL DO
cdInstance: CD.Instance ← instances.first;
subCellType: Core.CellType;
subErrors: INT;
subPublics: Core.WireSequence;
size: NAT;
actualWire: Core.Wire;
instance: CoreRecord.CellInstance;
[subCellType, subErrors] ← ExtractObj[coreDesign, cdDesign, cdInstance.ob];
nbErrors ← nbErrors + subErrors;
IF subCellType=NIL THEN LOOP; -- Symbolic object such as a pin
subPublics ← subCellType.publicWire.elements;
size ← subPublics.size;
actualWire ← NEW [Core.WireRec ← [name: "Bidon", structure: record, elements: NEW [Core.WireSequenceRec[size]]]];
instance ← NEW [CoreRecord.CellInstanceRec ← [actualWire: actualWire, type: subCellType]];
instance.properties ← CoreProperties.PutProp[instance.properties, sinixInstanceProp, cdInstance];
currentInstances ← CONS [instance, currentInstances];
we fill the actual
FOR i: NAT IN [0 .. size) DO
subPublic: Core.Wire ← subPublics[i];
newActual: Core.Wire ← NEW [Core.WireRec];
IF GetWireGeometryPropFromWire[subPublic]=NIL
THEN {} -- that means a non-connected subPublic
ELSE AddWireGeometryPropOnWire[newActual, NEW [CD.InstanceRep ← [ob: SinixBridge.WireToObjectBridge[cdInstance.ob, subPublic], location: cdInstance.location, orientation: cdInstance.orientation]]];
Fusion[currentWires, newActual];
actualWire.elements[i] ← newActual;
ENDLOOP;
ENDLOOP;
compute now the realInternalWires
BEGIN
ComputeRealWire: RefTab.EachPairAction = {
[key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOLEAN]
rootWire: Core.Wire ← Root[currentWires, NARROW[key]];
quit ← FALSE;
[] ← RefTab.Store[realInternalWires, rootWire, NIL];
};
[] ← RefTab.Pairs[currentWires, ComputeRealWire];
END;
compute now the realPublicWire by enumerating the pins
BEGIN
EachPin: PWPins.InstanceEnumerator = {
[inst: CD.Instance] RETURNS [quit: BOOL ← FALSE]
pinName: ROPE ← CDPinObjects.GetName[inst];
geometry: LIST OF CD.Instance ← LIST [inst];
lastRootWire: Core.Wire ← NIL;
EachWire: RefTab.EachPairAction = {
[key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOLEAN]
wire: Core.Wire ← NARROW[key];
quit ← FALSE;
IF ~TouchInstances[GetWireGeometryPropFromWire[wire], geometry] THEN RETURN;
IF lastRootWire#NIL THEN ERROR; -- 2 different nets touched by the same pin
lastRootWire ← wire;
IF wire.name=NIL OR Rope.Equal[wire.name, pinName] THEN wire.name ← pinName ELSE {
[] ← CDErrors.IncludeMessage[cdDesign, obj, RectAt[inst], Rope.Cat["Different names on the same net (probably 2 pins of different nets connected together): ", wire.name, pinName]];
nbErrors ← nbErrors+1;
};
};
[] ← RefTab.Pairs[realInternalWires, EachWire];
IF lastRootWire=NIL THEN ERROR; -- pin touches no net
[] ← RefTab.Store[realPublicWire, lastRootWire, NIL];
};
[] ← PWPins.EnumerateEdgePins[obj, EachPin];
END;
we build the CellType
cellTypeData ← NEW [CoreRecord.RecordCellTypeRec ← [internalWire: TableToWire[realInternalWires]]];
cellType ← NEW [Core.CellTypeRec ← [
class: CoreRecord.recordCellClass,
publicWire: TableToWire[realPublicWire],
data: cellTypeData]];
WHILE currentInstances#NIL DO
instance: CoreRecord.CellInstance ← currentInstances.first;
actualWire: Core.Wire ← instance.actualWire;
FOR i: NAT IN [0 .. actualWire.elements.size) DO
wire: Core.Wire ← Root[currentWires, actualWire.elements[i]];
IF GetWireGeometryPropFromWire[wire]=NIL THEN ERROR; -- non connected actualWire (that is a problem for transistors)
IF ~RefTab.Fetch[realInternalWires, wire].found THEN ERROR; -- BUG!
actualWire.elements[i] ← wire;
ENDLOOP;
cellTypeData.instances ← CONS [instance, cellTypeData.instances];
currentInstances ← currentInstances.rest;
ENDLOOP;
};
Geometry Primitives
touchProcProp: PUBLIC ATOM ← $TouchProc;
Touch: PUBLIC TouchProc = {
refProc: REF TouchProc;
IF ~CDBasics.Intersect[RectAt[instance1], RectAt[instance2]] THEN RETURN;
refProc ← NARROW [CDProperties.GetPropFromObject[instance1.ob, touchProcProp]];
IF refProc=NIL THEN refProc ← NARROW [CDObjectProcs.FetchFurther[instance1.ob.class, touchProcProp]];
yes ← (IF refProc=NIL THEN DefaultTouchProc ELSE refProc^)[instance1, instance2];
};
DefaultTouchProc: TouchProc = {
instance1 ← NEW [CD.InstanceRep ← [
ob: CDDirectory.ExpandHard[instance1.ob, NIL, NIL],
location: instance1.location, orientation: instance1.orientation
]];
IF instance1.ob=NIL THEN ERROR;
RETURN [Touch[instance1, instance2]];
};
PinTouchProc: TouchProc = {
RETURN [TouchRect[instance2, RectAt[instance1], CDPinObjects.GetLayer[instance1]]];
};
RectTouchProc: TouchProc = {
RETURN [TouchRect[instance2, RectAt[instance1], instance1.ob.layer]];
};
CellTouchProc: TouchProc = {
cellPtr: CD.CellPtr ← NARROW [instance1.ob.specificRef];
FOR instances: LIST OF CD.Instance ← cellPtr.contents, instances.rest WHILE instances#NIL DO
IF Touch[Transform[instance1, instances.first], instance2] THEN RETURN [TRUE];
ENDLOOP;
RETURN [FALSE];
};
Geometry Utilities
RectAt: PUBLIC PROC [instance: CD.Instance] RETURNS [rect: CD.Rect] = {
rect ← CDOrient.RectAt[instance.location, instance.ob.size, instance.orientation];
};
IRectAt: PUBLIC PROC [instance: CD.Instance] RETURNS [rect: CD.Rect] = {
rect ← CDOrient.MapRect[CD.InterestRect[instance.ob], instance.ob.size, instance.orientation, instance.location];
};
TouchRect: PUBLIC PROC [instance: CD.Instance, rect: CD.Rect, layer: CD.Layer] RETURNS [yes: BOOLFALSE] = {
rectInstance: CD.Instance;
IF ~CDBasics.Intersect[RectAt[instance], rect] THEN RETURN;
IF instance.ob.class.objectType=$Rect THEN RETURN [instance.ob.layer=layer];
rectInstance ← NEW [CD.InstanceRep ← [
ob: CDRects.CreateRect[CDBasics.SizeOfRect[rect], layer],
location: CDBasics.BaseOfRect[rect]
]];
yes ← Touch[instance, rectInstance];
};
Transform: PROC [transformation, instance: CD.Instance] RETURNS [result: CD.Instance] = {
RETURN [
NEW [CD.InstanceRep ← [
ob: instance.ob,
location: CDBasics.BaseOfRect[CDOrient.MapRect[
itemInCell: RectAt[instance],
cellSize: transformation.ob.size,
cellInstOrient: transformation.orientation,
cellInstPos: transformation.location
]],
orientation: CDOrient.ComposeOrient[itemOrientInCell: instance.orientation, cellOrientInWorld: transformation.orientation]
]]];
};
TransformList: PROC [transformation: CD.Instance, instances: LIST OF CD.Instance] RETURNS [result: LIST OF CD.Instance ← NIL] = {
WHILE instances#NIL DO
result ← CONS [Transform[transformation, instances.first], result];
instances ← instances.rest;
ENDLOOP;
};
TouchInstances: PROC [instances1, instances2: LIST OF CD.Instance] RETURNS [yes: BOOLFALSE] = {
FOR list1: LIST OF CD.Instance ← instances1, list1.rest WHILE list1#NIL DO
FOR list2: LIST OF CD.Instance ← instances2, list2.rest WHILE list2#NIL DO
IF Touch[list1.first, list2.first] THEN RETURN [TRUE];
ENDLOOP;
ENDLOOP;
};
Initialization
BEGIN
ENABLE {
CD.Error => IF debug AND ec=doubleRegistration THEN CONTINUE ELSE ERROR;
Core.StructureError => IF debug AND type=DuplicateName THEN RESUME ELSE ERROR;
};
Public Core Properties
CoreProperties.RegisterProperty[sinixObjectProp];
CoreProperties.RegisterProperty[sinixWireGeometryProp];
CoreProperties.RegisterProperty[sinixInstanceProp];
CD Properties
[] ← CDProperties.RegisterProperty[extractObjProcProp, $Sinix];
CDObjectProcs.RegisterFurther[extractObjProcProp];
CDObjectProcs.StoreFurther[CD.FetchObjectClass[$PinOb0], extractObjProcProp, NEW [ExtractObjProc ← PinExtractObj]];
CDObjectProcs.StoreFurther[CD.FetchObjectClass[$Transistor], extractObjProcProp, NEW [ExtractObjProc ← TransistorExtractObj]];
CDObjectProcs.StoreFurther[CD.FetchObjectClass[$Rect], extractObjProcProp, NEW [ExtractObjProc ← AtomicExtractObj]];
CDObjectProcs.StoreFurther[CD.FetchObjectClass[$Cell], extractObjProcProp, NEW [ExtractObjProc ← CellExtractObj]];
[] ← CDProperties.RegisterProperty[touchProcProp, $Sinix];
CDObjectProcs.RegisterFurther[touchProcProp];
CDObjectProcs.StoreFurther[CD.FetchObjectClass[$PinOb0], touchProcProp, NEW [TouchProc ← PinTouchProc]];
CDObjectProcs.StoreFurther[CD.FetchObjectClass[$Rect], touchProcProp, NEW [TouchProc ← RectTouchProc]];
CDObjectProcs.StoreFurther[CD.FetchObjectClass[$Cell], touchProcProp, NEW [TouchProc ← CellTouchProc]];
END;
END.