DIRECTORY AMTypes USING [TV, TVEqual, TVType, UnderClass], AMBridge USING [SomeRefFromTV, TVForFrame, TVForReferent, TVToRef], AMModel USING [Context], AMModelBridge USING [ContextForFrame], CD, CDBasics, CDCells, CDDirectory, CDImports, CDLayers, CDProperties, CDRects, CDSatellites, CDSequencer, CDSymbolicObjects, CDTexts, Convert, Core, CoreClasses, CoreOps, CoreProperties, CoreGeometry, IO, Interpreter USING [Evaluate], PrincOpsUtils, PW, RefTab, Rope, RopeList, Sinix, Sisyph, SymTab, TerminalIO; SisyphImpl: CEDAR PROGRAM IMPORTS AMBridge, AMModelBridge, AMTypes, CDBasics, CDCells, CDDirectory, CDImports, CDLayers, CDProperties, CDRects, CDSatellites, CDSequencer, CDTexts, Convert, CoreClasses, CoreOps, CoreProperties, CoreGeometry, Interpreter, IO, PrincOpsUtils, PW, RefTab, Rope, RopeList, Sinix, SymTab, TerminalIO EXPORTS Sisyph SHARES CDCells, CDImports, CDRects, CDTexts, Sinix = BEGIN OPEN Sisyph; expressionsProp: PUBLIC ATOM _ PW.RegisterProp[$SisyphExpressions, TRUE]; designRope: PRIVATE ROPE _ "design"; globalNamesRope: PRIVATE ROPE _ "globalNames"; corePropsRope: PUBLIC ROPE _ "coreProps"; coreInstPropsRope: PUBLIC ROPE _ "coreInstProps"; cdObjRope: PRIVATE ROPE _ "cdObj"; localVariablesRopes: ROPES = LIST ["&", "&&", corePropsRope, coreInstPropsRope, cdObjRope, "cI", "wI", "wire"]; parmNamesProp: PUBLIC ATOM _ PW.RegisterProp[$SisyphParmNames, TRUE]; defaultGlobalNames: PUBLIC ROPES _ LIST ["Vdd", "Gnd", "RosemaryLogicTime"]; mode: PUBLIC Sinix.Mode _ NEW [Sinix.ModeRec _ [ extractProcProp: PW.RegisterProp[$SisyphExtractProc, TRUE], decoration: CoreGeometry.CreateDecoration["Sisyph"], instanceEqualProc: InstanceEqual, objectEqualProc: ObjectEqual, instanceLayer: Sinix.DefaultInstanceLayer, userData: DefaultUserData, fusionByName: schematics, touchProc: Touch, nameProc: Name ]]; ResultFor: PROC [cx: Context, obj: CD.Object, properties: CD.PropList] RETURNS [result: REF _ NIL] = { codeFor: ROPE _ NARROW [CDProperties.GetListProp[properties, $CodeFor]]; iconFor: ROPE _ NARROW [CDProperties.GetListProp[properties, $IconFor]]; IF codeFor=NIL THEN codeFor _ NARROW [CDProperties.GetObjectProp[obj, $CodeFor]]; IF iconFor=NIL THEN iconFor _ NARROW [CDProperties.GetObjectProp[obj, $IconFor]]; SELECT TRUE FROM codeFor#NIL AND iconFor#NIL => ERROR; -- that's one two many! codeFor#NIL => { result _ EvalToRef[cx, codeFor]; IF result#NIL THEN WITH result SELECT FROM ct: CellType => {}; w: Wire => {}; w: Wires => {}; ENDCASE => ERROR; }; iconFor#NIL => result _ ES[iconFor, cx]; ENDCASE => ERROR; -- one of them at least should be present! }; ExtractCellIcon: PUBLIC Sinix.ExtractProc = { cx: Context _ EvaluateParameters[userData, obj, properties]; iconCT: CellType _ NARROW [Sinix.ExtractCell[obj, mode, NIL, cx].result]; iconName: ROPE _ Name[obj, cx]; cellType: CellType; name: ROPE; result _ ResultFor[cx, obj, properties]; IF result=NIL THEN RETURN; cellType _ NARROW [result]; name _ CoreOps.GetCellTypeName[cellType]; IF name=NIL THEN name _ CDNameToCTName[iconName, ".icon"]; cellType _ Sinix.CreateIcon[cellType: cellType, name: name]; result _ cellType; CoreGeometry.PutObject[mode.decoration, cellType, obj]; IF NOT CheckAndDecorate[iconName, obj, iconCT.public, cellType.public, GetGlobalNames[cx]] THEN { TerminalIO.PutF["*** Error: icon public and schematic public for cell icon %g do NOT conform\n", IO.rope[iconName]]; TerminalIO.PutF["Icon public is:"]; CoreOps.PrintWire[wire: iconCT.public, out: TerminalIO.TOS[], level: LAST [NAT]]; TerminalIO.PutF["\nSchematic public is:"]; CoreOps.PrintWire[wire: cellType.public, out: TerminalIO.TOS[], level: LAST [NAT]]; TerminalIO.PutF["\n"]; ERROR }; cellType.properties _ PutCoreProps[cellType.properties, GetCoreProps[cx]]; props _ GetCoreInstProps[cx]; }; ExtractNamedWireIcon: PUBLIC Sinix.ExtractProc = { cx: Context _ EvaluateParameters[userData, obj, properties]; iconCT: CellType _ NARROW [Sinix.ExtractCell[obj, mode, NIL, cx].result]; iconName: ROPE = Name[obj, cx]; resultWire: WireSeq; result _ ResultFor[cx, obj, properties]; IF result=NIL THEN {result _ resultWire _ iconCT.public; RETURN} ELSE WITH result SELECT FROM wires: Wires => { result _ resultWire _ CoreOps.CreateWire[wires]; resultWire.properties _ PutCoreProps[resultWire.properties, GetCoreProps[cx]]; }; ww: Wire => {result _ ww; resultWire _ CoreOps.CreateWire[LIST [ww]]}; cellType: CellType => result _ resultWire _ CoreOps.CopyWire[cellType.public]; ENDCASE => ERROR; SELECT TRUE FROM iconCT.public.size=1 AND resultWire.size=1 => { result _ resultWire _ resultWire[0]; CoreGeometry.PutIndirectLazyPins[mode.decoration, resultWire, iconCT.public[0]]; }; CheckAndDecorate[iconName, obj, iconCT.public, resultWire] => {}; ENDCASE => { TerminalIO.PutF["*** Error: icon wire and result wire for wire icon %g don't conform\n", IO.rope[iconName]]; TerminalIO.PutF["Icon wire is:"]; CoreOps.PrintWire[wire: iconCT.public, out: TerminalIO.TOS[], level: LAST [NAT]]; TerminalIO.PutF["\nResult wire is:"]; CoreOps.PrintWire[wire: resultWire, out: TerminalIO.TOS[], level: LAST [NAT]]; TerminalIO.PutF["\n"]; ERROR }; props _ GetCoreInstProps[cx]; }; ExtractUnNamedWireIcon: PUBLIC Sinix.ExtractProc = { FlushName: CoreOps.EachWireProc = {[] _ CoreOps.SetShortWireName[wire, NIL]}; wire: Wire; [result, props] _ ExtractNamedWireIcon[obj, mode, properties, userData]; wire _ NARROW [result]; [] _ CoreOps.VisitWire[wire, FlushName]; }; ExtractWire: Sinix.ExtractProc = { wire: Wire; cx: Context; resultVar, resultExpr: ROPE; IF obj.class#CDRects.bareRectClass THEN ERROR; IF obj.layer#CD.commentLayer THEN ERROR; [cx, resultVar, resultExpr] _ OldEvaluateParameters[userData, obj, properties, IsResultVar]; IF resultVar=NIL THEN wire _ CoreOps.CreateWire[] ELSE { EvalExpr[cx, resultVar, resultExpr, FALSE]; wire _ NARROW [GetRef[cx, "wire"]]; TerminalIO.PutF["*** Old Syntax: 'wire _%g'. Sisyph might not be able to cope with that in near future!\n", IO.rope[resultExpr]]; }; CoreGeometry.PutPins[mode.decoration, wire, LIST [[obj]]]; wire.properties _ PutCoreProps[wire.properties, GetCoreInstProps[cx]]; result _ wire; }; ExtractImport: Sinix.ExtractProc = { cx: Context = NARROW [userData]; design: CD.Design _ GetDesign[cx]; import: CDImports.ImportSpecific = NARROW [obj.specific]; CDSequencer.CheckAborted[design]; IF import.boundOb=NIL OR import.boundDesign=NIL THEN { IF NOT CDImports.LoadAndBindDesign[into: design, importeeName: import.designName, allowConflicts: interactive, useCache: TRUE] THEN {TerminalIO.PutF["*** Error: Cannot load import %g[%g] which is unbound.\n", IO.rope[import.objectName], IO.rope[import.designName]]; ERROR}; IF import.boundOb=NIL OR import.boundDesign=NIL THEN {TerminalIO.PutF["*** Error: Cannot bind import %g[%g].\n", IO.rope[import.objectName], IO.rope[import.designName]]; ERROR}; }; RETURN Sinix.Extract[obj: import.boundOb, mode: mode, properties: properties, userData: Create[import.boundDesign, cx]]; }; ES, ExtractSchematicByName: PUBLIC PROC [name: ROPE, cx: Context] RETURNS [CellType] = { design: CD.Design = GetDesign[cx]; obj: CD.Object = CDDirectory.Fetch[design, name].object; IF obj=NIL THEN {TerminalIO.PutF["*** Error: ES cannot find object '%g' in design '%g'.\n", IO.rope[name], IO.rope[design.name]]; ERROR}; RETURN [NARROW [Sinix.Extract[obj: obj, mode: mode, properties: NIL, userData: cx].result]]; }; Create: PUBLIC PROC [design: CD.Design, previousCx: Context _ NIL] RETURNS [cx: Context] = { EvalDesignExprs: PROC [exprs: ROPES] = { WHILE exprs#NIL DO expr: ROPE _ exprs.first; tokenKind1, tokenKind2: IO.TokenKind; token1, token2, rest: ROPE; [tokenKind1, token1, rest] _ ParseRope[expr]; [tokenKind2, token2, rest] _ ParseRope[rest]; SELECT TRUE FROM tokenKind1=tokenID AND IsParsedChar[tokenKind2, token2, '_] => EvalExpr[cx, token1, rest]; tokenKind1=tokenID AND IsParsedChar[tokenKind2, token2, '~] => EvalExpr[cx, token1, rest, FALSE]; ENDCASE => { TerminalIO.PutF["*** Old syntax in design satellite or expression: Side effect in '%g'.\n", IO.rope[expr]]; Eval[cx, expr]; }; exprs _ exprs.rest; ENDLOOP; }; cx _ IF previousCx=NIL THEN SymTab.Create[11] ELSE Copy[previousCx]; Store[cx, designRope, NEW [CD.Design _ design]]; Insert[cx, globalNamesRope, NEW [ROPES _ defaultGlobalNames]]; EvalDesignExprs[NARROW [CDProperties.GetDesignProp[design, expressionsProp]]]; EvalDesignExprs[CDSatellites.GetSatelliteRopes[design]]; }; Copy: PUBLIC PROC [oldCx: Context] RETURNS [cx: Context] = { cx _ SymTab.Copy[oldCx]; -- copy the table Store[cx, corePropsRope, NEW [Properties _ NIL]]; -- and erase some standard variables Store[cx, coreInstPropsRope, NEW [Properties _ NIL]]; Store[cx, cdObjRope, NEW [CD.Object _ NIL]]; }; Store: PUBLIC PROC [cx: Context, var: ROPE, value: REF _ NIL] = { [] _ SymTab.Store[cx, var, TVFromRef[value]]; }; Insert: PUBLIC PROC [cx: Context, var: ROPE, value: REF _ NIL] = { [] _ SymTab.Insert[cx, var, TVFromRef[value]]; }; FetchInt: PUBLIC PROC [cx: Context, var: ROPE] RETURNS [found: BOOL _ FALSE, value: INT] = { val: SymTab.Val _ SymTab.Fetch[cx, var].val; IF val=NIL THEN RETURN; WITH RefFromTV[val] SELECT FROM refInt: REF INT => RETURN [TRUE, refInt^]; refNat: REF NAT => RETURN [TRUE, INT[refNat^]]; ENDCASE => ERROR; -- Wrong type }; FetchAtom: PUBLIC PROC [cx: Context, var: ROPE] RETURNS [found: BOOL _ FALSE, value: ATOM] = { val: SymTab.Val _ SymTab.Fetch[cx, var].val; IF val=NIL THEN RETURN; RETURN [TRUE, NARROW [RefFromTV[val]]]; }; FetchRope: PUBLIC PROC [cx: Context, var: ROPE] RETURNS [found: BOOL _ FALSE, value: ROPE] = { val: SymTab.Val _ SymTab.Fetch[cx, var].val; IF val=NIL THEN RETURN; WITH RefFromTV[val] SELECT FROM rope: ROPE => RETURN [TRUE, rope]; text: REF TEXT => RETURN [TRUE, Rope.FromRefText[text]]; ENDCASE => ERROR; -- Wrong type }; EvalToTV: PROC [cx: Context, expr: ROPE] RETURNS [result: AMTypes.TV, errorRope: ROPE, noResult: BOOL] = TRUSTED { [result, errorRope, noResult] _ Interpreter.Evaluate[ rope: expr, context: AMModelBridge.ContextForFrame[ AMBridge.TVForFrame[PrincOpsUtils.GetReturnFrame[]] ], symbolsList: LIST [cx] ]; }; EvalToRef: PUBLIC PROC [cx: Context, expr: ROPE] RETURNS [result: REF] = TRUSTED { tv: AMTypes.TV; errorRope: ROPE; noResult: BOOL; [tv, errorRope, noResult] _ EvalToTV[cx, expr]; SELECT TRUE FROM errorRope#NIL => SIGNAL InterpreterError[cx, NIL, expr, errorRope]; noResult => SIGNAL InterpreterError[cx, NIL, expr, "No Result"]; ENDCASE => result _ RefFromTV[tv]; }; EvalExpr : PUBLIC PROC [cx: Context, var, expr: ROPE, checkDefined: BOOL _ TRUE] = { result: AMTypes.TV; errorRope: ROPE; noResult: BOOL; [result, errorRope, noResult] _ EvalToTV[cx, expr]; SELECT TRUE FROM errorRope#NIL => SIGNAL InterpreterError[cx, var, expr, errorRope]; noResult => SIGNAL InterpreterError[cx, var, expr, "No Result"]; Rope.Fetch[var]='& OR NOT checkDefined => [] _ SymTab.Store[cx, var, result]; ENDCASE => IF SymTab.Store[cx, var, result] THEN SIGNAL InterpreterError[cx, var, expr, "Variable has not been previously declared (with a Sisyph.Store)"]; }; AddProp: PUBLIC PROC [cx: Context, key: ATOM, expr: ROPE, inst: BOOL] = { AddPropInternal[cx, key, EvalToRef[cx, expr], inst]; }; AddPropInternal: PROC [cx: Context, key: ATOM, value: REF, inst: BOOL] = { previousProps: Properties _ (IF inst THEN GetCoreInstProps ELSE GetCoreProps)[cx]; Store[cx, IF inst THEN coreInstPropsRope ELSE corePropsRope, NEW [Properties _ CoreProperties.PutProp[previousProps, key, value]]]; }; Eval: PRIVATE PROC [cx: Context, expr: ROPE] = { result: AMTypes.TV; errorRope: ROPE; noResult: BOOL; TRUSTED {[result, errorRope, noResult] _ Interpreter.Evaluate[ rope: expr, context: AMModelBridge.ContextForFrame[ AMBridge.TVForFrame[PrincOpsUtils.GetReturnFrame[]] ], symbolsList: LIST [cx] ]}; IF errorRope=NIL THEN RETURN; SIGNAL InterpreterError[cx, NIL, expr, errorRope]; }; ContextEqual: PROC [cx1, cx2: Context, parmNames: ROPES] RETURNS [BOOL] = { IsSubset: PROC [a, b: Context] RETURNS [BOOL] = { CheckAbsentInb: SymTab.EachPairAction = { found: BOOL; bVal: SymTab.Val; IF val=NIL THEN RETURN [FALSE]; -- value is in fact not in a ... IF RopeList.Memb[localVariablesRopes, key] THEN RETURN [FALSE]; [found, bVal] _ SymTab.Fetch[b, key]; quit _ NOT found OR bVal=NIL OR NOT TVEqual[bVal, val]; }; RETURN [NOT SymTab.Pairs[a, CheckAbsentInb]]; }; SELECT TRUE FROM cx1=cx2 => RETURN [TRUE]; -- for sure... parmNames=NIL => RETURN [IsSubset[cx1, cx2] AND IsSubset[cx2, cx1]]; -- most general case parmNames.rest=NIL AND Rope.Equal[parmNames.first, "0"] => RETURN [TRUE]; -- no parameters ENDCASE => { -- limited parameter list, compare only those found1: BOOL; val1: SymTab.Val; found2: BOOL; val2: SymTab.Val; FOR keys: ROPES _ parmNames, keys.rest UNTIL keys=NIL DO [found1, val1] _ SymTab.Fetch[cx1, keys.first]; [found2, val2] _ SymTab.Fetch[cx2, keys.first]; found1 _ found1 AND val1#NIL; -- TV's are not supposed to be NIL ... found2 _ found2 AND val2#NIL; IF found1#found2 THEN RETURN[FALSE]; -- present in only one table IF found1 AND NOT TVEqual[val1, val2] THEN RETURN[FALSE]; --values differ ENDLOOP; RETURN [TRUE]; -- all parameters matched }; }; InstanceEqual: PROC [obj: CD.Object, p1: CD.PropList, ud1: REF, p2: CD.PropList, ud2: REF] RETURNS [BOOL] = { instArgs1: ROPES _ NARROW [CDProperties.GetListProp[p1, expressionsProp]]; satArgs1: ROPES _ NARROW [CDProperties.GetListProp[p1, Sinix.satellitesProp]]; extract1: ATOM _ NARROW [CDProperties.GetListProp[p1, mode.extractProcProp]]; instArgs2: ROPES _ NARROW [CDProperties.GetListProp[p2, expressionsProp]]; satArgs2: ROPES _ NARROW [CDProperties.GetListProp[p2, Sinix.satellitesProp]]; extract2: ATOM _ NARROW [CDProperties.GetListProp[p2, mode.extractProcProp]]; parmNames: ROPES _ NARROW [CDProperties.GetObjectProp[obj, parmNamesProp]]; IF extract1#extract2 THEN RETURN [FALSE]; IF NOT EqualRopes[instArgs1, instArgs2] OR NOT EqualRopes[satArgs1, satArgs2] THEN RETURN [FALSE]; IF parmNames#NIL AND Rope.Equal[parmNames.first, "0"] THEN RETURN [TRUE]; RETURN [ContextEqual[NARROW [ud1], NARROW [ud2], NIL]]; }; ObjectEqual: PROC [obj: CD.Object, ud1: REF, ud2: REF] RETURNS [BOOL] = { parmNames: ROPES _ NARROW [CDProperties.GetObjectProp[obj, parmNamesProp]]; IF parmNames#NIL AND Rope.Equal[parmNames.first, "0"] THEN RETURN [TRUE]; RETURN [ContextEqual[NARROW [ud1], NARROW [ud2], parmNames]]; }; EqualRopes: PUBLIC PROC [ropes1, ropes2: ROPES] RETURNS [BOOL] = { FOR r1: ROPES _ ropes1, r1.rest WHILE r1#NIL DO IF NOT RopeList.Memb[ropes2, r1.first] THEN RETURN [FALSE]; ENDLOOP; FOR r2: ROPES _ ropes2, r2.rest WHILE r2#NIL DO IF NOT RopeList.Memb[ropes1, r2.first] THEN RETURN [FALSE]; ENDLOOP; RETURN [TRUE]; }; Cons: PUBLIC PROC [r: ROPE, lor: ROPES] RETURNS [ROPES] = { RETURN [CONS [r, lor]]; }; List: PUBLIC PROC [r1, r2, r3, r4, r5, r6: ROPE _ NIL] RETURNS [lor: ROPES _ NIL] = { IF r6#NIL THEN lor _ CONS [r6, lor]; IF r5#NIL THEN lor _ CONS [r5, lor]; IF r4#NIL THEN lor _ CONS [r4, lor]; IF r3#NIL THEN lor _ CONS [r3, lor]; IF r2#NIL THEN lor _ CONS [r2, lor]; IF r1#NIL THEN lor _ CONS [r1, lor]; }; CheckAndDecorate: PROC [iconName: ROPE, icon: CD.Object, drawnPublic, resultPublic: WireSeq, globalNames: ROPES _ NIL] RETURNS [ok: BOOL _ TRUE] = { resultToDrawn: RefTab.Ref _ RefTab.Create[]; -- associates resultPublic to drawnPublic FOR i: NAT IN [0 .. drawnPublic.size) DO EachResultWire: CoreOps.EachWireProc = { resultName: ROPE _ CoreOps.GetShortWireName[wire]; IF NOT Rope.Equal[resultName, drawnName] THEN RETURN; IF wire=resultWire THEN RETURN; IF resultWire#NIL THEN {TerminalIO.PutF["*** Cell %g: Drawn Icon has a wire %g whose name appears more than once in the schematic\n", IO.rope[iconName], IO.rope[drawnName]]; quit _ TRUE; ok _ FALSE; RETURN}; resultWire _ wire; }; drawnWire: Wire _ drawnPublic[i]; drawnName: ROPE _ CoreOps.GetShortWireName[drawnWire]; resultWire: Wire _ NIL; IF drawnName=NIL THEN {TerminalIO.PutF["*** Cell %g: Drawn Icon has an unnamed wire\n", IO.rope[iconName]]; ok _ FALSE; LOOP}; IF CoreOps.VisitWire[resultPublic, EachResultWire] THEN LOOP; IF resultWire=NIL THEN {TerminalIO.PutF["*** Cell %g: Drawn Icon has wire %g that doesn't correspond to any wire in the schematic\n", IO.rope[iconName], IO.rope[drawnName]]; ok _ FALSE; LOOP}; CoreGeometry.PutIndirectLazyPins[mode.decoration, resultWire, drawnWire]; [] _ RefTab.Store[resultToDrawn, resultWire, drawnWire]; ENDLOOP; FOR i: NAT IN [0 .. resultPublic.size) DO resultWire: Wire _ resultPublic[i]; resultName: ROPE _ CoreOps.GetShortWireName[resultWire]; drawnWire: Wire _ NARROW [RefTab.Fetch[resultToDrawn, resultWire].val]; IF resultName=NIL THEN LOOP; IF drawnWire#NIL THEN LOOP; IF RopeList.Memb[globalNames, resultName] THEN LOOP; TerminalIO.PutF["*** Warning in Cell %g: schematic has wire %g that corresponds to no wire in the drawn Icon\n", IO.rope[iconName], IO.rope[resultName]]; ENDLOOP; }; ProcessGlobalName: PROC [record: CellType, name: ROPE] = { globals: Wires; ReplaceSeq: PROC [old: WireSeq] ~ { FOR i: NAT IN [0 .. old.size) DO old[i] _ Replace[old[i]] ENDLOOP; }; Replace: PROC [old: Wire] RETURNS [new: Wire] = { new _ old; -- presumably ... IF old.size#0 THEN FOR i: NAT IN [0 .. old.size) DO new[i] _ Replace[old[i]] ENDLOOP ELSE IF CoreOps.Member[globals, old] THEN new _ global; }; ReplaceAndCleanSeq: PROC [old: WireSeq] RETURNS [new: WireSeq] = { news: Wires _ LIST [global]; FOR i: NAT IN [0 .. old.size) DO new _ Replace[old[i]]; IF NOT CoreOps.Member[news, new] THEN news _ CONS [new, news]; ENDLOOP; new _ CoreOps.CreateWire[news]; }; InsertGlobal: PROC [wire: Wire] = { IF wire.size#0 THEN SIGNAL GlobalNonAtomic[record, name, wire]; IF NOT CoreOps.Member[globals, wire] THEN globals _ CONS [wire, globals]; }; FindGlobals: CoreOps.EachWirePairProc = { publicName: ROPE = CoreOps.GetShortWireName[publicWire]; IF Rope.Equal[publicName, name] THEN { -- a sub global candidate actualName: ROPE = CoreOps.GetShortWireName[actualWire]; IF actualName=NIL OR Rope.Equal[actualName, name] THEN InsertGlobal[actualWire]; }; }; FindWire: CoreOps.EachWireProc = { IF Rope.Equal[CoreOps.GetShortWireName[wire], name] THEN InsertGlobal[wire]; }; rct: CoreClasses.RecordCellType = NARROW [record.data]; global: Wire; FOR i: NAT IN [0..rct.size) DO [] _ CoreOps.VisitBindingSeq[rct[i].actual, rct[i].type.public, FindGlobals]; ENDLOOP; [] _ CoreOps.VisitWireSeq[rct.internal, FindWire]; IF globals=NIL THEN RETURN; IF globals.rest=NIL AND Rope.Equal[CoreOps.GetShortWireName[globals.first], name] AND CoreOps.RecursiveMember[record.public, globals.first] THEN RETURN; -- all right already, nothing to do! global _ CoreOps.SetShortWireName[globals.first, name]; globals _ globals.rest; record.public _ ReplaceAndCleanSeq[record.public]; rct.internal _ ReplaceAndCleanSeq[rct.internal]; FOR i: NAT IN [0..rct.size) DO ReplaceSeq[rct[i].actual] ENDLOOP; WHILE globals#NIL DO Sinix.FuseProperties[mode, globals.first, global, CoreOps.GetCellTypeName[record]]; globals _ globals.rest; ENDLOOP; }; Name: PROC [obj: CD.Object, userData: REF] RETURNS [ROPE] = { cx: Context _ NARROW [userData]; RETURN [CDDirectory.Name[obj, GetDesign[cx]]]; }; Touch: CoreGeometry.TouchProc = { IF instance1.obj.class#CDRects.bareRectClass OR instance2.obj.class#CDRects.bareRectClass THEN ERROR; -- the only thing we know is Rectangles! IF ~SilTouchRect[CoreGeometry.InlineBBox[instance1], CoreGeometry.InlineBBox[instance2]] THEN RETURN; RETURN [CDLayers.AbstractToPaint[instance1.obj.layer]=CDLayers.AbstractToPaint[instance2.obj.layer]]; }; SilTouchRect: PROC [r1, r2: CD.Rect] RETURNS [BOOL] = INLINE { Intersect: PROC [i1min, i1max, i2min, i2max: CD.Number] RETURNS [BOOL] = INLINE { RETURN [(i1max >= i2min) AND (i2max >= i1min)]; }; Adjoin: PROC [i1min, i1max, i2min, i2max: CD.Number] RETURNS [BOOL] = INLINE { RETURN [(i2min >= i1min AND i2min <= i1max AND i2max >= i1max) OR (i1min >= i2min AND i1min <= i2max AND i1max >= i2max)]; }; RETURN [(Intersect[r1.x1, r1.x2, r2.x1, r2.x2] AND Adjoin[r1.y1, r1.y2, r2.y1, r2.y2]) OR (Intersect[r1.y1, r1.y2, r2.y1, r2.y2] AND Adjoin[r1.x1, r1.x2, r2.x1, r2.x2]) OR CDBasics.Inside[r1, r2] OR CDBasics.Inside[r2, r1]] }; GetRef: PROC [cx: Context, var: ROPE] RETURNS [ref: REF] = { val: SymTab.Val _ SymTab.Fetch[cx, var].val; IF val=NIL THEN ERROR; ref _ RefFromTV[val]; }; GetCDObj: PUBLIC PROC [cx: Context] RETURNS [CD.Object] = { RETURN [NARROW [GetRef[cx, cdObjRope]]] }; GetCoreProps: PUBLIC PROC [cx: Context] RETURNS [Properties] = { RETURN [NARROW [GetRef[cx, corePropsRope]]] }; GetCoreInstProps: PUBLIC PROC [cx: Context] RETURNS [Properties] = { RETURN [NARROW [GetRef[cx, coreInstPropsRope]]] }; GetDesign: PUBLIC PROC [cx: Context] RETURNS [CD.Design] = { RETURN [NARROW [GetRef[cx, designRope]]] }; GetGlobalNames: PUBLIC PROC [cx: Context] RETURNS [ROPES] = { RETURN [NARROW [GetRef[cx, globalNamesRope]]] }; RefFromTV: PROC [tv: REF] RETURNS [REF] = { IF tv=NIL THEN RETURN [NIL]; IF ~ISTYPE [tv, AMTypes.TV] THEN ERROR; TRUSTED {RETURN [SELECT AMTypes.UnderClass[AMTypes.TVType[tv]] FROM nil, atom, rope, list, ref => AMBridge.TVToRef[tv], ENDCASE => AMBridge.SomeRefFromTV[tv]]}; }; TVFromRef: PROC [ref: REF] RETURNS [AMTypes.TV] = TRUSTED { RETURN [AMBridge.TVForReferent[ref]]; }; TVEqual: PROC [tv1, tv2: REF] RETURNS [BOOL] = { IF AMTypes.TVEqual[tv1, tv2] THEN RETURN [TRUE]; WITH RefFromTV[tv1] SELECT FROM -- manage standard types not covered by AMTypes rr1: ROPES => WITH RefFromTV[tv2] SELECT FROM rr2: ROPES => RETURN [EqualRopes[rr1, rr2]]; ENDCASE => RETURN [FALSE]; r1: ROPE => WITH RefFromTV[tv2] SELECT FROM r2: ROPE => RETURN [Rope.Equal[r1, r2]]; ENDCASE => RETURN [FALSE]; ENDCASE => RETURN [FALSE]; }; PutCoreProps: PROC [onto, from: Properties] RETURNS [new: Properties] = { PutProp: PROC [prop: ATOM, val: REF ANY] = { new _ CoreProperties.PutProp[new, prop, val]; }; new _ onto; CoreProperties.Enumerate[from, PutProp]; }; StripCellTypeName: PROC [cellType: CellType, dropPart: ROPE] = { [] _ CoreOps.SetCellTypeName[cellType, CDNameToCTName[CoreOps.GetCellTypeName[cellType], dropPart]]; }; CDNameToCTName: PROC [cdName, dropPart: ROPE] RETURNS [ctName: ROPE] = { ctName _ Rope.Substr[cdName, 0, Rope.Index[cdName, 0, dropPart]]; }; DefaultUserData: PROC [design: CD.Design] RETURNS [REF] ~ { RETURN [Create[design]]; }; ParseRope: PUBLIC PROC [rope: ROPE] RETURNS [tokenKind: IO.TokenKind, token, rest: ROPE] = { ENABLE { IO.Error => GOTO Error; IO.EndOfStream => GOTO EOF; }; stream: IO.STREAM _ IO.RIS[rope]; charsSkipped1: INT _ IO.SkipWhitespace[stream]; ampersand: BOOL _ IO.PeekChar[stream]='&; charsSkipped2: INT; IF ampersand THEN {[] _ IO.GetChar[stream]; charsSkipped1 _ charsSkipped1 + 1}; [tokenKind, token, charsSkipped2] _ IO.GetCedarTokenRope[stream]; rest _ Rope.Substr[rope, charsSkipped1+charsSkipped2+Rope.Length[token]]; IF ampersand THEN { IF tokenKind=tokenID THEN token _ Rope.Cat["&", token] ELSE GOTO Error; TerminalIO.PutF["*** Variable name starting with &: %g.\n", IO.rope[token]]; }; EXITS Error => RETURN [tokenERROR, NIL, NIL]; EOF => RETURN [tokenEOF, NIL, NIL]; }; IsParsedID: PUBLIC PROC [tokenKind: IO.TokenKind, token, id: ROPE] RETURNS [BOOL] = { RETURN [tokenKind=tokenID AND Rope.Equal[token, id]]; }; IsParsedChar: PUBLIC PROC [tokenKind: IO.TokenKind, token: ROPE, char: CHAR] RETURNS [BOOL] = { RETURN [tokenKind=tokenSINGLE AND Rope.Fetch[token]=char]; }; EvaluateParameters: PUBLIC PROC [userData: REF, obj: CD.Object, properties: CD.PropList] RETURNS [cx: Context] = { EvalExprs: PROC [exprs: ROPES, inst: BOOL] = { WHILE exprs#NIL DO expr: ROPE _ exprs.first; tokenKind1, tokenKind2: IO.TokenKind; token1, token2, rest: ROPE; [tokenKind1, token1, rest] _ ParseRope[expr]; [tokenKind2, token2, rest] _ ParseRope[rest]; SELECT TRUE FROM tokenKind1=tokenID AND IsParsedChar[tokenKind2, token2, '_] => EvalExpr[cx, token1, rest]; tokenKind1=tokenID AND IsParsedChar[tokenKind2, token2, ':] => AddProp[cx, Convert.AtomFromRope[token1], rest, inst]; tokenKind1=tokenID AND IsParsedChar[tokenKind2, token2, '~] => EvalExpr[cx, token1, rest, FALSE]; Rope.Find[expr, "_"]>=0 OR Rope.Find[expr, ":"]>=0=> { TerminalIO.PutF["*** Old syntax in %g: Side effect in '%g'.\n", IO.rope[Name[obj, userData]], IO.rope[expr]]; Eval[cx, expr]; }; ENDCASE => { previousName: ROPE _ NARROW [CoreProperties.GetProp[(IF inst THEN GetCoreInstProps ELSE GetCoreProps)[cx], CoreOps.nameProp]]; IF previousName#NIL AND NOT Rope.Equal[previousName, expr] THEN { TerminalIO.PutF["*** Error in object '%g': Conflicting names '%g' and '%g' [probably two satellites].\n", IO.rope[Name[obj, cx]], IO.rope[previousName], IO.rope[expr]]; ERROR; }; IF Rope.Find[expr, " "]>=0 THEN TerminalIO.PutF["*** Warning in %g: name contains space '%g'.\n", IO.rope[Name[obj, userData]], IO.rope[expr]]; AddPropInternal[cx, CoreOps.nameProp, expr, inst]; }; exprs _ exprs.rest; ENDLOOP; }; cx _ Copy[NARROW [userData]]; Store[cx, cdObjRope, NEW [CD.Object _ obj]]; CDSequencer.CheckAborted[GetDesign[cx]]; EvalExprs[NARROW [CDProperties.GetObjectProp[obj, expressionsProp]], FALSE]; EvalExprs[NARROW [CDProperties.GetObjectProp[obj, Sinix.satellitesProp]], FALSE]; EvalExprs[NARROW [CDProperties.GetListProp[properties, expressionsProp]], TRUE]; EvalExprs[NARROW [CDProperties.GetListProp[properties, Sinix.satellitesProp]], TRUE]; }; ProcessGlobalNames: PUBLIC PROC [record: CellType, cx: Context] = { FOR names: ROPES _ GetGlobalNames[cx], names.rest WHILE names#NIL DO ProcessGlobalName[record, names.first]; ENDLOOP; }; ExtractSchematic: PRIVATE Sinix.ExtractProc = { cx: Context; resultVar, resultExpr: ROPE; [cx, resultVar, resultExpr] _ OldEvaluateParameters[userData, obj, properties, IsResultVar]; SELECT TRUE FROM Rope.Equal[resultVar, "cI"] => { cellType: CellType; EvalExpr[cx, resultVar, resultExpr, FALSE]; cellType _ ExtractCellIconInternal[obj, cx]; TerminalIO.PutF["*** Old syntax for cell icon in %g: '%g _%g'. Convert!\n", IO.rope[Name[obj, userData]], IO.rope[resultVar], IO.rope[resultExpr]]; cellType.properties _ PutCoreProps[cellType.properties, GetCoreProps[cx]]; result _ cellType; props _ GetCoreInstProps[cx]; }; Rope.Equal[resultVar, "wI"] => { wire: Wire; EvalExpr[cx, resultVar, resultExpr, FALSE]; wire _ ExtractNamedWireIconInternal[obj, cx]; TerminalIO.PutF["*** Old syntax for named wire icon in %g: '%g _%g'. Convert!\n", IO.rope[Name[obj, userData]], IO.rope[resultVar], IO.rope[resultExpr]]; wire.properties _ PutCoreProps[wire.properties, GetCoreProps[cx]]; result _ wire; props _ GetCoreInstProps[cx]; }; Rope.Equal[resultVar, "wire"] => ERROR; ENDCASE => { cellType: CellType; result _ Sinix.ExtractCell[obj, mode, properties, cx].result; cellType _ NARROW [result]; ProcessGlobalNames[cellType, cx]; cellType.properties _ PutCoreProps[cellType.properties, GetCoreProps[cx]]; StripCellTypeName[cellType, ".sch"]; props _ GetCoreInstProps[cx]; }; }; ExtractCellIconInternal: PROC [icon: CD.Object, cx: Context] RETURNS [cellType: CellType] = { iconName: ROPE = Name[icon, cx]; iconCT: CellType _ NARROW [Sinix.ExtractCell[icon, mode, NIL, cx].result]; cellType _ NARROW [GetRef[cx, "cI"]]; IF cellType=NIL THEN { cellType _ CoreOps.CreateCellType[class: CoreClasses.unspecifiedCellClass, public: iconCT.public, name: CDNameToCTName[iconName, ".icon"]]; } ELSE { name: ROPE _ CoreOps.GetCellTypeName[cellType]; IF name=NIL THEN name _ CDNameToCTName[iconName, ".icon"]; cellType _ Sinix.CreateIcon[cellType: cellType, name: name]; }; CoreGeometry.PutObject[mode.decoration, cellType, icon]; IF NOT CheckAndDecorate[iconName, icon, iconCT.public, cellType.public, GetGlobalNames[cx]] THEN { TerminalIO.PutF["*** Error: icon public and schematic public for cell icon %g do NOT conform\n", IO.rope[iconName]]; TerminalIO.PutF["Icon public is:"]; CoreOps.PrintWire[wire: iconCT.public, out: TerminalIO.TOS[], level: LAST [NAT]]; TerminalIO.PutF["\nSchematic public is:"]; CoreOps.PrintWire[wire: cellType.public, out: TerminalIO.TOS[], level: LAST [NAT]]; TerminalIO.PutF["\n"]; ERROR } }; ExtractNamedWireIconInternal: PROC [icon: CD.Object, cx: Context] RETURNS [result: Wire] = { iconName: ROPE = Name[icon, cx]; iconCT: CellType _ NARROW [Sinix.ExtractCell[icon, mode, NIL, cx].result]; result _ NARROW [GetRef[cx, "wI"]]; IF result=NIL THEN ERROR; IF iconCT.public.size=1 THEN { CoreGeometry.PutPins[mode.decoration, result, CoreGeometry.GetPins[mode.decoration, iconCT.public[0]]]; RETURN; }; IF ~CheckAndDecorate[iconName, icon, iconCT.public, CoreOps.CreateWire[LIST [result]]] THEN { TerminalIO.PutF["*** Error: icon wire and result wire for wire icon %g don't conform\n", IO.rope[iconName]]; TerminalIO.PutF["Icon wire is:"]; CoreOps.PrintWire[wire: iconCT.public, out: TerminalIO.TOS[], level: LAST [NAT]]; TerminalIO.PutF["\nResult wire is:"]; CoreOps.PrintWire[wire: result, out: TerminalIO.TOS[], level: LAST [NAT]]; TerminalIO.PutF["\n"]; ERROR } }; IsResultVarProc: TYPE = PROC [var: ROPE] RETURNS [BOOL]; IsResultVar: IsResultVarProc = { RETURN [Rope.Equal[var, "cI"] OR Rope.Equal[var, "wI"] OR Rope.Equal[var, "wire"]]; }; OldEvaluateParameters: PROC [userData: REF, obj: CD.Object, properties: CD.PropList, isResultVar: IsResultVarProc _ NIL] RETURNS [cx: Context, resultVar, resultExpr: ROPE _ NIL] = { EvalExprs: PROC [exprs: ROPES, inst: BOOL] = { tempResultVar, tempResultExpr: ROPE _ NIL; WHILE exprs#NIL DO expr: ROPE _ exprs.first; tokenKind1, tokenKind2: IO.TokenKind; token1, token2, rest: ROPE; [tokenKind1, token1, rest] _ ParseRope[expr]; [tokenKind2, token2, rest] _ ParseRope[rest]; SELECT TRUE FROM tokenKind1=tokenID AND isResultVar#NIL AND isResultVar[token1] => { IF tempResultVar#NIL THEN {TerminalIO.PutF["*** Error: multiple result expressions encountered: '%g' and '%g'.\n", IO.rope[expr], IO.rope[tempResultVar]]; ERROR}; IF NOT IsParsedChar[tokenKind2, token2, '_] AND NOT IsParsedChar[tokenKind2, token2, ':] THEN {TerminalIO.PutF["*** Error: result expression has wrong syntax: '%g'.\n", IO.rope[expr]]; ERROR}; tempResultVar _ token1; tempResultExpr _ rest; }; inst AND IsParsedID[tokenKind1, token1, "name"] AND IsParsedChar[tokenKind2, token2, '_] => { tokenKind: IO.TokenKind; token, rr: ROPE; [tokenKind, token, rr] _ ParseRope[rest]; IF tokenKind=tokenROPE THEN TerminalIO.PutF["*** Old syntax in %g: Use an expression or a satellite %g instead of '%g'.\n", IO.rope[Name[obj, userData]], IO.rope[token], IO.rope[expr]] ELSE TerminalIO.PutF["*** Old syntax in %g: Use 'CoreName: %g' instead of '%g'.\n", IO.rope[Name[obj, userData]], IO.rope[rest], IO.rope[expr]]; AddProp[cx, CoreOps.nameProp, rest, inst]; }; tokenKind1=tokenID AND IsParsedChar[tokenKind2, token2, '_] => EvalExpr[cx, token1, rest]; tokenKind1=tokenID AND IsParsedChar[tokenKind2, token2, ':] => AddProp[cx, Convert.AtomFromRope[token1], rest, inst]; tokenKind1=tokenID AND IsParsedChar[tokenKind2, token2, '~] => EvalExpr[cx, token1, rest, FALSE]; Rope.Find[expr, "_"]>=0 OR Rope.Find[expr, ":"]>=0=> { TerminalIO.PutF["*** Old syntax in %g: Side effect in '%g'.\n", IO.rope[Name[obj, userData]], IO.rope[expr]]; Eval[cx, expr]; }; ENDCASE => { previousName: ROPE _ NARROW [CoreProperties.GetProp[(IF inst THEN GetCoreInstProps ELSE GetCoreProps)[cx], CoreOps.nameProp]]; IF previousName#NIL AND NOT Rope.Equal[previousName, expr] THEN { TerminalIO.PutF["*** Error in object '%g': Conflicting names '%g' and '%g' [probably two satellites].\n", IO.rope[Name[obj, cx]], IO.rope[previousName], IO.rope[expr]]; ERROR; }; IF Rope.Find[expr, " "]>=0 THEN TerminalIO.PutF["*** Warning in %g: name contains space '%g'.\n", IO.rope[Name[obj, userData]], IO.rope[expr]]; AddPropInternal[cx, CoreOps.nameProp, expr, inst]; }; exprs _ exprs.rest; ENDLOOP; IF tempResultVar#NIL THEN {resultVar _ tempResultVar; resultExpr _ tempResultExpr}; }; cx _ Copy[NARROW [userData]]; Store[cx, cdObjRope, NEW [CD.Object _ obj]]; CDSequencer.CheckAborted[GetDesign[cx]]; EvalExprs[NARROW [CDProperties.GetObjectProp[obj, expressionsProp]], FALSE]; EvalExprs[NARROW [CDProperties.GetObjectProp[obj, Sinix.satellitesProp]], FALSE]; EvalExprs[NARROW [CDProperties.GetListProp[properties, expressionsProp]], TRUE]; EvalExprs[NARROW [CDProperties.GetListProp[properties, Sinix.satellitesProp]], TRUE]; }; GlobalNonAtomic: PUBLIC SIGNAL [record: CellType, name: ROPE, wire: Wire] = CODE; InterpreterError: PUBLIC SIGNAL [cx: Context, var, expr, errorRope: ROPE] = CODE; Sinix.RegisterExtractProc[$SisyphExtractSchematic, ExtractSchematic]; Sinix.RegisterExtractProc[$SisyphExtractCellIcon, ExtractCellIcon]; Sinix.RegisterExtractProc[$SisyphExtractNamedWireIcon, ExtractNamedWireIcon]; Sinix.RegisterExtractProc[$SisyphExtractUnNamedWireIcon, ExtractUnNamedWireIcon]; Sinix.RegisterExtractProc[$SisyphExtractWire, ExtractWire]; Sinix.RegisterExtractProc[$SisyphExtractImport, ExtractImport]; CDProperties.PutProp[CDCells.pCellClass, mode.extractProcProp, $SisyphExtractSchematic]; CDProperties.PutProp[CDRects.bareRectClass, mode.extractProcProp, $SisyphExtractWire]; CDProperties.PutProp[CDTexts.rigidTextClass, mode.extractProcProp, $ExtractNull]; CDProperties.PutProp[CDTexts.flipTextClass, mode.extractProcProp, $ExtractNull]; CDProperties.PutProp[CDImports.importsClass, mode.extractProcProp, $SisyphExtractImport]; END. VSisyphImpl.mesa Copyright Σ 1985, 1986, 1987 by Xerox Corporation. All rights reserved. Created by Sindhu and Serlet, November 27, 1985 9:11:39 pm PDT Pradeep Sindhu June 25, 1987 4:59:16 pm PDT Barth, October 15, 1986 10:25:34 am PDT Bertrand Serlet, September 16, 1987 4:15:58 pm PDT Jean-Marc Frailong December 7, 1987 5:49:03 pm PST Christian Jacobi, July 15, 1986 6:24:40 pm PDT Don Curry May 7, 1987 10:30:40 pm PDT Constants and Variables name of Sisyph variable that holds the ChipNDale design. name of Sisyph variable that represents a list of names of global wires. name of Sisyph variable that holds the CD object being extracted. ExtractProcs Check public special case Special case mostly for compatibility IF obj.layer#CD.commentLayer THEN IF CDLayers.Kind[obj.layer]#paint OR CD.LayerTechnology[obj.layer]#NIL THEN ERROR; Once we get rid of "wire _ ..." we can avoid Evaluating the context, by just evaluating the coreInstProps. Things will gho much, much faster! Context Handling Procedures Copy: PUBLIC PROC [oldCx: Context] RETURNS [cx: Context] = { Old version that copies TVs. TVs should now be immutable... (needs to be checked...) CopyItem: SymTab.EachPairAction = { [] _ SymTab.Store[cx, key, AMTypes.Copy[val]]; }; cx _ SymTab.Create[(SymTab.GetSize[oldCx]/2)*2+3]; -- and Odd size, at least as big as oldCx [] _ SymTab.Pairs[oldCx, CopyItem]; Store[cx, corePropsRope, NEW [Properties _ NIL]]; Store[cx, coreInstPropsRope, NEW [Properties _ NIL]]; Store[cx, cdObjRope, NEW [CD.Object _ NIL]]; }; Conventions are the parmNames=LIST["0"] ==> no parameters at all Returns TRUE iff a is a subset of b, parmNames is always NIL in this routine If its a local variable then return right away It is a potential parameter. Check if its there in the context and equal Handle zero parameters as a special case Conveniences Utilities for the implementation Construct the association by searching in resultPublic for every name found in drawnPublic We decorate the resultWire with the pins of drawnWire Ensure that each resultPublic corresponds to some iconic Wire (apart may be from the wires in globalNames). Warning only for those. The algorithm is: - globals _ list of wires in internal/public to be identified with global `name' Identified by looking up the internal by name and the 1st levels bindings by name of the internal and actual simultaneously (actual may be unnamed) - if there is a single such wire, it has the right name and is public, then we're done - define the 1st elem of globals to be the new single wire representing `name' - cleanup public, internal and 1st level actuals - public and internal may change size (extra copies of the global are removed, global is forced to be public) - 1st level actuals cannot change sizes - merge properties of all other representative of global into it IF instance1.obj.layer=instance2.obj.layer THEN RETURN [TRUE]; more cases could be added in the SELECT statement, but some are not necessary (for example REF INT, due to the behavior of AMTypes.TVEqual). Semi-public Utilities Compatibility code We are trying to get rid of these ones, do not use them! This was the top-level extract proc. It evaluates the arguments to the schematic and then calls either ExtractCellIconInternal or Sinix.ExtractCell to do its job. High risk code here: it costed BS 3 days of debugging. The problem is that since Sinix.ExtractCell caches its result, some instances might have been created earlier with the returned cellType, and so it is incorrect to modify it in place. Therefore ProcessGlobalNames must not change the cellType when all the work has already been done. Properties are a bit funny too, and this code assumes that all cellType properties come from object expression/satellite, but not from an instance expression/satellite. Therefore it is incorrect to put "coreProps _ ..." as an instance satellite. This proc is called for cell icons. If a core definition is found then it is returned, otherwise a core cell of class Unspecified is returned. Compute core for the schematic Check public This proc is called for wire icons. If a core definition is found it is returned, otherwise an error is signalled. As for cell icons, pins provide the attatchment points to the wire. Check wire special case Tells if this variable is a result variable. following token must be ': or '_ (': is a hack for the sequence stuff) Exceptions Module Initialization Κ&{˜šœ™JšœH™HIcodešœ;Οk™>Kšœ(™+Kšœ$™'Kšœ2™2Kšœ2™2Kšœ+™.Kšœ"™%J˜—š ˜ Kšœœœ˜0Kšœ œ5˜CKšœœ ˜Kšœœ˜&Kšœ„˜†K˜ K˜+K˜ Kšœ˜Kšœ œ ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—J˜šΟn œœœ˜Jšœέœœ4˜­Jšœ˜Jšœ/˜5Jšœœ ˜—head™š œœœœ"œ˜IK˜—šœ œœ ˜$K™8—šœœœ˜.K™H—Kšœœœ˜)Kšœœœ˜1šœ œœ ˜"Kšœ'œ™AK˜—šœœœN˜oK˜—Kš œœœœ œ˜Ešœœœœ%˜LJ˜—šœœœ˜0Jšœœ"œ˜;Jšœ4˜4Jšœ!˜!Jšœ˜Jšœ*˜*Jšœ˜Jšœ˜Jšœ˜J˜J˜——šœ ™ šž œœœœ œ œœ˜fJšœ œœ2˜HJšœ œœ2˜HJšœ œœ œ-˜QJšœ œœ œ-˜Qšœœ˜Jš œœœ œœΟc˜=šœœ ˜Jšœ ˜ š œœœœœ˜*Jšœ˜Jšœ˜Jšœ˜Jšœœ˜—J˜—Jšœœœ˜.Jšœ œŸ*˜C—J˜J˜—šžœœ˜-Jšœ<˜œ˜MJ˜ JšœH˜HJšœœ ˜J˜(J˜J˜—šž œ˜"J˜ Jšœ ˜ Jšœœ˜Jšœ!œœ˜/Jšœ œœœ˜)šΠbkΟb  ‘ ‘™"Jš  ‘  ‘ ‘ ‘ ‘ ‘™R—JšœŽ™ŽJšœ]˜]šœ œ˜Jšœ˜!Jšœ˜Kšœ$œ˜+Jšœœ˜#Jšœmœ˜‚Jšœ˜—Jšœ,œ ˜:JšœF˜FJ˜Jšœ˜J™—šž œ˜$Kšœœ ˜ Kšœœ˜"Kšœ#œ˜9Jšœ!˜!š œœœœœ˜6KšœœsœœNœœœ˜‘Kšœœœœœ=œœœ˜±K˜—Kšœr˜xK˜K˜—š  œžœœœœœ˜XKšœœ˜"Kšœœ1˜8Kš œœœMœ œœ˜‰Kšœœ2œ˜\Kšœ˜——™š žœœœ œœœ˜\šžœœ œ˜(šœœ˜Kšœœ˜Kšœœ"œ˜AKšœ-˜-Kšœ-˜-šœœ˜KšœœD˜ZKšœœDœ˜ašœ˜ Kšœ\œ ˜kKšœ˜K˜——Kšœ˜Kšœ˜—K˜—Kš œœ œœœ˜DKšœœœ˜0Kšœœœ˜>Kšœœ8˜NKšœ8˜8Kšœ˜K˜—šžœœœœ™Kšœ ˜ šœ'˜'Kšœ3˜3Kšœ˜—Kšœ œ˜Kšœ˜—Kšœ œœœ˜Kšœœ˜2Kšœ˜K˜—š ž œœ œœœ˜KKšœœ™@šžœœœœ˜1Kšœœ@™Lšžœ˜)Kšœœ˜Kš œœœœœŸ ˜@K™.Kšœ)œœœ˜?K™HK˜%Jš œœœœœœ˜7K˜—Kšœœ"˜-Kšœ˜—šœœ˜Kšœ œœŸ˜(Kšœ œœœŸ˜YKš œœœ%œœŸ˜ZšœŸ-˜:Kšœœ˜Kšœœ˜š œœœœ˜8Kšœ/˜/Kšœ/˜/KšœœœŸ&˜DKšœœœ˜Kš œœœœŸ˜AKš œœœœœœŸ˜IKšœ˜—KšœœŸ˜(Kšœ˜——šœ˜K˜——šž œœœ œœœœœœ˜mKšœ œœ1˜JKšœ œœ6˜NKšœ œœ6˜MKšœ œœ1˜JKšœ œœ6˜NKšœ œœ6˜MKšœ œœ2˜KKšœœœœ˜)Kšœœ"œœ œœœ˜bK™(Kš œ œœ"œœœ˜IKšœœœœ˜7Kšœ˜K˜—šž œœœœœœœ˜IKšœ œœ2˜KKš œ œœ"œœœ˜IKšœœœ˜=Kšœ˜——™ š ž œœœœœœ˜Bš œœœœ˜/Kš œœ!œœœ˜;Kšœ˜ —š œœœœ˜/Kš œœ!œœœ˜;Kšœ˜ —Kšœœ˜˜K˜——šžœœœœœœœ˜;Kšœœ ˜Kšœ˜K˜—šžœœœœœœœœ˜UKšœœœœ ˜$Kšœœœœ ˜$Kšœœœœ ˜$Kšœœœœ ˜$Kšœœœœ ˜$Kšœœœœ ˜$J˜——™ š’œœ œœ:œœœœœ˜”Kšœ-Ÿ)˜VKšœZ™Zšœœœ˜(šžœ˜(Kšœ œ"˜2Kšœœ#œœ˜5Kšœœœ˜Kšœ œœpœœœœœ˜ΟKšœ˜K˜—Jšœ!˜!Kšœ œ'˜6Kšœœ˜Jš œ œœCœœœ˜~Kšœ1œœ˜=Kšœ œœpœœœœ˜ΐKšœ5™5KšœI˜IKšœ8˜8Jšœ˜—Kšœ„™„šœœœ˜)Jšœ#˜#Kšœ œ(˜8Kšœœ/˜GJšœ œœœ˜Jšœ œœœ˜Jšœ(œœ˜4Jšœqœœ˜šJšœ˜—K˜K˜—šžœœœ˜:™™PJ™“—J™VJ™N™0J™mJ™'—J™@—Jšœ˜šž œœ˜#Jš œœœœœ˜BJ˜—šžœœ œ˜1Jšœ Ÿ˜Jš œ œœœœœ˜TKšœœœ˜7J˜—šžœœœ˜BJšœœ ˜šœœœ˜ Jšœ˜Jšœœœœ ˜>Jšœ˜—Jšœ˜J˜—šž œœ˜#Jšœ œœ%˜?Jšœœœ œ˜IJ˜—šž œ˜)Jšœ œ(˜8šœœŸ˜@Jšœ œ(˜8Jšœ œœœ˜PJ˜—J˜—šžœ˜"Jšœ2œ˜LJ˜—Jšœ"œ˜7Jšœ ˜ šœœœ˜JšœM˜MJšœ˜—Jšœ2˜2Jšœ œœœ˜Jš œœœ;œ7œœŸ$˜½Jšœ7˜7Jšœ˜Jšœ2˜2Jšœ0˜0Jš œœœœœ˜Ašœ œ˜JšœS˜SJ˜Jšœ˜—J˜J˜—š žœœœœœœ˜=Jšœœ ˜ Jšœ(˜.J˜J˜—š’œ˜!Jš œ+œ+œœŸ(˜ŽJšœWœœ˜eJš ‘) ‘ ‘ ‘™>Jšœ_˜eJšœ˜J˜—š ž œœ œœœœ˜>š ž œœœ œœœ˜QJšœœ˜/J˜—š žœœœ œœœ˜Nšœœœ˜AJšœœœ˜9—J˜—Jš œ)œ%œ(œ%œœ˜ίJšœ˜K˜—š žœœœœœ˜