DIRECTORY Basics, BasicTime, CD, CDAtomicObjects, CDBasics, CDBasicsInline, CDCells, CDDirectory, CDInstances, CDLayers, CDProperties, CDRects, CDRoutingObjects, CDSatellites, CDSymbolicObjects, CedarProcess, Core, CoreClasses, CoreOps, CoreProperties, CoreGeometry, GList, InstanceTable, IO, MessageWindow, Process, PW, RefTab, Rope, RopeList, Saguaro, Sinix, SymTab, TerminalIO; SinixImpl: CEDAR PROGRAM IMPORTS Basics, BasicTime, CD, CDAtomicObjects, CDBasics, CDCells, CDDirectory, CDInstances, CDLayers, CDProperties, CDRects, CDSatellites, CDSymbolicObjects, CedarProcess, CoreClasses, CoreOps, CoreProperties, CoreGeometry, GList, InstanceTable, IO, MessageWindow, Process, PW, RefTab, Rope, RopeList, Saguaro, SymTab, TerminalIO EXPORTS Sinix SHARES CDRects, CoreGeometry = BEGIN OPEN Sinix; InternalBug: PUBLIC SIGNAL [name: ROPE] = CODE; CallerBug: PUBLIC SIGNAL [] = CODE; FusionPropMismatch: PUBLIC SIGNAL [name: ROPE, prop: ATOM, value1, value2: REF] = CODE; FusionStructureMismatch: PUBLIC SIGNAL [name: ROPE, wire1, wire2: Wire] = CODE; StructureMismatch: PUBLIC SIGNAL [name: ROPE, index: NAT, actual, subPublic: WireSeq] = CODE; FusionByNameMismatch: PUBLIC SIGNAL [name, msg: ROPE, wire: Wire] = CODE; StructuralLoop: PUBLIC SIGNAL [name: ROPE, wire: Wire] = CODE; ROPES: TYPE = LIST OF ROPE; Transformation: TYPE = CoreGeometry.Transformation; Instance: TYPE = CoreGeometry.Instance; Instances: TYPE = CoreGeometry.Instances; instanceCacheProp: ATOM _ PW.RegisterProp[$SinixInstanceCache, FALSE, TRUE]; objectCacheProp: ATOM _ PW.RegisterProp[$SinixObjectCache, FALSE, TRUE]; InstanceCache: TYPE = REF InstanceCacheRec; InstanceCacheRec: TYPE = RECORD [ mode: Mode, properties: CD.PropList _ NIL, userData: REF _ NIL, result: REF, props: Properties _ NIL ]; ObjectCache: TYPE = LIST OF ObjectCacheRec; ObjectCacheRec: TYPE = RECORD [ mode: Mode, userData: REF _ NIL, result: REF ]; SearchObjectCache: PROC [obj: Object, mode: Mode, userData: REF] RETURNS [result: REF _ NIL] = { FOR list: ObjectCache _ NARROW [CDProperties.GetObjectProp[obj, objectCacheProp]], list.rest WHILE list#NIL DO cache: ObjectCacheRec = list.first; IF cache.mode=mode AND mode.objectEqualProc[obj, cache.userData, userData] THEN RETURN [result: cache.result]; ENDLOOP; }; AddInCache: PROC [obj: Object, mode: Mode, userData: REF, result: REF] = { cache: ObjectCache _ NARROW [CDProperties.GetObjectProp[obj, objectCacheProp]]; cache _ CONS [[mode: mode, userData: userData, result: result], cache]; CDProperties.PutObjectProp[obj, objectCacheProp, cache]; }; FlushCache: PUBLIC PROC [obj: CD.Object] = { CDProperties.PutObjectProp[obj, instanceCacheProp, NIL]; CDProperties.PutObjectProp[obj, objectCacheProp, NIL]; }; NameWire: TYPE = RECORD [name: ROPE, wire: Wire]; FusionData: TYPE = REF FusionDataRec; FusionDataRec: TYPE = RECORD [ mode: Mode, -- to avoid passing it around nir: CD.Rect, -- Rectangles for which geometry that is strictly inside (edge excluded) is not promoted public name: ROPE, -- name of the object currently extracted isAbut: BOOL, -- recording publics depend on this property fused: RefTab.Ref, -- 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 InstanceTable.Table). For Cell, it is a LIST OF NameWire. This list is not sorted at creation time, and same name may appear several times. rects: SEQUENCE nbOfLayers: NAT OF InstanceTable.Table -- Association (per layer) [fusion geometry -> wire] [CD.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 InstanceTable.Table -- Association (per layer) [fusion geometry -> wire] [CD.Rect -> IW]. Wire may or may not be a root. ]; rect: PROC [r: CD.Rect] RETURNS [IO.Value] = { RETURN [IO.rope[IO.PutFR["[%g, %g, %g, %g]", IO.int[r.x1], IO.int[r.y1], IO.int[r.x2], IO.int[r.y2]]]]; }; 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.decoration.pinsProp => NIL, fusionData.mode.decoration.geometryProp => NIL, CoreOps.nameProp => NIL, ENDCASE => val; CoreProperties.PutWireProp[wire, prop, newVal]; }; wire _ CoreOps.CreateWires[size: size]; CoreProperties.Enumerate[props, EachProperty]; [] _ RefTab.Store[fusionData.fused, wire, NIL]; }; InsertInstances: PROC [fusionData: FusionData, transformation: Transformation, instances: Instances, wire: Wire, copyGeometry: BOOL] = { IF ~RefTab.Fetch[fusionData.fused, wire].found THEN SIGNAL InternalBug[fusionData.name]; IF RootWire[fusionData, wire]#wire THEN SIGNAL InternalBug[fusionData.name]; FOR is: Instances _ instances, is.rest WHILE is#NIL DO inst: Instance _ CoreGeometry.Transform[transformation, is.first]; layers: LayerRange _ fusionData.mode.instanceLayer[inst]; FOR i: NAT IN [layers.min .. layers.max] DO InstanceTable.Insert[fusionData[i], inst, wire] ENDLOOP; IF CoreGeometry.AtEdge[fusionData.nir, inst] THEN CoreProperties.PutWireProp[wire, $Public, $Public]; ENDLOOP; IF copyGeometry THEN CoreGeometry.AddGeometry[fusionData.mode.decoration, wire, CoreGeometry.TransformList[transformation, instances]]; }; CreateDAGWireSeq: PROC [table: RefTab.Ref] RETURNS [wire: WireSeq] = { wires: LIST OF Wire _ NIL; EachKeyDelete: RefTab.EachPairAction = { WireDelete: PROC [wire: Wire] = { IF ~RefTab.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: RefTab.EachPairAction = { wire[index] _ NARROW [key]; index _ index+1; }; [] _ RefTab.Pairs[table, EachKeyDelete]; wire _ CoreOps.CreateWires[RefTab.GetSize[table]]; [] _ RefTab.Pairs[table, SummarizeWires]; IF index#RefTab.GetSize[table] THEN SIGNAL InternalBug[NIL]; }; MakeResult: PROC [fusionData: FusionData, obj: CD.Object, cellInstances: LIST OF CoreClasses.CellInstance] RETURNS [record: CellType] = { decoration: CoreGeometry.Decoration = fusionData.mode.decoration; publics: RefTab.Ref _ RefTab.Create[3]; internals: RefTab.Ref _ RefTab.Create[5]; visitOnceTab: RefTab.Ref _ RefTab.Create[]; InternalDagIfy: RefTab.EachPairAction = { WireDagIfy: PROC [wire: Wire, maxIter: NAT _ 32] = { IF maxIter=0 THEN SIGNAL StructuralLoop[fusionData.name, wire]; -- probably loop in the Wire structure IF RootWire[fusionData, wire]#wire THEN SIGNAL InternalBug[fusionData.name]; 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 val#NIL THEN RETURN; -- we dagify only the roots [] _ RefTab.Store[internals, wire, NIL]; IF CoreProperties.GetWireProp[wire, $Public]#NIL THEN { [] _ RefTab.Store[publics, wire, NIL]; CoreProperties.PutWireProp[wire, $Public, NIL]; }; WireDagIfy[wire]; }; AddDecorateWire: CoreOps.EachWireProc = { pins: Instances _ NIL; AddPin: CoreGeometry.EachInstanceProc = { IF CoreGeometry.AtEdge[fusionData.nir, instance] THEN pins _ CONS [instance, pins]; }; IF ~RefTab.Store[visitOnceTab, wire, wire] THEN RETURN[FALSE, FALSE]; -- only once [] _ CoreGeometry.EnumerateGeometry[decoration, wire, AddPin]; CoreGeometry.AddPins[decoration, wire, pins]; }; [] _ RefTab.Pairs[fusionData.fused, InternalDagIfy]; FOR list: LIST OF CoreClasses.CellInstance _ cellInstances, 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.CorrectConform[wire, instance.type.public[i]] THEN SIGNAL StructureMismatch[fusionData.name, i, actual, instance.type.public]; actual[i] _ wire; ENDLOOP; ENDLOOP; record _ CoreClasses.CreateRecordCell[ public: CreateDAGWireSeq[publics], internal: CreateDAGWireSeq[internals], instances: cellInstances, name: fusionData.name, giveNames: TRUE ]; CoreGeometry.PutObject[decoration, record, obj]; CoreGeometry.PutRecordLazyPins[decoration, record, fusionData.nir]; [] _ CoreOps.VisitWireSeq[record.public, AddDecorateWire]; RefTab.Erase[visitOnceTab]; visitOnceTab _ NIL; FOR i: NAT IN [0 .. fusionData.mode.nbOfLayers) DO InstanceTable.DeleteOutside[fusionData[i], InstanceTable.empty]; ENDLOOP; }; LayoutFusionByName: PROC [fusionData: FusionData] = { refList: REF LIST OF NameWire = NARROW [fusionData.data]; nameToWire: SymTab.Ref = SymTab.Create[mod: 11]; FOR nameWires: LIST OF NameWire _ refList^, nameWires.rest WHILE nameWires#NIL DO wire: Wire _ RootWire[fusionData, nameWires.first.wire]; name: ROPE _ OrNames[nameWires.first.name, CoreOps.GetShortWireName[wire], fusionData.name]; previousWire: Wire _ NARROW [SymTab.Fetch[nameToWire, name].val]; IF previousWire#NIL THEN { previousWire _ RootWire[fusionData, previousWire]; IF previousWire#wire THEN { wire _ StructuredFusion[fusionData, wire, previousWire]; PutF["Fusion by name for '%g' in cell '%g'.\n", IO.rope[name], IO.rope[fusionData.name]]; CoreProperties.PutWireProp[wire, $FusedByName, $FusedByName]; }; }; [] _ SymTab.Store[nameToWire, name, wire]; [] _ CoreOps.SetShortWireName[wire, name]; ENDLOOP; }; NoFusionByName: PROC [fusionData: FusionData] = { refList: REF LIST OF NameWire = NARROW [fusionData.data]; EachNameWire: SymTab.EachPairAction = { uniqueID: INT _ 0; name: ROPE = NARROW [key]; wires: Wires _ NARROW [val]; [] _ CoreOps.SetShortWireName[wires.first, name]; wires _ wires.rest; IF wires=NIL THEN RETURN; PutF["NO fusion by name for '%g' in cell '%g'.\n", IO.rope[name], IO.rope[fusionData.name]]; WHILE wires#NIL DO [] _ CoreOps.SetShortWireName[wires.first, IO.PutFR["%g$%g$", IO.rope[name], IO.int[uniqueID]]]; uniqueID _ uniqueID + 1; wires _ wires.rest; ENDLOOP; }; nameToWires: SymTab.Ref = SymTab.Create[mod: 11]; -- contains (for every name) the list of roots that have it for name FOR nameWires: LIST OF NameWire _ refList^, nameWires.rest WHILE nameWires#NIL DO name: ROPE _ nameWires.first.name; wire: Wire = RootWire[fusionData, nameWires.first.wire]; wires: Wires _ NARROW [SymTab.Fetch[nameToWires, name].val]; IF NOT CoreOps.Member[wires, wire] THEN wires _ CONS [wire, wires]; [] _ SymTab.Store[nameToWires, name, wires]; ENDLOOP; [] _ SymTab.Pairs[nameToWires, EachNameWire]; }; SchematicsFusionByName: PROC [fusionData: FusionData] = { refList: REF LIST OF NameWire = NARROW [fusionData.data]; nameToWire: SymTab.Ref = SymTab.Create[mod: 11]; names: ROPES _ NIL; FOR nameWires: LIST OF NameWire _ refList^, nameWires.rest WHILE nameWires#NIL DO wire: Wire _ RootWire[fusionData, nameWires.first.wire]; name: ROPE _ OrNames[nameWires.first.name, CoreOps.GetShortWireName[wire], fusionData.name]; previousWire: Wire _ NARROW [SymTab.Fetch[nameToWire, name].val]; hasComponents: BOOL = CoreOps.ParseWireName[name].components#NIL; IF previousWire#NIL THEN previousWire _ RootWire[fusionData, previousWire]; IF previousWire#NIL AND previousWire#wire THEN wire _ StructuredFusion[fusionData, wire, previousWire] ELSE IF hasComponents THEN names _ CONS [name, names]; [] _ SymTab.Store[nameToWire, name, wire]; IF NOT hasComponents THEN [] _ CoreOps.SetShortWireName[wire, name]; ENDLOOP; FOR list: ROPES _ RopeList.Sort[names, RopeList.Compare], list.rest WHILE list#NIL DO name: ROPE _ list.first; wire: Wire = RootWire[fusionData, NARROW [SymTab.Fetch[nameToWire, name].val]]; base: ROPE; components: ROPES _ NIL; matchingWire: Wire; [base, components] _ CoreOps.ParseWireName[name]; matchingWire _ NARROW [SymTab.Fetch[nameToWire, base].val]; WHILE components#NIL DO index: INT _ -1; IF matchingWire=NIL THEN SIGNAL FusionByNameMismatch[fusionData.name, IO.PutFR["Path name %g does not correspond to any wire", IO.rope[name]], wire]; matchingWire _ RootWire[fusionData, matchingWire]; FOR i: NAT IN [0 .. matchingWire.size) DO subWireName: ROPE _ CoreOps.GetShortWireName[matchingWire[i]]; IF subWireName=NIL THEN subWireName _ IF i<256 THEN numbers[i] ELSE IO.PutR1[IO.int[i]]; -- JMF: speedup hack to avoid allocating lots of ropes IF Rope.Equal[subWireName, components.first] THEN { IF index=-1 THEN index _ i ELSE FusionByNameMismatch[fusionData.name, IO.PutFR["Current wire has 2 or more sub-wires with field `%g'", IO.rope[components.first]], wire]; }; ENDLOOP; IF index=-1 THEN SIGNAL FusionByNameMismatch[fusionData.name, IO.PutFR["Current wire does not have a sub-wire with field `%g'", IO.rope[components.first]], wire]; matchingWire _ matchingWire[index]; components _ components.rest; ENDLOOP; [] _ StructuredFusion[fusionData, matchingWire, wire]; ENDLOOP; }; AddNameWire: PROC [fusionData: FusionData, name: ROPE, wire: Wire] = { nameWires: REF LIST OF NameWire _ NARROW [fusionData.data]; nameWires^ _ CONS [[name: name, wire: wire], nameWires^]; }; RootWire: PROC [fusionData: FusionData, wire: Wire] RETURNS [rootWire: Wire] = { IF wire=NIL THEN SIGNAL InternalBug[fusionData.name]; rootWire _ NARROW [RefTab.Fetch[fusionData.fused, wire].val]; IF rootWire=NIL THEN RETURN [wire]; IF rootWire=wire THEN SIGNAL InternalBug[fusionData.name]; rootWire _ RootWire[fusionData, rootWire]; [] _ RefTab.Replace[fusionData.fused, wire, rootWire]; }; PropFusionProc: TYPE = PROC [prop: ATOM, value1, value2: REF ANY, name: ROPE] RETURNS [value: REF ANY]; NameFusion: PropFusionProc = { value _ OrNames[NARROW [value1], NARROW [value2], name]; }; DefaultFusion: PropFusionProc = { IF value1#NIL AND value2#NIL AND value1#value2 THEN SIGNAL FusionPropMismatch[name, prop, value1, value2]; value _ IF value1=NIL THEN value2 ELSE value1; }; FuseProperties: PUBLIC PROC [mode: Mode, fused, root: Wire, name: ROPE] = { EachProperty: PROC [prop: ATOM, val: REF ANY] = { rootValue: REF _ CoreProperties.GetWireProp[root, prop]; SELECT prop FROM CoreOps.nameProp => nameVal _ val; mode.decoration.geometryProp => geomVal _ val; mode.decoration.pinsProp => pinVal _ val; ENDCASE => CoreProperties.PutWireProp[root, prop, DefaultFusion[prop, val, rootValue, name]]; }; nameVal: REF ANY _ NIL; geomVal: REF ANY _ NIL; pinVal: REF ANY _ NIL; CoreProperties.Enumerate[fused.properties, EachProperty]; IF nameVal#NIL THEN { rootValue: REF ANY _ CoreProperties.GetWireProp[root, CoreOps.nameProp]; CoreProperties.PutWireProp[root, CoreOps.nameProp, NameFusion[CoreOps.nameProp, nameVal, rootValue, name]]; }; IF geomVal#NIL THEN CoreGeometry.AddGeometry[mode.decoration, root, CoreGeometry.GetGeometry[mode.decoration, fused]]; IF pinVal#NIL THEN CoreGeometry.AddPins[mode.decoration, root, CoreGeometry.GetPins[mode.decoration, fused]]; }; DeleteFused: PROC [fusionData: FusionData, fused, root: Wire] = { IF ~RefTab.Fetch[fusionData.fused, fused].found THEN SIGNAL InternalBug[fusionData.name]; IF RootWire[fusionData, fused]#fused THEN SIGNAL InternalBug[fusionData.name]; IF ~RefTab.Fetch[fusionData.fused, root].found THEN SIGNAL InternalBug[fusionData.name]; IF RootWire[fusionData, root]#root THEN SIGNAL InternalBug[fusionData.name]; IF fused=root THEN SIGNAL InternalBug[fusionData.name]; -- should never occur FuseProperties[fusionData.mode, fused, root, fusionData.name]; fused.properties _ NIL; -- to help GC [] _ RefTab.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 => {DeleteFused[fusionData, wire1, wire2]; wire _ wire2}; wire2.size=0 => {DeleteFused[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; DeleteFused[fusionData, wire1, wire]; DeleteFused[fusionData, wire2, wire]; }; ENDCASE => SIGNAL FusionStructureMismatch[fusionData.name, wire1, wire2]; }; FindTouchingWires: PROC [fusionData: FusionData, transformation: Transformation, geometry: Instances] RETURNS [touchingWires: LIST OF Wire _ NIL] = { FOR insts: Instances _ geometry, insts.rest WHILE insts#NIL DO inst: Instance _ CoreGeometry.Transform[transformation, insts.first]; layers: LayerRange _ fusionData.mode.instanceLayer[inst]; rect: CD.Rect _ CoreGeometry.InlineBBox[inst]; InternalFindTouchingWires: PROC [instance: Instance, value: InstanceTable.Value] = { wire: Wire _ RootWire[fusionData, NARROW [value]]; IF ~RefTab.Fetch[fusionData.fused, wire].found THEN SIGNAL InternalBug[fusionData.name]; IF CoreOps.Member[touchingWires, wire] THEN RETURN; IF fusionData.mode.touchProc[fusionData.mode.touchProc, instance, inst] THEN touchingWires _ CONS [wire, touchingWires]; }; FOR i: NAT IN [layers.min .. layers.max] DO InstanceTable.Enumerate[fusionData[i], InternalFindTouchingWires, rect]; ENDLOOP; ENDLOOP; }; FusionGeometry: PROC [fusionData: FusionData, transformation: Transformation, geometry: Instances, 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: RefTab.Ref, public: Wire, transformation: Transformation, copyProps: BOOL] RETURNS [actual: Wire] = { prevActual: Wire _ NARROW [RefTab.Fetch[dagTable, public].val]; structActual: Wire; publicName: ROPE _ CoreOps.GetShortWireName[public]; pins: Instances _ CoreGeometry.GetPins[fusionData.mode.decoration, public]; IF prevActual#NIL THEN RETURN [prevActual]; structActual _ CreateRoot[fusionData, public.size, IF copyProps THEN public.properties ELSE NIL]; 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 AddNameWire[fusionData, publicName, actual]; [] _ RefTab.Store[dagTable, public, actual]; }; FusionWireSeq: PROC [fusionData: FusionData, public: WireSeq, transformation: Transformation] RETURNS [actual: Wire] = { dagTable: RefTab.Ref _ RefTab.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[CDBasicsInline.MapRect[CD.InterestRect[inst.ob], inst.trans]]; -- JMF: new version, slightly faster RETURN [pos.x+pos.y]; }; Compare: GList.CompareProc = { RETURN [Basics.CompareInt[Eval[NARROW [ref1]], Eval[NARROW [ref2]]]]; }; sorted _ NARROW [GList.Sort[instances, Compare]]; }; InitialOverlap: PROC [bbox, nir: CD.Rect] RETURNS [overlap: INT _ 0] = { overlap _ UnionOverlap[overlap, bbox, [FIRST[INT], FIRST[INT], nir.x1, LAST[INT]]]; overlap _ UnionOverlap[overlap, bbox, [nir.x2, FIRST[INT], LAST[INT], LAST[INT]]]; overlap _ UnionOverlap[overlap, bbox, [FIRST[INT], FIRST[INT], LAST[INT], nir.y1]]; overlap _ UnionOverlap[overlap, bbox, [FIRST[INT], nir.y2, LAST[INT], LAST[INT]]]; }; UnionOverlap: PROC [overlap: INT, bbox, rect: CD.Rect] RETURNS [INT] = { interSize: CD.Position; IF overlap*2>bbox.x2-bbox.x1 OR overlap*2>bbox.y2-bbox.y1 THEN RETURN [overlap]; interSize _ CDBasics.SizeOfRect[CDBasics.Intersection[rect, CDBasics.Extend[bbox, -overlap]]]; overlap _ MAX [overlap, MIN [interSize.x, interSize.y]]; IF overlap*2>bbox.x2-bbox.x1 OR overlap*2>bbox.y2-bbox.y1 THEN RETURN [overlap]; interSize _ CDBasics.SizeOfRect[CDBasics.Intersection[rect, CDBasics.Extend[bbox, -overlap]]]; overlap _ MAX [overlap, MIN [interSize.x, interSize.y]]; RETURN [overlap]; }; ExtractCell: PUBLIC ExtractProc = { ir: CD.Rect _ CD.InterestRect[obj]; cdInstances: LIST OF CD.Instance _ NIL; nbOfInstances: INT = CDCells.CountInstances[obj]; fusionData: FusionData _ NEW [FusionDataRec[mode.nbOfLayers]]; currentInstances: LIST OF CoreClasses.CellInstance _ NIL; EachInstance: CDCells.InstEnumerator = {cdInstances _ CONS [inst, cdInstances]}; time: BasicTime.GMT = BasicTime.Now[]; result _ SearchObjectCache[obj, mode, userData]; IF result#NIL THEN RETURN; [] _ CDCells.EnumerateInstances[obj, EachInstance]; cdInstances _ SortInstances[cdInstances]; -- Modified in place! fusionData.mode _ mode; fusionData.name _ mode.nameProc[obj, userData]; fusionData.nir _ IF mode.fusionByName=none THEN CDBasics.Extend[ir, - NARROW [userData, REF INT]^] ELSE ir; fusionData.fused _ RefTab.Create[3]; fusionData.data _ NEW [LIST OF NameWire _ NIL]; fusionData.isAbut _ FALSE; FOR i: NAT IN [0 .. mode.nbOfLayers) DO fusionData[i] _ InstanceTable.Create[range: obj.bbox]; ENDLOOP; PutF["Extracting [%g] cell %g (bbox: %g, instances: %g)\n", IO.rope[IF mode.fusionByName=none THEN IO.PutFR["%g[%g]", IO.rope[mode.decoration.name], IO.int[NARROW [userData, REF INT]^]] ELSE mode.decoration.name], IO.rope[fusionData.name], rect[obj.bbox], IO.int[nbOfInstances]]; CDProperties.PutObjectProp[obj, satellitesProp, CDSatellites.GetSatelliteRopes[obj]]; -- to reinforce invariantes on the object (restriction of CDSatellites) WHILE cdInstances#NIL DO cdInstance: CD.Instance _ cdInstances.first; subUserData: REF _ userData; subResult: REF; subProps: Properties; CDProperties.PutInstanceProp[cdInstance, satellitesProp, CDSatellites.GetSatelliteRopes[cdInstance]]; IF mode.fusionByName=none THEN { EachInstanceOverlap: CDCells.InstEnumerator = { IF inst#cdInstance THEN overlap _ UnionOverlap[overlap, bbox, CDInstances.InstRectO[inst]]; }; bbox: CD.Rect _ CDInstances.InstRectI[cdInstance]; overlap: INT _ InitialOverlap[bbox, fusionData.nir]; [] _ CDCells.EnumerateInstances[obj, EachInstanceOverlap]; subUserData _ NEW [INT _ overlap]; }; [subResult, subProps] _ Extract[cdInstance.ob, mode, cdInstance.properties, subUserData]; IF subResult#NIL THEN WITH subResult SELECT FROM subWire: Wire => { [] _ FusionWire[fusionData, RefTab.Create[1], subWire, cdInstance.trans, TRUE]; }; subWires: Wires => { dagTable: RefTab.Ref _ RefTab.Create[3]; WHILE subWires#NIL DO [] _ FusionWire[fusionData, dagTable, subWires.first, cdInstance.trans, TRUE]; subWires _ subWires.rest; ENDLOOP; }; subCellType: CellType => { bbox: CD.Rect _ CDInstances.BoundingRectO[cdInstances.rest]; instance: CoreClasses.CellInstance _ CoreClasses.CreateInstance[ actual: FusionWireSeq[fusionData, subCellType.public, cdInstance.trans], type: subCellType, props: subProps ]; CoreGeometry.PutTrans[mode.decoration, instance, cdInstance.trans]; currentInstances _ CONS [instance, currentInstances]; FOR i: NAT IN [0 .. mode.nbOfLayers) DO InstanceTable.DeleteOutside[fusionData[i], bbox]; ENDLOOP; }; ENDCASE => SIGNAL InternalBug[fusionData.name]; cdInstances _ cdInstances.rest; ENDLOOP; SELECT mode.fusionByName FROM layout => LayoutFusionByName[fusionData]; none => NoFusionByName[fusionData]; schematics => SchematicsFusionByName[fusionData]; ENDCASE => CallerBug[]; --no way to do fusionByName in this mode! result _ MakeResult[fusionData, obj, currentInstances]; AddInCache[obj, mode, userData, result]; PutF["Extracted [%g] cell %g (%g sec.)\n", IO.rope[mode.decoration.name], IO.rope[fusionData.name], IO.int[BasicTime.Period[time, BasicTime.Now[]]]]; }; AbutFusionWire: PROC [fusionData: FusionData, dagTable: RefTab.Ref, public: Wire, transformation: Transformation, subIr: CD.Rect] RETURNS [actual: Wire] = { RecordEachPin: CoreGeometry.EachInstanceProc = { sides: CoreGeometry.Sides _ CoreGeometry.GetSides[subIr, instance]; IF (~inX AND sides[bottom]) OR (inX AND sides[left]) THEN thesePins _ CONS [instance, thesePins]; IF (~inX AND sides[top]) OR (inX AND sides[right]) THEN { inst: Instance _ CoreGeometry.Transform[transformation, instance]; layers: LayerRange _ mode.instanceLayer[inst]; FOR i: NAT IN [layers.min .. layers.max] DO InstanceTable.Insert[abutData[i], inst, structActual] ENDLOOP; }; IF NOT CoreGeometry.TransfedNotAtEdge[transformation, nir, instance] THEN CoreProperties.PutWireProp[structActual, $Public, $Public]; }; prevActual: Wire _ NARROW [RefTab.Fetch[dagTable, public].val]; structActual: Wire; abutData: AbutData _ NARROW [fusionData.data]; thesePins: Instances _ NIL; -- not transformed mode: Mode _ fusionData.mode; inX: BOOL _ abutData.inX; nir: CD.Rect _ fusionData.nir; IF prevActual#NIL THEN RETURN [prevActual]; structActual _ CreateRoot[fusionData, public.size]; [] _ CoreGeometry.EnumeratePins[fusionData.mode.decoration, public, RecordEachPin]; FOR i: NAT IN [0 .. public.size) DO structActual[i] _ AbutFusionWire[fusionData, dagTable, public[i], transformation, subIr]; ENDLOOP; actual _ IF thesePins=NIL THEN structActual ELSE StructuredFusion[ fusionData, structActual, FusionGeometry[fusionData, transformation, thesePins, FALSE] ]; [] _ RefTab.Store[dagTable, public, actual]; }; AbutFusionWireSeq: PROC [fusionData: FusionData, public: WireSeq, transformation: Transformation, subIr: CD.Rect] RETURNS [actual: Wire] = { dagTable: RefTab.Ref _ RefTab.Create[3]; actual _ CoreOps.CreateWires[public.size]; FOR i: NAT IN [0 .. actual.size) DO actual[i] _ AbutFusionWire[fusionData, dagTable, public[i], transformation, subIr]; ENDLOOP; }; ExtractAbut: PUBLIC ExtractProc = { ir: CD.Rect _ CD.InterestRect[obj]; range: CD.Rect _ obj.bbox; fusionData: FusionData _ NEW [FusionDataRec[mode.nbOfLayers]]; abutData: AbutData _ NEW [AbutDataRec[mode.nbOfLayers]]; currentInstances: LIST OF CoreClasses.CellInstance _ NIL; index: NAT _ 0; time: BasicTime.GMT = BasicTime.Now[]; EachAbutSubObject: PW.EachSubObjectProc = { subIr: CD.Rect _ CD.InterestRect[subObject]; -- in the transformation coordonnate system subResult: REF; subCellType: CellType; subProps: Properties; instance: CoreClasses.CellInstance; transformation: Transformation = [CDBasics.SubPoints[pos, CDBasics.BaseOfRect[subIr]]]; [subResult, subProps] _ Extract[subObject, mode, NIL, userData]; IF subResult=NIL THEN RETURN; subCellType _ NARROW [subResult]; instance _ CoreClasses.CreateInstance[ actual: AbutFusionWireSeq[fusionData, subCellType.public, transformation, subIr], type: subCellType, props: subProps ]; IF ~CoreOps.CorrectConform[instance.actual, subCellType.public] THEN SIGNAL StructureMismatch[fusionData.name, index, instance.actual, subCellType.public]; index _ index + 1; FOR i: NAT IN [0 .. mode.nbOfLayers) DO table: InstanceTable.Table _ fusionData[i]; fusionData[i] _ abutData[i]; abutData[i] _ table; InstanceTable.DeleteOutside[table, InstanceTable.empty]; ENDLOOP; CoreGeometry.PutTrans[mode.decoration, instance, transformation]; currentInstances _ CONS [instance, currentInstances]; }; result _ SearchObjectCache[obj, mode, userData]; IF result#NIL THEN RETURN; fusionData.mode _ mode; fusionData.name _ mode.nameProc[obj, userData]; fusionData.fused _ RefTab.Create[3]; fusionData.data _ abutData; fusionData.isAbut _ TRUE; fusionData.nir _ IF mode.fusionByName=none THEN CDBasics.Extend[ir, - NARROW [userData, REF INT]^] ELSE ir; abutData.inX _ obj.class=PW.abutXClass; FOR i: NAT IN [0 .. mode.nbOfLayers) DO abutData[i] _ InstanceTable.Create[range: range]; ENDLOOP; FOR i: NAT IN [0 .. mode.nbOfLayers) DO fusionData[i] _ InstanceTable.Create[range: range]; ENDLOOP; PutF["Extracting [%g] abut %g (bbox: %g, instances: %g)\n", IO.rope[mode.decoration.name], IO.rope[fusionData.name], rect[obj.bbox], IO.int[PW.CountSubObjects[obj]]]; [] _ PW.EnumerateSubObjects[obj, EachAbutSubObject]; result _ MakeResult[fusionData, obj, currentInstances]; AddInCache[obj, mode, userData, result]; PutF["Extracted [%g] abut %g (%g sec.)\n", IO.rope[mode.decoration.name], IO.rope[fusionData.name], IO.int[BasicTime.Period[time, BasicTime.Now[]]]]; FOR i: NAT IN [0 .. mode.nbOfLayers) DO InstanceTable.DeleteOutside[abutData[i], InstanceTable.empty]; ENDLOOP; }; Extract: PUBLIC ExtractProc = { instanceCache: InstanceCache _ NARROW [CDProperties.GetObjectProp[obj, instanceCacheProp]]; IF instanceCache#NIL AND instanceCache.mode=mode AND mode.instanceEqualProc[obj, instanceCache.properties, instanceCache.userData, properties, userData] THEN RETURN [result: instanceCache.result, props: instanceCache.props]; CDProperties.PutObjectProp[obj, satellitesProp, CDSatellites.GetSatelliteRopes[obj]]; 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 [RefTab.Fetch[registeredExtractProcs, atom].val]; IF refProc=NIL THEN { TerminalIO.PutF["*** 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]; WITH result SELECT FROM wire: Wire => {}; wires: Wires => {}; cellType: CellType => IF NOT CoreGeometry.HasObject[mode.decoration, cellType] THEN SIGNAL CallerBug[]; -- decorations missing! ENDCASE => IF result#NIL THEN SIGNAL CallerBug[]; -- probably some ExtractProc is grossly wrong CedarProcess.SetPriority[priority]; CDProperties.PutObjectProp[obj, instanceCacheProp, NEW [InstanceCacheRec _ [mode: mode, properties: properties, userData: userData, result: result, props: props]]]; END; }; registeredExtractProcs: RefTab.Ref _ RefTab.Create[]; RegisterExtractProc: PUBLIC PROC [key: ATOM, extractProc: ExtractProc] = { IF NOT RefTab.Store[registeredExtractProcs, key, NEW [ExtractProc _ extractProc]] THEN TerminalIO.PutF["ExtractProc overwritten for $%g.\n", IO.atom[key]]; }; ExtractRotation: PUBLIC ExtractProc = { specific: PW.RotationSpecific = NARROW [obj.specific]; trans: CD.Transformation = [[0, 0], specific.orientation]; result _ SearchObjectCache[obj, mode, userData]; IF result#NIL THEN RETURN; [result, props] _ Extract[specific.obj, mode, properties, userData]; IF result=NIL THEN RETURN; WITH result SELECT FROM wire: Wire => { newWire: Wire _ CoreOps.CopyWire[wire]; CoreGeometry.PutTransWireIRLazyPins[mode.decoration, newWire, wire, trans, CDBasics.universe]; result _ newWire; }; wires: Wires => { newWires: Wires _ NIL; WHILE wires#NIL DO newWire: Wire _ CoreOps.CopyWire[wires.first]; CoreGeometry.PutTransWireIRLazyPins[mode.decoration, newWire, wires.first, trans, CDBasics.universe]; newWires _ CONS [newWire, newWires]; wires _ wires.rest; ENDLOOP; result _ newWires; }; cellType: CellType => { public: Wire = CoreOps.CopyWire[cellType.public]; table: RefTab.Ref = CoreOps.CreateBindingTable[cellType.public, public]; newCellType: CellType = CoreClasses.CreatePermutedRecordCell[public, cellType, table, mode.nameProc[obj, userData]]; rct: CoreClasses.RecordCellType = NARROW [newCellType.data]; PutF["Extracting [%g] rotation %g (bbox: %g)\n", IO.rope[mode.decoration.name], IO.rope[mode.nameProc[obj, userData]], rect[obj.bbox]]; CoreGeometry.PutTrans[mode.decoration, rct[0], trans]; CoreGeometry.PutObject[mode.decoration, newCellType, obj]; CoreGeometry.PutRecordLazyPins[mode.decoration, newCellType, CD.InterestRect[obj]]; result _ newCellType; AddInCache[obj, mode, userData, result]; }; ENDCASE => ERROR; }; ExtractExpand: PUBLIC ExtractProc = { newObj: CD.Object _ CDDirectory.Expand1[obj, NIL, NIL].new; PutF["Expanding [%g] object %g of class %g\n", IO.rope[mode.decoration.name], IO.rope[mode.nameProc[obj, userData]], IO.atom[obj.class.objectType]]; IF newObj=NIL THEN SIGNAL CallerBug[]; -- no expand proc found for this object that we do not know how to extract! RETURN Extract[newObj, mode, CDProperties.DAppendProps[obj.properties, properties], userData]; }; OrNames: PROC [name1, name2, objName: ROPE] RETURNS [name: ROPE _ NIL] = { IF name1=NIL THEN RETURN [name2]; IF name2=NIL THEN RETURN [name1]; IF Rope.Equal[name1, name2] THEN RETURN [name1]; SIGNAL FusionPropMismatch[objName, CoreOps.nameProp, name1, name2]; }; NameFromSatellites: PUBLIC PROC [obj: Object, properties: CD.PropList] RETURNS [name: ROPE _ NIL] = { name _ NARROW [CDProperties.GetListProp[properties, $SignalName]]; FOR ropes: ROPES _ NARROW [CDProperties.GetListProp[properties, satellitesProp]], ropes.rest WHILE ropes#NIL DO name _ OrNames[name, ropes.first, CD.Describe[obj]] ENDLOOP; FOR ropes: ROPES _ NARROW [CDProperties.GetObjectProp[obj, satellitesProp]], ropes.rest WHILE ropes#NIL DO name _ OrNames[name, ropes.first, CD.Describe[obj]] ENDLOOP; }; ExtractRect: PUBLIC ExtractProc = { wire: Wire; IF obj.layer=CD.shadeLayer OR obj.layer=CD.errorLayer OR obj.layer=CD.backgroundLayer OR obj.layer=CD.outlineLayer OR obj.layer=CD.selectionLayer OR obj.layer=CD.commentLayer THEN RETURN [NIL]; wire _ CoreOps.CreateWire[name: NameFromSatellites[obj, properties]]; CoreGeometry.PutPins[mode.decoration, wire, LIST [[obj]]]; result _ wire; }; ExtractPin: PUBLIC ExtractProc = { wire: Wire; instance: CD.Instance _ CDInstances.NewInst[ob: obj, properties: properties]; layer: CD.Layer = CDSymbolicObjects.GetLayer[instance]; pinName: ROPE _ CDSymbolicObjects.GetName[instance]; IF NOT Rope.Equal[NameFromSatellites[obj, properties], pinName] THEN SIGNAL CallerBug[]; IF layer=CD.undefLayer THEN SIGNAL CallerBug[]; wire _ CoreOps.CreateWire[name: pinName]; CoreGeometry.PutPins[mode.decoration, wire, LIST [[CoreGeometry.CDPinToCoreGeometryPin[obj, properties]]]]; result _ wire; }; ExtractAtomic: PUBLIC ExtractProc = { wire: Wire; wire _ CoreOps.CreateWire[name: NameFromSatellites[obj, properties]]; CoreGeometry.PutPins[mode.decoration, wire, LIST [[obj]]]; result _ wire; }; ExtractWellAtomic: PUBLIC ExtractProc = { wellLayer: CD.Layer = CDLayers.layerData[obj.layer].well; paintLayer: CD.Layer = CDLayers.layerData[obj.layer].paint; newObj: CD.Object _ NIL; AddEachSubAtomic: CoreGeometry.EachInstanceProc = { SELECT TRUE FROM instance.obj.class=CDRects.bareRectClass AND instance.obj.layer=wellLayer => CoreGeometry.AddPins[mode.decoration, wellWire, LIST [instance]]; instance.obj.class=CDRects.bareRectClass => {}; ENDCASE => quit _ CoreGeometry.FlattenInstance[instance, AddEachSubAtomic]; }; paintWire, wellWire: Wire; wires: Wires; paintWire _ CoreOps.CreateWire[name: NameFromSatellites[obj, properties]]; wellWire _ CoreOps.CreateWire[]; [] _ CoreGeometry.FlattenInstance[[obj], AddEachSubAtomic]; newObj _ IF obj.class=CDRects.wellRectClass THEN CDRects.CreateRect[CD.InterestSize[obj], paintLayer] ELSE CDAtomicObjects.CreateAtomicOb[obj.class.objectType, CD.InterestSize[obj], CD.LayerTechnology[obj.layer], paintLayer]; IF newObj=NIL THEN ERROR; CoreGeometry.AddPins[mode.decoration, paintWire, LIST [[obj: newObj]]]; wires _ LIST [paintWire, wellWire]; result _ wires; }; ExtractTransistor: PUBLIC ExtractProc = { Decorate: PROC [port: CoreClasses.TransistorPort, geom: Saguaro.Geom] = { instances: Instances = CoreGeometry.DrawListToInstances[geom.layout]; wire: Wire = cellType.public[ORD [port]]; CoreGeometry.PutPins[mode.decoration, wire, instances]; CoreGeometry.PutGeometry[mode.decoration, wire, instances]; }; et: Saguaro.ExtractedTransistor; type: CoreClasses.TransistorType; cellType: CellType; result _ SearchObjectCache[obj, mode, userData]; IF result#NIL THEN RETURN; et _ Saguaro.ExtractTransistor[obj]; type _ SELECT et.type FROM nE => nE, pE => pE, ENDCASE => ERROR; cellType _ CoreClasses.CreateTransistor[ type: type, length: et.length, width: et.width, props: CoreProperties.Props[[CoreOps.nameProp, NameFromSatellites[obj, properties]]] ]; Decorate[gate, et.gate]; Decorate[ch1, et.ch1]; Decorate[ch2, et.ch2]; IF et.bulk.layout#NIL THEN Decorate[Vdd, et.bulk]; CoreGeometry.PutObject[mode.decoration, cellType, obj]; result _ cellType; AddInCache[obj, mode, userData, result]; }; LazyPinsEnumerate: CoreGeometry.LazyEnumerateProc = { node: CDRoutingObjects.Node _ NARROW [data1]; rir: REF CD.Rect _ NARROW [data2]; FOR i: NAT IN [0 .. node.size) DO instance: CoreGeometry.Instance = [node[i].object, [node[i].position]]; IF CoreGeometry.AtEdge[rir^, instance] THEN quit _ eachInstance[instance]; IF quit THEN RETURN; ENDLOOP; }; LazyGeometryEnumerate: CoreGeometry.LazyEnumerateProc = { node: CDRoutingObjects.Node _ NARROW [data1]; FOR i: NAT IN [0 .. node.size) DO quit _ eachInstance[[node[i].object, [node[i].position]]]; IF quit THEN RETURN; ENDLOOP; }; ExtractRouting: PUBLIC ExtractProc = { cellType: CellType; routing: CDRoutingObjects.RoutingSpecific = NARROW [obj.specific]; publics: LIST OF Wire _ NIL; result _ SearchObjectCache[obj, mode, userData]; IF result#NIL THEN RETURN; PutF["Extracting [%g] routing %g (nodes: %g)\n", IO.rope[mode.decoration.name], IO.rope[mode.nameProc[obj, userData]], IO.int[routing.size]]; FOR i: NAT IN [0 .. routing.size) DO node: CDRoutingObjects.Node = routing[i]; FOR j: NAT IN [0 .. node.size) DO IF CDLayers.layerData[node[j].object.layer].well#CD.undefLayer THEN { PutF["Routing cell %g containing well is expanded.\n", IO.rope[mode.nameProc[obj, userData]]]; RETURN Extract[CDDirectory.Expand1[obj].new, mode, properties, userData] }; ENDLOOP; ENDLOOP; FOR i: NAT IN [0 .. routing.size) DO node: CDRoutingObjects.Node = routing[i]; name: ROPE = NARROW [CDProperties.GetListProp[node.properties, $SignalName]]; wire: Wire _ CoreOps.CreateWire[name: name]; CoreGeometry.PutLazyGeometry[mode.decoration, wire, LazyGeometryEnumerate, node]; CoreGeometry.PutLazyPins[mode.decoration, wire, LazyPinsEnumerate, node, NEW [CD.Rect _ routing.ir]]; publics _ CONS [wire, publics]; ENDLOOP; cellType _ CoreClasses.CreateRecordCell[ public: CoreOps.CreateWire[publics], internal: CoreOps.CreateWire[publics], instances: NIL, name: mode.nameProc[obj, userData] ]; CoreGeometry.PutObject[mode.decoration, cellType, obj]; result _ cellType; AddInCache[obj, mode, userData, result]; }; TileInstanceArray: TYPE = REF TileInstanceArrayRec; TileInstanceArrayRec: TYPE = RECORD [c: SEQUENCE sizeY: NAT OF TileInstanceLine]; TileInstanceLine: TYPE = REF TileInstanceLineRec; TileInstanceLineRec: TYPE = RECORD [c: SEQUENCE sizeX: NAT OF TileInstance]; TileInstance: TYPE = RECORD [ instance: CoreClasses.CellInstance, table: RefTab.Ref -- maps sub publics to actuals ]; TilingRoot: PROC [fused: RefTab.Ref, wire: Wire] RETURNS [root: Wire] = { IF wire=NIL THEN ERROR; root _ NARROW [RefTab.Fetch[fused, wire].val]; IF root=NIL THEN { FOR i: NAT IN [0 .. wire.size) DO wire[i] _ TilingRoot[fused, wire[i]] ENDLOOP; RETURN [wire]; }; IF root=wire THEN ERROR; root _ TilingRoot[fused, root]; [] _ RefTab.Replace[fused, wire, root]; }; TilingFuse: PROC [fused: RefTab.Ref, wire1, wire2: Wire] = { root1: Wire = TilingRoot[fused, wire1]; root2: Wire = TilingRoot[fused, wire2]; IF root1=root2 THEN RETURN; IF root1.size#root2.size THEN ERROR; [] _ RefTab.Store[fused, root1, root2]; }; FuseNeighbors: PROC [mode: Mode, fused: RefTab.Ref, inX: BOOL, ti1, ti2: TileInstance, cache: RefTab.Ref] = { FOR list: LIST OF CoreGeometry.WirePair _ CoreGeometry.CachedEnumerateNeighbors[mode.decoration, mode.touchProc, inX, ti1.instance.type, ti2.instance.type, cache], list.rest WHILE list#NIL DO act1: Wire = NARROW [RefTab.Fetch[ti1.table, list.first.wire1].val]; act2: Wire = NARROW [RefTab.Fetch[ti2.table, list.first.wire2].val]; IF act1=NIL OR act2=NIL THEN ERROR; TilingFuse[fused, act1, act2]; ENDLOOP; }; ExtractTiling: PUBLIC ExtractProc = { ExtractEachTile: PW.EachTileProc = { subIr: CD.Rect _ CD.InterestRect[tile]; -- in the transformation coordonnate system trans: Transformation = [CDBasics.SubPoints[pos, CDBasics.BaseOfRect[subIr]]]; subCT: CellType _ NARROW [Extract[tile, mode, NIL, userData].result]; table: RefTab.Ref _ RefTab.Create[subCT.public.size+2]; actual: WireSeq _ CoreOps.CopyWireUsingTable[subCT.public, table, FALSE]; tileInstances[y][x].instance _ CoreClasses.CreateInstance[actual: actual, type: subCT]; tileInstances[y][x].table _ table; CoreGeometry.PutTrans[mode.decoration, tileInstances[y][x].instance, trans]; }; FixUpEachTile: PW.EachTileProc = { AddToPublics: CoreOps.EachWirePairProc = { EachInstance: CoreGeometry.EachInstanceProc = { quit _ NOT CoreGeometry.TransfedNotAtEdge[trans, ir, instance]; }; IF CoreGeometry.EnumeratePins[mode.decoration, publicWire, EachInstance] THEN [] _ RefTab.Store[publics, TilingRoot[fused, actualWire], NIL]; }; subIr: CD.Rect _ CD.InterestRect[tile]; -- in the transformation coordonnate system trans: Transformation = [CDBasics.SubPoints[pos, CDBasics.BaseOfRect[subIr]]]; instance: CoreClasses.CellInstance _ tileInstances[y][x].instance; actual: Wire _ instance.actual; strictlyInside: BOOL _ CDBasics.Inside[CoreGeometry.BBox[[tile, trans]], insideIR]; FOR i: NAT IN [0 .. actual.size) DO wire: Wire _ TilingRoot[fused, actual[i]]; [] _ RefTab.Store[internals, wire, NIL]; IF ~CoreOps.CorrectConform[wire, instance.type.public[i]] THEN SIGNAL StructureMismatch[name, i, actual, instance.type.public]; actual[i] _ wire; ENDLOOP; IF NOT strictlyInside THEN [] _ CoreOps.VisitBindingSeq[instance.actual, instance.type.public, AddToPublics]; instances _ CONS [instance, instances]; }; ir: CD.Rect = CD.InterestRect[obj]; insideIR: CD.Rect = CDBasics.Extend[ir, -1]; cellType: CellType; tileInstances: TileInstanceArray; sizeX, sizeY: NAT; cache: RefTab.Ref _ CoreGeometry.CreateNeighborsCache[]; fused: RefTab.Ref _ RefTab.Create[]; publics: RefTab.Ref _ RefTab.Create[]; internals: RefTab.Ref _ RefTab.Create[]; instances: LIST OF CoreClasses.CellInstance _ NIL; name: ROPE = mode.nameProc[obj, userData]; time: BasicTime.GMT = BasicTime.Now[]; result _ SearchObjectCache[obj, mode, userData]; IF result#NIL THEN RETURN; [sizeX, sizeY] _ PW.GetTilingSize[obj]; PutF["Extracting [%g] tiling %g (size: %g*%g)\n", IO.rope[mode.decoration.name], IO.rope[name], IO.int[sizeX], IO.int[sizeY]]; tileInstances _ NEW [TileInstanceArrayRec[sizeY]]; FOR y: NAT IN [0 .. sizeY) DO tileInstances[y] _ NEW [TileInstanceLineRec[sizeX]]; ENDLOOP; [] _ PW.EnumerateTiles[obj, ExtractEachTile]; FOR y: NAT IN [0 .. sizeY) DO FOR x: NAT IN [1 .. sizeX) DO FuseNeighbors[mode, fused, TRUE, tileInstances[y][x-1], tileInstances[y][x], cache]; ENDLOOP; ENDLOOP; cache _ CoreGeometry.CreateNeighborsCache[]; FOR x: NAT IN [0 .. sizeX) DO FOR y: NAT IN [1 .. sizeY) DO FuseNeighbors[mode, fused, FALSE, tileInstances[y-1][x], tileInstances[y][x], cache]; ENDLOOP; ENDLOOP; [] _ PW.EnumerateTiles[obj, FixUpEachTile]; cellType _ CoreClasses.CreateRecordCell[ public: CreateDAGWireSeq[publics], internal: CreateDAGWireSeq[internals], instances: instances, name: name ]; CoreGeometry.PutRecordLazyPins[mode.decoration, cellType, ir]; CoreGeometry.PutObject[mode.decoration, cellType, obj]; PutF["Extracted [%g] tiling %g (%g sec.)\n", IO.rope[mode.decoration.name], IO.rope[name], IO.int[BasicTime.Period[time, BasicTime.Now[]]]]; result _ cellType; AddInCache[obj, mode, userData, result]; }; ExtractIndirect: PUBLIC ExtractProc = { CopyPins: CoreOps.EachWirePairProc = { CoreGeometry.PutIndirectLazyPins[mode.decoration, actualWire, publicWire]; }; indObj: CD.Object = NARROW [obj.specific]; indCT, icon: CellType; result _ SearchObjectCache[obj, mode, userData]; IF result#NIL THEN RETURN; [result, props] _ Extract[indObj, mode, CDProperties.DAppendProps[obj.properties, properties], userData]; indCT _ NARROW [result]; icon _ CreateIcon[indCT]; CoreGeometry.PutObject[mode.decoration, icon, obj]; [] _ CoreOps.VisitBindingSeq[actual: icon.public, public: indCT.public, eachWirePair: CopyPins]; result _ icon; AddInCache[obj, mode, userData, result]; }; ExtractCellAsWire: PUBLIC ExtractProc = { wire: Wire _ CoreOps.CreateWire[]; CoreGeometry.PutPins[mode.decoration, wire, LIST [[obj]]]; result _ wire; }; ExtractNull: PUBLIC ExtractProc = {result _ NIL}; AlwaysTrue: PUBLIC PROC [Object, REF, REF] RETURNS [BOOL _ TRUE] = {}; CompareProperties: 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 ISTYPE [p1.first.key, ATOM] AND 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 ISTYPE [p2.first.key, ATOM] AND CDProperties.GetListProp[properties1, p2.first.key]#p2.first.val THEN RETURN [FALSE]; ENDLOOP; RETURN [TRUE]; }; DefaultName: PUBLIC PROC [obj: Object, userData: REF] RETURNS [ROPE] = { RETURN [PW.Name[obj]]; }; DefaultInstanceLayer: PUBLIC PROC [Instance] RETURNS [LayerRange] = {RETURN [[0, 0]]}; satellitesProp: PUBLIC ATOM _ PW.RegisterProp[$SinixSatellites]; iconClass: PUBLIC Core.CellClass _ CoreOps.SetClassPrintProc[NEW [Core.CellClassRec _ [name: "Icon", recast: RecastIcon, layersProps: TRUE]], PrintIcon]; CreateIcon: PUBLIC PROC [cellType: CellType, name: ROPE _ NIL, props: Properties _ NIL] RETURNS [icon: CellType] = { icon _ CoreOps.CreateCellType[ class: iconClass, public: CoreOps.CopyWire[cellType.public], data: cellType, name: name, props: props ]; }; RecastIcon: Core.RecastProc = {new _ NARROW [me.data]}; PrintIcon: CoreOps.PrintClassProc = { ct: CellType _ NARROW [data]; CoreOps.PrintIndent[indent, out]; out.PutF["Icon of `%g':\n", IO.rope[CoreOps.GetCellTypeName[ct]]]; CoreOps.PrintCellType[cellType: ct, out: out, indent: indent, level: level]; }; lazyExtractClass: PUBLIC Core.CellClass _ NEW [Core.CellClassRec _ [name: "LazyExtract", recast: RecastLazyExtract]]; LazyExtractData: TYPE = REF LazyExtractDataRec; LazyExtractDataRec: TYPE = RECORD [ obj: Object, mode: Mode, properties: CD.PropList _ NIL, userData: REF _ NIL ]; CreateLazyExtract: PUBLIC PROC [public: WireSeq, obj: Object, mode: Mode, properties: CD.PropList _ NIL, userData: REF _ NIL] RETURNS [cellType: CellType] = { cellType _ CoreOps.CreateCellType[ class: lazyExtractClass, public: public, data: NEW [LazyExtractDataRec _ [obj: obj, mode: mode, properties: properties, userData: userData]]]; CoreGeometry.PutObject[mode.decoration, cellType, obj]; }; RecastLazyExtract: Core.RecastProc = { data: LazyExtractData _ NARROW [me.data]; atom: ATOM _ NARROW [CDProperties.GetProp[data.obj.class, data.mode.extractProcProp]]; extractProc: ExtractProc _ IF atom=NIL THEN ExtractExpand ELSE NARROW [RefTab.Fetch[registeredExtractProcs, atom].val, REF ExtractProc]^; ect: CellType _ NARROW [extractProc[data.obj, data.mode, data.properties, data.userData].result]; extractedToSource: RefTab.Ref _ MapExtractedToSource[me.public, ect.public, data.obj, data.mode]; permuted: CellType _ CoreClasses.CreatePermutedRecordCell[me.public, ect, extractedToSource]; CoreGeometry.PutTrans[data.mode.decoration, NARROW [permuted.data, CoreClasses.RecordCellType][0], []]; RETURN [permuted]; }; DecorateObjectWithLazyExtract: PUBLIC PROC [public: WireSeq, obj: Object, mode: Mode, properties: CD.PropList _ NIL, userData: REF _ NIL] = { CDProperties.PutObjectProp[obj, mode.extractProcProp, $LazyExtract]; CDProperties.PutObjectProp[obj, $LazyExtractResult, CreateLazyExtract[public, obj, mode, properties, userData]]; }; LazyExtract: ExtractProc = { result _ CDProperties.GetObjectProp[obj, $LazyExtractResult]; }; PinsCorrespondingToSeveralPublics: PUBLIC SIGNAL [obj: Object, public1, public2: Wire, name1, name2: ROPE, geometry: CoreGeometry.Instances] = CODE; InstanceTableFromPublic: PUBLIC PROC [decoration: CoreGeometry.Decoration, bbox: CD.Rect, public: WireSeq] RETURNS [table: InstanceTable.Table] = { FillInstanceTable: PROC [wire: Core.Wire] = { AddPinInTable: CoreGeometry.EachInstanceProc = { InstanceTable.Insert[table, instance, wire]; }; [] _ CoreGeometry.EnumeratePins[decoration, wire, AddPinInTable]; }; table _ InstanceTable.Create[bbox]; CoreOps.VisitRootAtomics[public, FillInstanceTable]; }; MapExtractedToSource: PUBLIC PROC [source, extracted: WireSeq, obj: Object, mode: Mode] RETURNS [extractedToSource: RefTab.Ref] = { FillTable: PROC [sourcePublic: Core.Wire] = { EachSourcePin: CoreGeometry.EachInstanceProc = { Action: PROC [extractedInstance: CoreGeometry.Instance, value: InstanceTable.Value] = { extractedWire: Core.Wire = NARROW [value]; prevSource: Core.Wire _ NARROW [RefTab.Fetch[extractedToSource, extractedWire].val]; IF prevSource=sourcePublic THEN RETURN; -- already considered IF NOT mode.touchProc[mode.touchProc, instance, extractedInstance] THEN RETURN; IF prevSource#NIL THEN SIGNAL PinsCorrespondingToSeveralPublics[ obj, prevSource, sourcePublic, CoreOps.GetFullWireName[source, prevSource], CoreOps.GetFullWireName[source, sourcePublic], LIST [instance, extractedInstance] ]; [] _ RefTab.Store[extractedToSource, extractedWire, sourcePublic]; }; InstanceTable.Enumerate[extractedInstances, Action, CoreGeometry.BBox[instance]]; }; [] _ CoreGeometry.EnumeratePins[mode.decoration, sourcePublic, EachSourcePin]; }; extractedInstances: InstanceTable.Table; -- table instance -> extractedPublic extractedToSource _ RefTab.Create[]; -- maps extractedWire to source extractedInstances _ InstanceTableFromPublic[mode.decoration, obj.bbox, extracted]; CoreOps.VisitRootAtomics[source, FillTable]; }; OutputType: TYPE = {none, terminal, messageWindow}; outputFlag: OutputType _ terminal; PutF: PUBLIC PROC [format: ROPE, v1, v2, v3, v4, v5: IO.Value _ [null[]]] = { SELECT outputFlag FROM terminal => TerminalIO.PutF[format, v1, v2, v3, v4, v5]; messageWindow => MessageWindow.Append[IO.PutFR[format, v1, v2, v3, v4, v5], TRUE]; ENDCASE => {}; }; numbers: ARRAY [0..256) OF ROPE; -- JMF: speedup hack for SchematicsFusionByName FOR i: NAT IN [0..256) DO numbers[i] _ IO.PutR1[IO.int[i]] ENDLOOP; RegisterExtractProc[$ExtractCell, ExtractCell]; RegisterExtractProc[$ExtractAbut, ExtractAbut]; RegisterExtractProc[$ExtractRotation, ExtractRotation]; RegisterExtractProc[$ExtractExpand, ExtractExpand]; RegisterExtractProc[$ExtractRect, ExtractRect]; RegisterExtractProc[$ExtractPin, ExtractPin]; RegisterExtractProc[$ExtractAtomic, ExtractAtomic]; RegisterExtractProc[$ExtractWellAtomic, ExtractWellAtomic]; RegisterExtractProc[$ExtractTransistor, ExtractTransistor]; RegisterExtractProc[$ExtractRouting, ExtractRouting]; RegisterExtractProc[$ExtractTiling, ExtractTiling]; RegisterExtractProc[$ExtractIndirect, ExtractIndirect]; RegisterExtractProc[$ExtractCellAsWire, ExtractCellAsWire]; RegisterExtractProc[$ExtractNull, ExtractNull]; RegisterExtractProc[$LazyExtract, LazyExtract]; END. าSinixImpl.mesa Copyright ำ 1985, 1986, 1987 by Xerox Corporation. All rights reversed. Created by Bertrand Serlet August 15, 1985 2:09:54 pm PDT Bertrand Serlet August 31, 1988 10:14:57 am PDT Pradeep Sindhu May 5, 1986 5:16:10 pm PDT Barth, April 18, 1986 4:42:48 pm PST gbb April 16, 1987 6:19:54 pm PDT Jean-Marc Frailong January 17, 1988 9:07:29 pm PST Signals Type Aliases Caches Searches the object cache. result=NIL if not in cache We fill the object cache Fusion data structure and internal manipulation 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). If a pin is found we just note that this is a public wire Fusion external manipulation Creates a DAG Wire from a RefTab, getting rid of wires that have their father also in the list. delete all the sons 32 should be enough to avoid 815 We find out who are the publics and internals We replace in all instances wires by their roots We build the CellType We set all pins to be lazy for that record We correct previous statement for all explicit geometry We empty all tables We first fuse all the nameWire with same name, and at the same time prepare the list of all the names that have components We sort the names, using the trick that foo[2].mumble or foo[2][3] are after foo[2] in the lexicographic order names _ RopeList.Sort[names, RopeList.Compare]; -- JMF: deleted, already done next line IF subWireName=NIL THEN subWireName _ IO.PutR1[IO.int[i]]; -- JMF: speedup The following PROC implements Fisher-Galler fusion, not for efficiency, but for simplicity This mechanism could be exported if we wanted that. Appends the properties of fused to the ones of root, but treating short names specially this never happens during Cell or Abut extraction, because pins are not yet there, but might occur when called from SisyphImpl.ProcessGlobalName FuseProperties: PUBLIC PROC [mode: Mode, fused, root: Wire, name: ROPE] = { EachProperty: PROC [prop: ATOM, val: REF ANY] = { rootValue: REF _ CoreProperties.GetWireProp[root, prop]; SELECT prop FROM CoreOps.nameProp => CoreProperties.PutWireProp[root, prop, NameFusion[prop, val, rootValue, name]]; mode.decoration.geometryProp => CoreGeometry.AddGeometry[mode.decoration, root, CoreGeometry.GetGeometry[mode.decoration, fused]]; mode.decoration.pinsProp => CoreGeometry.AddPins[mode.decoration, root, CoreGeometry.GetPins[mode.decoration, fused]]; -- this never happens during Cell or Abut extraction, because pins are not yet there, but might occur when called from SisyphImpl.ProcessGlobalName ENDCASE => CoreProperties.PutWireProp[root, prop, DefaultFusion[prop, val, rootValue, name]]; }; CoreProperties.Enumerate[fused.properties, EachProperty]; }; 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 Attention: modifies physically its argument! pos: CD.Position _ CDBasics.BaseOfRect[CDInstances.InstRectI[inst]]; -- JMF : speedup Cell and Abut Extraction Compute the right overlap of theses cells on this instance it is impossible here to check for conformance, since fusion might have been done differently in different parts of the DAG 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! Attention! does not work for Raw Extraction. The main loop over "instances". Attention, we are assuming here that we are seing instances from left to right and bottom to top [this assumption is made in AbutFusionWire by the chosen sides] Extraction We detect trivial causes of bugs! Hack, hack, hack We check if none of the objects contains well, and expand if not We build the CellType Attention! does not work for Raw Extraction. We extract sub objects and build instances We fuse neighbors We replace in all instances wires by their roots, and accumulate instances, publics and internals We build the CellType We set all pins to be lazy for that record We fill the object cache Extraction mode procs Icon class Lazy Extraction Progress Report Initialization ส5 – "cedar" style˜codešœ™KšœH™HKšœ6ฯk™9Kšœ/™/Kšœ&™)Kšœ!™$Kšœ™!K™2—K™š œ˜ Kšœ˜Kšœฃ˜ฅKšœ˜Kšœ,˜,Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ#˜#—K˜•StartOfExpansion[]šะbn œœ˜Kšœœฺœœ5˜สKšœ˜ Kšœ˜Kšœœ˜—head™Jš ฯn œœœœœ˜/Jšž œœœœ˜#JšŸœœœœœœœ˜WJš Ÿœœœœœ˜OJš Ÿœœœœ œ œ˜]Jš Ÿœœœ œœ˜IJš Ÿœœœœœ˜>—™ Jš œœœœœ˜Kšœœ˜3Kšœ œ˜'Kšœ œ˜)—™Jš œœœ#œœ˜Lš œœœ!œœ˜HJ˜—Jšœœœ˜+šœœœ˜!Jš œœ œ œœ˜@Jšœœ˜$Jšœ˜—Jšœ œœ˜+šœœœ˜Jšœœœ˜!Jšœ˜ Jšœ˜J˜—Jšœ6™6š Ÿœœ%œœ œœ˜`š œœ?œœ˜nJšœ#˜#Jšœœ5œœ˜nJšœ˜—J˜J˜—J™šŸ œœ%œ œ˜JJšœœ4˜OJšœœ;˜GJšœ8˜8J˜J˜—šŸ œœœœ ˜,Jšœ3œ˜8Jšœ1œ˜6Jšœ˜——™/šœ œœœ˜1J˜—Jšœ œœ˜%šœœœ˜Jšœฯc˜.Jšœœ  _˜rJšœœ )˜:Jšœœ ,˜>Jšœ ’˜ฆJšœœ ๅ˜๖Jšœœ œœ g˜žJ˜J˜—Jšœ œœ ˜!šœ œœ˜Jšœœ ˜-Jšœ œ œœ g˜ขJ˜J˜—š œœœœœ ˜.Kšœœœœ œ œ œ˜gKšœ˜K˜—š Ÿ œœ œœœ˜fš Ÿ œœœœœœ˜7šœœœœ˜"Jšœ'œ˜+Jšœ+œ˜/Jšœœ˜Jšœ˜—Jšœ/˜/J˜—Jšœ'˜'Jšœ.˜.Jšœ*œ˜/J˜J˜—Jšœฟ™ฟšŸœœjœ˜ˆšœ-˜/Jšœœ˜)—Jšœ!œœ˜Lšœ$œœ˜6JšœB˜BJšœ9˜9Jš œœœœ1œ˜dJšœ9™9šœ+˜-Jšœ4˜8—Jšœ˜—Jšœœs˜‡J˜——™Jšœ œT™ašŸœœœ˜FJšœœœœ˜šž œ˜(šŸ œœ˜!Jšœœœ ˜;šœœœ˜!Jšœ˜Jšœ˜—J˜—Jšœ œ˜šœœœœ˜"Jšœ™Jšœ˜Jšœ˜—J˜—Jšœœ˜šžœ˜)Jšœœ˜J˜J˜—Jšœ(˜(Jšœ2˜2Jšœ)˜)Jšœœœ œ˜˜>Jšœ-˜-J˜—Jšœ-™-Jšœ4˜4Jšœ0™0š œœœ5œœ˜WJšœ0˜0Jšœ˜šœœœ˜#Jšœ-˜-Jšœ8œœF˜‹Jšœ˜Jšœ˜—Jšœ˜—Jšœ™šœ&˜&JšœI˜IJšœ˜Jšœ˜Jšœ ˜J˜—Jšœ0˜0Jšœ*™*JšœC˜CJšœ7™7Jšœ:˜:J™Jšœ+œ˜/šœœœ#˜2Jšœ@˜@Jšœ˜—J˜J˜—šŸœœ˜5Jš œ œœœ œ˜9Jšœ0˜0š œ œœ%œ œ˜QJšœ8˜8JšœœS˜]Jšœœ&˜Ašœœœ˜Jšœ2˜2šœœ˜Jšœ8˜8Jšœ0œ œ˜YJšœ=˜=J˜—J˜—Jšœ*˜*Jšœ*˜*Jšœ˜—J˜J˜—šŸœœ˜1Jš œ œœœ œ˜9šŸ œ˜'Jšœ œ˜Jšœœœ˜Jšœœ˜Jšœ1˜1Jšœ˜Jšœœœœ˜Jšœ3œ œ˜\šœœ˜Jšœ+œœ œ˜`Jšœ˜Jšœ˜Jšœ˜—J˜—Jšœ2 D˜vš œ œœ%œ œ˜QJšœœ˜#Jšœ8˜8Jšœœ'˜Jš œ œœœœ ฯbœ ™JKšœ œœœœ œœœ  ก 0˜šœ+œ˜3Jš œ œ œ'œ?œ ˜ฉJšœ˜—Jšœ˜—Jš œ œœ'œ@œ ˜ขJšœ#˜#Jšœ˜Jšœ˜—Jšœ6˜6Jšœ˜—J˜J˜—šŸ œœ œ˜FJš œ œœœ œ˜;Jšœ œ(˜9J˜K˜—JšœœH™ZšŸœœ&œ˜PJšœœœœ˜5Jšœ œ,˜=Jšœ œœœ˜#Jšœœœ˜:Jšœ*˜*Jšœ6˜6J˜J˜—K™3šœœœœœœœœ œœ˜gK˜—šž œ˜Kšœœ œ˜8K˜K˜—šž œ˜!Jšœœœœœœœ0˜jJš œœœœœ˜.K˜J™—JšœW™WšŸœœœ'œ˜Kš Ÿ œœœœœ˜1Jšœ œ*˜8šœ˜Jšœ%˜%Jšœ.˜.Jšœ*˜*Jšœ\˜c—J˜—Jšœ œœœ˜Jšœ œœœ˜Jšœœœœ˜Jšœ9˜9šœ œœ˜Jšœ œœ6˜HKšœk˜kK˜—Kšœ œœc˜všœœœ\˜nKšœ™—J˜J˜—šŸœœœ'œ™Kš Ÿ œœœœœ™1Jšœ œ*™8šœ™Jšœf™fJšœ‚™‚Jšœx “™‹Jšœ\™c—J™—Jšœ9™9J™J™—Jšœ‡™‡šŸ œœ0˜AJšœ.œœ˜YJšœ#œœ˜NJšœ-œœ˜XJšœ!œœ˜LJšœ œœ ˜MJšœ?˜?Jšœœ  ˜%Jšœ1˜1J˜J˜—šŸœœ.œ˜\Jšœ$˜$Jšœ$˜$Jšœ œœ ˜#šœœ˜Jšœ˜JšœJ˜JJšœI˜Išœ˜Jšœ+˜+šœœœ˜!Jšœ;˜;Jšœ˜—Jšœ%˜%Jšœ%˜%J˜—Jšœœ9˜N—J˜J˜—š ŸœœOœœœœ˜•šœ)œœ˜>JšœE˜EJšœ9˜9J–> -- [key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOLEAN]šœœ&˜.šžœœ5˜TJšœ"œ ˜2Jšœ-œœ˜XJšœ%œœ˜3JšœFœœ˜xJ˜—šœœœ˜+JšœH˜HJšœ˜—Jšœ˜—J˜——™š Ÿœœ]œœœ˜•Jšœœœ@˜Všœœœ˜Jšœ"˜"JšœJ˜JJšœ˜J˜—Jšœ˜JšœJ˜JJšœ#˜#šœœ˜Jšœ"˜"Jšœ1˜1Jšœ#˜#Jšœ˜—J˜J˜—JšœE™HšŸ œœiœœ˜™Jšœœ&˜?Jšœ˜Jšœ œ$˜4JšœK˜KJšœ œœœ˜+Jš œ3œ œœœ˜bšœœœ˜#JšœY˜YJšœ˜—šœ œœ˜Jšœ˜šœ˜Jšœ˜Jšœ;˜;Jšœ˜——Jšœ œ œœ-˜QJšœ,˜,J˜J˜—šŸ œœKœ˜xJšœ(˜(Jšœ*˜*šœœœœ˜$JšœHœ˜OJšœ˜—J˜J˜—Jšœ,™,šŸ œœ œœœ œ œœœ œ˜dš Ÿœœœ œœ˜0JšœœAขœ ™UJšœœ7œ& ก ˜ŠJšœ˜J˜—šŸœ˜Jšœœœ ˜EJ˜—Jšœ œ#˜2J˜——™š Ÿœœ œœ œ ˜HJš œ'œœœœ œœ˜SJš œ/œœœœœœ˜RJš œ'œœœœœœ ˜SJš œ'œœ œœœœ˜RJ˜—š Ÿ œœ œœœœ˜HJšœ œ ˜Jšœœœœ ˜PJšœ^˜^Jšœ œ œ˜8Jšœœœœ ˜PJšœ^˜^Jšœ œ œ˜8Jšœ ˜J˜J˜—šž œœ˜#Jšœœœ˜#Jš œ œœœ œ˜'Jšœœ˜1Jšœœ"˜>Jšœœœœ˜9JšŸ œ*œ˜PJšœœ˜&Jšœ0˜0Jšœœœœ˜Jšœ3˜3Jšœ* ˜?JšœH˜Hšœœ˜+Jš œœ œœœ˜A—Jš œ7œœœ œœ˜ošœœœ˜'Jšœ6˜6Jšœ˜—Jšœ<œœœœœœœ œœœœ(œ˜—JšœV G˜šœ œ˜Jšœ œ˜,Jšœ œ ˜Jšœ œ˜%Jšœe˜ešœœ˜ šŸœ˜/šœœ˜JšœC˜C—Jšœ˜—Jšœ:™:Jšœœ*˜2Jšœ œ(˜4Jšœ:˜:Jšœœœ ˜"J˜—JšœY˜Yš œ œœœ œ˜0šœ˜JšœIœ˜OJ˜—šœ˜Jšœ(˜(šœ œ˜JšœHœ˜NJšœ˜Jšœ˜—J˜—šœ˜Jšœœ4˜<šœ@˜@JšœI˜IJšœ"˜"Jšœ˜—Jšœx™{JšœC˜CJšœœ˜5Jšœr™ršœœœ˜'Jšœ1˜1Jšœ˜—J˜—Jšœœ˜2—Jšœ˜Jšœ˜—J™šœ˜Jšœ*˜*Jšœ%˜%Jšœ1˜1Jšœ )˜B—Jšœ7˜7Jšœ(˜(Jšœ+œœœ/˜•J˜J˜—šŸœœeœœ˜œšŸ œ#˜0JšœC˜Cšœœœœ˜5Jšœ œ˜,—š œœ œœœ˜9JšœB˜BJšœ.˜.Jš œœœœ7œ˜jJ˜—šœœ?˜EJšœ<˜@—J˜—Jšœœ&˜?Jšœ˜Jšœœ˜.Jšœœ ˜.Jšœ˜Jšœœ˜Jšœœ˜Jšœ œœœ˜+Jšœ4˜4JšœS˜Sšœœœ˜#JšœY˜YJšœ˜—šœ œ œ˜Jšœ˜šœ˜Jšœ˜Jšœ6œ˜Jšœœ ˜8Jšœœœœ˜9Jšœœ˜Jšœœ˜&šŸœœ˜+Jšœœœ +˜XJšœ œ.˜œœP˜›Jšœ˜šœœœ˜'Jšœ+˜+Jšœ2˜2Jšœ8˜8Jšœ˜—JšœA˜AJšœœ˜5J˜—Jšœ0˜0Jšœœœœ˜Jšœœ˜ขšœœ˜+Jš œœ œœœ˜A—Jšœœ ˜(šœœœ˜'Jšœ1˜1Jšœ˜—šœœœ˜'Jšœ3˜3Jšœ˜—Jš œ<œœ(œœ˜ฆJšœม™มJšœœ-˜4Jšœ7˜7Jšœ(˜(Jšœ+œœœ/˜•šœœœ˜'Jšœ>˜>Jšœ˜—Jšœ˜J˜——™ šžœœ˜Jšœœ6˜[Jš œœœœeœœ<˜เJšœU˜Uš˜Jšœ=˜=Jšœœœ>˜QJ˜Jšœœœœ9˜WJšœœœœ9˜Wšœœœœ˜3Jšœ œœ2˜Sšœ œœ˜Jšœ`œœ ˜ƒJ˜—Jšœ˜J˜—Jšœ˜Jšœ%˜%Jšœ˜Jšœ?˜?Jšœ!™!šœœ˜J˜J˜Jš œœœ3œœ ˜€Jš œœœœœ -˜b—Jšœ#˜#Jšœ3œn˜คJšœ˜—J˜J˜—šœ5˜5J˜—šŸœœœœ˜JJš œœ+œœ7œ ˜›J˜J˜—šŸœœ˜'Jšœ œœ˜6Jšœœ1˜:Jšœ0˜0Jšœœœœ˜JšœD˜DJšœœœœ˜šœœ˜˜J˜'Jšœ^˜^J˜J˜—˜Jšœœ˜šœœ˜J˜.Jšœe˜eJšœ œ˜$J˜Jšœ˜—J˜J˜—˜J˜1JšœH˜HJšœt˜tJšœ"œ˜˜>Jšœ7˜7J™Jšœ-œœ œ/˜ŒJšœ˜Jšœ(˜(Kšœ˜K˜—šžœœ˜'–f -- [actualWire: Core.Wire, publicWire: Core.Wire] RETURNS [subWires: BOOL _ TRUE, quit: BOOL _ FALSE]šŸœ˜&JšœJ˜JJ˜—Jšœœ œ˜*J˜Jšœ0˜0Jšœœœœ˜Jšœi˜iJšœœ ˜Jšœ˜Jšœ3˜3J–Z[actual: Core.WireSeq, public: Core.WireSeq, eachWirePair: CoreOps.EachWirePairProc]˜`Jšœ˜Jšœ(˜(J˜J˜—šŸœœ˜)Jšœ"˜"Jšœ,œ ˜:J˜J˜J˜—Jšž œœœ˜1—™JšŸ œœœ œœœœœ˜FšŸœœœœœœœœœœ˜–š œœ!œœ˜:JšœœœœBœœœ˜xJšœ˜—š œœ!œœ˜:JšœœœœBœœœ˜xJšœ˜—Jšœœ˜Jšœ˜J˜—š Ÿ œœœœœœ˜HJšœœ ˜J˜J˜—š Ÿœœœ œœ ˜VJ˜—Jšœœœœ ˜@—™ šœ œ,œFœ˜™K˜—šŸ œœœœœœœ˜tšœ˜Kšœ<˜