<> <> <> <> <> <> <<>> 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; <> 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]]; }; <> 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]; }; <> Signal: PUBLIC SIGNAL [cause: ATOM, data: LIST OF REF _ NIL] = 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. ]; <> <<>> 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: IW _ NARROW [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 ANY _ NIL] = { newVal: REF ANY _ SELECT 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]; }; <> 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]; <> 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: IW _ NEW [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; }; <> <> 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 <> 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]; }; <<>> <> 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: ROPE _ NARROW [value1]; rope2: ROPE _ NARROW [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; }; <<>> <> FusionProperties: PROC [fusionData: FusionData, fused, root: Wire] = { EachProperty: PROC [prop: ATOM, val: REF ANY _ NIL] = { rootValue: REF _ CoreProperties.GetWireProp[root, prop]; <> 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! }; <<>> <> 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: BOOL _ FALSE] = { iw: IW _ NARROW [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; }; <> 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; }; <> 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> cachePropertiesProp: ATOM _ PW.RegisterProp[$SinixPropertiesCache, TRUE, TRUE]; cacheUserDataProp: ATOM _ PW.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: ATOM _ NARROW [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]; <> FOR i: NAT IN [0 .. mode.nbOfLayers) DO DeleteOutsideRange: PROC [table: D2Intervals.Table, value: D2Intervals.Value] RETURNS [quit: BOOL _ FALSE] = { 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; <