DIRECTORY Atom USING [GetPName], Basics USING [CompareINT, Comparison], CD, CDInstances, CDBasics, CDOps USING [LayerRope], CDProperties USING [DCopyProps, GetProp, GetInstanceProp, GetListProp, PutInstanceProp], Convert USING [RopeFromInt], PropertyLists USING [GetProp, PropList, PutProp], RedBlackTree USING [Compare, Create, DuplicateKey, GetKey, Insert, LookupNextLarger, LookupSmallest, Table], RefTab USING [Create, EachPairAction, Fetch, GetSize, Insert, Pairs, Ref, Store], Rope USING [Cat, FromRefText, Equal, ROPE], SX USING [AdjustmentMode, AreaPerimRec, AttachedNode, BoxMapProc, Circuit, CircuitNode, Constraint, ConversionProc, LogicalCell, MapRec, MergeRec, MergeRecList, NodeLinkage, SignalName, SpinifexLayerIndex], SXAccess USING [stopFlag, sxTech], SXAccessInternal USING [GetLogicalCell, PutError], SXAtoms USING [export, InstanceName, Rect, SignalName, spinifex], SXQuadTree USING [AreaSplit, Store, QuadTree, QuadTreeRoot, Rectangle, RectDelta]; SXImpl: CEDAR PROGRAM IMPORTS Atom, Basics, CD, CDInstances, CDBasics, CDOps, CDProperties, Convert, PropertyLists, RedBlackTree, RefTab, Rope, SXAccess, SXAccessInternal, SXAtoms, SXQuadTree EXPORTS SX = BEGIN AreaPerimRec: TYPE = SX.AreaPerimRec; AttachedNode: TYPE = SX.AttachedNode; Circuit: TYPE = SX.Circuit; Constraint: TYPE = SX.Constraint; LogicalCell: TYPE = SX.LogicalCell; MapRec: TYPE = SX.MapRec; MergeRec: TYPE = SX.MergeRec; NodeLinkage: TYPE = SX.NodeLinkage; SignalName: TYPE = SX.SignalName; SpinifexLayerIndex: TYPE = SX.SpinifexLayerIndex; IllegalConstruct: PUBLIC ERROR [rect: CD.Rect, reason: Rope.ROPE] = CODE; IllegalLayer: PUBLIC ERROR [rect: CD.Rect, lev: CD.Layer] = CODE; specialLayers: CD.Layer = MAX [CD.shadeLayer, CD.errorLayer, CD.backgroundLayer, CD.outlineLayer, CD.selectionLayer, CD.commentLayer]; repetitionInstanceNamePrefix: Rope.ROPE _ ""; repetitionInstanceNamePostfix: Rope.ROPE _ ""; IsSimpleRect: PROC [ob: CD.Object] RETURNS [BOOL] = INLINE BEGIN RETURN [ob.class.objectType = SXAtoms.Rect] END; -- IsSimpleRect TranslateChild: CD.DrawProc = BEGIN sxThrough: REF LogicalCell = NARROW [pr.devicePrivate]; cir: REF Circuit = sxThrough.circuit; IF inst.ob.class.symbolic THEN RETURN; IF IsSimpleRect[inst.ob] THEN { IF inst.ob.layer > specialLayers THEN { node: REF SX.CircuitNode = AddRect [cir: cir, lev: inst.ob.layer, dim: inst.ob.bbox, trans: trans ! IllegalLayer => { SXAccessInternal.PutError[sxThrough.cellObj, rect, Rope.Cat["material on layer ", CDOps.LayerRope[lev], " must not appear as isolated rectangles.\n"]]; GOTO BadRect } ]; IF node # NIL THEN CopyNodeProperties [cir, node, inst.properties]; EXITS BadRect => NULL }; RETURN } -- end simple rectangle. ELSE { sx: REF LogicalCell _ SXAccessInternal.GetLogicalCell [inst.ob]; IF (sx # NIL) AND (sx.analysisState = useCircuit) THEN { subcircuit: REF Circuit = sx.circuit; myInst: CD.Instance = NEW [CD.InstanceRep _ [ob: inst.ob, trans: trans, properties: CDProperties.DCopyProps [propList: inst.properties]]]; FOR i: SpinifexLayerIndex IN [0..SXAccess.sxTech.numSpinifexLayers) DO IF subcircuit.spinifexLayers[i].private # NIL THEN { IF (cir.subcircuits = NIL) OR (cir.subcircuits.first # myInst) THEN { cir.subcircuits _ CONS [myInst, cir.subcircuits]; }; [] _ AddBox [cir: cir, trans: trans, spinifexLayer: i, dim: subcircuit.spinifexLayers[i].size, value: myInst]; } ENDLOOP; cir.linkageCount.inChildren _ cir.linkageCount.inChildren + subcircuit.linkageCount.inSelf + subcircuit.linkageCount.inChildren; } ELSE { -- expand special objects (transistors) and conditional objects WITH CDProperties.GetProp [from: inst.ob.class.properties, prop: SXAtoms.spinifex] SELECT FROM convProc: REF SX.ConversionProc => convProc^[inst, trans, cir ! IllegalConstruct => { SXAccessInternal.PutError [sxThrough.cellObj, CDBasics.MapRect[itemInCell: rect, cellInWorld: trans], reason]; CONTINUE} ]; ENDCASE => inst.ob.class.drawMe[inst, trans, pr] -- analysis state: notYetDone } } END; -- TranslateChild TranslateRect: CD.DrawRectProc = BEGIN IF CDBasics.NonEmpty[r] AND l # CD.errorLayer THEN { sxc: REF LogicalCell = NARROW [pr.devicePrivate]; [] _ AddRect [cir: sxc.circuit, lev: l, dim: r ! IllegalLayer => { SXAccessInternal.PutError [sxc.cellObj, rect, Rope.Cat ["rectangle on layer ", CDOps.LayerRope [lev], " cannot be analyzed in this context.\n"]]; CONTINUE} ] } END; SKey: TYPE = REF CD.Position; -- RedBlackTree.Key SRec: TYPE = RECORD [key: SKey, instance: CD.Instance]; SData: TYPE = REF SRec; -- RedBlackTree.UserData InstKey: RedBlackTree.GetKey = BEGIN RETURN [NARROW [data, SData].key] END; -- InstKey InstComp: RedBlackTree.Compare = BEGIN c: Basics.Comparison; sk: SKey = NARROW [k]; d: SData = NARROW [data]; c _ Basics.CompareINT [sk.x, d.key.x]; IF c = equal THEN c _ Basics.CompareINT [sk.y, d.key.y]; RETURN [c] END; -- InstComp SInsert: PROCEDURE [s: RedBlackTree.Table, inst: CD.Instance] RETURNS [duplicate: BOOL] = BEGIN ENABLE RedBlackTree.DuplicateKey => GOTO dupl; sk: SKey _ NEW [CD.Position _ CDBasics.BaseOfRect[CDInstances.InstRectO[inst]]]; data: SData _ NEW [SRec _ [key: sk, instance: inst]]; RedBlackTree.Insert [s, data, sk]; RETURN [FALSE]; EXITS dupl => RETURN [TRUE] END; -- SInsert PutInstanceNamesIfRepetition: PROC [cir: REF Circuit] = { IF cir.subcircuits#NIL AND cir.subcircuits.rest#NIL AND cir.subcircuits.rest.rest#NIL THEN BEGIN FOR sub: CD.InstanceList _ cir.subcircuits, sub.rest WHILE sub#NIL DO IF cir.subcircuits.first.trans.orient # sub.first.trans.orient THEN EXIT; IF cir.subcircuits.first.ob # sub.first.ob THEN EXIT; REPEAT FINISHED => BEGIN sTab: RedBlackTree.Table = RedBlackTree.Create [InstKey, InstComp]; lastApp, currApp: SData; delta: CD.Position; FOR sub: CD.InstanceList _ cir.subcircuits, sub.rest WHILE sub#NIL DO IF SInsert [sTab, sub.first] THEN GOTO EqualAppls; ENDLOOP; lastApp _ NARROW [RedBlackTree.LookupSmallest[sTab]]; currApp _ NARROW [RedBlackTree.LookupNextLarger[sTab,lastApp.key]]; delta _ CDBasics.SubPoints[currApp.instance.trans.off, lastApp.instance.trans.off]; lastApp _ currApp; WHILE (currApp _ NARROW[RedBlackTree.LookupNextLarger[sTab, lastApp.key]]) # NIL DO IF delta # CDBasics.SubPoints[currApp.instance.trans.off, lastApp.instance.trans.off] THEN EXIT; lastApp _ currApp; REPEAT FINISHED => BEGIN index: INT _ 1; FOR a: SData _ NARROW[RedBlackTree.LookupSmallest[sTab]], NARROW[RedBlackTree.LookupNextLarger[sTab, a.key]] WHILE a # NIL DO IF CDProperties.GetInstanceProp[from: a.instance, prop: SXAtoms.InstanceName]=NIL THEN BEGIN instanceName: Rope.ROPE _ repetitionInstanceNamePrefix.Cat[Convert.RopeFromInt[index], repetitionInstanceNamePostfix]; CDProperties.PutInstanceProp [a.instance, SXAtoms.InstanceName, instanceName]; END; index _ index+1 ENDLOOP END; ENDLOOP; EXITS EqualAppls => NULL END ENDLOOP; END }; sxContextFilter: REF CD.ContextFilter; TranslateGeometry: PUBLIC PROC [cell: REF LogicalCell] = BEGIN cir: REF Circuit = cell.circuit; dr: CD.DrawRef = CD.CreateDrawRef [[ drawRect: TranslateRect, drawChild: TranslateChild, devicePrivate: cell, contextFilter: sxContextFilter, stopFlag: SXAccess.stopFlag ]]; cell.cellObj.class.drawMe[CDInstances.NewInst[cell.cellObj], [], dr]; FOR link: LIST OF REF NodeLinkage _ cir.linkages, link.rest WHILE link#NIL DO cir.linkageCount.inSelf _ cir.linkageCount.inSelf + 1 ENDLOOP; PutInstanceNamesIfRepetition[cir]; END; UniformBloat: PROC [d: INT] RETURNS [SXQuadTree.RectDelta] = INLINE { RETURN [[d,d,d,d]] }; AddRect: PUBLIC PROC [ cir: REF Circuit, lev: CD.Layer, dim: CD.Rect, trans: CD.Transformation _ [], value: REF SX.CircuitNode _ NIL] RETURNS [cirNode: REF SX.CircuitNode _ NIL] = BEGIN IF SXAccess.sxTech.illegalLayer[lev] THEN ERROR IllegalLayer [CDBasics.MapRect [itemInCell: dim, cellInWorld: trans], lev]; IF CDBasics.NonEmpty[dim] THEN -- Silently ignore empty boxes FOR map: LIST OF MapRec _ SXAccess.sxTech.cdLayerMapping[lev], map.rest WHILE map#NIL DO cn: REF SX.CircuitNode; WITH map.first.value SELECT FROM mappingFunc: REF SX.BoxMapProc => cn _ mappingFunc^[ cir: cir, dim: dim, trans: trans, node: (IF cirNode#NIL THEN cirNode ELSE value)]; ENDCASE => cn _ AddBox [cir: cir, spinifexLayer: map.first.spinifexLayer, dim: dim, trans: trans, interestBloat: UniformBloat[map.first.bloatFactor], value: (IF map.first.value#NIL THEN map.first.value ELSE value)]; IF cn#NIL THEN cirNode _ cn ENDLOOP; END; -- AddRect AddEmptyBox: ERROR = CODE; AddBox: PUBLIC PROC [ cir: REF Circuit, spinifexLayer: SpinifexLayerIndex, dim: CD.Rect, trans: CD.Transformation _ [], interestBloat: SXQuadTree.RectDelta _ [0,0,0,0], value: REF ANY _ NIL] RETURNS [cirNode: REF SX.CircuitNode _ NIL] = BEGIN A: PROC [r: CD.Rect] RETURNS [area: INT] = INLINE BEGIN area _ (r.x2-r.x1) * (r.y2-r.y1) END; -- A P: PROC [r: CD.Rect] RETURNS [perim: INT] = INLINE BEGIN perim _ ((r.x2-r.x1) + (r.y2-r.y1)) * 2 END; -- P IF ~CDBasics.NonEmpty [dim] THEN ERROR AddEmptyBox ELSE { bloatedDim, bloatedMapped, mappedDim: CD.Rect; newRect: REF SXQuadTree.Rectangle; bloatedDim _ [x1: dim.x1-interestBloat.dx1, y1: dim.y1-interestBloat.dy1, x2: dim.x2+interestBloat.dx2, y2: dim.y2+interestBloat.dy2]; bloatedMapped _ CDBasics.MapRect [itemInCell: bloatedDim, cellInWorld: trans]; mappedDim _ CDBasics.MapRect [itemInCell: dim, cellInWorld: trans]; IF value = NIL THEN { value _ cirNode _ NEW [SX.CircuitNode _ [ dim: LIST[[layer: spinifexLayer, area: A[dim], perim: P[dim]]], loc: [CDBasics.Center[mappedDim], spinifexLayer] ]]; AddCircuitNode [cir, cirNode] } ELSE WITH value SELECT FROM cn: REF SX.CircuitNode => { cirNode _ cn; AdjustNode [cirNode, spinifexLayer, A[dim], P[dim]] }; ENDCASE => NULL; newRect _ NEW [SXQuadTree.Rectangle _ [ interestBound: bloatedMapped, dimDecr: [ dx1: mappedDim.x1-bloatedMapped.x1, dy1: mappedDim.y1-bloatedMapped.y1, dx2: bloatedMapped.x2-mappedDim.x2, dy2: bloatedMapped.y2-mappedDim.y2], nodeInformation: value ]]; cir.spinifexLayers[spinifexLayer] _ SXQuadTree.Store [quadTree: cir.spinifexLayers[spinifexLayer], rect: newRect] } END; -- AddBox MergeNode: PUBLIC PROC [circuit: REF Circuit, to, from: REF SX.CircuitNode] = BEGIN IF from.superceded#NIL THEN from _ LookupNode [from]; IF to.superceded#NIL THEN to _ LookupNode [to]; IF from=to THEN RETURN; FOR fromList: LIST OF AreaPerimRec _ from.dim, fromList.rest WHILE fromList#NIL DO AdjustNode [to, fromList.first.layer, fromList.first.area, fromList.first.perim] ENDLOOP; CopyNodeProperties [circuit, to, from.properties]; from.properties _ NIL; from.superceded _ to END; -- MergeNode CopyNodeProperties: PROC [ circuit: REF Circuit, node: REF SX.CircuitNode, properties: PropertyLists.PropList, qual: LIST OF CD.Instance _ NIL] = BEGIN CopySignal: PROC [sig: REF ANY, depth: INTEGER] RETURNS [REF SignalName] = BEGIN IF sig=NIL THEN RETURN [NIL]; WITH sig SELECT FROM r: Rope.ROPE => RETURN [NEW[SignalName _ [depth: depth, name: r]]]; t: REF TEXT => RETURN [NEW[SignalName _ [depth: depth, name: Rope.FromRefText[t]]]]; a: ATOM => RETURN [NEW[SignalName _ [depth: depth, name: Atom.GetPName[a]]]]; s: REF SignalName => BEGIN copyHead, copyTail: REF SignalName; copyHead _ NEW [SignalName _ [depth: s.depth+depth, name: s.name, makePort: s.makePort]]; copyTail _ copyHead; FOR source: REF SignalName _ s.alias, source.alias WHILE source#NIL DO copyTail.alias _ NEW [SignalName _ [depth: source.depth+depth, name: source.name]]; copyTail _ copyTail.alias; ENDLOOP; RETURN [copyHead]; END; ENDCASE => ERROR; END; -- CopySignal MergeAliases: PROC [to, from: REF SignalName] = BEGIN WHILE from # NIL DO FOR existingAlias: REF SignalName _ to, existingAlias.alias WHILE existingAlias#NIL DO IF from.name.Equal[existingAlias.name] THEN BEGIN IF from.depth < existingAlias.depth THEN existingAlias.depth _ from.depth; from _ from.alias; EXIT END REPEAT FINISHED => BEGIN tmp: REF SignalName = from; from _ from.alias; tmp.alias _ to.alias; to.alias _ tmp END ENDLOOP ENDLOOP END; -- MergeAliases fromSigProp: REF ANY ~ PropertyLists.GetProp [properties, SXAtoms.SignalName]; exportProp: REF ANY = PropertyLists.GetProp [properties, SXAtoms.export]; toSigProp: REF ANY ~ PropertyLists.GetProp [node.properties, SXAtoms.SignalName]; IF SXAccess.sxTech.combineNodeProperties#NIL AND properties#NIL THEN node.properties _ SXAccess.sxTech.combineNodeProperties[circuit, node.properties, properties, qual]; BEGIN fromSignal: REF SignalName; toSignal: REF SignalName; depth: INTEGER _ 0; FOR q: LIST OF CD.Instance _ qual, q.rest WHILE q#NIL DO depth _ depth.SUCC ENDLOOP; fromSignal _ CopySignal [fromSigProp, depth]; IF fromSignal # NIL THEN fromSignal.makePort _ (fromSignal.makePort OR exportProp=$TRUE); toSignal _ NARROW[toSigProp]; IF (toSignal # NIL) AND (fromSignal # NIL) THEN BEGIN IF toSignal.depth > fromSignal.depth THEN BEGIN node.properties _ PropertyLists.PutProp [node.properties, SXAtoms.SignalName, fromSignal]; MergeAliases [fromSignal, toSignal] END ELSE MergeAliases [toSignal, fromSignal] END ELSE IF (fromSignal # NIL) THEN node.properties _ PropertyLists.PutProp[node.properties, SXAtoms.SignalName, fromSignal] END; node.properties _ PropertyLists.PutProp [node.properties, UnMerged]; END; -- CopyNodeProperties AdjustNode: PUBLIC PROC [ node: REF SX.CircuitNode, layer: SpinifexLayerIndex, area: INT, perim: INT, mode: SX.AdjustmentMode _ relative] = BEGIN apRec: LIST OF AreaPerimRec _ node.dim; IF node.superceded # NIL THEN node _ LookupNode[node]; -- added Ch. J. Jan 30, 1985 WHILE apRec # NIL DO IF apRec.first.layer = layer THEN EXIT; apRec _ apRec.rest; REPEAT FINISHED => BEGIN node.dim _ CONS [AreaPerimRec [layer: layer, area: area, perim: perim], node.dim]; RETURN END ENDLOOP; SELECT mode FROM relative => BEGIN apRec.first.area _ apRec.first.area + area; apRec.first.perim _ apRec.first.perim + perim END; absolute => BEGIN apRec.first.area _ area; apRec.first.perim _ perim END; ENDCASE END; -- AdjustNode NormalizeCircuit: PUBLIC PROC [cir: REF Circuit] = BEGIN CompressCircuitNodeList: PROC = BEGIN mySpecialCN: REF SX.CircuitNode = NEW [SX.CircuitNode]; indirectList: LIST OF REF SX.CircuitNode ~ CONS [mySpecialCN, cir.nodes]; cn: LIST OF REF SX.CircuitNode; IF cir.nodes = NIL THEN RETURN; mySpecialCN.superceded _ NIL; mySpecialCN.properties _ NIL; cn _ indirectList; WHILE cn.rest # NIL DO node: REF SX.CircuitNode ~ cn.rest.first; IF (node.superceded # NIL) OR (CDProperties.GetListProp [propList: node.properties, prop: UnMerged] # NIL) THEN cn.rest _ cn.rest.rest ELSE cn _ cn.rest ENDLOOP; IF cir.nodes = NIL THEN ERROR; -- Impossible! We would have returned at start if NIL list, and at least some of the nodes must be non-superceded. cn _ indirectList; WHILE cn.rest # NIL DO IF cn.rest.first.superceded = mySpecialCN THEN cn.rest _ cn.rest.rest ELSE {cn _ cn.rest; cn.first.superceded _ mySpecialCN} ENDLOOP; cn _ cir.nodes _ indirectList.rest; WHILE cn # NIL DO cn.first.superceded _ NIL; cn _ cn.rest ENDLOOP; END; -- CompressCircuitNodeList CompressLinkages: PROC = BEGIN FOR linkages: LIST OF REF NodeLinkage _ cir.linkages, linkages.rest WHILE linkages#NIL DO FOR attached: LIST OF REF AttachedNode _ linkages.first.nodes, attached.rest WHILE attached#NIL DO IF attached.first.node#NIL THEN attached.first.node _ LookupNode[attached.first.node]; ENDLOOP ENDLOOP END; -- CompressLinkages CompressMergeDirectoryEntries: PROC = BEGIN IF cir.mergeDirectory # NIL THEN BEGIN dummy: SX.MergeRecList = CONS [[], NIL]; CountUnMerged: RefTab.EachPairAction = BEGIN IF CDProperties.GetListProp [NARROW[key, REF SX.CircuitNode].properties, UnMerged] # NIL THEN oldSize _ oldSize.PRED; RETURN [FALSE] END; -- CountUnMerged CompressMerge: RefTab.EachPairAction = BEGIN mergeList: SX.MergeRecList; IF CDProperties.GetListProp[NARROW[key, REF SX.CircuitNode].properties, UnMerged] = NIL THEN BEGIN dummy.rest _ NARROW [val]; mergeList _ dummy; WHILE mergeList.rest # NIL DO mergeList.rest.first.becomes _ LookupNode [mergeList.rest.first.becomes]; IF CDProperties.GetListProp [mergeList.rest.first.becomes.properties, UnMerged] # NIL THEN mergeList.rest _ mergeList.rest.rest ELSE mergeList _ mergeList.rest ENDLOOP; IF dummy.rest # NIL THEN IF NOT newTab.Insert [key, dummy.rest] THEN ERROR END; RETURN [FALSE] END; -- CompressMerge oldSize: INT _ RefTab.GetSize [cir.mergeDirectory]; newTab: RefTab.Ref; [] _ RefTab.Pairs [cir.mergeDirectory, CountUnMerged]; IF oldSize <= 0 THEN {cir.mergeDirectory _ NIL; RETURN}; newTab _ RefTab.Create [((oldSize/3)*4)+1]; [] _ RefTab.Pairs [cir.mergeDirectory, CompressMerge]; cir.mergeDirectory _ newTab; IF (RefTab.GetSize [newTab] = 0) THEN cir.mergeDirectory _ NIL END -- if cir.mergeDirectory # NIL END; -- CompressMergeDirectoryEntries CompressBoxPaths: PROC [qt: REF SXQuadTree.QuadTree] = BEGIN FOR boxes: LIST OF REF SXQuadTree.Rectangle _ qt.boxes, boxes.rest WHILE boxes#NIL DO WITH boxes.first.nodeInformation SELECT FROM inst: CD.Instance => NULL; cn: REF SX.CircuitNode => boxes.first.nodeInformation _ LookupNode [cn]; cc: REF Constraint => NULL; ENDCASE => ERROR; ENDLOOP; FOR quad: SXQuadTree.AreaSplit IN SXQuadTree.AreaSplit DO IF qt.subTrees[quad] # NIL THEN CompressBoxPaths [qt.subTrees[quad]] ENDLOOP END; -- CompressBoxPaths CompressCircuitNodeList []; CompressLinkages []; CompressMergeDirectoryEntries []; FOR layer: SpinifexLayerIndex IN [0..SXAccess.sxTech.numSpinifexLayers) DO IF (cir.spinifexLayers[layer].geometry # NIL) THEN CompressBoxPaths [cir.spinifexLayers[layer].geometry] ENDLOOP END; -- Normalise Circuit LookupNode: PUBLIC PROC [node: REF SX.CircuitNode] RETURNS [REF SX.CircuitNode] = BEGIN IF node.superceded#NIL THEN { n1: REF SX.CircuitNode _ node; WHILE node.superceded#NIL DO node _ node.superceded ENDLOOP; WHILE n1.superceded#NIL DO n2: REF SX.CircuitNode _ n1.superceded; n1.superceded _ node; n1 _ n2; ENDLOOP; }; RETURN [node] END; -- LookupNode LookupMergeDirectory: PROC [ dir: RefTab.Ref, cn: REF SX.CircuitNode, qual: LIST OF CD.Instance] RETURNS [merge: SX.MergeRecList, newQual: LIST OF CD.Instance] = BEGIN found: BOOL; val: REF ANY; [found, val] _ RefTab.Fetch [dir, cn]; IF found THEN BEGIN FOR mergeList: SX.MergeRecList _ NARROW[val], mergeList.rest WHILE mergeList#NIL DO qApplChain: LIST OF CD.Instance _ qual; FOR applChain: LIST OF CD.Instance _ mergeList.first.applChain, applChain.rest DO IF applChain = NIL THEN RETURN [mergeList, qApplChain]; IF (qApplChain = NIL) OR (qApplChain.first # applChain.first) THEN EXIT; qApplChain _ qApplChain.rest ENDLOOP ENDLOOP END; -- found RETURN [NIL, qual] END; -- LookupMergeDirectory UnMerged: ATOM = $SXPrivateUnMerged; FindRootNode: PUBLIC PROC [ circuit: REF Circuit, subcircuitNode: REF SX.CircuitNode, qualifier: LIST OF CD.Instance, insertIfNotInCircuit: BOOL _ FALSE] RETURNS [node: REF SX.CircuitNode, rootQualifier: LIST OF CD.Instance] = BEGIN AddCircuitNodeMerge: PROC [sourceNode: REF SX.CircuitNode, qual: LIST OF CD.Instance] RETURNS [newNode: REF SX.CircuitNode] = BEGIN found: BOOL; mergeList: SX.MergeRecList _ NIL; IF circuit.mergeDirectory = NIL THEN BEGIN IF insertIfNotInCircuit THEN BEGIN circuit.mergeDirectory _ RefTab.Create [521]; -- A prime. found _ FALSE END END ELSE BEGIN -- circuit.mergeDirectory # NIL val: REF ANY; [found, val] _ RefTab.Fetch [circuit.mergeDirectory, sourceNode]; IF found THEN BEGIN mergeList _ NARROW [val]; FOR m: SX.MergeRecList _ mergeList, m.rest WHILE m#NIL DO q: LIST OF CD.Instance _ qual; FOR applChain: LIST OF CD.Instance _ m.first.applChain, applChain.rest DO IF (applChain = NIL) OR (q = NIL) THEN IF (applChain = NIL) AND (q = NIL) THEN RETURN [newNode _ m.first.becomes] ELSE EXIT ELSE IF (applChain.first # q.first) THEN EXIT; q _ q.rest ENDLOOP ENDLOOP END -- found END; -- circuit.mergeDirectory # NIL IF ~insertIfNotInCircuit THEN RETURN [newNode _ NIL]; newNode _ NEW [SX.CircuitNode _ [NIL, NIL, sourceNode.loc, NIL]]; FOR qa: LIST OF CD.Instance _ qual, qa.rest WHILE qa # NIL DO newNode.loc.xy _ CDBasics.MapPoint [pointInCell: newNode.loc.xy, cellInWorld: qa.first.trans] ENDLOOP; CopyNodeProperties [circuit, newNode, sourceNode.properties, qual]; newNode.properties _ PropertyLists.PutProp [newNode.properties, UnMerged, UnMerged]; mergeList _ CONS [[applChain: qual, becomes: newNode], mergeList]; IF RefTab.Store[circuit.mergeDirectory, sourceNode, mergeList] = found THEN ERROR; AddCircuitNode [circuit, newNode] END; -- AddCircuitNodeMerge IF qualifier=NIL THEN RETURN [subcircuitNode, NIL]; FOR q: LIST OF CD.Instance _ qualifier.rest, q.rest WHILE q#NIL DO subcircuit: REF Circuit _ SXAccessInternal.GetLogicalCell[q.first.ob].circuit; IF subcircuit.mergeDirectory # NIL THEN BEGIN tmp: SX.MergeRecList; oldQual: LIST OF CD.Instance _ qualifier; [merge: tmp, newQual: qualifier] _ LookupMergeDirectory [subcircuit.mergeDirectory, subcircuitNode, qualifier]; IF tmp # NIL THEN BEGIN IF oldQual = NIL THEN ERROR; IF (qualifier # NIL) AND (qualifier.first.ob # q.first.ob) THEN ERROR; subcircuitNode _ tmp.first.becomes END END ENDLOOP; IF (node _ AddCircuitNodeMerge[sourceNode: subcircuitNode, qual: qualifier])=NIL THEN {node _ subcircuitNode; rootQualifier _ qualifier} ELSE rootQualifier _ NIL END; -- FindRootNode AddCircuitNode: PROC [cir: REF Circuit, cn: REF SX.CircuitNode] = INLINE BEGIN cir.nodes _ CONS[cn, cir.nodes] END; -- AddCircuitNode CreateLinkage: PUBLIC PROC [cir: REF Circuit, source: CD.Instance, length, width: CD.Number] RETURNS [REF NodeLinkage] = BEGIN cir.linkages _ CONS [NEW[NodeLinkage _ [source: source, l: length, w: width]], cir.linkages]; RETURN [cir.linkages.first]; END; -- CreateLinkage LinkageAttach: PUBLIC PROC [ link: REF NodeLinkage, attachType: ATOM, node: REF SX.CircuitNode _ NIL] = BEGIN link.nodes _ CONS [NEW [AttachedNode _ [attachType, node]], link.nodes] END; -- LinkageAttach MakeContextFilter: PROC [] = { sxContextFilter _ NEW[CD.ContextFilter_ALL[TRUE]]; sxContextFilter[CD.errorLayer] _ FALSE; sxContextFilter[CD.commentLayer] _ FALSE; sxContextFilter[CD.backgroundLayer] _ FALSE; sxContextFilter[CD.shadeLayer] _ FALSE; sxContextFilter[CD.selectionLayer] _ FALSE; }; MakeContextFilter[] END. $hSXImpl.mesa Creates a representation of the layout suitable for hierarchical analysis. Copyright c 1984, 1985, 1986 by Xerox Corporation. All rights reserved. Written by Mark Shand, September 12, 1983 11:40 pm Last Edited by: Shand, March 13, 1985 2:57:23 pm PST Last Edited by: Spreitzer, January 15, 1985 2:09:09 pm PST Last Edited by: Jacobi, April 8, 1985 5:07:49 pm PST Last edited by: Christian Jacobi, November 17, 1986 6:22:56 pm PST Last edited by: gbb June 9, 1986 4:55:58 pm PDT TYPES from Interface. Implementation. --PROC [inst: Instance, trans: Transformation, pr: REF DrawInformation] --This object is a logical subcircuit. --It is the 1st non-empty geom-layer.  Stuff for RedBlackTree (used in TranslateGeometry) Raises DuplicateKey if appl with same location already added.  There are at least three subcircuits. They all have the same orientation, and are all are of the same type. They are sorted. Hence they are logically a repetition. Provide default instance names for repetition elements. Added by Spreitzer November 24, 1984 12:08:57 pm PST. Genralized by Shand, March 13, 1985 2:20:08 pm PST. Translates ChipNDale layers into Spinifex layers (e.g. only explicit contacts [which must be correct and hence are not checked] are allowed. Also a node number is assigned, which is used to identify the nodes. The translation is performed using the drawRect mechanism of ChipNDale. The ChipNDale design is translated into a quad-tree. It is not possible to use a tesselation because of overlaps. The quad-tree contains only cells already analysed. There are three types of rectangles in the Quad-Tree: 1. constraints; 2. material; 3. bounding boxes for subcell rectangles. --count devices calling LookupNode and equal test introduced by Ch. J. Jan 30, 1985 Combine areas and perimeters. Combine properties. Creates a SignalName RECORD with appropriate depth from a ChipNDale Signal name (ROPE) or an existing SignalName RECORD. Insert in list. Copy Technology Dependent PropertyLists Copy SignalName property Delete UnMerged property. Search for a AreaPerimRec on this layer. This is an important step ... It results in the deallocation of superceded SX.CircuitNodes, and the removal of duplicates, superceded and UnMerged nodes from cir.nodes, and Discard superceded & UnMerged nodes. Discard duplicated nodes. Normally no SX.CircuitNodes in subcells will be unmerged at this point, however this is not true in the case of Normalization following SpinifexOutput. SpinifexOutput introduces extra intermediate nodes, such merge directory entries should be deleted. Main of CompressMergeDirectoryEntries: Ensure size is not a power of 2 (seems like a good idea). Main of Normalize Circuit Takes the node and returns the most recent version of it. Side effect: cleans all intermediate version to point to the most recent one. Mark called this "(partial) Galler-Fisher path compression", had a recursive solution which was more elegant but slower. LookupNode: PROC [l: REF SX.CircuitNode] RETURNS [REF SX.CircuitNode] ~ { --Implements (partial) Galler-Fisher path compression. RETURN [IF l.superceded#NIL THEN (l.superceded _ LookupNode[l.superceded]) ELSE l] }; --find the actual node --now node is the result --but as side effect, set all superceded fields to point to the result node Search mergeList for qual Compare mergeList.first.applChain to qual This is a renaming of cn, qual gets to be what's left, and we continue looking for higher intervening renamings. UnMerged: Private property Key to flag unmerged nodes for removal during circuit NormalizeCircuit. This key is deleted by CopyNodeProperties, which is called when ever nodes are merged. Make it big, it will get cleaned up in NormalizeCircuit anyway. Check we don't already know about it. FindRootNode Check each intermediate cell to see if subcircuitNode is renamed, return a SX.CircuitNode based on the uppermost found. Note qualifier always has at least one CD.Instance. Add to mergeDirectory. For use in cells further up in hierarchy. Edited on January 4, 1985 6:23:42 pm PST, by Jacobi NewInstanceRepI does offset position; Spinifex does not want that Edited on January 22, 1985 4:00:55 pm PST, by Beretta Unneseted SortBoxes; added comments. Edited on January 30, 1985 8:25:40 pm PST, by Jacobi MergeNode; calling LookupNode and equal test introduced AdjustNode; calling LookupNode introduced Edited on February 19, 1985 3:58:48 pm PST, by Shand Fixed serious bug in ansiotropic interest bloats when box is transformed changes to: AddBox to transform box dimension and interest bloat., TranslateGeometry, SortGeometry Edited on February 21, 1985 6:19:44 pm PST, by Beretta changes to: DIRECTORY, PaintErrorRect, TranslateChild, TranslateRect Edited on March 4, 1985 3:24:49 pm PST, by Shand Spinifex DRC errors now reported through CDErrors module. Changed role for errorContext field in LogicalCell RECORD. changes to: DIRECTORY CDErrors, IMPORTS CDErrors, PaintErrorRect calls CDErrors.IncludeMessage, DataForChildren deleted fields which handled deletion of old errors, TranslateGeometry Replaced enumeration of old errors by call to CDErrors.RemoveMessages, TranslateGeometry, IMPORTS, TranslateChild, PaintErrorRect Edited on March 7, 1985 12:58:15 pm PST, by Shand changes to: DIRECTORY, CopySignal (local of CopyNodeProperties), s (local of CopySignal, local of CopyNodeProperties) Fixed bug in reading ChipMonk files- allowed case of signal name being ATOM, PaintErrorRect added bloating of error rect by half lambda, EnumerateGeometry Improved search pruning, FlattenTree (local of EnumerateGeometry) Improved search pruning Edited on March 8, 1985 1:37:29 pm PST, by Shand Changed name of CircuitConstraint in SX to Constraint changes to: Constraint, CompressBoxPaths (local of NormalizeCircuit) Edited on March 9, 1985 10:57:10 pm PST, by Shand Two things: 1st: Extensions to NormalizeCircuit to remove nodes which were inserted by FindRootNode but never actually merged into other nodes in this cell. This is done using a special property UnMerged which is attached to nodes created for subcell nodes and then deleted during merging by CopyNodeProperties. If node is never merged it still has UnMerged property during NormalizeCircuit, and should be removed from both node list and mergeDirectory. 2nd: When first created mergeDirectory is made large (521 entries). During NormalizeCircuit it is remade with slightly more space than required number of entries. This is to improve performance on large designs. changes to: DIRECTORY, CopySignal (local of CopyNodeProperties), CopyNodeProperties, NormalizeCircuit, CompressCircuitNodeList (local of NormalizeCircuit), CompressLinkages (local of NormalizeCircuit), CompressMergeDirectoryEntries (local of NormalizeCircuit), CompressMerge (local of CompressMergeDirectoryEntries, local of NormalizeCircuit), LookupNode, UnMerged, FindRootNode, AddCircuitNodeMerge (local of FindRootNode) Edited on March 10, 1985 7:11:03 pm PST, by Shand Deleted obsolete field attached from SX.CircuitNode. Added code to keep some point on the node in the SX.CircuitNode RECORD for each node. Deleted obsolete parameters from LinkageAttach. More work on MergeDirectory Normalization. changes to: MergeNode, LinkageAttach, DIRECTORY, AddBox, FindRootNode, AddCircuitNodeMerge (local of FindRootNode), DIRECTORY, CountUnMerged (local of CompressMergeDirectoryEntries, local of NormalizeCircuit), CompressMerge (local of CompressMergeDirectoryEntries, local of NormalizeCircuit), CompressMergeDirectoryEntries (local of NormalizeCircuit), SortGeometry, AddBox Edited on March 11, 1985 7:11:03 pm PST, by Shand Deleted obsolete field unsortedBoxes from SX.QuadTreeRoot. changes to: SortGeometry, AddBox cleaned up so as not to use unsortedBoxes. Edited on March 13, 1985 2:28:03 pm PST, by Shand Detection and labelling of repetitions. changes to: DIRECTORY, IMPORTS, TranslateChild, TranslateGeometry, ApplComp Edited on May 6, 1985 11:26:55 am PDT, by Beretta Converted to ChipNDale CD20 Edited on July 8, 1985 4:45:21 pm PDT, by Beretta If an object has the property export and if the value is $TRUE and the cell is at the root of analysis, then the signal name of the node with this property will be used as a parameter (port). changes to: CopyNodeProperties: added handling of new property. Last edited by: gbb July 17, 1985 3:56:55 pm PDT Replaced ordered symbol table stuff by red-black trees for Cedar 6.0 Last edited by: gbb July 23, 1985 4:37:38 pm PDT Added storage of length, width for transistors. changes to: CreateLinkage: new parameters, NodeLinkage: new fields. gbb January 10, 1986 6:01:50 pm PST Clean-up while chasing a bug. gbb May 19, 1986 9:10:23 am PDT Instead of ignoring only material in the error layer, now all special layers are ignored. changes to: specialLayers: max value of special layers, TranslateChild changed layer test. gbb May 20, 1986 3:04:36 pm PDT Circumvented a temporary bug in the compiler. changes to: specialLayers: omitted. gbb June 9, 1986 4:55:58 pm PDT Added provisions for signal names that are of type REF TEXT instead of Rope.ROPE. changes to: CopySignal (local of CopyNodeProperties): additional case., DIRECTORY Christian Jacobi November 14, 1986 7:16:49 pm PST Analyze non rectilinear geometry Κ I˜codešœ ™ KšœJ™JIcode2šœ Οmœ=™HK™2K™4K™:K™4K™BK™/—šΟk ˜ Kšœžœ ˜Kšœžœ˜&Kšžœ˜Kšœ ˜ Kšœ ˜ Kšœžœ ˜Kšœ žœF˜XKšœžœ˜Kšœžœ˜1Kšœ žœZ˜lKšœžœE˜QKšœžœžœ˜+KšžœžœΖ˜ΞKšœ žœ˜"Kšœžœ˜2Kšœžœ4˜AKšœ žœB˜R—šΠalœžœž˜Lšžœ žœ‘˜©Lšžœžœ˜ —Lšž˜™Kšœžœžœ˜%Kšœžœžœ˜%Kšœ žœžœ ˜Kšœ žœžœ ˜!Kšœ žœžœ ˜#Kšœžœžœ˜Kšœ žœžœ ˜Kšœ žœžœ ˜#Kšœ žœžœ ˜!Kšœžœžœ˜1—L™Kš œžœžœžœžœžœ˜IKš œžœžœžœ žœ žœ˜AKšœžœ žœžœ žœ žœžœžœžœ˜†Kšœ#žœ˜-Kšœ$žœ˜.š Οn œžœžœ žœžœžœž˜@Kšžœ%˜+KšžœΟc˜—K˜šΟbœžœ ž˜#Kšœ3žœ™HKšœ žœžœ˜8Kšœžœ˜%Kšžœžœžœ˜&šžœžœ˜šžœžœ˜'šœžœžœV˜bšœ˜Kšœ—˜—Kšžœ˜ Kšœ˜—Kšœ˜—Kšžœžœžœ1˜CKšžœ ž˜Kšœ˜—Kšž˜Kšœ‘Πce‘˜—šžœ˜Kšœžœ9˜@šžœžœžœ!žœ˜8K™&Kšœ žœ˜%Kšœžœ žœžœm˜Ššžœžœ(ž˜Fšžœ(žœžœ˜4•StartOfExpansion[itemInCell: CD.Rect, cellSize: CD.Position, cellInstOrient: CD.Orientation, cellInstPos: CD.Position _ [x: 0, y: 0]]šžœžœžœ"žœ˜FKšœ%™%Kšœžœ˜1Kšœ˜—Kšœn˜nKšœ˜—Kšžœ˜—Kšœ€˜€Kšœ˜—šžœ‘?˜F–%[p: CD.ObjectProcs, key: REF ANY]šžœOžœž˜^šœ žœžœ˜#šœ˜šœ˜Kšœn˜nKšžœ˜ —Kšœ˜——Kšžœ*‘˜N—Kšœ˜—K˜—Kšžœ‘£˜—K˜š’ œžœž˜&š žœžœžœ žœž˜5Kšœžœžœ˜2šœ.˜.šœ˜Kšœ‘˜‘Kšžœ˜ —Kšœ˜—Kšž˜—Kšžœ˜—™ Iunitšœ2™2Kšœžœžœžœ ‘˜1Kšœžœžœžœ ˜7Kšœžœžœ‘˜0š œž˜$Kšžœžœ˜!Kšžœ‘ ˜—š œž˜&K˜Kšœ žœ˜Kšœ žœ˜Kšœ&˜&Kšžœ žœ'˜8Kšžœ˜ Kšžœ‘ ˜—š  œž œžœ žœ žœž˜_Kšžœžœ˜.Kšœ žœžœ>˜PKšœžœ$˜5Kšœ"˜"Kš‘=™=Kšžœžœ˜šž˜Kšœžœžœ˜—Kšžœ‘ ˜—Lšœ ™ —š œžœžœ ˜9šžœžœžœžœžœžœžœž˜`Kšœ%™%š žœžœ*žœžœž˜EKšžœ=žœžœ˜IKšžœ)žœžœ˜5šžœžœž˜KšœE™EKšœC˜CKšœ˜Kšœžœ ˜š žœžœ*žœžœž˜EKšžœžœžœ ˜3Kšžœ˜—Kšœ žœ%˜5Kšœ žœ3˜CKšœS˜SKšœ˜šžœ žœ6žœž˜SKšžœTžœžœ˜`Kšœ˜šžœžœž˜K™8Kšœžœ˜š žœ žœ%žœ-žœžœž˜}šžœLžœžœž˜\K™7Kšœ1žœ™5Kšœ/žœ™3Kšœžœ_˜vKšœN˜NKšžœ˜—Kšœ˜Kšž˜—Kšžœ˜—Kšžœ˜—Kšžœž˜Kšž˜—Kšžœ˜—Kšž˜—Lšœ˜—K˜Kšœžœžœ˜&K˜š  œžœžœžœž˜>KšœΌ™ΌKšœžœ˜ šœžœ žœ˜$Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—KšœE˜EK™š žœžœžœžœ'žœžœž˜MKšœ5˜5Kšž˜—Kšœ"˜"Kšžœ˜—K˜š   œžœžœžœžœ˜EKšžœ ˜Kšœ˜—K˜š œžœžœžœžœ žœžœžœžœžœžœ žœžœžœž˜Ήšžœ#ž˜)KšžœL˜Q—šžœžœ‘˜>š žœžœžœ8žœžœž˜XKšœžœžœ ˜šžœžœž˜ Kš œ žœžœKžœ žœžœ žœ ˜‡Kš žœ—žœžœžœžœ ˜Χ—Kšžœžœžœ ˜Kšžœ˜——Kšžœ‘£˜—Lšœ žœžœ˜K˜š œžœžœ žœ3žœžœOžœžœžœžœ žœžœžœž˜υšΡbklœžœžœžœžœžœžœ˜8Kšœ!˜!Kšžœ‘˜ —š€œžœžœžœ žœžœžœ˜9Kšœ(˜(Kšžœ‘˜ —Kšžœžœžœ ˜2šžœ˜Kšœ&žœ˜.Kšœ žœ˜"Kšœ†˜†KšœN˜NKšœC˜Cšžœ žœžœ˜šœžœžœ˜)Kšœžœ6˜?Kšœ0˜0Kšœ˜—Kšœ˜Kšœ˜—šžœžœžœž˜šœžœžœ˜KšœA˜AKšœ˜—Kšžœžœ˜—šœ žœ˜'Kšœ˜šœ ˜ Kšœ#˜#Kšœ#˜#Kšœ#˜#Kšœ$˜$—Kšœ˜Kšœ˜—Kšœq˜qKšœ‘˜—Kšžœ‘£˜—š   œžœžœ žœžœž˜SšœC™CKšžœžœžœ˜5Kšžœžœžœ˜/Kšžœ žœžœ˜—Kšœ™š žœ žœžœ(žœ žœž˜RKšœP˜PKšžœ˜—Kšœ™Kšœ2˜2Kšœžœ˜+Kšžœ‘ ˜—š œžœ žœžœžœ9žœžœžœ žœž˜šš  œžœžœžœ žœžœžœž˜PKšœžœVžœ™xKš žœžœžœžœžœ˜šžœžœž˜Kšœžœžœžœ(˜CKš œžœžœžœžœ:˜TKšœžœžœžœ7˜Mšœžœž˜Kšœžœ ˜#Kšœ žœK˜YKšœ˜š žœ žœ$žœžœž˜FKšœžœ?˜SKšœ˜Kšžœ˜—Kšžœ ˜Kšžœ˜—Kšžœžœ˜—Kšžœ‘£ ˜—š  œžœ žœž˜5šžœžœž˜š žœžœ&žœžœž˜Všžœ%žœž˜1Kšžœ"žœ"˜JKšœ˜Kšž˜Kšž˜—šžœžœž˜K™Kšœžœ˜Kšœ7˜7Kšž˜—Kšž˜—Kšž˜—Kšžœ‘£ ˜—Mšœ žœžœ:˜NKšœ žœžœ6˜IKšœ žœžœ?˜QMšœ'™'š žœ'žœžœ žœž˜DKšœd˜d—Mšœ™šž˜Kšœ žœ ˜Kšœ žœ ˜Kšœžœ˜š žœžœžœžœžœžœž˜8Kšœž˜Kšžœ˜—Kšœ-˜-Kšžœžœžœ,žœ˜YKšœ žœ ˜š žœ žœžœžœžœž˜5šžœ#žœž˜/KšœZ˜ZKšœ#˜#Kšž˜—šž˜Kšœ#˜#—Kšž˜—šžœžœžœž˜KšœX˜X—Kšžœ˜—Kšœ™KšœD˜DKšžœ‘£˜—š  œžœžœ žœžœ/žœ žœžœž˜‘Kšœ(™(Kšœžœžœ˜'Kšžœžœžœ‘˜Sšžœ žœž˜Kšžœžœžœ˜'K˜šžœžœž˜Kšœ žœC˜RKšž˜Kšž˜—Kšžœ˜—šžœž˜šœ ž˜Kšœ+˜+Kšœ-˜-Kšžœ˜—šœ ž˜Kšœ2˜2Kšžœ˜—Kšž˜—Kšžœ‘£ ˜—š  œžœžœžœ ž˜8šœ™KšœlΟeœ™—š œžœž˜%Kš œ žœžœžœžœ˜7Kš œžœžœžœžœžœ˜IKš œžœžœžœžœ ˜Mšžœ žœžœžœ˜Kšœ₯œ™$Kšœžœžœ˜;Kšœ˜šžœ žœž˜Kšœžœžœ˜)Kš žœžœžœIžœžœ˜†Kšžœ ˜Kšžœ˜—M™Kš žœ žœžœžœ‘s˜“Kšœ˜šžœ žœž˜Kšžœ(žœ˜EKšžœ3˜7Kšžœ˜—Kšœ#˜#šžœžœž˜Kšœžœ˜'Kšžœ˜—Kšžœ‘£˜—š œžœž˜š žœ žœžœžœ+žœ žœž˜Yš žœ žœžœžœ4žœ žœž˜bšžœžœž˜Kšœ6˜6—Kšž˜—Kšž˜—Kšžœ‘˜—š œžœž˜+šžœžœžœž˜&Kšœžœžœžœ˜(Kšœό™όš’ œž˜,Kšžœžœžœžœ&žœžœžœ˜uKšžœžœ˜Kšžœ‘˜—š’ œž˜,Kšœ žœ˜š žœžœžœžœ&žœžœž˜bKšœ žœ˜Kšœ˜šžœžœž˜KšœI˜IKšžœPžœžœ%˜Kšžœ˜Kšžœ˜—šžœžœž˜Kšžœžœ!žœž˜2—Kšžœ˜—Kšžœžœ˜Kšžœ‘£ ˜—Mšœ₯™&K™9Kšœ žœ'˜3Kšœ˜Mšœ6˜6Kšžœžœžœžœ˜8Kšœ+˜+Kšœ6˜6Kšœ˜Kšžœžœž˜>Kšžœ‘˜"—Kšžœ‘£˜%—š œžœžœž˜<š žœžœžœžœ-žœžœž˜Ušžœžœž˜,Kšœžœ žœ˜Kšœžœžœ>˜HKšœžœžœ˜Kšžœžœ˜—Kšžœ˜—šžœžœž˜9Kšžœžœžœ%˜DKšž˜—Kšžœ‘˜—Mšœ™Kšœ˜K˜K˜!šžœžœ(ž˜Jšžœ'žœž˜2Kšœ5˜5—Kšž˜—Kšžœ‘£˜—š  œžœžœžœžœžœžœžœž˜WKšœ9™9Kš’ œA™MKšœL™Lšœ+™+š’ œ?™IKšœ6™6KšœR™RKšœ™——šžœžœžœ˜Kšœžœžœ˜Kšœ™Kšžœžœžœžœ˜