DIRECTORY Basics, BitOps, Convert, CoreClasses, CoreFlat, CoreOps, CoreProperties, IO, RefTab, Rope; CoreFlatImpl: CEDAR PROGRAM IMPORTS Basics, BitOps, Convert, CoreClasses, CoreOps, CoreProperties, IO, RefTab, Rope EXPORTS CoreFlat = BEGIN OPEN CoreFlat; PathError: PUBLIC ERROR [msg: ROPE _ NIL] = CODE; MakeError: PROC [m: ROPE _ NIL] = { IF m=NIL THEN m _ "parse failed"; ERROR PathError[m]; }; cutLabelProp: ATOM _ CoreProperties.RegisterProperty[$CoreCutLabel]; CellInstanceCutLabels: PUBLIC PROC [on: CellInstance, l1, l2, l3, l4, l5, l6: ROPE _ NIL] RETURNS [same: CellInstance] = { same _ CellInstanceCutLabelList[on, LabelList[l1, l2, l3, l4, l5, l6]] }; CellInstanceCutLabelList: PUBLIC PROC [on: CellInstance, labels: LIST OF ROPE] RETURNS [same: CellInstance] = { lbls: LIST OF ROPE _ NARROW[CoreProperties.GetCellInstanceProp[on, cutLabelProp]]; lbls _ CombineLabelLists[lbls, labels]; CoreProperties.PutCellInstanceProp[on, cutLabelProp, lbls]; same _ on; }; CellTypeCutLabels: PUBLIC PROC [on: CellType, l1, l2, l3, l4, l5, l6: ROPE _ NIL] RETURNS [same: CellType] = { same _ CellTypeCutLabelList[on, LabelList[l1, l2, l3, l4, l5, l6]] }; CellTypeCutLabelList: PUBLIC PROC [on: CellType, labels: LIST OF ROPE] RETURNS [same: CellType] = { lbls: LIST OF ROPE _ NARROW[CoreProperties.GetCellTypeProp[on, cutLabelProp]]; lbls _ CombineLabelLists[lbls, labels]; CoreProperties.PutCellTypeProp[on, cutLabelProp, lbls]; same _ on; }; CellClassCutLabels: PUBLIC PROC [on: CellClass, l1, l2, l3, l4, l5, l6: ROPE _ NIL] RETURNS [same: CellClass] = { same _ CellClassCutLabelList[on, LabelList[l1, l2, l3, l4, l5, l6]] }; CellClassCutLabelList: PUBLIC PROC [on: CellClass, labels: LIST OF ROPE] RETURNS [same: CellClass] = { lbls: LIST OF ROPE _ NARROW[CoreProperties.GetCellClassProp[on, cutLabelProp]]; lbls _ CombineLabelLists[lbls, labels]; CoreProperties.PutCellClassProp[on, cutLabelProp, lbls]; same _ on; }; CreateCutSet: PUBLIC PROC [instances, cellTypes, cellClasses, labels: LIST OF ROPE _ NIL, flatCells: FlatCellTypes _ NIL, flatten: FlatCellTypes _ NIL, change: FlatCellTypeCutSets _ NIL] RETURNS [cutSet: CutSet] = { cutSet _ NEW[CutSetRec _ [ instances: instances, cellTypes: cellTypes, cellClasses: cellClasses, labels: labels, flatCells: flatCells, flatten: flatten, change: change]]; }; CutSetMember: PUBLIC PROC [root: CellType, flatCell: FlatCellTypeRec, cutSet: CutSet] RETURNS [member: BOOL _ FALSE] = { parent: CellType; instance: CellInstance; cellType: CellType; [parent, instance, cellType] _ ResolveFlatCellType[root, flatCell]; member _ CutSetMemberResolved[flatCell, instance, cellType, cutSet] }; CutSetMemberResolved: PUBLIC PROC [flatCell: FlatCellTypeRec, instance: CellInstance, cellType: CellType, cutSet: CutSet] RETURNS [member: BOOL _ FALSE] = { name: ROPE _ NIL; IF cellType.class=CoreClasses.transistorCellClass OR cellType.class=CoreClasses.unspecifiedCellClass THEN RETURN[TRUE]; IF cutSet=NIL THEN RETURN[FALSE]; FOR cl: FlatCellTypeCutSets _ cutSet.change, cl.rest UNTIL cl=NIL DO IF flatCell.path.length >= cl.first.flatCell.path.length THEN { FOR i: InstancePathIndex IN [0..cl.first.flatCell.path.length) DO IF flatCell.path.bits[i]#cl.first.flatCell.path.bits[i] THEN EXIT; REPEAT FINISHED => RETURN[CutSetMemberResolved[flatCell, instance, cellType, cl.first.cutSet]]; ENDLOOP; }; ENDLOOP; FOR flats: FlatCellTypes _ cutSet.flatten, flats.rest UNTIL flats=NIL DO IF FlatCellTypeEqualRec[flats.first^, flatCell] THEN RETURN[FALSE]; ENDLOOP; FOR flats: FlatCellTypes _ cutSet.flatCells, flats.rest UNTIL flats=NIL DO IF FlatCellTypeEqualRec[flats.first^, flatCell] THEN RETURN[TRUE]; ENDLOOP; IF instance#NIL THEN { name _ CoreClasses.GetCellInstanceName[instance]; IF name#NIL THEN IF OneInOther[LIST[name], cutSet.instances] THEN RETURN [TRUE]; }; name _ CoreOps.GetCellTypeName[cellType]; IF name#NIL THEN IF OneInOther[LIST[name], cutSet.cellTypes] THEN RETURN [TRUE]; IF OneInOther[LIST[cellType.class.name], cutSet.cellClasses] THEN RETURN [TRUE]; IF instance#NIL THEN IF OneInOther[NARROW[CoreProperties.GetCellInstanceProp[instance, cutLabelProp]], cutSet.labels] THEN RETURN [TRUE]; IF OneInOther[NARROW[CoreProperties.GetCellTypeProp[cellType, cutLabelProp]], cutSet.labels] THEN RETURN [TRUE]; IF OneInOther[NARROW[CoreProperties.GetCellClassProp[cellType.class, cutLabelProp]], cutSet.labels] THEN RETURN [TRUE]; }; OneInOther: PROC [one, other: LIST OF ROPE] RETURNS [yes: BOOL _ FALSE] = { FOR this: LIST OF ROPE _ one, this.rest UNTIL this=NIL DO FOR that: LIST OF ROPE _ other, that.rest UNTIL that=NIL DO IF Rope.Equal[CoreOps.FixStupidRef[this.first], CoreOps.FixStupidRef[that.first]] THEN RETURN[TRUE]; ENDLOOP; ENDLOOP; }; LabelList: PROC [l1, l2, l3, l4, l5, l6: ROPE _ NIL] RETURNS [labels: LIST OF ROPE _ NIL] = { IF l1#NIL THEN labels _ CONS[l1, labels]; IF l2#NIL THEN labels _ CONS[l2, labels]; IF l3#NIL THEN labels _ CONS[l3, labels]; IF l4#NIL THEN labels _ CONS[l4, labels]; IF l5#NIL THEN labels _ CONS[l5, labels]; IF l6#NIL THEN labels _ CONS[l6, labels]; }; CombineLabelLists: PROC [l1, l2: LIST OF ROPE _ NIL] RETURNS [combined: LIST OF ROPE] = { combined _ l1; FOR lbls: LIST OF ROPE _ l2, lbls.rest UNTIL lbls=NIL DO combined _ CONS[lbls.first, combined]; ENDLOOP; }; ParseInstancePath: PUBLIC PROC [root: CellType, pathRope: ROPE, cutSet: CutSet] RETURNS [path: InstancePath] = { instance: CellInstance; within: CellType; token: ROPE; ts: IO.STREAM; firstChar: CHAR; tokenKind: IO.TokenKind; [path, instance, within, token, ts, firstChar, tokenKind] _ ParsePartialInstancePath[root, pathRope, cutSet]; path _ AddInstance[path, instance, within]; CheckNoMore[ts, firstChar, tokenKind]; }; InstancePathRope: PUBLIC PROC [root: CellType, path: InstancePath] RETURNS [pathRope: ROPE _ NIL] = { AppendName: UnboundFlatCellProc = { IF instance#NIL AND cell=instance.type THEN { name: ROPE _ CoreClasses.GetCellInstanceName[instance]; IF name=NIL THEN { cellTypeName: ROPE _ CoreOps.InheritCellTypeName[instance.type]; name _ Convert.RopeFromInt[CoreClasses.InstanceIndex[parent, instance]]; IF cellTypeName#NIL THEN name _ Rope.Cat[name, "(", cellTypeName, ")"]; }; pathRope _ Rope.Cat[pathRope, "/", name]; }; NextUnboundCellType[cell, target, flatCell, instance, index, parent, flatParent, data, AppendName]; }; AppendName[root, [path, 0]]; }; InstancePathEqual: PUBLIC PROC [one, other: InstancePath] RETURNS [equal: BOOL] = { equal _ one.length=other.length AND one.bits=other.bits; }; InstancePathHash: PUBLIC PROC [path: InstancePath] RETURNS [hash: CARDINAL _ 0] = { bits: BitOps.BitQWord _ BitOps.QuadShift[LOOPHOLE[path.bits], path.length-64]; FOR i: NAT IN [0..4) DO hash _ Basics.BITXOR[hash, bits[i]]; ENDLOOP; }; AddInstance: PUBLIC PROC [currentPath: InstancePath, instance: CoreClasses.CellInstance, parent: CellType] RETURNS [newPath: InstancePath] = { newPath _ currentPath; IF instance#NIL THEN { withinCT: CellType _ CoreOps.ToBasic[parent]; withinRCT: CoreClasses.RecordCellType _ NARROW[withinCT.data]; index: NAT _ CoreClasses.InstanceIndex[withinCT, instance]; IF index=-1 THEN ERROR; -- instance not found in parent CellType newPath _ ExtendPath[currentPath, index, withinRCT]; }; }; ExtendPath: PUBLIC PROC [currentPath: InstancePath, index: NAT, rct: CoreClasses.RecordCellType] RETURNS [newPath: InstancePath] = { pathBits: NAT _ BitOps.NBits[rct.size]; newPath _ currentPath; FOR bit: NAT IN [0..pathBits) DO newPath.bits[newPath.length+bit] _ BitOps.EBFW[index, bit, pathBits]; ENDLOOP; newPath.length _ newPath.length + pathBits; }; BindInstance: PUBLIC PROC [parent: FlatCellTypeRec, actual, public: WireSeq, bindings: Bindings] RETURNS [newBindings: Bindings] = { BindPublicToActual: CoreOps.EachWirePairProc = { bind: FlatWire _ NIL; IF bindings#NIL THEN bind _ NARROW [RefTab.Fetch[x: bindings, key: actualWire].val]; [] _ RefTab.Store[x: newBindings, key: publicWire, val: IF bind=NIL THEN NEW[FlatWireRec _ [flatCell: parent, wire: actualWire]] ELSE bind]; }; newBindings _ RefTab.Create[public.size+1]; IF CoreOps.VisitBindingSeq[actual: actual, public: public, eachWirePair: BindPublicToActual] THEN ERROR; }; RaiseRootOfInstancePath: PUBLIC PROC [by, path: InstancePath] RETURNS [raised: InstancePath] ~ { length: NATURAL ~ NATURAL[path.length] + by.length; raised _ [ length: length, bits: LOOPHOLE[BitOps.QOR[ LOOPHOLE[by.bits], BitOps.QShift[LOOPHOLE[path.bits], -by.length] ]]]; RETURN}; ParseCellTypePath: PUBLIC PROC [root: CellType, pathRope: ROPE, cutSet: CutSet] RETURNS [flatCell: FlatCellTypeRec] = { instance: CellInstance; within: CellType; token: ROPE; ts: IO.STREAM; firstChar: CHAR; tokenKind: IO.TokenKind; thisCell: CellType; [flatCell, instance, within, token, ts, firstChar, tokenKind, thisCell] _ ParsePartialCellTypePath[root, pathRope, cutSet]; flatCell.path _ AddInstance[flatCell.path, instance, within]; CheckNoMore[ts, firstChar, tokenKind]; }; CellTypePathRope: PUBLIC PROC [root: CellType, flatCell: FlatCellTypeRec] RETURNS [pathRope: ROPE] = { pathRope _ InstancePathRope[root, flatCell.path]; IF flatCell.recastCount>0 THEN pathRope _ Rope.Cat[pathRope, "*", Convert.RopeFromInt[flatCell.recastCount]]; }; FlatCellTypeEqual: PUBLIC PROC [key1, key2: REF ANY] RETURNS [equal: BOOL] = { equal _ FlatCellTypeEqualRec[NARROW [key1, FlatCellType]^, NARROW [key2, FlatCellType]^]; }; FlatCellTypeEqualRec: PUBLIC PROC [one, other: FlatCellTypeRec] RETURNS [equal: BOOL] = { equal _ InstancePathEqual[one.path, other.path] AND one.recastCount=other.recastCount; }; FlatCellTypeHash: PUBLIC PROC [flatCell: REF ANY] RETURNS [hash: CARDINAL] = { hash _ FlatCellTypeHashRec[NARROW[flatCell, FlatCellType]^]; }; FlatCellTypeHashRec: PUBLIC PROC [flatCell: FlatCellTypeRec] RETURNS [hash: CARDINAL] = { hash _ InstancePathHash[flatCell.path]; hash _ Basics.BITXOR[hash, flatCell.recastCount]; }; ResolveFlatCellType: PUBLIC PROC [root: CellType, flatCell: FlatCellTypeRec] RETURNS [parent: CellType, instance: CellInstance, cellType: CellType] = { Search: UnboundFlatCellProc = { upParent _ parent; upInstance _ instance; upCellType _ cell; NextUnboundCellType[cell, target, flatCell, instance, index, parent, flatParent, data, Search] }; upParent: CellType _ NIL; upInstance: CellInstance _ NIL; upCellType: CellType _ NIL; Search[cell: root, target: flatCell]; parent _ upParent; instance _ upInstance; cellType _ upCellType; }; BoundFlatCellType: PUBLIC PROC [root: CellType, flatCell: FlatCellTypeRec] RETURNS [bindings: Bindings, instance: CellInstance, cellType: CellType] = { Search: BoundFlatCellProc = { upBindings _ bindings; upInstance _ instance; upCellType _ cell; NextBoundCellType[cell, target, flatCell, instance, index, parent, flatParent, data, bindings, Search] }; upBindings: Bindings _ NIL; upInstance: CellInstance _ NIL; upCellType: CellType _ NIL; Search[cell: root, target: flatCell]; bindings _ upBindings; instance _ upInstance; cellType _ upCellType; }; FindAnyFlatCell: PUBLIC PROC [root: CellType, cellType: CellType] RETURNS [flatCellType: FlatCellTypeRec _ []] = { Find: PROC [cell: CellType, flatCell: FlatCellTypeRec _ []] RETURNS [BOOL] = { IF RefTab.Fetch[cellTypeVisit, cell].found THEN RETURN [FALSE]; IF NOT RefTab.Insert[cellTypeVisit, cell, $Visited] THEN ERROR; IF cell=cellType THEN { flatCellType _ flatCell; RETURN [TRUE]; }; SELECT TRUE FROM cell.class=CoreClasses.transistorCellClass => NULL; cell.class=CoreClasses.recordCellClass => { rct: CoreClasses.RecordCellType _ NARROW[cell.data]; FOR i: NAT IN [0..rct.size) DO IF Find[rct[i].type, [ExtendPath[flatCell.path, i, rct], 0]] THEN RETURN [TRUE]; ENDLOOP; }; ENDCASE => { new: CellType _ CoreOps.Recast[cell]; IF Find[new, [flatCell.path, IF cell=new THEN flatCell.recastCount ELSE flatCell.recastCount+1]] THEN RETURN [TRUE]; }; RETURN [FALSE]; }; cellTypeVisit: RefTab.Ref _ RefTab.Create[]; -- Marks visited cells IF NOT Find[root] THEN ERROR PathError["Cell type is not reachable from root"]; }; RaiseRootOfFlatCell: PUBLIC PROC [by: InstancePath, flatCell: FlatCellTypeRec] RETURNS [raised: FlatCellTypeRec] ~ { raised _ flatCell; raised.path _ RaiseRootOfInstancePath[by, raised.path]; RETURN}; ParseWirePath: PUBLIC PROC [root: CellType, pathRope: ROPE, cutSet: CutSet] RETURNS [flatWire: FlatWireRec] = { AddWire: PROC [subWire: NAT] = { pathBits: NAT _ BitOps.NBits[flatWire.wire.size]; instanceBits: PACKED ARRAY [0..16) OF BOOL _ LOOPHOLE[subWire]; FOR bit: NAT IN [0..pathBits) DO flatWire.path.bits[flatWire.path.length+bit] _ instanceBits[16-pathBits+bit]; ENDLOOP; flatWire.path.length _ flatWire.path.length + pathBits; flatWire.wire _ flatWire.wire[subWire]; IF flatWire.wireRoot=actual THEN publicWire _ publicWire[subWire]; }; InternalRoot: PROC = { rct: CoreClasses.RecordCellType _ NIL; flatWire.flatCell.path _ AddInstance[flatWire.flatCell.path, instance, within]; flatWire.flatCell.recastCount _ 0; [rct, flatWire.flatCell] _ MakeRecord[IF instance=NIL THEN root ELSE instance.type, instance, flatWire.flatCell, cutSet]; flatWire.wire _ rct.internal; flatWire.wireRoot _ internal; }; ParseQuotedNameWire: PROC = { depth: NAT _ 1; DO char: CHAR _ IO.GetChar[ts ! IO.EndOfStream => GOTO oops]; token _ Rope.Cat[token, Rope.FromChar[char]]; SELECT char FROM '{ => depth _ depth+1; '} => {IF depth=1 THEN EXIT; depth _ depth-1}; ENDCASE; ENDLOOP; EXITS oops => MakeError["Missing end brace on quoted short name"]; }; AppendNameWire: PROC = { state _ sawWireNameOrNumber; IF RootWire[]#none THEN MakeError["Cannot name a wire actual, internal, or public"]; FOR subWire: CARDINAL IN [0..flatWire.wire.size) DO IF Rope.Equal[token, CoreOps.GetShortWireName[IF flatWire.wireRoot=actual THEN publicWire[subWire] ELSE flatWire.wire[subWire]]] THEN { AddWire[subWire]; EXIT; }; REPEAT FINISHED => { -- This hack is for Don Curry's benefit hackName: ROPE _ token; DO [token, firstChar, tokenKind] _ ParseToken[ts ! IO.EndOfStream => EXIT]; hackName _ Rope.Cat[hackName, token]; ENDLOOP; FOR subWire: CARDINAL IN [0..flatWire.wire.size) DO IF Rope.Equal[hackName, CoreOps.GetShortWireName[IF flatWire.wireRoot=actual THEN publicWire[subWire] ELSE flatWire.wire[subWire]]] THEN { AddWire[subWire]; EXIT; }; REPEAT FINISHED => MakeError["Can't find wire"]; ENDLOOP; }; ENDLOOP; }; AppendNumberWire: PROC = { subWire: CARDINAL _ Convert.CardFromRope[token]; IF flatWire.wire=NIL THEN InternalRoot[]; IF subWire>=flatWire.wire.size THEN MakeError["No such wire"]; AddWire[subWire]; }; PossibleRootWire: PROC = { wireType: RootWireType _ RootWire[]; SELECT wireType FROM public => { state _ sawWireRoot; flatWire.flatCell.path _ AddInstance[flatWire.flatCell.path, instance, within]; flatWire.wire _ thisCell.public; flatWire.wireRoot _ public; }; internal => { state _ sawWireRoot; InternalRoot[]; }; actual => { parentCT: CellType _ within; IF instance=NIL THEN MakeError["Can't access actual of root"]; state _ sawWireRoot; flatWire.wire _ instance.actual; publicWire _ instance.type.public; flatWire.wireRoot _ actual; flatWire.flatCell.recastCount _ 0; UNTIL parentCT.class=CoreClasses.recordCellClass DO new: CellType _ CoreOps.Recast[parentCT]; IF new#parentCT THEN flatWire.flatCell.recastCount _ flatWire.flatCell.recastCount + 1; parentCT _ new; ENDLOOP; flatWire.instanceIndex _ CoreClasses.InstanceIndex[parentCT, instance]; }; none => { InternalRoot[]; AppendNameWire[]; }; ENDCASE => ERROR; }; RootWireType: TYPE = {public, internal, actual, none}; RootWire: PROC RETURNS [RootWireType] = { RETURN [SELECT TRUE FROM Rope.Equal[token, "PUBLIC", FALSE] => public, Rope.Equal[token, "INTERNAL", FALSE] => internal, Rope.Equal[token, "ACTUAL", FALSE] => actual, ENDCASE => none]; }; WirePathParseStates: TYPE = {start, expectMaybeRoot, sawWireRoot, expectWireNameOrNumber, sawWireNameOrNumber, sawLeft, sawNumber, sawRight}; instance: CoreClasses.CellInstance; within: CellType; token: ROPE; ts: IO.STREAM; firstChar: CHAR; tokenKind: IO.TokenKind; thisCell: CellType; publicWire: Wire _ NIL; state: WirePathParseStates _ start; [flatWire.flatCell, instance, within, token, ts, firstChar, tokenKind, thisCell] _ ParsePartialCellTypePath[root, pathRope, cutSet]; flatWire.validPath _ TRUE; DO SELECT state FROM start => SELECT tokenKind FROM tokenSINGLE => SELECT firstChar FROM '[ => state _ sawLeft; '. => state _ expectMaybeRoot; '{ => {ParseQuotedNameWire[]; PossibleRootWire[]}; ENDCASE => MakeError[]; tokenID => PossibleRootWire[]; tokenDECIMAL => {AppendNumberWire[]; state _ sawWireNameOrNumber}; ENDCASE => MakeError[]; expectMaybeRoot => SELECT tokenKind FROM tokenSINGLE => SELECT firstChar FROM '[ => state _ sawLeft; '{ => {ParseQuotedNameWire[]; PossibleRootWire[]}; ENDCASE => MakeError[]; tokenID => PossibleRootWire[]; tokenDECIMAL => {AppendNumberWire[]; state _ sawWireNameOrNumber}; ENDCASE => MakeError[]; sawWireRoot => SELECT tokenKind FROM tokenSINGLE => SELECT firstChar FROM '. => state _ expectWireNameOrNumber; ENDCASE => MakeError[]; ENDCASE => MakeError[]; expectWireNameOrNumber => SELECT tokenKind FROM tokenSINGLE => SELECT firstChar FROM '[ => state _ sawLeft; '{ => {ParseQuotedNameWire[]; AppendNameWire[]}; ENDCASE => MakeError[]; tokenID => AppendNameWire[]; tokenDECIMAL => {AppendNumberWire[]; state _ sawWireNameOrNumber}; ENDCASE => MakeError[]; sawWireNameOrNumber => SELECT tokenKind FROM tokenSINGLE => SELECT firstChar FROM '. => state _ expectWireNameOrNumber; '[ => state _ sawLeft; ENDCASE => MakeError[]; ENDCASE => MakeError[]; sawLeft => SELECT tokenKind FROM tokenDECIMAL => {AppendNumberWire[]; state _ sawNumber}; ENDCASE => MakeError[]; sawNumber => SELECT tokenKind FROM tokenSINGLE => SELECT firstChar FROM '] => state _ sawRight; ENDCASE => MakeError[]; ENDCASE => MakeError[]; sawRight => SELECT tokenKind FROM tokenSINGLE => SELECT firstChar FROM '. => state _ expectWireNameOrNumber; '[ => state _ sawLeft; '{ => {ParseQuotedNameWire[]; AppendNameWire[]}; ENDCASE => MakeError[]; tokenID => AppendNameWire[]; tokenDECIMAL => {AppendNumberWire[]; state _ sawWireNameOrNumber}; ENDCASE => MakeError[]; ENDCASE => MakeError[]; [token, firstChar, tokenKind] _ ParseToken[ts ! IO.EndOfStream => {tokenKind _ tokenEOF; EXIT}]; ENDLOOP; IF state=sawWireRoot OR state=expectWireNameOrNumber OR state=sawLeft OR state=sawNumber THEN MakeError[]; }; WirePathRope: PUBLIC PROC [root: CellType, wire: FlatWireRec] RETURNS [pathRope: ROPE] = { cellType: CellType _ ResolveFlatCellType[root, wire.flatCell].cellType; rootWire: Wire; IF wire.wireRoot=actual THEN { wire.flatCell.path _ ExtendPath[wire.flatCell.path, wire.instanceIndex, NARROW[cellType.data, CoreClasses.RecordCellType]]; wire.flatCell.recastCount _ 0; }; pathRope _ CellTypePathRope[root, wire.flatCell]; IF (NOT Rope.IsEmpty[pathRope]) AND wire.wireRoot#internal THEN pathRope _ Rope.Cat[pathRope, "."]; pathRope _ Rope.Cat[pathRope, SELECT wire.wireRoot FROM internal => NIL, public => "public", actual => "actual", ENDCASE => ERROR]; rootWire _ SELECT wire.wireRoot FROM public => cellType.public, internal => NARROW [cellType.data, CoreClasses.RecordCellType].internal, actual => NARROW [cellType.data, CoreClasses.RecordCellType][wire.instanceIndex].type.public, ENDCASE => ERROR; IF wire.validPath THEN { visitWire: Wire _ rootWire; begin: NAT _ 0; index: NAT; name: ROPE; UNTIL begin=wire.path.length DO pathBits: NAT _ BitOps.NBits[visitWire.size]; instanceBits: PACKED ARRAY [0..16) OF BOOL _ ALL [FALSE]; FOR bit: NAT IN [0..pathBits) DO instanceBits[16-pathBits+bit] _ wire.path.bits[begin+bit]; ENDLOOP; begin _ begin + pathBits; index _ LOOPHOLE[instanceBits]; visitWire _ visitWire[index]; name _ CoreOps.GetShortWireName[visitWire]; IF name=NIL THEN name _ Convert.RopeFromInt[index]; IF NOT Rope.IsEmpty[pathRope] THEN pathRope _ Rope.Cat[pathRope, "."]; pathRope _ Rope.Cat[pathRope, name]; ENDLOOP; } ELSE { IF NOT Rope.IsEmpty[pathRope] THEN pathRope _ Rope.Cat[pathRope, "."]; pathRope _ Rope.Cat[pathRope, CoreOps.GetFullWireName[rootWire, wire.wire]]; }; }; FlatWireEqual: PUBLIC PROC [key1, key2: REF ANY] RETURNS [equal: BOOL] = { equal _ FlatWireEqualRec[NARROW [key1, FlatWire]^, NARROW [key2, FlatWire]^]; }; FlatWireEqualRec: PUBLIC PROC [one, other: FlatWireRec] RETURNS [equal: BOOL] = { equal _ one.wire=other.wire AND FlatCellTypeEqualRec[one.flatCell, other.flatCell]; }; FlatWireHash: PUBLIC PROC [wire: REF ANY] RETURNS [hash: CARDINAL] = { hash _ FlatWireHashRec[NARROW [wire, FlatWire]^]; }; FlatWireHashRec: PUBLIC PROC [wire: FlatWireRec] RETURNS [hash: CARDINAL] = { hash _ FlatCellTypeHashRec[wire.flatCell]; hash _ Basics.BITXOR[hash, Basics.LowHalf[LOOPHOLE[wire.wire]]]; hash _ Basics.BITXOR[hash, Basics.HighHalf[LOOPHOLE[wire.wire]]]; }; PublicUpToInternal: PROC [actual, public, wire: Wire] RETURNS [new: Wire] ~ { IF actual.size#public.size THEN ERROR; -- non-conforming !!! IF public=wire THEN RETURN [new: actual]; FOR i: NAT IN [0..actual.size) DO new _ PublicUpToInternal[actual: actual[i], public: public[i], wire: wire]; IF new#NIL THEN RETURN; ENDLOOP; RETURN [new: NIL]; -- not found }; CanonizeWire: PUBLIC PROC [root: CellType, child: FlatWireRec] RETURNS [parent: FlatWireRec] = { WindUp: UnboundFlatCellProc = { new: Wire; -- will contain recomputed value if possible previousCells _ CONS [cell, previousCells]; -- save for recast wind up previousInstances _ CONS [instance, previousInstances]; -- save for recast wind up NextUnboundCellType[cell, target, flatCell, instance, index, parent, flatParent, NIL, WindUp]; previousCells _ previousCells.rest; -- restore to entry state previousInstances _ previousInstances.rest; -- restore to entry state IF stop OR previousCells=NIL THEN RETURN; -- at top level... IF instance=previousInstances.first AND cell=previousCells.first THEN RETURN; -- In-place reacst new _ PublicUpToInternal[actual: IF instance=NIL OR instance.type#cell THEN previousCells.first.public ELSE instance.actual, public: cell.public, wire: canonized.wire]; -- recast or RCT IF new=NIL THEN stop _ TRUE -- can't proceed any further ELSE canonized _ [flatCell: flatParent, wireRoot: internal, wire: new]; }; canonized: FlatWireRec _ child; -- will be backtracked in place previousCells: LIST OF CellType _ NIL; -- to keep track of recasts previousInstances: LIST OF CellInstance _ NIL; -- to keep track of recasts stop: BOOL _ FALSE; WindUp[cell: root, target: child.flatCell]; IF CoreOps.RecursiveMember[root.public, canonized.wire] THEN canonized.wireRoot _ public; -- final upgrade: we went up to the last recursion stage succesfully RETURN [parent: canonized]; -- too bad we must rename the result... }; RaiseRootOfFlatWire: PUBLIC PROC [by: InstancePath, flatWire: FlatWireRec] RETURNS [raised: FlatWireRec] ~ { raised _ flatWire; raised.flatCell _ RaiseRootOfFlatCell[by, raised.flatCell]; RETURN}; NextUnboundCellType: PUBLIC PROC [cell: CellType, target: FlatCellTypeRec, flatCell: FlatCellTypeRec, instance: CellInstance, index: NAT, parent: CellType, flatParent: FlatCellTypeRec, data: REF ANY, proc: UnboundFlatCellProc] = { IF FlatCellTypeEqualRec[target, flatCell] THEN RETURN; IF cell.class=CoreClasses.recordCellClass THEN { rct: CoreClasses.RecordCellType _ NARROW[cell.data]; pathBits: NAT _ BitOps.NBits[rct.size]; childFlatCell: FlatCellTypeRec _ [flatCell.path, 0]; instance: CellInstance; IF FlatCellTypeEqualRec[target, allFlatCells] THEN { FOR inst: NAT IN [0..rct.size) DO instance _ rct[inst]; childFlatCell.path _ ExtendPath[flatCell.path, inst, rct]; proc[cell: instance.type, target: target, flatCell: childFlatCell, instance: instance, index: inst, parent: cell, flatParent: flatCell, data: data]; ENDLOOP; } ELSE { instanceBits: PACKED ARRAY [0..16) OF BOOL _ ALL [FALSE]; IF target.path.length<=flatCell.path.length THEN ERROR; -- illegal move FOR bit: NAT IN [0..pathBits) DO instanceBits[16-pathBits+bit] _ target.path.bits[flatCell.path.length+bit]; childFlatCell.path.bits[flatCell.path.length+bit] _ target.path.bits[flatCell.path.length+bit]; ENDLOOP; index _ LOOPHOLE[instanceBits]; instance _ rct[index]; childFlatCell.path.length _ childFlatCell.path.length + pathBits; proc[cell: instance.type, target: target, flatCell: childFlatCell, instance: instance, index: index, parent: cell, flatParent: flatCell, data: data]; } } ELSE { new: CellType _ NIL; IF cell.class.recast=NIL THEN ERROR; -- illegal move new _ CoreOps.Recast[cell]; IF new#cell THEN flatCell.recastCount _ flatCell.recastCount + 1; proc[cell: new, target: target, flatCell: flatCell, instance: instance, index: index, parent: parent, flatParent: flatParent, data: data]; }; }; NextBoundCellType: PUBLIC PROC [cell: CellType, target: FlatCellTypeRec, flatCell: FlatCellTypeRec, instance: CellInstance, index: NAT, parent: CellType, flatParent: FlatCellTypeRec, data: REF ANY, bindings: Bindings, proc: BoundFlatCellProc] = { BindCellType: UnboundFlatCellProc = { newBindings: Bindings _ IF instance=previousInstance AND cell=previousCell THEN bindings ELSE BindInstance[parent: flatParent, actual: IF instance=NIL OR instance.type#cell THEN previousCell.public ELSE instance.actual, public: cell.public, bindings: bindings]; proc[cell, target, flatCell, instance, index, parent, flatParent, data, newBindings]; }; previousCell: CellType _ cell; previousInstance: CellInstance _ instance; NextUnboundCellType[cell, target, flatCell, instance, index, parent, flatParent, data, BindCellType]; }; InitialBindingTable: PUBLIC PROC [root: CellType] RETURNS [bindings: Bindings] = { Bind: CoreOps.EachWireProc = { IF subWires _ (NOT RefTab.Fetch[bindings, wire].found) THEN { fw: FlatWire = NEW [FlatWireRec _ [wireRoot: public, wire: wire]]; IF NOT RefTab.Insert[bindings, wire, fw] THEN ERROR; }; }; bindings _ RefTab.Create[]; IF CoreOps.VisitWireSeq[root.public, Bind] THEN ERROR; bindings _ bindings; }; ParsePartialCellTypePath: PROC [root: CellType, pathRope: ROPE, cutSet: CutSet] RETURNS [flatCell: FlatCellTypeRec, instance: CellInstance _ NIL, within: CellType, token: ROPE, ts: IO.STREAM, firstChar: CHAR, tokenKind: IO.TokenKind, thisCell: CellType _ NIL] = { RecastToClass: PROC = { DO IF NOT first THEN { new: CellType _ NIL; CheckRecast[flatCell, instance, thisCell, cutSet]; new _ CoreOps.Recast[thisCell]; IF new#thisCell THEN flatCell.recastCount _ flatCell.recastCount + 1; thisCell _ new; }; first _ FALSE; IF Rope.Equal[token, thisCell.class.name] THEN EXIT; ENDLOOP; state _ sawCellClassNameOrRecastNumber; }; RecastByNumber: PROC = { recastNumber: CARDINAL _ Convert.CardFromRope[token]; FOR rn: CARDINAL IN [0..recastNumber) DO new: CellType _ NIL; CheckRecast[flatCell, instance, thisCell, cutSet]; new _ CoreOps.Recast[thisCell]; IF new#thisCell THEN flatCell.recastCount _ flatCell.recastCount + 1; thisCell _ new; ENDLOOP; state _ sawRecastNumber; }; CheckCellClassName: PROC = { IF NOT Rope.Equal[token, thisCell.class.name] THEN MakeError[Rope.Cat["Incorrect cell class name ", token]]; state _ sawCellClassName; }; CellTypePathParseStates: TYPE = {start, sawAsterisk, sawRecastNumber, sawLeftParan, sawCellClassName, sawCellClassNameOrRecastNumber}; state: CellTypePathParseStates _ start; first: BOOL _ TRUE; [flatCell.path, instance, within, token, ts, firstChar, tokenKind] _ ParsePartialInstancePath[root, pathRope, cutSet]; thisCell _ IF instance=NIL THEN root ELSE instance.type; flatCell.recastCount _ 0; IF tokenKind#tokenEOF THEN DO SELECT state FROM start => SELECT tokenKind FROM tokenSINGLE => SELECT firstChar FROM '* => state _ sawAsterisk; '., '[, '{ => EXIT; ENDCASE => MakeError[]; tokenID => EXIT; tokenDECIMAL => EXIT; ENDCASE => MakeError[]; sawAsterisk => SELECT tokenKind FROM tokenID => RecastToClass[]; tokenDECIMAL => RecastByNumber[]; ENDCASE => MakeError[]; sawRecastNumber => SELECT tokenKind FROM tokenSINGLE => SELECT firstChar FROM '( => state _ sawLeftParan; '* => state _ sawAsterisk; '., '[, '{ => EXIT; ENDCASE => MakeError[]; ENDCASE => MakeError[]; sawLeftParan => SELECT tokenKind FROM tokenID => CheckCellClassName[]; ENDCASE => MakeError[]; sawCellClassName => SELECT tokenKind FROM tokenSINGLE => SELECT firstChar FROM ') => state _ sawCellClassNameOrRecastNumber; ENDCASE => MakeError[]; ENDCASE => MakeError[]; sawCellClassNameOrRecastNumber => SELECT tokenKind FROM tokenSINGLE => SELECT firstChar FROM '* => state _ sawAsterisk; '., '[, '{ => EXIT; ENDCASE => MakeError[]; ENDCASE => MakeError[]; ENDCASE => MakeError[]; [token, firstChar, tokenKind] _ ParseToken[ts ! IO.EndOfStream => {tokenKind _ tokenEOF; EXIT}]; ENDLOOP; IF state=sawAsterisk OR state=sawLeftParan OR state=sawCellClassName THEN MakeError[]; }; ParsePartialInstancePath: PROC [root: CellType, pathRope: ROPE, cutSet: CutSet] RETURNS [path: InstancePath _ nullInstancePath, instance: CellInstance _ NIL, within: CellType, token: ROPE, ts: IO.STREAM, firstChar: CHAR, tokenKind: IO.TokenKind] = { AppendNameInstance: PROC = { found: BOOL _ FALSE; rct: CoreClasses.RecordCellType; path _ AddInstance[path, instance, within]; within _ IF instance=NIL THEN root ELSE instance.type; rct _ MakeRecord[within, instance, [path, 0], cutSet].rct; FOR inst: CARDINAL IN [0..rct.size) DO IF Rope.Equal[token, CoreClasses.GetCellInstanceName[rct[inst]]] THEN { instance _ rct[inst]; found _ TRUE; EXIT; }; REPEAT FINISHED => FOR inst: CARDINAL IN [0..rct.size) DO IF Rope.Equal[token, CoreOps.GetCellTypeName[rct[inst].type]] THEN { IF found THEN MakeError["Append by cell type name is ambiguous"]; instance _ rct[inst]; found _ TRUE; }; ENDLOOP; ENDLOOP; IF NOT found THEN MakeError[Rope.Cat["Can't find instance or cell type of name ", token]]; state _ sawInstanceNameOrNumber; }; AppendNumberInstance: PROC = { rct: CoreClasses.RecordCellType; inst: CARDINAL _ Convert.CardFromRope[token]; path _ AddInstance[path, instance, within]; within _ IF instance=NIL THEN root ELSE instance.type; rct _ MakeRecord[within, instance, [path, 0], cutSet].rct; IF inst>=rct.size THEN MakeError[Rope.Cat["No such instance ", token]]; instance _ rct[inst]; state _ sawInstanceNumber; }; CheckCellTypeName: PROC = { IF NOT Rope.Equal[token, CoreOps.InheritCellTypeName[instance.type]] THEN MakeError[Rope.Cat["Incorrect cell type name ", token]]; state _ sawCellTypeName; }; InstancePathParseStates: TYPE = {start, expectInstanceNameOrNumber, sawInstanceNumber, sawLeftParan, sawCellTypeName, sawInstanceNameOrNumber}; state: InstancePathParseStates _ start; within _ root; ts _ IO.RIS[pathRope]; DO [token, firstChar, tokenKind] _ ParseToken[ts ! IO.EndOfStream => {tokenKind _ tokenEOF; EXIT}]; SELECT state FROM start => SELECT tokenKind FROM tokenSINGLE => SELECT firstChar FROM '/ => state _ expectInstanceNameOrNumber; '*, '[, '{ => EXIT; ENDCASE => MakeError[]; tokenID => EXIT; tokenDECIMAL => EXIT; ENDCASE => MakeError[]; expectInstanceNameOrNumber => SELECT tokenKind FROM tokenID => AppendNameInstance[]; tokenDECIMAL => AppendNumberInstance[]; ENDCASE => MakeError[]; sawInstanceNumber => SELECT tokenKind FROM tokenSINGLE => SELECT firstChar FROM '( => state _ sawLeftParan; '/ => state _ expectInstanceNameOrNumber; '*, '., '[, '{ => EXIT; ENDCASE => MakeError[]; ENDCASE => MakeError[]; sawLeftParan => SELECT tokenKind FROM tokenID => CheckCellTypeName[]; ENDCASE => MakeError[]; sawCellTypeName => SELECT tokenKind FROM tokenSINGLE => SELECT firstChar FROM ') => state _ sawInstanceNameOrNumber; ENDCASE => MakeError[]; ENDCASE => MakeError[]; sawInstanceNameOrNumber => SELECT tokenKind FROM tokenSINGLE => SELECT firstChar FROM '/ => state _ expectInstanceNameOrNumber; '*, '., '[, '{ => EXIT; ENDCASE => MakeError[]; ENDCASE => MakeError[]; ENDCASE => MakeError[]; ENDLOOP; IF state=expectInstanceNameOrNumber OR state=sawLeftParan OR state=sawCellTypeName THEN MakeError[]; }; MakeRecord: PROC [cellType: CellType, instance: CellInstance, flatCell: FlatCellTypeRec, cutSet: CutSet] RETURNS [rct: CoreClasses.RecordCellType, newFlatCell: FlatCellTypeRec] = { UNTIL cellType.class=CoreClasses.recordCellClass DO new: CellType _ NIL; CheckRecast[flatCell, instance, cellType, cutSet]; new _ CoreOps.Recast[cellType]; IF new#cellType THEN flatCell.recastCount _ flatCell.recastCount + 1; cellType _ new; ENDLOOP; rct _ NARROW [cellType.data]; newFlatCell _ flatCell }; CheckRecast: PROC [flatCell: FlatCellTypeRec, instance: CellInstance, cellType: CellType, cutSet: CutSet] = { IF cellType.class.recast=NIL THEN MakeError["Attempting to name something inside of a primitive element"]; IF CutSetMemberResolved[flatCell, instance, cellType, cutSet] THEN MakeError["Attempting to name something below the current cutSet"]; }; CheckNoMore: PROC [ts: IO.STREAM, firstChar: CHAR, tokenKind: IO.TokenKind] = { IF tokenKind#tokenEOF THEN MakeError[]; }; ParseToken: PROC [ts: IO.STREAM] RETURNS [token: ROPE, firstChar: CHAR, tokenKind: IO.TokenKind] = { token _ IO.GetTokenRope[ts, Breaks].token; firstChar _ Rope.Fetch[token]; tokenKind _ SELECT TRUE FROM Rope.Length[token]=1 AND Breaks[firstChar]=break => tokenSINGLE, firstChar IN ['0..'9] => tokenDECIMAL, ENDCASE => tokenID; }; Breaks: IO.BreakProc = { RETURN[SELECT char FROM IN [IO.NUL .. IO.SP] => sepr, '{, '}, '/, '., '(, '), '[, '], '* => break, IN ['0..'9], IN ['a..'z], IN ['A..'Z] => other, ENDCASE => ERROR PathError["Illegal character"]]; }; END. 2CoreFlatImpl.mesa Copyright Σ 1985, 1986, 1987 by Xerox Corporation. All rights reserved. Barth, October 5, 1987 5:37:58 pm PDT Last Edited by: Gasbarro October 21, 1987 12:25:04 pm PDT Last Edited by: Louis Monier January 20, 1987 10:42:41 am PST Last tweaked by Mike Spreitzer on November 2, 1987 3:53:04 pm PST Jean-Marc Frailong December 5, 1987 6:31:00 pm PST Bertrand Serlet September 25, 1987 1:08:03 pm PDT Mike Spreitzer February 27, 1987 3:45:39 pm PST Error Cut Sets Instances oneBits: ARRAY [0..2) OF INT _ LOOPHOLE[one.bits]; otherBits: ARRAY [0..2) OF INT _ LOOPHOLE[other.bits]; equal _ one.length=other.length AND oneBits=otherBits; IF equal THEN FOR bit: NAT IN [0..one.length) DO IF one.bits[bit]#other.bits[bit] THEN { equal _ FALSE; EXIT; }; ENDLOOP; CellTypes Wires WirePath ::= {start} ?((PUBLIC | INTERNAL | ACTUAL ) {sawWireRoot} . {expectWireNameOrNumber} ) (( QuotedName | Name | Number ) {sawWireNameOrNumber} ?( . {expectWireNameOrNumber})) | ( [ {sawLeft} Number {sawNumber} ] {sawRight} ) CanonizeWire: PUBLIC PROC [root: CellType, child: FlatWireRec] RETURNS [parent: FlatWireRec] = { -- this is the old version. Kept if a problem arises with the new (faster) one Search: BoundFlatCellProc = { upBindings _ bindings; NextBoundCellType[cell, target, flatCell, instance, index, parent, flatParent, data, bindings, Search] }; upBindings: Bindings _ NIL; parentRef: FlatWire _ NIL; Search[cell: root, target: child.flatCell, bindings: InitialBindingTable[root]]; parentRef _ NARROW[RefTab.Fetch[upBindings, child.wire].val]; parent _ IF parentRef=NIL THEN child ELSE parentRef^; }; Transport wire from public to actual, return NIL if not found. Should use WireSeq... This procedure is only an optimization of a simple CoreOps.VisitBinding, but speed is quite important at this point because routers use canonization very heavily. The procedure should some day migrate into CoreOps. On return of recursion, transport wire across boundaries. Stop all recursion when unable to proceed (avoids scanning the publics of cells above the canonical wire origin). Enumeration Utilities CellTypePath ::= {start} * {sawAsterisk} ( Name | (Number {sawRecastNumber} ?( ( {sawLeftParan} Name {sawCellClassName} ) ) ) {sawCellClassNameOrRecastNumber} ) InstancePath ::= {start} / {expectInstanceNameOrNumber} ( Name | (Number {sawInstanceNumber} ?( ( {sawLeftParan} Name {sawCellTypeName} ) ) ) {sawInstanceNameOrNumber} ) token: ROPE; IF tokenKind=tokenSINGLE AND firstChar='. THEN [token, firstChar, tokenKind] _ ParseToken[ts ! IO.EndOfStream => {tokenKind _ tokenEOF; CONTINUE}]; Κ'Š– "cedar" style˜codešœ™KšœH™HK™%K™9K™=K™AK™2K™1K™/K™—KšΟk œJœ˜dK˜•StartOfExpansion[]šΠbn œœ˜Kšœ@œ˜WKšœ ˜Kšœœœ ˜—K˜head™š Οn œœœœœœ˜1K˜—šŸ œœœœ˜#Kšœœœ˜!Kšœ˜K˜K˜——™šœœ2˜DK˜—š Ÿœœœ,œœœ˜zJšœF˜FKšœ˜J˜—šŸœœœœœœœ˜oJš œœœœœ7˜RJšœ'˜'Jšœ;˜;J˜ Kšœ˜J˜—š Ÿœœœ(œœœ˜nJšœB˜BKšœ˜J˜—šŸœœœœœœœ˜cJš œœœœœ3˜NJšœ'˜'Jšœ7˜7J˜ Kšœ˜J˜—š Ÿœœœ)œœœ˜qJšœC˜CKšœ˜J˜—šŸœœœœœœœ˜fJš œœœœœ4˜OJšœ'˜'Jšœ8˜8J˜ Kšœ˜J˜—šŸ œœœ-œœœœœœ œœ˜Χšœ œ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—Kšœ˜K˜—š Ÿ œœœ=œ œœ˜xK˜K˜K˜KšœC˜CKšœC˜CKšœ˜K˜—š ŸœœœYœ œœ˜œKšœœœ˜Kš œ0œ1œœœ˜wKš œœœœœ˜!šœ2œœ˜Dšœ7œ˜?šœœ$˜AKšœ6œœ˜BKšœœœF˜_Kšœ˜—K˜—Kšœ˜—šœ3œœ˜HKšœ.œœœ˜CKšœ˜—šœ5œœ˜JKšœ.œœœ˜BKšœ˜—šœ œœ˜Kšœ1˜1Kšœœœœ œœœœ˜PK˜—Kšœ)˜)Kšœœœœ œœœœ˜PKš œ œ+œœœ˜PKšœ œœœ œMœœœ˜‰Kš œ œIœœœ˜pKš œ œPœœœ˜wKšœ˜K˜—šŸ œœœœœœœœ˜Kš œœœœœœ˜9š œœœœœœ˜;KšœPœœœ˜dKšœ˜—Kšœ˜—Kšœ˜K˜—šŸ œœœœœ œœœœ˜]Jšœœœ œ ˜)Jšœœœ œ ˜)Jšœœœ œ ˜)Jšœœœ œ ˜)Jšœœœ œ ˜)Jšœœœ œ ˜)Kšœ˜K˜—šŸœœ œœœœœ œœœ˜YKšœ˜š œœœœœœ˜8Jšœ œ˜&Jšœ˜—Kšœ˜K˜——™ š Ÿœœœœœ˜pKšœ˜Kšœ˜Kšœœ˜ Kšœœœ˜Kšœ œ˜Kšœ œ ˜Kšœm˜mKšœ+˜+Kšœ&˜&Kšœ˜K˜—š Ÿœœœ&œ œœ˜eK˜šž œ˜#šœ œœ˜-Kšœœ-˜7šœœœ˜Kšœœ.˜@KšœH˜HKšœœœ/˜GK˜—Kšœ)˜)K˜—Kšœc˜cKšœ˜K˜—Kšœ˜Kšœ˜K˜—š Ÿœœœœ œ˜SKšœ œ˜8Kš œ œœœœ ™2Kš œ œœœœ ™6Kšœ œ™6š œœœœœ™0šœœ™'Kšœœ™Kšœ™K™—Kšœ™—Kšœ˜K˜—š Ÿœœœœœ ˜SKšœ)œ˜Nšœœœ˜Jšœœ˜$Jšœ˜—Kšœ˜K˜—šŸ œœœSœ˜ŽKšœ˜šœ œœ˜Kšœ-˜-Kšœ(œ˜>Kšœœ1˜;Kšœ œœΟc(˜@Kšœ4˜4Kšœ˜—Kšœ˜K˜—š Ÿ œœœ$œ#œ˜„Kšœ œ˜'Kšœ˜šœœœ˜ Kšœ*œ˜EKšœ˜—Kšœ+˜+K˜K˜—šŸ œœœHœ˜„K˜šŸœ˜0Kšœœ˜Kšœ œœœ2˜TKš œ8œœœœ5œ˜ŒKšœ˜K˜—Kšœ+˜+Kšœ[œœ˜hKšœ˜K˜—šŸœœœœ˜`Kšœœœ˜3šœ ˜ Kšœ˜šœœœ˜Kšœ ˜Kšœœ˜.Kšœ˜——Kšœ˜K˜——™ š Ÿœœœœœ ˜wKšœ˜Kšœ˜Kšœœ˜ Kšœœœ˜Kšœ œ˜Kšœ œ ˜Kšœ˜Kšœ{˜{Kšœ=˜=Kšœ&˜&Kšœ˜K˜—š Ÿœœœ-œ œ˜fKšœ1˜1KšœœO˜mKšœ˜K˜—šŸœœœœœœ œ˜NKšœœœ˜YKšœ˜K˜—š Ÿœœœœ œ˜YKšœ0œ#˜VKšœ˜K˜—šŸœœœ œœœœ˜NKšœœ˜Kšœ˜Kšœ˜K˜—šŸœœ˜Kšœ$˜$šœ ˜šœ ˜ Kšœ˜KšœO˜OKšœ ˜ Kšœ˜K˜—šœ ˜ Kšœ˜Kšœ˜K˜—šœ ˜ K˜Kšœ œœ*˜>Kšœ˜Kšœ ˜ Kšœ"˜"Kšœ˜Kšœ"˜"šœ,˜3Kšœ)˜)KšœœC˜WKšœ˜Kšœ˜—KšœG˜GK˜—šœ ˜ Kšœ˜Kšœ˜K˜—Kšœœ˜—K˜K˜—šœœ$˜6K˜—šŸœœœ˜)šœœœ˜Kšœœ ˜-Kšœœ˜1Kšœœ ˜-Kšœ ˜—K˜K˜—Kš"Οb œ‘œ‘œœ‘œœ‘œ*‘œ‘œ ‘œ‘œ‘œ‘œ‘œ‘œ‘œ-‘™θKšœœt˜Kšœ#˜#Kšœ˜Kšœœ˜ Kšœœœ˜Kšœ œ˜Kšœ œ ˜Kšœ˜Kšœœ˜Kšœ#˜#Kšœ„˜„Kšœœ˜š˜šœ˜šœ œ ˜šœœ ˜$Kšœ˜Kšœ˜Kšœ2˜2Kšœ˜—Kšœ˜KšœB˜BKšœ˜—šœœ ˜(šœœ ˜$Kšœ˜Kšœ2˜2Kšœ˜—Kšœ˜KšœB˜BKšœ˜—šœœ ˜$šœœ ˜$Kšœ%˜%Kšœ˜—Kšœ˜—šœœ ˜/šœœ ˜$Kšœ˜Kšœ0˜0Kšœ˜—Kšœ˜KšœB˜BKšœ˜—šœœ ˜,šœœ ˜$Kšœ%˜%Kšœ˜Kšœ˜—Kšœ˜—šœ œ ˜ Kšœ8˜8Kšœ˜—šœ œ ˜"šœœ ˜$Kšœ˜Kšœ˜—Kšœ˜—šœ œ ˜!šœœ ˜$Kšœ%˜%Kšœ˜Kšœ0˜0Kšœ˜—Kšœ˜KšœB˜BKšœ˜—Kšœ˜—Kšœ0œ'œ˜`Kšœ˜—Kš œœœœœ ˜jK˜K˜—š Ÿ œœœ%œ œ˜ZKšœG˜GKšœ˜šœœ˜KšœHœ-˜{Kšœ˜K˜—Kšœ1˜1Kšœœœœ%˜dKš œœœ œ*œœ˜ƒšœ œ˜$Kšœ˜Kšœ œ6˜HKšœ œM˜]Kšœœ˜—šœœ˜K˜Kšœœ˜Kšœœ˜ Kšœœ˜ šœ˜Kšœ œ ˜-Kš œœœ œœœœ˜9šœœœ˜ Kšœ:˜:Kšœ˜—Kšœ˜Kšœœ˜Kšœ˜K˜+Kšœœœ#˜3Kšœœœ%˜GKšœ$˜$Kšœ˜—Kšœ˜—šœ˜Kšœœœ%˜GKšœL˜LK˜—Kšœ˜K˜—šŸ œœœœœœ œ˜JKšœœœ˜MKšœ˜K˜—š Ÿœœœœ œ˜QJšœœ4˜SKšœ˜K˜—šŸ œœœœœœœ˜FKšœœ˜1Kšœ˜K˜—š Ÿœœœœœ˜MJšœ*˜*Jšœœœ˜@Jšœœœ˜AKšœ˜K˜—šŸ œœœ&œi™―K™šŸœ™Kšœ™Kšœf™fK™K™—Kšœœ™Kšœœ™KšœP™PKšœ œ+™=Kš œ œ œœœ ™5Kšœ™K™—šŸœœœ˜MKšœ-œ$™TK™ΦKšœœœ ˜ ˜ΉKš œœœœ ˜8KšœC˜GK˜—Kšœ  ˜?Kšœœœ œ ˜BKšœœœœ ˜JKšœœœ˜Kšœ+˜+Kšœ6œ D˜žKšœ '˜CKšœ˜K˜—šŸœœœ+œ˜lK˜Kšœ;˜;Kšœ˜K˜——™ š Ÿœœœeœ7œœ ˜ζKšœ(œœ˜6šœ(œ˜0Kšœ"œ ˜4Kšœ œ˜'Kšœ4˜4K˜šœ,œ˜4šœœœ˜!K˜Kšœ:˜:Kšœ”˜”Kšœ˜—K˜—šœ˜Kš œœœ œœœœ˜9Kšœ*œœ ˜Hšœœœ˜ KšœK˜KKšœ_˜_Kšœ˜—Kšœœ˜Kšœ˜KšœA˜AKšœ•˜•K˜—K˜—šœ˜Kšœœ˜Kš œœœœ ˜5Kšœ˜Kšœ œ1˜AKšœŠ˜ŠK˜—Kšœ˜K˜—š Ÿœœœeœ7œœ2˜φK˜šŸ œ˜%Kšœœœœ œ*œ œœœœ;˜…KšœU˜UK˜K˜—K˜Kšœ*˜*Kšœe˜eKšœ˜K˜—šŸœœœœ˜RšŸœ˜šœ œ%œ˜=Kšœœ0˜BKšœœ#œœ˜4K˜—K˜—K˜Kšœ)œœ˜6K˜K˜K˜——™ šŸœœœœ6œœœœ œ œ!œ˜‡K˜šŸ œœ˜š˜šœœœ˜Kšœœ˜Kšœ2˜2Kšœ˜Kšœœ1˜EKšœ˜K˜—Kšœœ˜Kšœ(œœ˜4Kšœ˜—Kšœ'˜'Kšœ˜K˜—šŸœœ˜Kšœœ˜5šœœœ˜(Kšœœ˜Kšœ2˜2Kšœ˜Kšœœ1˜EKšœ˜Kšœ˜—Kšœ˜Kšœ˜K˜—šŸœœ˜Kšœœ(œ:˜lKšœ˜Kšœ˜K˜—Kš‘œ‘œ‘œ‘œ‘œ‘œ,‘œ‘œ#‘™‘Kšœœi˜†Kšœ'˜'Kšœœœ˜Kšœv˜vKš œ œ œœœ˜8K˜šœœ˜šœ˜šœ œ ˜šœœ ˜$Kšœ˜Kšœœ˜Kšœ˜—Kšœ œ˜Kšœœ˜Kšœ˜—šœœ ˜$Kšœ˜Kšœ!˜!Kšœ˜—šœœ ˜(šœœ ˜$Kšœ˜Kšœ˜Kšœœ˜Kšœ˜—Kšœ˜—šœœ ˜%Kšœ ˜ Kšœ˜—šœœ ˜)šœœ ˜$Kšœ-˜-Kšœ˜—Kšœ˜—šœ"œ ˜7šœœ ˜$Kšœ˜Kšœœ˜Kšœ˜—Kšœ˜—Kšœ˜—Kšœ0œ'œ˜`Kšœ˜—Kšœœœœ ˜VKšœ˜K˜—šŸœœœœBœœœœ œ œ˜ωK˜šŸœœ˜Kšœœœ˜Kšœ ˜ Kšœ+˜+Kš œ œ œœœ˜6Kšœ:˜:šœœœ˜&šœ?œ˜GKšœ˜Kšœœ˜ Kšœ˜K˜—š œœœœœ˜9šœ<œ˜DKšœœ4˜AKšœ˜Kšœœ˜ K˜—Kšœ˜—Kšœ˜—KšœœœI˜ZKšœ ˜ K˜K˜—šŸœœ˜Kšœ ˜ Kšœœ˜-Kšœ+˜+Kš œ œ œœœ˜6Kšœ:˜:Kšœœ1˜GKšœ˜Kšœ˜Kšœ˜K˜—šŸœœ˜Kšœœ?œ9˜‚Kšœ˜K˜K˜—Kš‘œ‘œ‘œ‘œ‘œ‘œ+‘œ‘œ‘™ͺKšœœr˜Kšœ'˜'Kšœ˜Kšœœœ ˜š˜Kšœ0œ'œ˜`šœ˜šœ œ ˜šœœ ˜$Kšœ)˜)Kšœœ˜Kšœ˜—Kšœ œ˜Kšœœ˜Kšœ˜—šœœ ˜3Kšœ ˜ Kšœ'˜'Kšœ˜—šœœ ˜*šœœ ˜$Kšœ˜Kšœ)˜)Kšœœ˜Kšœ˜—Kšœ˜—šœœ ˜%Kšœ˜Kšœ˜—šœœ ˜(šœœ ˜$Kšœ&˜&Kšœ˜—Kšœ˜—šœœ ˜0šœœ ˜$Kšœ)˜)Kšœœ˜Kšœ˜—Kšœ˜—Kšœ˜—Kšœ˜—Kšœ"œœœ ˜dKšœ˜K˜—šŸ œœYœD˜΄šœ,˜3Kšœœ˜Kšœ2˜2Kšœ˜Kšœœ1˜EKšœ˜Kšœ˜—Kšœœ˜Kšœ˜K˜K˜—šŸ œœ\˜mKšœœœI˜jKšœ<œD˜†K˜K˜—š Ÿ œœœœ œ œ˜OKšœœ™ Kš œœœ1œ'œ™“Kšœœ ˜'K˜K˜—šŸ œœœœœ œ œ œ˜dKšœœ ˜*Kšœ˜šœ œœ˜Kšœœ(˜@Kšœ œ˜&Kšœ ˜—Kšœ˜K˜—šžœœ˜šœœ˜Kš œœœœœ ˜Kšœ,˜,Kšœ œ œ˜/Kšœœ!˜1—K˜K˜——Kšœ˜—…—‚³Π