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 { 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; 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 ROPE _ NIL; 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; BEGIN InternalDagIfy: HashTable.EachPairAction = { WireDagIfy: PROC [wire: Wire, maxIter: NAT _ 32] = { 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; 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; cellType _ CoreClasses.CreateRecordCell[ public: CreateDAGWire[publics], internal: CreateDAGWire[internals], instances: currentInstances, name: CDDirectory.Name[obj] ]; 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; 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: IW _ NEW [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]]; 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; BEGIN InternalDagIfy: HashTable.EachPairAction = { WireDagIfy: PROC [wire: Wire, maxIter: NAT _ 32] = { 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; 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; cellType _ CoreClasses.CreateRecordCell[ public: CreateDAGWire[publics], internal: CreateDAGWire[internals], instances: currentInstances, name: CDDirectory.Name[expanded] ]; 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; 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]; }; AlwaysTrue: PUBLIC PROC [obj: CD.Object, properties1: CD.PropList, userData1: REF, properties2: CD.PropList, userData2: REF] RETURNS [BOOL _ TRUE] = {}; AlwaysFalse: PUBLIC PROC [obj: CD.Object, properties1: CD.PropList, userData1: REF, properties2: CD.PropList, userData2: REF] RETURNS [BOOL _ FALSE] = {}; 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]; }; touchProcProp: PUBLIC ATOM _ PW.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; }; 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: BOOL _ FALSE] = { 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: BOOL _ FALSE] = { 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: BOOL _ FALSE] = { FOR list: LIST OF CD.Instance _ instances1, list.rest WHILE list#NIL DO IF TouchList[mode, instances2, list.first] THEN RETURN [TRUE]; ENDLOOP; }; RegisterExtractProc[$ExtractCell, ExtractCell]; RegisterExtractProc[$ExtractAbut, ExtractAbut]; RegisterExtractProc[$ExtractExpand, ExtractExpand]; RegisterExtractProc[$ExtractWire, ExtractWire]; RegisterExtractProc[$ExtractPin, ExtractPin]; RegisterExtractProc[$ExtractNull, ExtractNull]; RegisterExtractProc[$ExtractError, ExtractError]; END. βSinixImpl.mesa Copyright c 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 Operations for an easy management of properties HighLighting errors utilities Fusion data structure and internal manipulation Geometry can be attached at all levels of a structured wire. 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). note that if condition true, geometry is duplicated Fusion external manipulation Creates a DAG Wire from a HashTable, getting rid of wires that have their father also in the list. delete all the sons The following PROC implements Fisher-Galler fusion, not for efficiency, but for simplicity Appends the properties of fused to the ones of root, but treating short names specially refFusionProc: REF PropFusionProc _ NARROW [CoreProperties.GetProp[CoreProperties.FetchProperties[prop], $PropFusionProc]]; This proc really does the fusion of fused and root, by wiping fused of some tables, and adding interesting properties of fused to root. Other Internal utilities The complexity of this proc is partly due to the fact that we have a DAG Extraction We try to simplify fusionData by getting rid of all pieces of geometry which are outside the bounding box for sure Time to do fusion by name! We replace all components of structured wires by their roots. We compute internals and publics on the way! 32 should be enough to avoid 815 We replace in all instances wires by their roots We build the CellType Enable the retrieval of pins Let us recover for circular data structures cdInstances _ SortInstances[cdInstances]; -- we know they are already in reverse order We replace all components of structured wires by their roots. We compute internals and publics on the way! 32 should be enough to avoid 815 We replace in all instances wires by their roots We build the CellType Enable the retrieval of pins Let us recover for circular data structures Extraction mode procs Geometry Primitives Geometry Utilities Initialization Κ*€– "cedar" style˜codešœ™Kšœ Οmœ1™˜>J˜J˜—š œžœ žœžœžœ'žœ+žœžœžœžœžœ˜ΚJšœžœ:˜Dš œ˜&Jšžœžœžœ˜Jšœ˜š žœžœžœžœ<žœ žœž˜oJšœžœ1˜9Jšžœlžœžœ˜ŸJšžœ˜—J˜—Jšœ˜JšœK˜KJ˜J˜—š œžœžœžœ žœžœžœžœžœ˜wJšœžœ˜#Jšœ&žœ˜=Jšœžœ˜Jšœžœ˜Jšœ'˜'J˜šžœžœžœž˜$Jšœ0˜0Jšœ˜Jšœžœ˜JšœN˜Nšžœ žœ˜Jšœ(˜(Jšœ*˜*Jšœ3˜3J˜—Jšžœ˜—Jšžœžœžœ#žœ”˜υJšžœžœ˜8J˜J˜—Jšœžœžœ˜)Jšœžœžœ žœ˜Fš œžœžœ žœžœ žœžœžœ˜zJšœžœ˜+Jšœžœ ˜*š žœžœžœžœHžœ žœž˜{Jšœžœ1˜9Jšžœlžœ žœ˜”Jšžœ˜—J˜J˜—š  œžœžœ$žœžœžœ˜_šžœ žœžœ˜Jšœ1˜1Jšœ˜Jšžœ˜—J˜—J˜š œžœžœ&žœ˜VJšœ žœ0˜TJ˜—J˜š  œžœžœ$žœžœžœ˜\JšœB˜BJ˜—J˜š œžœžœžœ žœžœžœ˜eJšœ žœ;˜LJ˜J˜—š œžœžœ:žœ˜tJšœH˜HJ˜—J˜š  œžœžœ2žœ žœ˜}Jšœ žœC˜RJ˜——™š  œžœžœ žœžœ ˜;Jšœ žœ ˜Jšœ!˜!Jšœ žœ˜$Jšœžœ˜2Jšœ˜J˜—J˜š  œžœ žœžœžœ ˜WJšžœžœžœBžœ˜\J˜—J˜š  œžœ žœ˜MJšœE˜EJšœ=˜=J˜—J˜š  œžœžœžœžœžœ˜MJšžœ žœžœCžœ˜`J˜—J˜š œžœžœžœ˜@Jšœ žœ žœ˜0šœžœ˜(Jšœ&žœ˜6Jšœ8˜8—Jšœžœ˜2J˜——™/Jš œžœžœ žœžœžœžœžœžœ˜DJ˜Jšœ žœžœ˜%šœžœžœ˜JšœΟc˜.Jšœžœ ‘-˜?Jšœ‘’˜«Jšœžœ‘Ε˜ΦJšœžœ žœžœ‘p˜₯J˜—J˜J™šžœžœžœž˜!Jšœ˜Jšžœ˜—J˜—Jšœ žœ˜šžœžœžœžœ˜"Jšœ™Jšœ˜Jšžœ˜—J˜—Jšœžœ˜šŸœ˜,Jšœžœ˜J˜J˜—Jšœ+˜+Jšœ5˜5Jšœ,˜,Jšžœ žœ˜Jšœ+‘˜BJšœ4˜4J˜J˜—š œžœ.žœ˜\Jšœ$˜$Jšœ$˜$Jšžœ žœžœ ˜#šžœžœž˜Jšœ˜JšœM˜MJšœL˜Lšœ˜Jšœ+˜+šžœžœžœž˜!Jšœ;˜;Jšžœ˜—Jšœ(˜(Jšœ(˜(J˜—Jšžœ$˜+—J˜—J˜š œžœ*žœžœžœžœ žœžœžœžœ˜œš žœžœžœžœ!žœžœž˜HJšœžœ3˜;Jš œžœžœžœžœ&˜‡J–> -- [key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOLEAN]šœ?˜?š Ÿœžœ6žœžœžœ˜uJšœžœžœ ˜Jšœ žœ˜$Jšœ+˜+Jšžœ0žœ˜LJšžœ%žœžœ˜3Jšžœ(žœžœ˜ZJ˜—šžœžœžœž˜+JšœK˜KJšžœ˜—Jšžœ˜—J˜——™š œžœ*žœžœžœžœžœžœžœ˜œJšœžœžœ@˜Všžœžœžœ˜Jšœ"˜"JšœJ˜JJšžœ˜J˜—Jšœ˜JšœJ˜JJšœ#˜#šžœžœž˜Jšœ"˜"Jšœ1˜1Jšœ#˜#Jšžœ˜—J˜—J˜JšœH™Hš   œžœSžœžœžœ˜›Jšœžœ+˜DJš œ9žœ žœžœžœ˜hJšœ žœ$˜4Jšœžœžœžœ1˜AJšžœ žœžœžœ˜+šžœžœžœž˜#JšœY˜YJšžœ˜—šœ žœžœ˜Jšžœ˜šžœ˜Jšœ˜Jšœ;˜;Jšœ˜——Jšžœ žœ žœžœ6˜ZJšœ/˜/J˜—J˜š  œžœ8žœ žœ˜pJšœ0˜0Jšœ*˜*šžœžœžœžœ˜$JšœHžœ˜OJšžœ˜—J˜J˜—š  œžœ žœžœžœ žœ žœžœžœ žœ˜dš  œžœžœ žœžœ˜0Jšœžœ=˜DJšžœ˜J˜—Jš žœ žœžœžœžœ˜#Jšœ žœ/˜<šžœ žœžœ˜Jšœžœ˜$Jšœžœ˜Jšœžœžœžœ˜"Jšœ˜Jšžœžœ žœžœ˜FJš žœ žœžœžœžœ˜KJšœ žœ˜!Jšžœ˜—J˜J˜——™ Jš œžœžœ%žœžœ˜OJš œžœžœ#žœžœ˜KJ˜šŸœžœ˜Jšœ9˜9šžœžœžœ˜!Jšœ˜Jšžœ9˜?Jšžœ7˜=Jšœ ˜ Jšœ˜šœ˜šžœ˜Jšœžœ8˜FJšžœ˜J˜———šž˜Jšœ=˜=Jšœžœžœ>˜QJ˜Jšžœžœžœžœ9˜WJšžœžœžœžœ9˜Wšžœžœžœžœ˜3Jšœ žœžœ7˜Xšžœ žœžœ˜JšžœTžœ!˜yJ˜—Jšœ˜J˜—Jšœ˜Jšœ%˜%Jšœ˜Jšœ?˜?Jšœ#˜#Jšœ8˜8Jšœ<˜Jšœžœžœžœ˜9J–> -- [key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOLEAN]šœžœ˜Jšžœžœžœžœ#žœžœžœžœ˜aJš žœEžœžœžœžœžœ ˜²JšœŒ˜Œšžœžœžœž˜'šœ#˜#JšœS˜SJšœ˜Jšœ˜—Jšžœ˜—šžœ žœž˜Jšœ žœ˜,Jšœ žœ˜%JšœV˜Vš žœ žœžœžœ žœž˜0šœ˜JšœNžœ˜TJ˜—šœ˜Jšœžœ4˜<šœ@˜@JšœA˜AJšœ"˜"Jšœ˜—Jšžœ7žœ˜YJšœ:˜:Jšœžœ˜5Jšœr™ršžœžœžœž˜'š Ÿœžœ6žœžœžœ˜nJšœ žœ žœ žœ ˜5Jšžœ>žœ*˜nJ˜—Jšœ@žœžœ8˜Jšœ[žœžœ˜€JšœXžœžœ ˜Jšœsžœžœ˜€Jšžœ˜—J˜—Jšžœ˜#—Jšœ˜Jšžœ˜—J™šž˜šŸ œ˜"šŸœ˜1Jšœ žœ˜Jšœ"˜"Jšžœ3žœžœ˜AJšžœ&žœžœ˜XJ˜—Jš œžœžœžœžœžœ˜2Jšœžœžœžœ˜"Jšœ˜Jšœ"˜"Jšžœžœ2˜MJšœ<˜Jš žœ žœžœžœžœ ˜:Jšžœ+žœ žœ˜^Jšžœ˜—Jš žœ žœžœžœ ‘>˜|Jš žœžœžœžœ ‘;˜~Jšœ4˜4Jšœ˜Jšžœ˜—Jšœ6˜6J˜—J˜—Jšœ.˜.Jšžœ˜—J™kšž˜šŸœ˜,š  œžœžœ ˜4Jšœ ™ Jšžœ žœ‘&˜QJšžœ!žœ˜=šžœžœžœž˜!Jšœ(˜(Jšœ˜Jšžœ˜—J˜—Jšœ žœ˜Jš žœžœžœžœ‘˜5Jšœ&žœ˜+Jšžœ+žœžœ%žœ˜_Jšœ˜J˜—Jšœ7˜7Jšžœ˜—Jšœ0™0š žœžœžœ8žœžœž˜ZJšœ0˜0Jšœ˜šžœžœžœž˜#Jšœ-˜-Jšžœ1žœ‘ ˜tJšœ˜Jšžœ˜—Jšžœ˜—Jšœ™šœ(˜(Jšœ ˜ Jšœ#˜#Jšœ˜Jšœ˜J˜—J™šž˜JšœžœN˜nš  œ˜%Jšœžœžœžœ$˜4Jšžœžœžœ-žœ˜Eš žœžœžœ9žœžœž˜]JšœB˜BJšžœ˜—J˜J˜—š  œ˜%Jšœ*žœ˜/J˜—J˜5Jšœ5˜5Jšžœ˜—Jšœ+™+Jš žœžœžœžœ"žœ˜WJ˜J˜J˜—š œžœSžœ žœ˜ŽJšœžœ+˜DJšœ:˜:Jšœžœ˜.Jš œ žœžœžœ žœ‘˜8Jš œ žœžœžœ žœ‘˜7Jšœ˜Jšœžœ˜Jšœžœ˜Jšžœ žœžœžœ˜+š žœžœžœžœ<žœžœž˜aJšœžœ˜Jšœ žœ+‘+˜aJšœžœžœ"‘+˜`JšœžœL˜UJšœžœL˜VJšœžœL˜XJšœžœL˜WJš žœžœžœžœžœ žœ˜LJš žœžœ žœžœžœ žœ˜LJšžœ†žœ<˜ΘJšžœ˜—š žœžœžœžœžœžœž˜?Jšœžœ0˜8Jšœžœžœ0˜Jšœžœ ˜8Jšœžœžœžœ˜9J–> -- [key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOLEAN]šœžœ˜Jšœo˜oJšœ/˜/šžœžœžœž˜'JšœT˜TJšžœ˜—šžœžœžœž˜'JšœV˜VJšžœ˜—Jšžœžœžœžœ#žœžœžœžœ˜aJš žœEžœžœžœžœžœ ˜²Jšœ*‘,™Všžœ žœž˜Jšœ žœ˜,Jšœ žœ.˜Jšžœ˜—J˜——™Jšœ/˜/Jšœ/˜/Jšœ3˜3Jšœ/˜/Jšœ-˜-Jšœ/˜/Jšœ1˜1K˜Kšžœ˜K˜——…—8ΠΎ