SinixImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reversed.
Created by Bertrand Serlet August 15, 1985 2:09:54 pm PDT
Bertrand Serlet June 3, 1986 12:37:26 pm PDT
Pradeep Sindhu May 5, 1986 5:16:10 pm PDT
Barth, April 18, 1986 4:42:48 pm PST
DIRECTORY
CD, CDAtomicObjects, CDBasics, CDCells, CDDirectory, CDInstances, CDLayers, CDOrient, CDProperties, CDRects, CDSymbolicObjects,
CedarProcess,
Core, CoreClasses, CoreOps, CoreProperties,
D2Intervals, HashTable, IO, Process,
PW, PWObjects, PWPins,
RedBlackTree, Rope,
Sinix;
SinixImpl: CEDAR PROGRAM
IMPORTS CD, CDBasics, CDCells, CDDirectory, CDInstances, CDLayers, CDOrient, CDProperties, CDRects, CDSymbolicObjects, CedarProcess, CoreClasses, CoreOps, CoreProperties, D2Intervals, HashTable, IO, Process, PW, PWObjects, PWPins, RedBlackTree, Rope
EXPORTS Sinix
SHARES CDCells, CDRects =
BEGIN OPEN Sinix;
Operations for an easy management of properties
AppendPinsProp: PUBLIC PROC [mode: Mode, wire: Wire, pins: LIST OF CD.Instance] = {
WHILE pins#NIL DO AddPinsProp[mode, wire, pins.first]; pins ← pins.rest ENDLOOP;
};
AddPinsProp: PUBLIC PROC [mode: Mode, wire: Wire, pin: CD.Instance] = {
PutPinsProp[mode, wire, CONS [pin, GetPinsProp[mode, wire]]];
};
PutPinsProp: PUBLIC PROC [mode: Mode, wire: Wire, geometry: LIST OF CD.Instance] = {
CoreProperties.PutWireProp[wire, mode.pinsProp, geometry];
};
GetPinsProp: PUBLIC PROC [mode: Mode, wire: Wire] RETURNS [geometry: LIST OF CD.Instance] = {
value: REF ← CoreProperties.GetWireProp[wire, mode.pinsProp];
IF value=NIL THEN RETURN [NIL];
WITH value SELECT FROM
geom: LIST OF CD.Instance  => geometry ← geom;
lazyPinsData: LazyPinsData => geometry ← lazyPinsData.getLazyPins[mode, wire, lazyPinsData.ir, lazyPinsData.data];
ENDCASE       => ERROR;
};
PutLazyPinsProp: PUBLIC PROC [mode: Mode, wire: Wire, lazyPinsData: LazyPinsData] = {
CoreProperties.PutWireProp[wire, mode.pinsProp, lazyPinsData];
};
AppendInstancePins: PROC [prevPins: LIST OF CD.Instance, mode: Mode, wire: Wire, ir: CD.Rect, instance: CoreClasses.CellInstance] RETURNS [pins: LIST OF CD.Instance, count: NAT ← 0, subPublic: Wire] = {
transf: CD.Instance ← GetInstanceTransformationProp[mode, instance];
EachBind: CoreOps.EachWirePairProc = {
IF actualWire#wire THEN RETURN;
subPublic ← publicWire;
FOR subGeometry: LIST OF CD.Instance ← GetPinsProp[mode, publicWire], subGeometry.rest WHILE subGeometry#NIL DO
inst: CD.Instance ← Transform[transf, subGeometry.first];
IF ~CDBasics.Inside[CDBasics.Extend[CDInstances.InstRectO[inst], mode.clipDistance], CDBasics.Extend[ir, -1]] THEN {count ← count+1; pins ← CONS [inst, pins]};
ENDLOOP;
};
pins ← prevPins;
[] ← CoreOps.VisitBinding[instance.actual, instance.type.public, EachBind];
};
RecordGetLazyPins: PUBLIC PROC [mode: Mode, wire: Wire, ir: CD.Rect, data: REF] RETURNS [pins: LIST OF CD.Instance] = {
cellType: CellType ← NARROW [data];
recData: CoreClasses.RecordCellType ← NARROW [cellType.data];
countInstanceWire: NAT ← 0;
countInstances: NAT ← 0;
onlyInstance: CoreClasses.CellInstance;
onlySubPublic: Wire;
FOR i: NAT IN [0 .. recData.size) DO
instance: CoreClasses.CellInstance ← recData[i];
subPublic: Wire;
count: NAT ← 0;
[pins, count, subPublic] ← AppendInstancePins[pins, mode, wire, ir, instance];
IF count#0 THEN {
countInstances ← countInstances + count;
countInstanceWire ← countInstanceWire + 1;
onlyInstance ← instance; onlySubPublic ← subPublic;
};
ENDLOOP;
IF countInstanceWire=1 THEN PutLazyPinsProp[mode, wire, NEW [LazyPinsDataRec ← [ir: ir, data: NEW [InstanceWireRec ← [transf: GetInstanceTransformationProp[mode, onlyInstance], subPublic: onlySubPublic]], getLazyPins: InstanceWireGetLazyPins]]];
IF countInstances<=2 THEN PutPinsProp[mode, wire, pins];
};
InstanceWire: TYPE = REF InstanceWireRec;
InstanceWireRec: TYPE = RECORD [transf: CD.Instance, subPublic: Wire];
InstanceWireGetLazyPins: PROC [mode: Mode, wire: Wire, ir: CD.Rect, data: REF] RETURNS [geometry: LIST OF CD.Instance] = {
instanceWire: InstanceWire ← NARROW [data];
transf: CD.Instance ← instanceWire.transf;
FOR subGeometry: LIST OF CD.Instance ← GetPinsProp[mode, instanceWire.subPublic], subGeometry.rest WHILE subGeometry#NIL DO
inst: CD.Instance ← Transform[transf, subGeometry.first];
IF ~CDBasics.Inside[CDBasics.Extend[CDInstances.InstRectO[inst], mode.clipDistance], CDBasics.Extend[ir, -1]] THEN geometry ← CONS [inst, geometry];
ENDLOOP;
};
AppendWireGeometryProp: PUBLIC PROC [mode: Mode, wire: Wire, geometry: LIST OF CD.Instance] = {
WHILE geometry#NIL DO
AddWireGeometryProp[mode, wire, geometry.first];
geometry ← geometry.rest;
ENDLOOP;
};
AddWireGeometryProp: PUBLIC PROC [mode: Mode, wire: Wire, cdInstance: CD.Instance] = {
PutWireGeometryProp[mode, wire, CONS [cdInstance, GetWireGeometryProp[mode, wire]]];
};
PutWireGeometryProp: PUBLIC PROC [mode: Mode, wire: Wire, geometry: LIST OF CD.Instance] = {
CoreProperties.PutWireProp[wire, mode.wireGeometryProp, geometry];
};
GetWireGeometryProp: PUBLIC PROC [mode: Mode, wire: Wire] RETURNS [geometry: LIST OF CD.Instance] = {
geometry ← NARROW [CoreProperties.GetWireProp[wire, mode.wireGeometryProp]];
};
PutInstanceTransformationProp: PUBLIC PROC [mode: Mode, instance: CoreClasses.CellInstance, transf: CD.Instance] = {
CoreProperties.PutCellInstanceProp[instance, mode.instanceProp, transf];
};
GetInstanceTransformationProp: PUBLIC PROC [mode: Mode, instance: CoreClasses.CellInstance] RETURNS [transf: CD.Instance] = {
transf ← NARROW [CoreProperties.GetCellInstanceProp[instance, mode.instanceProp]];
};
HighLighting errors utilities
Cellize: PROC [obj: CD.Object] RETURNS [cell: CD.Object]= {
cellPtr: CD.CellPtr;
cell ← CDCells.CreateEmptyCell[];
cellPtr ← NARROW [cell.specificRef];
cellPtr.contents ← LIST [PWPins.NewInstance[obj]];
cell.size ← obj.size;
};
HighLightWires: PROC [fusionData: FusionData, cell: CD.Object, wires: LIST OF Wire] = {
WHILE wires#NIL DO HighLightWire[fusionData, cell, wires.first]; wires ← wires.rest ENDLOOP;
};
HighLightWire: PROC [fusionData: FusionData, cell: CD.Object, wire: Wire] = {
HighLightInstances[cell, GetWireGeometryProp[fusionData.mode, wire]];
HighLightInstances[cell, GetPinsProp[fusionData.mode, wire]];
};
HighLightInstances: PROC [cell: CD.Object, geometry: LIST OF CD.Instance] = {
WHILE geometry#NIL DO HighLightInstance[cell, geometry.first]; geometry ← geometry.rest ENDLOOP;
};
HighLightInstance: PROC [cell: CD.Object, inst: CD.Instance] = {
cellPtr: CD.CellPtr ← NARROW [cell.specificRef];
hinst: CD.Instance ← PWPins.NewInstance[
ob: CDRects.CreateRect[inst.ob.size, CD.shadeLayer],
location: inst.location, orientation: inst.orientation];
cellPtr.contents ← CONS [hinst, cellPtr.contents];
};
Fusion data structure and internal manipulation
Signal: PUBLIC SIGNAL [cause: ATOM, data: LIST OF REFNIL] = CODE;
FusionData: TYPE = REF FusionDataRec;
FusionDataRec: TYPE = RECORD [
mode: Mode,      -- to avoid passing it around
ir: CD.Rect,      -- Interest Rect of obj (for finding publics)
fused: HashTable.Table,  -- Association [fused -> root] [Wire -> Wire]. If root=NIL, then this wire is a root. Basically all the wires ever created belong to this table.
data: REF,       -- different information for Abut and Cell. For abuts it contains the next rects, (REF D2Intervals.Table). For Cell, it is a RedBlackTree.Table, Association [name -> Wires] [ROPE -> LIST OF Wire]
rects: SEQUENCE nbOfLayers: NAT OF D2Intervals.Table -- Association (per layer) [fusion geometry -> wire] [D2Intervals.Rect -> IW]. Wire may or may not be a root.
];
Geometry can be attached at all levels of a structured wire.
AbutData: TYPE = REF AbutDataRec;
AbutDataRec: TYPE = RECORD [
inX: BOOL,      -- to avoid passing it around
nextRects: SEQUENCE nbOfLayers: NAT OF D2Intervals.Table -- Association (per layer) [fusion geometry -> wire] [D2Intervals.Rect -> IW]. Wire may or may not be a root.
];
IW: TYPE = REF IWRec;
IWRec: TYPE = RECORD [instance: CD.Instance, wire: Wire];
RectToRect: PROC [mode: Mode, cdRect: CD.Rect] RETURNS [rect: D2Intervals.Rect] = {
clip: INT ← mode.clipDistance;
rect ← [[cdRect.x1-clip, cdRect.x2+clip], [cdRect.y1-clip, cdRect.y2+clip]];
};
InstanceToRect: PROC [mode: Mode, inst: CD.Instance] RETURNS [rect: D2Intervals.Rect] = {
rect ← RectToRect[mode, CDBasics.Surround[CDInstances.InstRectO[inst], CDInstances.InstRectI[inst]]];
};
IWToRect: PROC [table: D2Intervals.Table, value: D2Intervals.Value] RETURNS [rect: D2Intervals.Rect] = {
iw: IWNARROW [value];
mode: Mode ← NARROW [table.userData];
rect ← InstanceToRect[mode, iw.instance];
};
CreateRoot: PROC [fusionData: FusionData, size: NAT, props: Properties ← NIL] RETURNS [wire: Wire] = {
EachProperty: PROC [prop: ATOM, val: REF ANYNIL] = {
newVal: REF ANYSELECT prop FROM
fusionData.mode.pinsProp => NIL,
fusionData.mode.wireGeometryProp => NIL,
CoreOps.nameProp => NIL,
ENDCASE => val;
CoreProperties.PutWireProp[wire, prop, newVal];
};
wire ← CoreOps.CreateWires[size: size];
CoreProperties.Enumerate[props, EachProperty];
[] ← HashTable.Store[fusionData.fused, wire, NIL];
};
copyGeometry indicates if this geometry is only going to be used for fusion and does not have to figure in the geometry and pins properties (real geometry versus geometry at the level below).
InsertInstances: PROC [fusionData: FusionData, transformation: CD.Instance, instances: LIST OF CD.Instance, wire: Wire, copyGeometry: BOOL] = {
geometry: LIST OF CD.Instance ← GetWireGeometryProp[fusionData.mode, wire];
pins: LIST OF CD.Instance ← GetPinsProp[fusionData.mode, wire];
IF ~HashTable.Fetch[fusionData.fused, wire].found THEN Signal[$InternalBug];
IF RootWire[fusionData, wire]#wire THEN Signal[$InternalBug];
FOR is: LIST OF CD.Instance ← instances, is.rest WHILE is#NIL DO
inst: CD.Instance ← Transform[transformation, is.first];
IF NOT CDBasics.Inside[CDBasics.Extend[CDInstances.InstRectO[inst], fusionData.mode.clipDistance], CDBasics.Extend[fusionData.ir, -1]] THEN {
CoreProperties.PutWireProp[wire, $Public, $Public];
IF copyGeometry THEN pins ← CONS [inst, pins];
};
ENDLOOP;
IF copyGeometry THEN geometry ← CDInstances.AppendToList[TransformList[transformation, instances], geometry];
note that if condition true, geometry is duplicated
PutWireGeometryProp[fusionData.mode, wire, geometry];
PutPinsProp[fusionData.mode, wire, pins];
FOR is: LIST OF CD.Instance ← instances, is.rest WHILE is#NIL DO
inst: CD.Instance ← Transform[transformation, is.first];
iw: IWNEW [IWRec ← [instance: inst, wire: wire]];
layers: LayerRange ← (IF fusionData.mode.instanceLayer=NIL THEN [0, fusionData.nbOfLayers-1] ELSE fusionData.mode.instanceLayer[inst]);
FOR i: NAT IN [layers.min .. layers.max] DO D2Intervals.Insert[fusionData[i], iw] ENDLOOP;
ENDLOOP;
};
Fusion external manipulation
Creates a DAG Wire from a HashTable, getting rid of wires that have their father also in the list.
CreateDAGWire: PROC [table: HashTable.Table] RETURNS [wire: Wire] = {
wires: LIST OF Wire ← NIL;
EachKeyDelete: HashTable.EachPairAction = {
WireDelete: PROC [wire: Wire] = {
IF ~HashTable.Delete[table, wire] THEN RETURN; -- already done
FOR i: NAT IN [0 .. wire.size) DO
WireDelete[wire[i]];
ENDLOOP;
};
wire: Wire ← NARROW [key];
FOR i: NAT IN [0 .. wire.size) DO
delete all the sons
WireDelete[wire[i]];
ENDLOOP;
};
index: NAT ← 0;
SummarizeWires: HashTable.EachPairAction = {
wire[index] ← NARROW [key];
index ← index+1;
};
[] ← HashTable.Pairs[table, EachKeyDelete];
wire ← CoreOps.CreateWires[HashTable.GetSize[table]];
[] ← HashTable.Pairs[table, SummarizeWires];
IF index#HashTable.GetSize[table] THEN Signal[$InternalBug];
};
NameWire: TYPE = REF NameWireRec;
NameWireRec: TYPE = RECORD [name: ROPE, wire: Wire];
EachNameWireProc: TYPE = PROC [name: ROPE, wire: Wire];
GetKey: RedBlackTree.GetKey = {
nameWire: NameWire ← NARROW [data];
RETURN [nameWire.name];
};
Compare: RedBlackTree.Compare = {
nameWire: NameWire ← NARROW [data];
RETURN [Rope.Compare[NARROW [k], nameWire.name]];
};
AddNameWire: PROC [fusionData: FusionData, name: ROPE, wire: Wire] RETURNS [newWire: Wire] = {
nameTable: RedBlackTree.Table ← NARROW [fusionData.data];
data: RedBlackTree.UserData ← RedBlackTree.Lookup[nameTable, name];
IF data=NIL THEN {
RedBlackTree.Insert[nameTable, NEW [NameWireRec ← [name: name, wire: wire]], name];
newWire ← wire;
} ELSE {
nameWire: NameWire ← NARROW [data];
newWire ← StructuredFusion[fusionData, wire, nameWire.wire];
nameWire.wire ← newWire;
};
};
EnumerateIncreasing: PROC [fusionData: FusionData, eachNameWire: EachNameWireProc] = {
nameTable: RedBlackTree.Table ← NARROW [fusionData.data];
EachNode: RedBlackTree.EachNode = {
nameWire: NameWire ← NARROW [data];
eachNameWire[nameWire.name, nameWire.wire];
};
RedBlackTree.EnumerateIncreasing[nameTable, EachNode];
};
The following PROC implements Fisher-Galler fusion, not for efficiency, but for simplicity
RootWire: PROC [fusionData: FusionData, wire: Wire] RETURNS [rootWire: Wire] = {
rootWire ← NARROW [HashTable.Fetch[fusionData.fused, wire].value];
IF rootWire=NIL THEN RETURN [wire];
IF rootWire=wire THEN Signal[$InternalBug];
rootWire ← RootWire[fusionData, rootWire];
[] ← HashTable.Replace[fusionData.fused, wire, rootWire];
};
PropFusionProc: TYPE = PROC [prop: ATOM, value1, value2: REF ANY] RETURNS [value: REF ANY];
NameFusion: PropFusionProc = {
rope1: ROPENARROW [value1];
rope2: ROPENARROW [value2];
IF rope1#NIL AND rope2#NIL AND ~Rope.Equal[rope1, rope2] THEN {
PW.WriteF["Two wires that do not have the same name are fused: %g and %g.\n", IO.rope[rope1], IO.rope[rope2]];
Signal[$FusionPropError, LIST [prop, rope1, rope2]];
};
value ← IF rope1=NIL THEN rope2 ELSE rope1;
};
InstancesFusion: PropFusionProc = {
instances1: LIST OF CD.Instance ← NARROW [value1];
instances2: LIST OF CD.Instance ← NARROW [value2];
value ← CDInstances.AppendToList[instances1, instances2];
};
DefaultFusion: PropFusionProc = {
IF value1#NIL AND value2#NIL AND value1#value2 THEN {
PW.WriteF["Two wires that do not have the same %g property value are fused: %g and %g.\n", IO.atom[prop], IO.refAny[value1], IO.refAny[value2]];
Signal[$FusionPropError, LIST [prop, value1, value2]];
};
value ← IF value1=NIL THEN value2 ELSE value1;
};
Appends the properties of fused to the ones of root, but treating short names specially
FusionProperties: PROC [fusionData: FusionData, fused, root: Wire] = {
EachProperty: PROC [prop: ATOM, val: REF ANYNIL] = {
rootValue: REF ← CoreProperties.GetWireProp[root, prop];
refFusionProc: REF PropFusionProc ← NARROW [CoreProperties.GetProp[CoreProperties.FetchProperties[prop], $PropFusionProc]];
fusionProc: PropFusionProc ← SELECT prop FROM
fusionData.mode.pinsProp     => InstancesFusion,
fusionData.mode.wireGeometryProp => InstancesFusion,
CoreOps.nameProp      => NameFusion,
ENDCASE         => DefaultFusion;
CoreProperties.PutWireProp[root, prop, fusionProc[prop, val, rootValue]];
};
CoreProperties.Enumerate[fused.properties, EachProperty];
fused.properties ← NIL; -- to help the GC!
};
This proc really does the fusion of fused and root, by wiping fused of some tables, and adding interesting properties of fused to root.
DeleteFusioned: PROC [fusionData: FusionData, fused, root: Wire] = {
IF ~HashTable.Fetch[fusionData.fused, fused].found THEN Signal[$InternalBug];
IF RootWire[fusionData, fused]#fused THEN Signal[$InternalBug];
IF ~HashTable.Fetch[fusionData.fused, root].found THEN Signal[$InternalBug];
IF RootWire[fusionData, root]#root THEN Signal[$InternalBug];
IF fused=root THEN Signal[$InternalBug]; -- should never occur
FusionProperties[fusionData, fused, root]; -- name, pins, geometry
[] ← HashTable.Store[fusionData.fused, fused, root];
};
StructuredFusion: PROC [fusionData: FusionData, wire1, wire2: Wire] RETURNS [wire: Wire] = {
wire1 ← RootWire[fusionData, wire1];
wire2 ← RootWire[fusionData, wire2];
IF wire1=wire2 THEN RETURN [wire1];
SELECT TRUE FROM
wire1=wire2    => wire ← wire1;
wire1.size=0     => {DeleteFusioned[fusionData, wire1, wire2]; wire ← wire2};
wire2.size=0    => {DeleteFusioned[fusionData, wire2, wire1]; wire ← wire1};
wire1.size=wire2.size => {
wire ← CreateRoot[fusionData, wire1.size];
FOR i: NAT IN [0 .. wire.size) DO
wire[i] ← StructuredFusion[fusionData, wire1[i], wire2[i]];
ENDLOOP;
DeleteFusioned[fusionData, wire1, wire];
DeleteFusioned[fusionData, wire2, wire];
};
ENDCASE     => Signal[$StructureMismatch];
};
FindTouchingWires: PROC [fusionData: FusionData, transformation: CD.Instance, geometry: LIST OF CD.Instance] RETURNS [touchingWires: LIST OF Wire ← NIL] = {
FOR insts: LIST OF CD.Instance ← geometry, insts.rest WHILE insts#NIL DO
inst: CD.Instance ← Transform[transformation, insts.first];
layers: LayerRange ← (IF fusionData.mode.instanceLayer=NIL THEN [0, fusionData.nbOfLayers-1] ELSE fusionData.mode.instanceLayer[inst]);
rect: D2Intervals.Rect ← InstanceToRect[fusionData.mode, inst];
InternalFindTouchingWires: PROC [table: D2Intervals.Table, value: D2Intervals.Value] RETURNS [quit: BOOLFALSE] = {
iw: IWNARROW [value];
instance: CD.Instance ← iw.instance;
wire: Wire ← RootWire[fusionData, iw.wire];
IF ~HashTable.Fetch[fusionData.fused, wire].found THEN Signal[$InternalBug];
IF CoreOps.Member[touchingWires, wire] THEN RETURN;
IF Touch[fusionData.mode, instance, inst] THEN touchingWires ← CONS [wire, touchingWires];
};
FOR i: NAT IN [layers.min .. layers.max] DO
[] ← D2Intervals.Enumerate[fusionData[i], InternalFindTouchingWires, rect];
ENDLOOP;
ENDLOOP;
};
Other Internal utilities
FusionGeometry: PROC [fusionData: FusionData, transformation: CD.Instance, geometry: LIST OF CD.Instance, copyGeometry: BOOL] RETURNS [wire: Wire ← NIL] = {
touchingWires: LIST OF Wire ← FindTouchingWires[fusionData, transformation, geometry];
IF touchingWires=NIL THEN {
wire ← CreateRoot[fusionData, 0];
InsertInstances[fusionData, transformation, geometry, wire, copyGeometry];
RETURN;
};
wire ← touchingWires.first;
InsertInstances[fusionData, transformation, geometry, wire, copyGeometry];
touchingWires ← touchingWires.rest;
WHILE touchingWires#NIL DO
fused: Wire ← touchingWires.first;
wire ← StructuredFusion[fusionData, fused, wire];
touchingWires ← touchingWires.rest;
ENDLOOP;
};
The complexity of this proc is partly due to the fact that we have a DAG
FusionWire: PROC [fusionData: FusionData, dagTable: HashTable.Table, public: Wire, transformation: CD.Instance, copyProps: BOOL] RETURNS [actual: Wire] = {
prevActual: Wire ← NARROW [HashTable.Fetch[dagTable, public].value];
structActual: Wire ← CreateRoot[fusionData, public.size, IF copyProps THEN public.properties ELSE NIL];
publicName: ROPE ← CoreOps.GetShortWireName[public];
pins: LIST OF CD.Instance ← GetPinsProp[fusionData.mode, public];
IF prevActual#NIL THEN RETURN [prevActual];
FOR i: NAT IN [0 .. public.size) DO
structActual[i] ← FusionWire[fusionData, dagTable, public[i], transformation, copyProps];
ENDLOOP;
actual ← IF pins=NIL
THEN structActual
ELSE StructuredFusion[
fusionData, structActual,
FusionGeometry[fusionData, transformation, pins, copyProps]
];
IF copyProps AND publicName#NIL THEN actual ← AddNameWire[fusionData, publicName, actual];
[] ← HashTable.Store[dagTable, public, actual];
};
FusionWires: PROC [fusionData: FusionData, public: Wire, transformation: CD.Instance] RETURNS [actual: Wire] = {
dagTable: HashTable.Table ← HashTable.Create[3];
actual ← CoreOps.CreateWires[public.size];
FOR i: NAT IN [0 .. actual.size) DO
actual[i] ← FusionWire[fusionData, dagTable, public[i], transformation, FALSE];
ENDLOOP;
};
SortInstances: PROC [instances: LIST OF CD.Instance] RETURNS [sorted: LIST OF CD.Instance ← NIL] = {
Eval: PROC [inst: CD.Instance] RETURNS [INT] = {
pos: CD.Position ← CDBasics.BaseOfRect[CDInstances.InstRectI[inst]];
RETURN [pos.x+pos.y];
};
IF instances=NIL THEN RETURN [NIL];
sorted ← LIST [instances.first]; instances ← instances.rest;
WHILE instances#NIL DO
inst: CD.Instance ← instances.first;
eval: INT ← Eval[inst];
aux: LIST OF CD.Instance ← sorted;
instances ← instances.rest;
IF eval>=Eval[sorted.first] THEN {sorted ← CONS [inst, sorted]; LOOP};
WHILE aux.rest#NIL AND eval<Eval[aux.rest.first] DO aux ← aux.rest ENDLOOP;
aux.rest ← CONS [inst, aux.rest];
ENDLOOP;
};
Extraction
cachePropertiesProp: ATOMPW.RegisterProp[$SinixPropertiesCache, TRUE, TRUE];
cacheUserDataProp: ATOMPW.RegisterProp[$SinixUserDataCache, TRUE, TRUE];
Extract: PUBLIC ExtractProc = {
result ← CDProperties.GetObjectProp[obj, mode.cacheProp];
IF result#NIL AND mode.equalProc[
obj,
NARROW [CDProperties.GetObjectProp[obj, cachePropertiesProp]],
NARROW [CDProperties.GetObjectProp[obj, cacheUserDataProp]],
properties,
userData
]
THEN {
props ← NARROW [CDProperties.GetObjectProp[obj, mode.cachePropsProp]];
RETURN;
};
BEGIN
priority: CedarProcess.Priority ← CedarProcess.GetPriority[];
atom: ATOMNARROW [CDProperties.GetListProp[properties, mode.extractProcProp]];
extractProc: ExtractProc;
IF atom=NIL THEN atom ← NARROW [CDProperties.GetObjectProp[obj, mode.extractProcProp]];
IF atom=NIL THEN atom ← NARROW [CDProperties.GetProp[obj.class, mode.extractProcProp]];
IF atom=NIL THEN extractProc ← ExtractExpand ELSE {
refProc: REF ExtractProc ← NARROW [HashTable.Fetch[registeredExtractProcs, atom].value];
IF refProc=NIL THEN {
PW.WriteF["ExtractProc $%g not registered. You must run the program defining it.\n", IO.atom[atom]]; Signal[$CallerBug];
};
extractProc ← refProc^;
};
CedarProcess.CheckAbort[];
CedarProcess.SetPriority[background];
Process.Yield[];
[result, props] ← extractProc[obj, mode, properties, userData];
CedarProcess.SetPriority[priority];
CDProperties.PutObjectProp[obj, mode.cacheProp, result];
CDProperties.PutObjectProp[obj, mode.cachePropsProp, props];
CDProperties.PutObjectProp[obj, cachePropertiesProp, properties];
CDProperties.PutObjectProp[obj, cacheUserDataProp, userData];
END;
};
registeredExtractProcs: HashTable.Table ← HashTable.Create[];
RegisterExtractProc: PUBLIC PROC [key: ATOM, extractProc: ExtractProc] = {
IF NOT HashTable.Store[registeredExtractProcs, key, NEW [ExtractProc ← extractProc]] THEN PW.WriteF["ExtractProc overwritten for $%g.\n", IO.atom[key]];
};
ExtractCell: PUBLIC ExtractProc = {
cellType: CellType; -- the result
ir: CD.Rect ← CD.InterestRect[obj];
publics: HashTable.Table ← HashTable.Create[3];
internals: HashTable.Table ← HashTable.Create[3];
cellPtr: CD.CellPtr ← NARROW [obj.specificRef];
cdInstances: LIST OF CD.Instance ← SortInstances[cellPtr.contents];
fusionData: FusionData ← NEW [FusionDataRec[mode.nbOfLayers]];
currentInstances: LIST OF CoreClasses.CellInstance ← NIL;
count: NAT ← 0;
FOR list: LIST OF CD.Instance ← cdInstances, list.rest WHILE list#NIL DO count ← count+1 ENDLOOP;
PW.WriteF["Extracting [%g] cell %g (size: [%g, %g], instances: %g)\n", IO.rope[mode.name], IO.rope[CDDirectory.Name[obj]], IO.int[obj.size.x], IO.int[obj.size.y], IO.int[count]];
fusionData.mode ← mode; fusionData.ir ← ir; fusionData.fused ← HashTable.Create[3]; fusionData.data ← RedBlackTree.Create[GetKey, Compare];
FOR i: NAT IN [0 .. mode.nbOfLayers) DO
fusionData[i] ← D2Intervals.Create[
range: RectToRect[mode, CDBasics.Surround[CDBasics.RectAt[[0, 0], obj.size], ir]],
valueRect: IWToRect,
userData: mode];
ENDLOOP;
WHILE cdInstances#NIL DO
cdInstance: CD.Instance ← cdInstances.first;
subResult: REF; subProps: Properties;
[subResult, subProps] ← Extract[cdInstance.ob, mode, cdInstance.properties, userData];
IF subResult#NIL THEN WITH subResult SELECT FROM
subWire: Wire    => {
wire: Wire ← FusionWire[fusionData, HashTable.Create[1], subWire, cdInstance, TRUE];
};
subCellType: CellType => {
bbox: CD.Rect ← CDInstances.BoundingRectO[cdInstances.rest];
instance: CoreClasses.CellInstance ← CoreClasses.CreateInstance[
actual: FusionWires[fusionData, subCellType.public, cdInstance],
type: subCellType, props: subProps
];
IF ~CoreOps.Conform[instance.actual, subCellType.public] THEN Signal[$StructureMismatch];
PutInstanceTransformationProp[mode, instance, cdInstance];
currentInstances ← CONS [instance, currentInstances];
We try to simplify fusionData by getting rid of all pieces of geometry which are outside the bounding box for sure
FOR i: NAT IN [0 .. mode.nbOfLayers) DO
DeleteOutsideRange: PROC [table: D2Intervals.Table, value: D2Intervals.Value] RETURNS [quit: BOOLFALSE] = {
valueInst: CD.Instance ← NARROW [value, IW].instance;
IF ~IntersectRect[mode, bbox, CDInstances.InstRectO[valueInst]] THEN D2Intervals.Delete[fusionData[i], value];
};
[] ← D2Intervals.Enumerate[fusionData[i], DeleteOutsideRange, [[FIRST[INT], bbox.x1-mode.clipDistance], D2Intervals.universe.y]];
[] ← D2Intervals.Enumerate[fusionData[i], DeleteOutsideRange, [[bbox.x2+mode.clipDistance, LAST[INT]], D2Intervals.universe.y]];
[] ← D2Intervals.Enumerate[fusionData[i], DeleteOutsideRange, [D2Intervals.universe.x, [FIRST[INT], bbox.y1-mode.clipDistance]]];
[] ← D2Intervals.Enumerate[fusionData[i], DeleteOutsideRange, [D2Intervals.universe.x, [bbox.y2+mode.clipDistance, LAST[INT]]]];
ENDLOOP;
};
ENDCASE    => Signal[$InternalBug];
cdInstances ← cdInstances.rest;
ENDLOOP;
Time to do fusion by name!
BEGIN
EachNameWire: EachNameWireProc = {
AppendMatchingWires: HashTable.EachPairAction = {
wire: Wire ← NARROW [key];
wire ← RootWire[fusionData, wire];
IF ~Rope.Equal[CoreOps.GetShortWireName[wire], base] THEN RETURN;
IF ~CoreOps.Member[matchingWires, wire] THEN matchingWires ← CONS [wire, matchingWires];
};
base: ROPE ← name; components: LIST OF ROPENIL;
matchingWires: LIST OF Wire ← NIL;
matchingWire: Wire;
wire ← RootWire[fusionData, wire];
IF ~mode.flatNameSpace THEN [base, components] ← CoreOps.ParseWireName[name];
[] ← HashTable.Pairs[fusionData.fused, AppendMatchingWires];
matchingWire ← IF matchingWires=NIL THEN NIL ELSE matchingWires.first;
IF matchingWires#NIL AND matchingWires.rest#NIL THEN Signal[$InternalBug]; -- at a given time 2 wires should not have the same name
IF components=NIL THEN {
previousWireName: ROPE ← CoreOps.GetShortWireName[wire];
IF previousWireName#NIL AND ~Rope.Equal[name, previousWireName] THEN {
cell: CD.Object ← Cellize[obj];
HighLightWire[fusionData, cell, wire];
PW.WriteF["*** Sinix: fusing two wires having name %g and %g\n", IO.rope[name], IO.rope[previousWireName]];
[] ← PW.Draw[cell];
Signal[$FusionPropError, LIST [CoreOps.nameProp, name, previousWireName]]; -- wire has 2 names
};
[] ← CoreOps.SetShortWireName[wire, name];
IF matchingWire#NIL THEN [] ← StructuredFusion[fusionData, matchingWire, wire];
} ELSE {
WHILE components#NIL DO
subWires: LIST OF Wire ← NIL;
IF matchingWire=NIL THEN Signal[$FusionByNameError, LIST [name]]; -- path name do not correspond to any wire
FOR i: NAT IN [0 .. matchingWire.size) DO
subWireName: ROPE ← CoreOps.GetShortWireName[matchingWire[i]];
IF subWireName=NIL THEN subWireName ← IO.PutR1[IO.int[i]];
IF Rope.Equal[subWireName, components.first] THEN subWires ← CONS [matchingWire[i], subWires];
ENDLOOP;
IF subWires=NIL THEN Signal[$FusionByNameError, LIST [name]]; -- currentWire does not have the component with name fieldName
IF subWires.rest#NIL THEN Signal[$FusionByNameError, LIST [name]]; -- currentWire has 2 or more components with name fieldName
matchingWire ← RootWire[fusionData, subWires.first];
components ← components.rest;
ENDLOOP;
[] ← StructuredFusion[fusionData, matchingWire, wire];
};
};
EnumerateIncreasing[fusionData, EachNameWire];
END;
We replace all components of structured wires by their roots. We compute internals and publics on the way!
BEGIN
InternalDagIfy: HashTable.EachPairAction = {
WireDagIfy: PROC [wire: Wire, maxIter: NAT ← 32] = {
32 should be enough to avoid 815
IF maxIter=0 THEN Signal[$StructuralLoop]; -- probably loop in the Wire structure
IF RootWire[fusionData, wire]#wire THEN Signal[$InternalBug];
FOR i: NAT IN [0 .. wire.size) DO
wire[i] ← RootWire[fusionData, wire[i]];
WireDagIfy[wire[i], maxIter-1];
ENDLOOP;
};
wire: Wire ← NARROW [key];
IF value#NIL THEN RETURN; -- we dagify only the roots
[] ← HashTable.Store[internals, wire, NIL];
IF CoreProperties.GetWireProp[wire, $Public]#NIL THEN [] ← HashTable.Store[publics, wire, NIL];
WireDagIfy[wire];
};
[] ← HashTable.Pairs[fusionData.fused, InternalDagIfy];
END;
We replace in all instances wires by their roots
FOR list: LIST OF CoreClasses.CellInstance ← currentInstances, list.rest WHILE list#NIL DO
instance: CoreClasses.CellInstance ← list.first;
actual: Wire ← instance.actual;
FOR i: NAT IN [0 .. actual.size) DO
wire: Wire ← RootWire[fusionData, actual[i]];
IF ~CoreOps.Conform[wire, instance.type.public[i]] THEN Signal[$StructureMismatch]; -- probably because of structure
actual[i] ← wire;
ENDLOOP;
ENDLOOP;
We build the CellType
cellType ← CoreClasses.CreateRecordCell[
public: CreateDAGWire[publics],
internal: CreateDAGWire[internals],
instances: currentInstances,
name: CDDirectory.Name[obj]
];
Enable the retrieval of pins
BEGIN
lazyPinsData: LazyPinsData ← NEW [LazyPinsDataRec ← [ir: ir, getLazyPins: RecordGetLazyPins, data: cellType]];
SetLazyPins: CoreOps.EachWireProc = {
pins: LIST OF CD.Instance ← GetPinsProp[mode, wire];
IF pins=NIL THEN {PutLazyPinsProp[mode, wire, lazyPinsData]; RETURN};
FOR insts: LIST OF CoreClasses.CellInstance ← currentInstances, insts.rest WHILE insts#NIL DO
pins ← AppendInstancePins[pins, mode, wire, ir, insts.first].pins;
ENDLOOP;
PutPinsProp[mode, wire, pins];
};
ClearPublic: CoreOps.EachWireProc = {
CoreProperties.PutWireProp[wire, $Public, NIL];
};
[] ← CoreOps.VisitWire[cellType.public, SetLazyPins];
[] ← CoreOps.VisitWire[cellType.public, ClearPublic];
END;
Let us recover for circular data structures
FOR i: NAT IN [0 .. fusionData.nbOfLayers) DO D2Intervals.Erase[fusionData[i]] ENDLOOP;
result ← cellType;
};
AbutFusionWire: PROC [fusionData: FusionData, dagTable: HashTable.Table, public: Wire, transformation: CD.Instance] RETURNS [actual: Wire] = {
prevActual: Wire ← NARROW [HashTable.Fetch[dagTable, public].value];
structActual: Wire ← CreateRoot[fusionData, public.size];
abutData: AbutData ← NARROW [fusionData.data];
thesePins: LIST OF CD.Instance ← NIL; -- not transformed
nextPins: LIST OF CD.Instance ← NIL; -- not transformed
mode: Mode ← fusionData.mode;
inX: BOOL ← abutData.inX;
ir: CD.Rect ← fusionData.ir;
IF prevActual#NIL THEN RETURN [prevActual];
FOR pins: LIST OF CD.Instance ← GetPinsProp[fusionData.mode, public], pins.rest WHILE pins#NIL DO
pin: CD.Instance ← pins.first;
pinRect: CD.Rect ← CDInstances.InstRectO[pins.first]; -- in the transformation coordonnate system
subIr: CD.Rect ← CD.InterestRect[transformation.ob]; -- in the transformation coordonnate system
top: BOOL ← IntersectRect[mode, pinRect, [subIr.x1, subIr.y2-1, subIr.x2, subIr.y2]];
left: BOOL ← IntersectRect[mode, pinRect, [subIr.x1, subIr.y1, subIr.x1+1, subIr.y2]];
bottom: BOOL ← IntersectRect[mode, pinRect, [subIr.x1, subIr.y1, subIr.x2, subIr.y1+1]];
right: BOOL ← IntersectRect[mode, pinRect, [subIr.x2-1, subIr.y1, subIr.x2, subIr.y2]];
IF (~inX AND top) OR (inX AND right) THEN thesePins ← CONS [pin, thesePins];
IF (~inX AND bottom) OR (inX AND left) THEN nextPins ← CONS [pin, nextPins];
IF ~CDBasics.Inside[CDBasics.Extend[CDInstances.InstRectO[Transform[transformation, pin]], mode.clipDistance], CDBasics.Extend[ir, -1]] THEN CoreProperties.PutWireProp[structActual, $Public, $Public];
ENDLOOP;
FOR is: LIST OF CD.Instance ← nextPins, is.rest WHILE is#NIL DO
inst: CD.Instance ← Transform[transformation, is.first];
iw: IWNEW [IWRec ← [instance: inst, wire: structActual]];
layers: LayerRange ← (IF mode.instanceLayer=NIL THEN [0, fusionData.nbOfLayers-1] ELSE mode.instanceLayer[inst]);
FOR i: NAT IN [layers.min .. layers.max] DO D2Intervals.Insert[abutData[i], iw] ENDLOOP;
ENDLOOP;
FOR i: NAT IN [0 .. public.size) DO
structActual[i] ← AbutFusionWire[fusionData, dagTable, public[i], transformation];
ENDLOOP;
actual ← IF thesePins=NIL
THEN structActual
ELSE StructuredFusion[
fusionData, structActual,
FusionGeometry[fusionData, transformation, thesePins, FALSE]
];
[] ← HashTable.Store[dagTable, public, actual];
};
AbutFusionWires: PROC [fusionData: FusionData, public: Wire, transformation: CD.Instance] RETURNS [actual: Wire] = {
dagTable: HashTable.Table ← HashTable.Create[3];
actual ← CoreOps.CreateWires[public.size];
FOR i: NAT IN [0 .. actual.size) DO
actual[i] ← AbutFusionWire[fusionData, dagTable, public[i], transformation];
ENDLOOP;
};
ExtractAbut: PUBLIC ExtractProc = {
cellType: CellType; -- the result
publics: HashTable.Table ← HashTable.Create[3];
internals: HashTable.Table ← HashTable.Create[3];
ir: CD.Rect ← CD.InterestRect[obj];
expanded: CD.Object ← CDDirectory.Expand[obj].new;
cellPtr: CD.CellPtr ← NARROW [expanded.specificRef];
cdInstances: LIST OF CD.Instance ← cellPtr.contents;
range: D2Intervals.Rect ← RectToRect[mode, CDBasics.Surround[CDBasics.RectAt[[0, 0], expanded.size], ir]];
fusionData: FusionData ← NEW [FusionDataRec[mode.nbOfLayers]];
abutData: AbutData ← NEW [AbutDataRec[mode.nbOfLayers]];
currentInstances: LIST OF CoreClasses.CellInstance ← NIL;
count: NAT ← 0;
fusionData.mode ← mode; fusionData.ir ← ir; fusionData.fused ← HashTable.Create[3]; fusionData.data ← abutData;
abutData.inX ← obj.class=PWObjects.abutXClass;
FOR i: NAT IN [0 .. mode.nbOfLayers) DO
abutData[i] ← D2Intervals.Create[range: range, valueRect: IWToRect, userData: mode];
ENDLOOP;
FOR i: NAT IN [0 .. mode.nbOfLayers) DO
fusionData[i] ← D2Intervals.Create[range: range, valueRect: IWToRect, userData: mode];
ENDLOOP;
FOR list: LIST OF CD.Instance ← cdInstances, list.rest WHILE list#NIL DO count ← count+1 ENDLOOP;
PW.WriteF["Extracting [%g] abut %g (size: [%g, %g], instances: %g)\n", IO.rope[mode.name], IO.rope[CDDirectory.Name[obj]], IO.int[obj.size.x], IO.int[obj.size.y], IO.int[count]];
cdInstances ← SortInstances[cdInstances]; -- we know they are already in reverse order
WHILE cdInstances#NIL DO
cdInstance: CD.Instance ← cdInstances.first;
subResult: REF; subCellType: CellType; subProps: Properties;
instance: CoreClasses.CellInstance;
[subResult, subProps] ← Extract[cdInstance.ob, mode, cdInstance.properties, userData];
subCellType ← NARROW [subResult];
instance ← CoreClasses.CreateInstance[
actual: AbutFusionWires[fusionData, subCellType.public, cdInstance],
type: subCellType, props: subProps
];
IF ~CoreOps.Conform[instance.actual, subCellType.public] THEN Signal[$StructureMismatch];
FOR i: NAT IN [0 .. mode.nbOfLayers) DO
table: D2Intervals.Table ← fusionData[i];
fusionData[i] ← abutData[i]; abutData[i] ← table; D2Intervals.Erase[table];
ENDLOOP;
PutInstanceTransformationProp[mode, instance, cdInstance];
currentInstances ← CONS [instance, currentInstances];
cdInstances ← cdInstances.rest;
ENDLOOP;
We replace all components of structured wires by their roots. We compute internals and publics on the way!
BEGIN
InternalDagIfy: HashTable.EachPairAction = {
WireDagIfy: PROC [wire: Wire, maxIter: NAT ← 32] = {
32 should be enough to avoid 815
IF maxIter=0 THEN Signal[$StructuralLoop]; -- probably loop in the Wire structure
IF RootWire[fusionData, wire]#wire THEN Signal[$InternalBug];
FOR i: NAT IN [0 .. wire.size) DO
wire[i] ← RootWire[fusionData, wire[i]];
WireDagIfy[wire[i], maxIter-1];
ENDLOOP;
};
wire: Wire ← NARROW [key];
IF value#NIL THEN RETURN; -- we dagify only the roots
[] ← HashTable.Store[internals, wire, NIL];
IF CoreProperties.GetWireProp[wire, $Public]#NIL THEN [] ← HashTable.Store[publics, wire, NIL];
WireDagIfy[wire];
};
[] ← HashTable.Pairs[fusionData.fused, InternalDagIfy];
END;
We replace in all instances wires by their roots
FOR list: LIST OF CoreClasses.CellInstance ← currentInstances, list.rest WHILE list#NIL DO
instance: CoreClasses.CellInstance ← list.first;
actual: Wire ← instance.actual;
FOR i: NAT IN [0 .. actual.size) DO
wire: Wire ← RootWire[fusionData, actual[i]];
IF ~CoreOps.Conform[wire, instance.type.public[i]] THEN Signal[$StructureMismatch]; -- probably because of structure
actual[i] ← wire;
ENDLOOP;
ENDLOOP;
We build the CellType
cellType ← CoreClasses.CreateRecordCell[
public: CreateDAGWire[publics],
internal: CreateDAGWire[internals],
instances: currentInstances,
name: CDDirectory.Name[expanded]
];
Enable the retrieval of pins
BEGIN
lazyPinsData: LazyPinsData ← NEW [LazyPinsDataRec ← [ir: ir, getLazyPins: RecordGetLazyPins, data: cellType]];
SetLazyPins: CoreOps.EachWireProc = {
PutLazyPinsProp[mode, wire, lazyPinsData];
};
ClearPublic: CoreOps.EachWireProc = {
CoreProperties.PutWireProp[wire, $Public, NIL];
};
[] ← CoreOps.VisitWire[cellType.public, SetLazyPins];
[] ← CoreOps.VisitWire[cellType.public, ClearPublic];
END;
result ← cellType;
Let us recover for circular data structures
FOR i: NAT IN [0 .. fusionData.nbOfLayers) DO D2Intervals.Erase[fusionData[i]] ENDLOOP;
FOR i: NAT IN [0 .. fusionData.nbOfLayers) DO D2Intervals.Erase[abutData[i]] ENDLOOP;
};
ExtractExpand: PUBLIC ExtractProc = {
newObj: CD.Object ← CDDirectory.Expand[obj, NIL, NIL].new;
PW.WriteF["Expanding [%g] object %g of class %g\n", IO.rope[mode.name], IO.rope[CDDirectory.Name[obj]], IO.atom[obj.class.objectType]];
IF newObj=NIL THEN Signal[$CallerBug]; -- no expand proc found for this object!
RETURN Extract[newObj, mode, CDProperties.DAppendProps[obj.properties, properties], userData];
};
ExtractWire: PUBLIC ExtractProc = {
wire: Wire;
wire ← CoreOps.CreateWire[];
AddPinsProp[mode, wire, PWPins.NewInstance[obj]];
result ← wire;
};
ExtractPin: PUBLIC ExtractProc = {
wire: Wire;
instance: CD.Instance ← PWPins.NewInstance[ob: obj, properties: properties];
pinName: ROPE ← CDSymbolicObjects.GetName[instance];
wire ← CoreOps.CreateWire[name: pinName];
AddPinsProp[mode, wire, instance];
result ← wire;
};
ExtractNull: PUBLIC ExtractProc = {result ← NIL};
ExtractError: PUBLIC ExtractProc = {
PW.WriteF["*** This object should not be extracted\n"]; Signal[$CallerBug];
};
Extraction mode procs
AlwaysTrue: PUBLIC PROC [obj: CD.Object, properties1: CD.PropList, userData1: REF, properties2: CD.PropList, userData2: REF] RETURNS [BOOLTRUE] = {};
AlwaysFalse: PUBLIC PROC [obj: CD.Object, properties1: CD.PropList, userData1: REF, properties2: CD.PropList, userData2: REF] RETURNS [BOOLFALSE] = {};
CompareProps: PUBLIC PROC [obj: CD.Object, properties1: CD.PropList, userData1: REF, properties2: CD.PropList, userData2: REF] RETURNS [BOOL] = {
FOR p1: CD.PropList ← properties1, p1.rest WHILE p1#NIL DO
IF CDProperties.GetListProp[properties2, p1.first.key]#p1.first.val THEN RETURN [FALSE];
ENDLOOP;
FOR p2: CD.PropList ← properties2, p2.rest WHILE p2#NIL DO
IF CDProperties.GetListProp[properties1, p2.first.key]#p2.first.val THEN RETURN [FALSE];
ENDLOOP;
RETURN [TRUE];
};
Geometry Primitives
touchProcProp: PUBLIC ATOMPW.RegisterProp[$TouchProc, TRUE];
Touch: PUBLIC TouchProc = {
refProc: REF TouchProc;
IF ~IntersectRect[mode, CDInstances.InstRectO[instance1], CDInstances.InstRectO[instance2]] THEN RETURN;
refProc ← NARROW [CDProperties.GetInstanceProp[instance1, touchProcProp]];
IF refProc=NIL THEN refProc ← NARROW [CDProperties.GetObjectProp[instance1.ob, touchProcProp]];
IF refProc=NIL THEN refProc ← NARROW [CDProperties.GetProp[instance1.ob.class, touchProcProp]];
yes ← (IF refProc=NIL THEN TouchExpand ELSE refProc^)[mode, instance1, instance2];
};
TouchExpand: PUBLIC TouchProc = {
instance1 ← PWPins.NewInstance[
ob: CDDirectory.Expand[instance1.ob, NIL, NIL].new,
location: instance1.location, orientation: instance1.orientation
];
IF instance1.ob=NIL THEN Signal[$CallerBug];
RETURN [Touch[mode, instance1, instance2]];
};
TouchPin: PUBLIC TouchProc = {
RETURN [TouchRectObject[mode, instance2, CDInstances.InstRectO[instance1], CDSymbolicObjects.GetLayer[instance1]]];
};
TouchRect: PUBLIC TouchProc = {
RETURN [TouchRectObject[mode, instance2, CDInstances.InstRectO[instance1], instance1.ob.layer]];
};
TouchCell: PUBLIC TouchProc = {
cellPtr: CD.CellPtr ← NARROW [instance1.ob.specificRef];
RETURN [TouchList[mode, TransformList[instance1, cellPtr.contents], instance2]];
};
TouchAtomic: PUBLIC TouchProc = {
FOR rList: CDAtomicObjects.DrawList ← NARROW [instance1.ob.specificRef, CDAtomicObjects.AtomicObsPtr].rList, rList.rest WHILE rList#NIL DO
IF TouchRectObject[mode, instance2, CDOrient.MapRect[rList.first.r, instance1.ob.size, instance1.orientation, instance1.location], rList.first.lev] THEN RETURN [TRUE];
ENDLOOP;
};
Geometry Utilities
IntersectRect: PROC [mode: Mode, rect1, rect2: CD.Rect] RETURNS [yes: BOOL] = {
yes ← CDBasics.Intersect[CDBasics.Extend[rect1, mode.clipDistance], rect2];
};
TouchRectObject: PUBLIC PROC [mode: Mode, instance: CD.Instance, rect: CD.Rect, layer: CD.Layer] RETURNS [yes: BOOLFALSE] = {
rectInstance: CD.Instance;
IF ~IntersectRect[mode, CDInstances.InstRectO[instance], rect] THEN RETURN;
IF instance.ob.class=CDRects.bareRectClass THEN {
IF ~CDLayers.AbstractToPaint[instance.ob.layer]=CDLayers.AbstractToPaint[layer] THEN RETURN [FALSE];
RETURN [CDBasics.Intersect[CDInstances.InstRectO[instance], rect]];
};
rectInstance ← PWPins.NewInstance[
ob: CDRects.CreateRect[CDBasics.SizeOfRect[rect], layer],
location: CDBasics.BaseOfRect[rect]
];
yes ← Touch[mode, instance, rectInstance];
};
Transform: PUBLIC PROC [transformation, instance: CD.Instance] RETURNS [result: CD.Instance] = {
RETURN [PWPins.TransformInstance[instance, transformation.ob.size, transformation.location, transformation.orientation]];
};
TransformList: PUBLIC 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;
};
TouchList: PUBLIC PROC [mode: Mode, instances: LIST OF CD.Instance, instance: CD.Instance] RETURNS [yes: BOOLFALSE] = {
FOR list: LIST OF CD.Instance ← instances, list.rest WHILE list#NIL DO
IF Touch[mode, list.first, instance] THEN RETURN [TRUE];
ENDLOOP;
};
TouchListList: PUBLIC PROC [mode: Mode, instances1, instances2: LIST OF CD.Instance] RETURNS [yes: BOOLFALSE] = {
FOR list: LIST OF CD.Instance ← instances1, list.rest WHILE list#NIL DO
IF TouchList[mode, instances2, list.first] THEN RETURN [TRUE];
ENDLOOP;
};
Initialization
RegisterExtractProc[$ExtractCell, ExtractCell];
RegisterExtractProc[$ExtractAbut, ExtractAbut];
RegisterExtractProc[$ExtractExpand, ExtractExpand];
RegisterExtractProc[$ExtractWire, ExtractWire];
RegisterExtractProc[$ExtractPin, ExtractPin];
RegisterExtractProc[$ExtractNull, ExtractNull];
RegisterExtractProc[$ExtractError, ExtractError];
END.