DIRECTORY Atom, Basics, Cache, CacheOps, Cluster, Core, CoreClasses, CoreCreate, CoreFlat, CoreOps, Dragon, DragonRosemary, DragOpsCross, DragOpsCrossUtils, EU, FileNames, IFUTop, IFUPublic, IFUTest, IO, LizardCache, LizardHeart, Ports, Process, RandomCode, REFBit, Rope, Rosemary, RosemaryUser, RosemaryVector, SparseMemory, TerminalIO, TypeScript, ViewerClasses, ViewerIO, ViewRec; ClusterImpl: CEDAR PROGRAM IMPORTS Atom, Cache, CacheOps, CoreCreate, CoreFlat, CoreOps, DragonRosemary, DragOpsCrossUtils, EU, FileNames, IFUTop, IFUPublic, IO, LizardCache, LizardHeart, Ports, Process, RandomCode, REFBit, Rope, Rosemary, RosemaryUser, RosemaryVector, SparseMemory, TerminalIO, TypeScript, ViewerIO, ViewRec EXPORTS Cluster = BEGIN KitchenSink: TYPE = Cluster.KitchenSink; OpaqueKitchenSink: TYPE = Cluster.OpaqueKitchenSink; LizardSimulation: TYPE = Cluster.LizardSimulation; Instances: TYPE = Cluster.Instances; ClusterState: TYPE = Cluster.ClusterState; IFUState: TYPE = IFUTop.IFUState; EUState: TYPE = EU.EUState; CacheSt: TYPE = REF Cache.CacheState; nCacheLines: PUBLIC NAT _ 200; skipIFURejects: PUBLIC BOOL _ FALSE; skipEURejects: PUBLIC BOOL _ FALSE; fullEU: PUBLIC BOOL _ FALSE; fullIFU: PUBLIC BOOL _ FALSE; fullIFUCuts: PUBLIC LIST OF Core.ROPE _ NIL; quickIFU: PUBLIC BOOL _ FALSE; rawIFU: PUBLIC BOOL _ FALSE; recordPlotData: PUBLIC BOOL _ TRUE; chrgdMemNodesOk: PUBLIC BOOL _ FALSE; -- TRUE when getting started initIFUVectorWt: PUBLIC BOOL _ FALSE; -- initial controlPanel value initEUVectorWt: PUBLIC BOOL _ FALSE; -- initial controlPanel value lastKs: PUBLIC KitchenSink _ NIL; MakeCluster: PUBLIC PROC RETURNS [ks: KitchenSink] = { ifuRoseInst, euRoseInst, iCacheRoseInst, eCacheRoseInst: CoreClasses.CellInstance _ NIL; tempInstances: CoreClasses.CellInstances _ NIL; public: Core.Wire = CoreOps.CreateWire[LIST[ IFUPublic.PortWire[TRUE, "ResetAB", 1, force], IFUPublic.PortWire[TRUE, "RescheduleAB", 1, force], IFUPublic.PortWire[TRUE, "Clk", 1, force], IFUPublic.PortWire[TRUE, "PhAOut", 1], IFUPublic.PortWire[TRUE, "PhBOut", 1], IFUPublic.PortWire[TRUE, "PhA", 1, force], IFUPublic.PortWire[TRUE, "PhB", 1, force], IFUPublic.PortWire[TRUE, "Vdd", 1, infinite, H], IFUPublic.PortWire[TRUE, "Gnd", 1, infinite, L], IFUPublic.PortWire[TRUE, "PadVdd", 1, infinite, H], IFUPublic.PortWire[TRUE, "PadGnd", 1, infinite, L], IFUPublic.PortWire[TRUE, "IFUDShA", 1, force], IFUPublic.PortWire[TRUE, "IFUDShB", 1, force], IFUPublic.PortWire[TRUE, "IFUDShRd", 1, force], IFUPublic.PortWire[TRUE, "IFUDShWt", 1, force], IFUPublic.PortWire[TRUE, "IFUDShIn", 1, force], IFUPublic.PortWire[TRUE, "IFUDShOut", 1], IFUPublic.PortWire[TRUE, "EUDShA", 1, force], IFUPublic.PortWire[TRUE, "EUDShB", 1, force], IFUPublic.PortWire[TRUE, "EUDShRd", 1, force], IFUPublic.PortWire[TRUE, "EUDShWt", 1, force], IFUPublic.PortWire[TRUE, "EUDShIn", 1, force], IFUPublic.PortWire[TRUE, "EUDShOut", 1], IFUPublic.PortWire[TRUE, "DStAd", 4, force], IFUPublic.PortWire[TRUE, "DHold", 1, force] ] ]; iOnly: Core.Wire = CoreCreate.WireList[LIST[ "UserMode2BA", "IPCmdFetchA", "IPFaultingB", CoreCreate.Seq[ "IPFaultingXB", 3], CoreCreate.Seq[ "IPData", 32], CoreCreate.Seq[ "DPCmdA", 8], CoreCreate.Seq[ "DPFaultB", 4], CoreCreate.Seq[ "DPData", 32], CoreCreate.Seq[ "EUAluOp2AB", 4], CoreCreate.Seq[ "EUCondSel2AB", 4], CoreCreate.Seq[ "KBus", 32], "EURdFromPBus3AB", "EUWriteToPBus3AB", "EUCondition2B", "DPRejectB", "IPRejectB", "VbbGen" ] ]; ks _ lastKs _ NEW[Cluster.KitchenSinkRec _ [ log: ViewerIO.CreateViewerStreams[ name: "Rosemary Cluster Simulation", backingFile: "Cluster.log" ].out, vm: CacheOps.NewVirtualMemory[] ]]; TypeScript.ChangeLooks[ViewerIO.GetViewerFromStream[ks.log], 'f]; ks.iCache _ CacheOps.NewCache[mem: ks.vm, nLines: nCacheLines]; ks.eCache _ CacheOps.NewCache[mem: ks.vm, nLines: nCacheLines]; ks.coreInsts[iCache] _ CoreCreate.InstanceList[ type: CoreFlat.CellTypeCutLabels[ on: Cache.Create[vm: ks.iCache, skipRejects: skipIFURejects], l1: "TopLevel"], pas: LIST[ ["PUserMode", "Gnd"], ["PData", "IPData"], ["PCmdA[7]", "Gnd"], ["PCmdA[6]", "Gnd"], ["PCmdA[5]", "Gnd"], ["PCmdA[4]", "IPCmdFetchA"], ["PCmdA[3]", "IPCmdFetchA"], ["PCmdA[2]", "IPCmdFetchA"], ["PCmdA[1]", "IPCmdFetchA"], ["PCmdA[0]", "IPCmdFetchA"], ["PRejectB", "IPRejectB"], ["PFaultB[0]", "IPFaultingB"], ["PFaultB[1]", "IPFaultingXB[0]"], ["PFaultB[2]", "IPFaultingXB[1]"], ["PFaultB[3]", "IPFaultingXB[2]"] ] ]; ks.coreInsts[eCache] _ CoreCreate.InstanceList[ type: CoreFlat.CellTypeCutLabels[ on: Cache.Create[vm: ks.eCache, skipRejects: skipEURejects], l1: "TopLevel"], pas: LIST[ ["PUserMode", "UserMode2BA"], ["PData", "DPData"], ["PCmdA", "DPCmdA"], ["PRejectB", "DPRejectB"], ["PFaultB", "DPFaultB"] ] ]; ks.coreInsts[ifu] _ CoreCreate.InstanceList[ type: CoreFlat.CellTypeCutLabels[ on: IFUTop.CreateIFU[NEW[IFUTop.IFUTypeData _ [data: ks, getLog: GetLog, checkSynch: CheckSynch, getCycle: GetCycle ]], fullIFU, quickIFU, rawIFU], l1: "TopLevel" ], pas: LIST[ ["KBus", "KBus"], ["EUAluOp", "EUAluOp2AB"], ["EUCondSel", "EUCondSel2AB"], ["EUCondition", "EUCondition2B"], ["EURdFromPBus", "EURdFromPBus3AB"], ["EUWriteToPBus", "EUWriteToPBus3AB"], ["UserMode", "UserMode2BA"], ["DPCmd", "DPCmdA"], ["DPReject", "DPRejectB"], ["DPFault", "DPFaultB"], ["IPCmdFetch", "IPCmdFetchA"], ["IPReject", "IPRejectB"], ["IPFaulting", "IPFaultingB"], ["IPData", "IPData"], ["Reset", "ResetAB"], ["Reschedule", "RescheduleAB"], ["DShA", "IFUDShA"], ["DShB", "IFUDShB"], ["DShRd", "IFUDShRd"], ["DShWt", "IFUDShWt"], ["DShIn", "IFUDShIn"], ["DShOut", "IFUDShOut"], ["Vbb", "Vdd"], ["VbbGen", "VbbGen"], ["Clk", "Clk"], ["PhAOut", "PhAOut"], ["PhBOut", "PhBOut"], ["PhA", "PhA"], ["PhB", "PhB"], ["Vdd", "Vdd"], ["Gnd", "Gnd"], ["PadVdd", "PadVdd"], ["PadGnd", "PadGnd"] ] ]; ks.coreInsts[eu] _ CoreCreate.InstanceList[ type: CoreFlat.CellTypeCutLabels[ on: EU.CreateEU[ typeData: NEW[EU.EUTypeData_[data: ks, storeNoted: FALSE, noteStore: NoteRegStore]], fullEU: fullEU, useCkPt: fullEU], l1: "TopLevel" ], pas: LIST[ ["DShA", "EUDShA"], ["DShB", "EUDShB"], ["DShRd", "EUDShRd"], ["DShWt", "EUDShWt"], ["DShIn", "EUDShIn"], ["DShOut", "EUDShOut"] ] ]; FOR inst: Instances DECREASING IN Instances DO tempInstances _ CONS[ks.coreInsts[inst], tempInstances] ENDLOOP; IFUTop.MarkMemoryWires[iOnly[CoreOps.GetWireIndex[iOnly, "DPFaultB"]]]; IFUTop.MarkMemoryWires[iOnly[CoreOps.GetWireIndex[iOnly, "IPFaultingB"]]]; IFUTop.MarkMemoryWires[iOnly[CoreOps.GetWireIndex[iOnly, "IPFaultingXB"]]]; IFUTop.MarkMemoryWires[iOnly[CoreOps.GetWireIndex[iOnly, "DPRejectB"]]]; IFUTop.MarkMemoryWires[iOnly[CoreOps.GetWireIndex[iOnly, "IPRejectB"]]]; IFUTop.MarkMemoryWires[iOnly[CoreOps.GetWireIndex[iOnly, "IPData"]]]; IFUTop.MarkMemoryWires[iOnly[CoreOps.GetWireIndex[iOnly, "KBus"]]]; ks.cluster _ CoreCreate.Cell[ public: public, onlyInternal: iOnly, instances: tempInstances, name: "Cluster" ]; ks.clusterIOPort _ Ports.CreatePort[ks.cluster]; ks.rosemarySimulation _ Rosemary.Instantiate[ cellType: ks.cluster, testPort: ks.clusterIOPort, cutSet: CoreFlat.CreateCutSet[labels: LIST["TopLevel"] ] ]; FOR inst: Instances IN Instances DO ks.flatCT[inst] _ NEW[CoreFlat.FlatCellTypeRec _ CoreFlat.ParseCellTypePath[ks.cluster, IO.PutFR["/%g", IO.int[Instances[inst].ORD]]]]; ks.stateTop[0].refCy _ NEW[INT _ 0]; ks.stateTop[0].refPh _ NEW[Dragon.Phase _ a]; ks.stateTop[0].data[inst] _ Rosemary.GetState[ks.rosemarySimulation, ks.flatCT[inst]]; ENDLOOP; FOR i: NAT IN [1..Cluster.historySize) DO ks.stateTop[i].refCy _ NEW[INT _ 0]; ks.stateTop[i].refPh _ NEW[Dragon.Phase _ a]; ks.stateTop[i].data _ [ ifu: NEW[IFUTop.IFUStateRec], eu: NEW[EU.EUStateRec], iCache: NEW[Cache.CacheState], eCache: NEW[Cache.CacheState]]; ENDLOOP; FOR i: NAT IN [0..Cluster.historySize) DO ks.stateFull[i].refCy _ NEW[INT _ 0]; ks.stateFull[i].refPh _ NEW[Dragon.Phase _ a]; ks.stateFull[i].data _ [ ifu: NEW[IFUTop.IFUStateRec], eu: NEW[EU.EUStateRec], iCache: NEW[Cache.CacheState], eCache: NEW[Cache.CacheState]]; ENDLOOP; ks.euReject _ NEW[CoreFlat.FlatWireRec _ CoreFlat.ParseWirePath[ks.cluster, "DPRejectB"]]; ks.ifuSimulationTruthPort _ Ports.CreatePort[ks.coreInsts[ifu].type, TRUE]; IF fullIFU THEN { ifuCellType: Core.CellType _ ks.coreInsts[ifu].type; TerminalIO.PutF["Make IFU Simulation %g\n", IO.time[]]; ks.ifuSimulationTestPort _ Ports.CreatePort[ifuCellType, TRUE]; ks.ifuSimulation _ Rosemary.Instantiate[ ifuCellType, ks.ifuSimulationTestPort, CoreFlat.CreateCutSet[labels: fullIFUCuts]]; ks.ifuDisplay _ RosemaryUser.DisplayViewer[ks.ifuSimulation, ifuCellType, "IFUTop", RosemaryUser.DisplayPortLeafWires[ifuCellType]]; Rosemary.Initialize[ks.ifuSimulation, FALSE]; RosemaryUser.InitializeDeltas[ks.ifuDisplay]; TerminalIO.PutF["IFU Instantiated %g\n", IO.time[]]}; ks.euSimulationTruthPort _ Ports.CreatePort[ks.coreInsts[eu].type, TRUE]; IF fullEU THEN { euCellType: Core.CellType _ ks.coreInsts[eu].type; TerminalIO.PutF["Make EU Simulation %g\n", IO.time[]]; ks.euSimulationTestPort _ Ports.CreatePort[euCellType, TRUE]; ks.euSimulation _ Rosemary.Instantiate[ euCellType, ks.euSimulationTestPort, CoreFlat.CreateCutSet[labels: LIST["Logic"]]]; ks.euDisplay _ RosemaryUser.DisplayViewer[ks.euSimulation, euCellType, "EU", RosemaryUser.DisplayPortLeafWires[euCellType]]; Rosemary.Initialize[ks.euSimulation, FALSE]; RosemaryUser.InitializeDeltas[ks.euDisplay]; TerminalIO.PutF["EU Instantiated %g\n", IO.time[]]}; StartIFUScanPanel[ks]; StartPanel[ks]}; DoCluster: PUBLIC PROC [ks: KitchenSink, diagnostic: Core.ROPE _ NIL] = { originalPriority: Process.Priority = Process.GetPriority[]; diagnosticName: Core.ROPE _ "unknown"; IF ks=NIL THEN ks _ MakeCluster[]; { ENABLE UNWIND => { ks.log.PutF["\nSimulation of %g aborted\n\n", IO.rope[diagnosticName]]; ks.log.Flush[]; Process.SetPriority[ originalPriority ] }; time: INT _ -1; DoEval: PROC = { inhibitExpects: BOOL _ ks.controlPanel.reset OR ks.protCyclesAfterReject>0; time _ time+1; ks.controlPanel.continueTestFromAbort _ FALSE; IF GetPublicBool[ks, $PhA] THEN { SetPublicBool[ks, $RescheduleAB, ks.controlPanel.resched]; SetPublicBool[ks, $ResetAB, ks.controlPanel.reset] }; Rosemary.Settle[ ks.rosemarySimulation ! ABORTED => IF ks.controlPanel.continueTestFromAbort THEN CONTINUE ELSE REJECT]; CopyClusterArrayContents[ks.stateTop[0], ks.stateFull[0]]; Rosemary.SettleToTest[simulation: ks.rosemarySimulation, flatCell: ks.flatCT[ifu], test: ks.ifuSimulationTruthPort]; IF fullIFU THEN { Ports.CopyPortValue[from: ks.ifuSimulationTruthPort, to: ks.ifuSimulationTestPort]; IF ks.controlPanel.recordPlotData THEN LogSettle[ks.ifuDisplay, time, ks.controlPanel.chrgdMemNodesOk ! Rosemary.Stop => IF reason # $BoolWireHasX THEN REJECT ELSE IF ks.controlPanel.reset OR ks.protCyclesAfterReject>0 THEN RESUME ELSE { TerminalIO.PutF["%g = X\n", IO.rope[ CoreOps.GetShortWireName[NARROW[data, CoreFlat.FlatWire].wire]]]; RosemaryUser.UpdateDisplay[ks.ifuDisplay]; RESUME}] ELSE Rosemary.Settle[ks.ifuSimulation, NIL, ks.controlPanel.chrgdMemNodesOk ! Rosemary.Stop => IF reason # $BoolWireHasX THEN REJECT ELSE IF ks.controlPanel.reset OR ks.protCyclesAfterReject>0 THEN RESUME ELSE { TerminalIO.PutF["%g = X\n", IO.rope[ CoreOps.GetShortWireName[NARROW[data, CoreFlat.FlatWire].wire]]]; RosemaryUser.UpdateDisplay[ks.ifuDisplay]; RESUME}]; IF ks.controlPanel.sampleFullIFU AND GetPublicBool[ks, $PhA] THEN UpdateIFUState [ks.ifuSimulation, NARROW[ks.stateFull[0].data[ifu]], ks.controlPanel.cycle, A]; IF ks.controlPanel.sampleFullIFU AND GetPublicBool[ks, $PhB] THEN UpdateIFUState [ks.ifuSimulation, NARROW[ks.stateFull[0].data[ifu]], ks.controlPanel.cycle, B]; RosemaryUser.UpdateDisplay[ks.ifuDisplay]; Ports.CheckPortValue[root: ks.coreInsts[ifu].type.public, truth: ks.ifuSimulationTruthPort, question: ks.ifuSimulationTestPort ! Ports.CheckError => IF NOT (ks.controlPanel.proceedFromCheckPort OR ks.protCyclesAfterReject>0) THEN REJECT ELSE {TerminalIO.PutF["%g\n", IO.rope[msg]]; RESUME}] }; Rosemary.SettleToTest[simulation: ks.rosemarySimulation, flatCell: ks.flatCT[eu], test: ks.euSimulationTruthPort]; IF fullEU THEN { Ports.CopyPortValue[from: ks.euSimulationTruthPort, to: ks.euSimulationTestPort]; RosemaryUser.LogSettle[ks.euDisplay, time ! Rosemary.Stop => IF ks.protCyclesAfterReject>0 AND reason = $BoolWireHasX THEN RESUME ELSE {RosemaryUser.UpdateDisplay[ks.euDisplay]; REJECT}]; RosemaryUser.UpdateDisplay[ks.euDisplay]; Ports.CheckPortValue[root: ks.coreInsts[eu].type.public, truth: ks.euSimulationTruthPort, question: ks.euSimulationTestPort ! Ports.CheckError => IF NOT ks.controlPanel.proceedFromCheckPort THEN REJECT ELSE {TerminalIO.PutF["%g\n", IO.rope[msg]]; RESUME}]}; IF ks.controlPanel.reset THEN ks.controlPanel.instrCount _ -1; IF ks.ifuVectors#NIL THEN RosemaryVector.WriteVector[ks.ifuVectors, inhibitExpects]; IF ks.euVectors#NIL THEN RosemaryVector.WriteVector[ks.euVectors, inhibitExpects]; Process.Yield[]; ks.controlPanel.continueTestFromAbort _ FALSE}; LogSettle: PROC [handle: RosemaryUser.RoseDisplay, time: INT, memory: BOOL _ TRUE] = { UpdateWire: Rosemary.UpdateProc = { coreWire: CoreFlat.FlatWireRec; RosemaryUser.RecordDelta[handle, roseWire, time]; IF NOT handle.traceChanges THEN RETURN; RosemaryUser.UpdateDisplay[handle]; coreWire _ roseWire.wire; wireKey^ _ coreWire; IO.PutF[handle.tsout, "%g_%g ", IO.rope[CoreFlat.WirePathRope[handle.cellType, coreWire]], IO.rope[Ports.LevelSequenceToRope[Rosemary.WireValue[ handle.simulation, wireKey]]]]}; wireKey: CoreFlat.FlatWire _ NEW[CoreFlat.FlatWireRec]; Rosemary.Settle[handle.simulation, UpdateWire, memory]; RosemaryUser.DeltaFinished[handle, time]; IF handle.traceChanges THEN IO.PutRope[handle.tsout, "\n\n"]}; UpdateIFUState: IFUTest.UpdateProc = { comp: IFUState _ NARROW[ks.stateTop[0].data[ifu]]; atom: ATOM _ $IFUUpdateProc; -- IFUTest.ifuUpdateProc updateProc: REF IFUTest.UpdateProc _ NARROW[Atom.GetProp[atom, atom]]; IF updateProc=NIL OR rawIFU THEN RETURN; updateProc^[sim, state, pass, qph]; comp.cycle _ state.cycle; comp.ph _ state.ph; IF state^#comp^ THEN IF ks.controlPanel.reset OR ks.protCyclesAfterReject>0 OR ks.controlPanel.proceedFromCompareTest THEN TerminalIO.PutF["#\n"] ELSE Signal[]}; Signal: SIGNAL = CODE; CopyClusterArrayContents: PROC[fm, to: ClusterState] = { to.refCy^ _ fm.refCy^; to.refPh^ _ fm.refPh^; NARROW[ to.data[ifu], IFUState]^ _ NARROW[ fm.data[ifu], IFUState]^; NARROW[ to.data[eu], EUState]^ _ NARROW[ fm.data[eu], EUState]^; NARROW[ to.data[iCache], CacheSt]^ _ NARROW[ fm.data[iCache], CacheSt]^; NARROW[ to.data[eCache], CacheSt]^ _ NARROW[ fm.data[eCache], CacheSt]^}; Cycles: PROC [ n: INT ] = {FOR i: INT IN [0..n) DO DoPh[a]; DoPh[b] ENDLOOP}; Remark: PROC [explan: Core.ROPE] = { ks.controlPanel.msg _ explan; ks.controlPanel.running _ FALSE; DoEval[]; UNTIL ks.controlPanel.running DO Process.Pause[Process.MsecToTicks[1000]] ENDLOOP; ks.controlPanel.msg _ runningMsg; DoEval[]; }; DoDRd: PROC = { SetPublicBool[ks, $IFUDShRd, TRUE]; DoEval[]; SetPublicBool[ks, $IFUDShRd, FALSE]; DoEval[]}; DoDShift: PROC[in, out: IFUPublic.ScanRef] = { size: NAT _ REFBit.Size[in]; FOR i: INT IN [0..size) DO ks.controlPanel.ifuDebugScanLoc _ i; IF NOT ks.controlPanel.running THEN Remark[ (IF ks.controlPanel.msg = runningMsg THEN "Simulation manually suspended..." ELSE ks.controlPanel.msg)]; ks.controlPanel.msg _ runningMsg; SetPublicBool[ks, $IFUDShIn, NOT IFUPublic.GetScanBit[in, size-1-i]]; SetPublicBool[ks, $IFUDShA, TRUE]; DoEval[]; SetPublicBool[ks, $IFUDShA, FALSE]; DoEval[]; SetPublicBool[ks, $IFUDShB, TRUE]; DoEval[]; SetPublicBool[ks, $IFUDShB, FALSE]; DoEval[]; IFUPublic.SetScanBit[out, size-1-i, NOT GetPublicBool[ks, $IFUDShOut]]; ENDLOOP}; DoDWt: PROC = { SetPublicBool[ks, $IFUDShWt, TRUE]; DoEval[]; SetPublicBool[ks, $IFUDShWt, FALSE]; DoEval[]}; DoPh: PROC [ ph: Dragon.Phase ] = { first: BOOL _ TRUE; ks.controlPanel.phase _ ph; WHILE first OR ks.controlPanel.repeatPhase DO SetPublicBool[ks, $PhA, ph=a]; SetPublicBool[ks, $PhB, ph=b]; ks.stateTop[0].refPh^ _ ks.stateFull[0].refPh^ _ ks.controlPanel.phase; ks.stateTop[0].refCy^ _ ks.stateFull[0].refCy^ _ ks.controlPanel.cycle; IF ks.controlPanel.running THEN {ks.controlPanel.msg _ runningMsg; DoEval[]} ELSE Remark[(IF ks.controlPanel.msg = runningMsg THEN "Simulation manually suspended..." ELSE ks.controlPanel.msg)]; IF first THEN { OPEN cp: ks.controlPanel; IF cp.stopInPh[ph] AND (cp.cycle >= cp.slowFromCycle OR (cp.cycle >= 0 AND cp.instrCount >= cp.slowFromInstr)) THEN Remark[IO.PutFR["Doing cycle %g Ph%g...", IO.int[cp.cycle], IO.char[IF ph=a THEN 'A ELSE 'B]]]} ELSE Remark[IO.PutFR["...repeating cycle %g Ph%g..", IO.int[ks.controlPanel.cycle], IO.char[IF ph=a THEN 'A ELSE 'B]]]; IF first THEN { -- cycle history buffers [1..top) lastTop: ClusterState _ ks.stateTop [Cluster.historySize-1]; lastFull: ClusterState _ ks.stateFull [Cluster.historySize-1]; FOR i: NAT DECREASING IN (1..Cluster.historySize) DO ks.stateTop [i] _ ks.stateTop [i-1]; ks.stateFull [i] _ ks.stateFull [i-1] ENDLOOP; ks.stateTop[1] _ lastTop; ks.stateFull[1] _ lastFull; CopyClusterArrayContents[ks.stateTop[0], ks.stateTop[1]]; CopyClusterArrayContents[ks.stateFull[0], ks.stateFull[1]]; first _ FALSE }; SetPublicBool[ks, $PhB, FALSE]; SetPublicBool[ks, $PhA, FALSE]; DoEval[]; ENDLOOP; ks.protCyclesAfterReject _ SELECT TRUE FROM ks.controlPanel.reset => 3, ph=a OR Rosemary.WireValue[simulation: ks.rosemarySimulation, flatWire: ks.euReject][0]=H => ks.protCyclesAfterReject, ks.protCyclesAfterReject>0 => ks.protCyclesAfterReject-1, ENDCASE => 0}; Process.SetPriority[ Process.priorityBackground ]; ks.diagnostics _ IF diagnostic=NIL THEN "test end" ELSE diagnostic; ks.controlPanel.diagnostic _ ks.diagnostics; ks.controlPanel.running _ TRUE; DO -- over all diagnostics Chop: PROC RETURNS [ first, rest: Rope.ROPE _ NIL ] = { dStream: IO.STREAM = IO.RIS[ks.controlPanel.diagnostic]; first _ dStream.GetTokenRope[IO.IDProc ! IO.EndOfStream => CONTINUE].token; rest _ ks.controlPanel.diagnostic.Substr[dStream.GetIndex]}; file, root: Core.ROPE; diagnosticFileName: Core.ROPE _ diagnosticName _ Chop[].first; IF ks.ifuVectors # NIL THEN {RosemaryVector.CloseVectorFile[ks.ifuVectors]; ks.ifuVectors _ NIL}; IF ks.euVectors # NIL THEN {RosemaryVector.CloseVectorFile[ks.euVectors]; ks.euVectors _ NIL}; ks.log.Flush[]; IF Rope.Length[diagnosticFileName] = 0 OR (Rope.Equal[s1: diagnosticFileName, s2: "END", case: FALSE] AND ks.controlPanel.randomSeed=0) THEN EXIT; file _ FileNames.GetShortName[diagnosticFileName]; root _ file.Substr[0, file.Index[0, "."]]; ks.controlPanel.reset _ TRUE; WHILE ks.controlPanel.reset DO -- as often as RESET is asserted in the same diagnostic IF ks.controlPanel.enaIFUVectorWt AND ks.ifuVectors=NIL THEN ks.ifuVectors _ RosemaryVector.OpenVectorFile [root.Cat[".ifuVectors"], ks.ifuSimulationTruthPort, FALSE]; IF ks.controlPanel.enaEUVectorWt AND ks.euVectors=NIL THEN ks.euVectors _ RosemaryVector.OpenVectorFile [root.Cat[".euVectors"], ks.euSimulationTruthPort, FALSE]; ks.controlPanel.stopInPh _ ALL[TRUE]; ks.controlPanel.repeatPhase _ ks.controlPanel.resched _ FALSE; ks.controlPanel.cycle _ -1; ks.controlPanel.instrCount _ -1; { public: Core.Wire _ ks.cluster.public; ks.clusterIOPort[CoreOps.GetWireIndex[public, "DHold"]].b _ FALSE; ks.clusterIOPort[CoreOps.GetWireIndex[public, "DStAd"]].c _ 0; ks.clusterIOPort[CoreOps.GetWireIndex[public, "Clk"]].b _ TRUE; ks.clusterIOPort[CoreOps.GetWireIndex[public, "IFUDShA"]].b _ TRUE; ks.clusterIOPort[CoreOps.GetWireIndex[public, "IFUDShB"]].b _ TRUE; ks.clusterIOPort[CoreOps.GetWireIndex[public, "IFUDShRd"]].b _ FALSE; ks.clusterIOPort[CoreOps.GetWireIndex[public, "IFUDShWt"]].b _ FALSE; ks.clusterIOPort[CoreOps.GetWireIndex[public, "IFUDShIn"]].b _ FALSE; ks.clusterIOPort[CoreOps.GetWireIndex[public, "EUDShA"]].b _ TRUE; ks.clusterIOPort[CoreOps.GetWireIndex[public, "EUDShB"]].b _ TRUE; ks.clusterIOPort[CoreOps.GetWireIndex[public, "EUDShRd"]].b _ FALSE; ks.clusterIOPort[CoreOps.GetWireIndex[public, "EUDShWt"]].b _ FALSE; ks.clusterIOPort[CoreOps.GetWireIndex[public, "EUDShIn"]].b _ FALSE; }; FOR j: NAT IN [0..8) DO DoPh[a ! DragonRosemary.AssertionFailed => RESUME; Rosemary.Stop => IF reason = $FailedAssertion OR reason = $BoolWireHasX THEN RESUME ELSE REJECT; IFUTop.IFUInconsistent => CONTINUE ]; DoPh[b ! DragonRosemary.AssertionFailed => RESUME; Rosemary.Stop => IF reason = $FailedAssertion OR reason = $BoolWireHasX THEN RESUME ELSE REJECT; IFUTop.IFUInconsistent => CONTINUE ]; ENDLOOP; { public: Core.Wire _ ks.cluster.public; ks.clusterIOPort[CoreOps.GetWireIndex[public, "IFUDShA"]].b _ FALSE; ks.clusterIOPort[CoreOps.GetWireIndex[public, "IFUDShB"]].b _ FALSE; ks.clusterIOPort[CoreOps.GetWireIndex[public, "EUDShA"]].b _ FALSE; ks.clusterIOPort[CoreOps.GetWireIndex[public, "EUDShB"]].b _ FALSE; }; Cycles[2]; SELECT TRUE FROM diagnosticFileName # NIL => { fullName: Core.ROPE _ FileNames.FileWithSearchRules [diagnosticFileName, NIL, FALSE, TRUE, NIL].fullPath; CacheOps.VirtualMemoryFromFile[ks.vm, fullName ]; ks.lizardSimulation _ (IF ks.controlPanel.lizardToo THEN StartNewLizard[ks.vm] ELSE NIL)}; ks.controlPanel.randomSeed#0 => { diagnosticName _ IO.PutFR["random code (seed = %d)", IO.int[ks.controlPanel.randomSeed]]; InsertRandomProgramInVM[ks]; ks.lizardSimulation _ (IF ks.controlPanel.lizardToo THEN StartNewLizard[ks.vm] ELSE NIL)}; ENDCASE => ERROR; ks.controlPanel.reset _ FALSE; DoPh[a]; IF ks.controlPanel.reset THEN LOOP; -- restart this diagnostic DoPh[b]; IF ks.controlPanel.reset THEN LOOP; -- restart this diagnostic IF ks.controlPanel.slowFromCycle<=0 THEN Remark["Processor has been reset..."]; ks.controlPanel.cycle _ 0; ks.rosemaryStores _ NIL; ks.log.PutF["\n\n\n%g Dragon Rosemary simulation of %g beginning...\n\n", IO.time[], IO.rope[diagnosticName]]; WHILE ks.controlPanel.randomSeed=0 OR ks.controlPanel.cycle<=ks.controlPanel.randomCycleLimit DO ENABLE { Breakpoint => { ks.log.PutF["\n%g Breakpoint XOP in %g at instruction %d, cycle %d.\n\n", IO.time[], IO.rope[diagnosticName], IO.int[ks.controlPanel.instrCount], IO.int[ks.controlPanel.cycle]]; SELECT TRUE FROM ks.controlPanel.emulateBreakpoint => RESUME; diagnosticFileName # NIL => REJECT; ENDCASE => EXIT } }; IF ks.controlPanel.ifuDebugScanOut THEN { DoDRd[]; DoDShift[ks.ifuScanBuffer, ks.ifuScanBuffer]; ks.controlPanel.ifuDebugScanOut _ FALSE}; DoPh[a]; IF ks.controlPanel.reset THEN EXIT; -- restart this diagnostic DoPh[b]; IF GetSuccessHalt[] THEN { ks.log.PutF["\n%g Success XOP in %g at instruction %d, cycle %d.\n\n", IO.time[], IO.rope[diagnosticName], IO.int[ks.controlPanel.instrCount], IO.int[ks.controlPanel.cycle]]; SetSuccessHalt[FALSE]; EXIT}; IF ks.controlPanel.reset THEN EXIT; -- restart this diagnostic ks.controlPanel.cycle _ ks.controlPanel.cycle+1; IF NOT ks.controlPanel.enaIFUVectorWt AND (ks.ifuVectors # NIL) THEN {RosemaryVector.CloseVectorFile[ks.ifuVectors]; ks.ifuVectors _ NIL}; IF NOT ks.controlPanel.enaEUVectorWt AND (ks.euVectors # NIL) THEN {RosemaryVector.CloseVectorFile[ks.euVectors]; ks.euVectors _ NIL}; ENDLOOP; -- on ks.controlPanel.cycle ENDLOOP; -- on a single diagnostic SELECT TRUE FROM diagnosticFileName # NIL => { first, rest: Rope.ROPE; [first, rest] _ Chop[]; IF first.Equal[diagnosticFileName] THEN ks.controlPanel.diagnostic _ Rope.Cat[rest, " ",first]}; ks.controlPanel.randomSeed # 0 => ks.controlPanel.randomSeed _ ks.controlPanel.randomSeed+1; ENDCASE => NULL; ENDLOOP; -- on ks.diagnostic or ks.controlPanel.randomSeed }; -- for catching UNWIND Process.SetPriority[ originalPriority ]}; SetPublic: PUBLIC PROC [ks: KitchenSink, signal: ATOM, value: REF ANY _ NIL ] = { WITH value SELECT FROM refBool: REF BOOL => ks.clusterIOPort[CoreOps.GetWireIndex[ks.rosemarySimulation.cellType.public, Atom.GetPName[signal]]].b _ refBool^; ENDCASE => ERROR}; SetPublicBool: PUBLIC PROC [ks: KitchenSink, signal: ATOM, value: BOOL ] = {SetPublic[ks, signal, NEW[BOOL _ value]]}; SetPublicAndSettle: PUBLIC PROC [ks: KitchenSink, signal: ATOM, value: REF ANY _ NIL ] = { SetPublic[ks, signal, value]; Rosemary.Settle[ ks.rosemarySimulation ! ABORTED => IF ks.controlPanel.continueTestFromAbort THEN CONTINUE ELSE REJECT ]; ks.controlPanel.continueTestFromAbort _ FALSE}; GetPublicBool: PUBLIC PROC [ks: KitchenSink, signal: ATOM] RETURNS [value: BOOL] = {value _ ks.clusterIOPort[CoreOps.GetWireIndex[ks.rosemarySimulation.cellType.public, Atom.GetPName[signal]]].b}; GetLog: PROC [ data: OpaqueKitchenSink ] RETURNS [ Core.STREAM ] = {ks: KitchenSink = NARROW[data]; RETURN [ ks.log ]}; GetCycle: PROC [ data: OpaqueKitchenSink ] RETURNS [ cycle: INT ] = {ks: KitchenSink = NARROW[data]; RETURN [ ks.controlPanel.cycle ]}; NoteRegStore: PROC [ data: REF ANY, reg: [0..256), value: Dragon.Word ] = { ks: KitchenSink = NARROW[data]; ks.rosemaryStores _ CONS[NEW[Dragon.RegStoreRec _ [instr: ks.controlPanel.instrCount, reg: VAL[reg], data: value]], ks.rosemaryStores]}; randomStartPC: Dragon.Word _ 102000H; runningMsg: Core.ROPE _ "Running..."; randomBackground: Core.ROPE _ "RandomBackground.quad"; InsertRandomProgramInVM: PROC[ ks: KitchenSink ] = { WriteOneCodeByte: PROC [byte: [0..255]] = { background: Basics.LongNumber; CacheOps.SetFlags[c: ks.eCache, address: nextByteAddr/4, mapped: TRUE, memAccessProtect: FALSE, dirty: FALSE]; background.lc _ CacheOps.Access[c: ks.eCache, address: nextByteAddr/4].data; SELECT nextByteAddr MOD 4 FROM 0 => background.hh _ byte; 1 => background.hl _ byte; 2 => background.lh _ byte; 3 => background.ll _ byte; ENDCASE => ERROR; CacheOps.Write[c: ks.eCache, address: nextByteAddr/4, data: background.lc]; nextByteAddr _ nextByteAddr+1}; fullName: Core.ROPE _ FileNames.FileWithSearchRules [randomBackground, NIL, FALSE, TRUE, NIL].fullPath; nextByteAddr: Dragon.Word _ randomStartPC; CacheOps.VirtualMemoryFromFile[ks.vm, fullName]; RandomCode.GenerateRandomProgramBytes[ initialByteAddress: randomStartPC, randomSeed: ks.controlPanel.randomSeed, seeOneByte: WriteOneCodeByte, dribble: ks.log ]; ks.eCache _ CacheOps.NewCache[ks.eCache]}; -- resets first free cycle, cache lines LizardEUCacheFetchTrap: PROC [base: LizardCache.CacheBase, addr: LizardCache.Word, cycle: INT, userMode: BOOL, noEffect: BOOL _ FALSE] RETURNS [data: LizardCache.Word, status: LizardCache.TrapIndex, rejectCycles: INT] = { sim: LizardSimulation = NARROW[base.data]; [data: data, status: status, rejectCycles: rejectCycles] _ sim.euCache.fetch [base: sim.euCache, addr: addr, cycle: cycle, userMode: userMode, noEffect: noEffect]; sim.lastInstrOps _ CONS[ NEW[Dragon.CacheTransRec _ [ instr: sim.processor.stats.instructions, cmd: Fetch, -- might be FetchHold, we can't tell here addr: DragOpsCrossUtils.WordToCard[addr], data: DragOpsCrossUtils.WordToCard[data], fault: SELECT status FROM ALUCondFalse => none, MemAccessFault => memAccess, IOAccessFault => ioAccess, MapFault => map, AUFault => au, DynaBusTimeOut => timeOut, DynaBusOtherFault => other, ENDCASE => ERROR ]], sim.lastInstrOps]}; LizardEUCacheStoreTrap: PROC [base: LizardCache.CacheBase, addr: LizardCache.Word, data: LizardCache.Word, cycle: INT, userMode: BOOL] RETURNS [old: LizardCache.Word, status: LizardCache.TrapIndex, rejectCycles: INT] = { sim: LizardSimulation = NARROW[base.data]; [old: old, status: status, rejectCycles: rejectCycles] _ sim.euCache.store[base: sim.euCache, addr:addr, data:data, cycle:cycle, userMode:userMode]; sim.lastInstrOps _ CONS[ NEW[Dragon.CacheTransRec _ [ instr: sim.processor.stats.instructions, cmd: Store, addr: DragOpsCrossUtils.WordToCard[addr], data: DragOpsCrossUtils.WordToCard[data], fault: SELECT status FROM ALUCondFalse => none, MemAccessFault => memAccess, IOAccessFault => ioAccess, MapFault => map, AUFault => au, DynaBusTimeOut => timeOut, DynaBusOtherFault => other, ENDCASE => ERROR ]], sim.lastInstrOps]}; NoteChangedReg: PROC[data: REF, processor: LizardHeart.Processor, reg: DragOpsCross.ProcessorRegister, old,new: DragOpsCross.Word] = { sim: LizardSimulation = NARROW[data]; sim.lastInstrOps _ CONS[ NEW[Dragon.RegStoreRec _ [ instr: sim.processor.stats.instructions, reg: reg, data: DragOpsCrossUtils.WordToCard[new] ]], sim.lastInstrOps]}; NoteInstDone: PROC [data: REF, processor: LizardHeart.Processor, newPC, rtnPC: DragOpsCross.Word, control: LizardHeart.Control, cycles: INT] = -- LizardHeart.InstDoneProc-- {sim: LizardSimulation = NARROW[data]; sim.control _ control}; StartNewLizard: PUBLIC PROC [ m: REF -- CacheOps.VM -- ] RETURNS [ sim: LizardSimulation ] = { StoreWord: PROC [ addr, data: Dragon.Word, readOnly, dirty: BOOL _ FALSE, privateData: REF _ NIL ] = {SparseMemory.Store[base: lizardVM, index: DragOpsCrossUtils.CardToWord[addr], new: DragOpsCrossUtils.CardToWord[data]]}; lizardVM: SparseMemory.Base; lizardSharedVM: LizardCache.SharedBase; sim _ NEW[Cluster.LizardSimulationRec]; lizardVM _ SparseMemory.Create[]; lizardSharedVM _ LizardCache.NewBase[lizardVM]; CacheOps.EnumerateVirtualMemory[m, StoreWord]; -- initialize Lizard's memory sim.euCache _ LizardCache.NewCache[lizardSharedVM]; sim.processor _ LizardHeart.NewProcessor[ ifuCache: LizardCache.NewCache[lizardSharedVM], euCache: NEW[LizardCache.CacheBaseRep _ [ fetch: LizardEUCacheFetchTrap, store: LizardEUCacheStoreTrap, sharedBase: sim.euCache.sharedBase, private: sim.euCache.private, data: sim ]], logger: NEW[LizardHeart.ChangeLoggerRep _ [ data: sim, regChange: NoteChangedReg, instDone: NoteInstDone ]] ]}; successHalt: BOOL _ FALSE; SetSuccessHalt: PUBLIC PROC[new: BOOL] = {successHalt _ new}; GetSuccessHalt: PUBLIC PROC RETURNS[BOOL] = {RETURN[successHalt]}; Breakpoint: PUBLIC SIGNAL = CODE; CheckSynch: PUBLIC PROC [ data: OpaqueKitchenSink, basicInst: IFUTop.BasicInst ] RETURNS [deltaInstrCount: INT _ 1] -- IFUTop.CheckSynchProc -- = { retry: BOOL _ TRUE; WHILE retry DO retry _ FALSE; deltaInstrCount _ csProcRec.proc[data: data, basicInst: basicInst ]; -- debugger might set retry to TRUE NULL; -- for breakpoints and what-have-you ENDLOOP}; DefaultCheckSynch: PUBLIC IFUTop.CheckSynchProc = {RETURN[1]}; csProcRec: PUBLIC Cluster.CSProcRec _ [DefaultCheckSynch]; StartIFUScanPanel: PROC [ks: KitchenSink] = { IF ks.ifuScanBuffer = NIL THEN ks.ifuScanBuffer _ NEW[IFUPublic.ScanRec]; }; StartPanel: PROC [ks: KitchenSink] = { IF ks.controlPanel = NIL THEN { ks.controlPanel _ NEW[Cluster.ControlPanelRec _ [ msg: "Initialized...", enaIFULog: TRUE, recordPlotData: recordPlotData, chrgdMemNodesOk: chrgdMemNodesOk, enaIFUVectorWt: initIFUVectorWt, enaEUVectorWt: initEUVectorWt, diagnostic: ks.diagnostics ]]; ViewRec.SetBehavior[newBehavior: [delayParms: [min: 2000.0]]]; [] _ ViewRec.ViewRef[ agg: ks.controlPanel, label: "Dragon Cluster Control Panel", specs: LIST[ ["cycle", Value[val:NIL, visible:TRUE, dontAssign:TRUE]], ["phase", Value[val:NIL, visible:TRUE, dontAssign:TRUE]], ["instrCount", Value[val:NIL, visible:TRUE, dontAssign:TRUE]] ]] } }; END. TClusterImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. McCreight, May 13, 1986 2:28:33 pm PDT Louis Monier April 18, 1986 9:58:08 am PST Barth, April 28, 1986 4:25:45 pm PDT Curry, October 24, 1986 2:52:26 pm PDT Don Curry May 1, 1987 3:40:53 pm PDT Last Edited by: Louis Monier April 23, 1987 1:24:16 am PDT Last Edited by: Don Curry February 23, 1988 5:59:00 pm PST I put this in so that you can get your hands on the kitchen sink from a new command tool. If you take it out, I may not rip your lungs out, but ... IFUPublic.PortWire[TRUE, "NotPhA", 1, force], -- IFU no longer uses. Does EU? IFUPublic.PortWire[TRUE, "NotPhB", 1, force], -- IFU no longer uses. Does EU? IF fullIFU THEN { data: CoreClasses.RecordCellType _ NARROW[ks.coreInsts[ifu].type.data]; xbus: Core.Wire _ data.internal[CoreOps.GetWireIndex[data.internal, "XBus"]]; TerminalIO.PutRope["Marking XBus with Memory TRUE\n"]; IFUTop.MarkMemoryWires[xbus]}; SetPublicBool[ks, $NotPhA, ph#a]; SetPublicBool[ks, $NotPhB, ph#b]; SetPublicBool[ks, $NotPhA, TRUE]; SetPublicBool[ks, $NotPhB, TRUE]; Main body of Inner Main LOOP EXIT EU.NoteRegStoreProc Lizard.CacheFetchProc Lizard.CacheStoreProc LizardHeart.RegChangeProc ViewRec.SetBehavior[newBehavior: [delayParms: [min: 2000.0]]]; [] _ ViewRec.ViewRef[agg: ks.ifuScanBuffer, label: "IFU Debug Scan Record"]; Κ ‹˜šœ™Jšœ Οmœ1™šœ*˜*Jšœ ˜ Jšœ˜Jšœžœ ˜.—Jšœ^Ÿœ˜€Jšœ%žœ˜,Jšœ,˜,Jšœ(žœ ˜4—J˜Jšœ˜Jšœ˜J˜—J˜š Ÿ œžœžœ$žœžœ˜IJšœ;˜;Jšœžœ ˜&Jšžœžœžœ˜"šœ˜šžœžœ˜Jšœ.žœ˜GJšœ˜Jšœ*˜*J˜——Jšœžœ˜J˜šŸœžœ˜Jšœžœžœ˜KJšœ˜Jšœ(žœ˜.šžœžœ˜!Jšœ:˜:Jšœ5˜5—šœ&˜&Jš œžœžœ&žœžœžœžœ˜Q—Jšœ:˜:Jšœt˜tšžœ žœ˜JšœS˜Sšžœ˜!šžœ?˜Cšœžœ˜,š žœžœžœžœžœ˜Gšžœžœžœ˜šœžœ˜$Jšœžœ"˜A—Jšœ*˜*Jšžœ˜————šžœ#žœ!˜Kšœžœ˜,š žœžœžœžœžœ˜Gšžœžœžœ˜šœžœ˜$Jšœžœ"˜A—Jšœ*˜*Jšžœ˜ —————šžœžœžœ˜PJšœžœ7˜P—šžœžœžœ˜PJšœžœ7˜P—Jšœ*˜*šœ•˜•šžœžœ'žœ˜KJšžœž˜ Jšžœžœ žœ˜8———Jšœr˜ršžœžœ˜JšœQ˜Qšœ)˜)šœžœžœ˜KJšžœžœžœ,žœ˜E——Jšœ)˜)šœ’˜’šžœžœ%˜+Jšžœž˜ Jšžœžœ žœ˜7———Jšžœžœ!˜>Jšžœžœžœ;˜TJšžœžœžœ:˜RJšœ˜Jšœ(žœ˜/J˜—š Ÿ œžœ*žœžœžœ˜VšŸ œ˜#Kšœ˜Kšœ1˜1Kšžœžœžœžœ˜'Kšœ#˜#Kšœ˜Kšœ˜Kšžœžœ9žœT˜±—Kšœžœ˜7Kšœ7˜7Kšœ)˜)šžœžœžœ ˜>K˜——šŸœ˜&Jšœžœ˜4Jšœžœ+˜7Jšœ žœžœ˜FJš žœ žœžœžœžœ˜(Jšœ#˜#Jšœ˜Jšœ˜šžœžœž˜Jšœž˜Jšœž˜šœ&˜&Jšžœžœ ˜+———J˜JšŸœžœžœ˜J˜šŸœžœ˜8Jšœ˜Jšœ˜Jšžœžœ˜FJšžœžœ˜CJšžœžœ˜HJšžœžœ˜I—J˜šŸœžœžœ˜Jš œžœžœžœžœžœ˜3—J˜šŸœžœžœ˜$Jšœ˜Jšœžœ˜ Jšœ ˜ Jšžœžœ*žœ˜RJšœ!˜!Jšœ ˜ Jšœ˜J˜—šŸœžœ˜Jšœžœ ˜.Jšœžœ ˜/—šŸœžœ ˜.Jšœžœ˜šžœžœžœ ž˜Jšœ$˜$šžœžœžœ˜+šœžœ!˜$Jšžœ#˜'Jšžœ˜——Jšœ!˜!Jšœžœ%˜EJšœžœ ˜,Jšœžœ ˜-Jšœžœ ˜,Jšœžœ ˜-Jšœ$žœ ˜GJšžœ˜ ——šŸœžœ˜Jšœžœ ˜-Jšœžœ ˜/—J˜šŸœžœ˜#Jšœžœžœ˜Jšœ˜šžœžœž˜-Jšœ˜Jšœ˜Jšœ!™!Jšœ!™!JšœG˜GJšœG˜Gšžœ˜Jšžœ-˜1šžœ žœ!˜0Jšžœ$žœ˜C——šžœžœ˜Jšžœ˜šžœž˜Jšœž˜ šœžœ%ž˜;šœžœ ˜)Jš žœžœžœžœžœ˜5———šžœžœ&˜4Jš žœžœžœžœžœ˜B——J˜šžœžœ "˜2Jšœ=˜=Jšœ>˜>š žœžœž œžœž˜4Jšœ%˜%Jšœ%žœ˜.—Jšœ˜Jšœ˜Jšœ9˜9Jšœ;˜;Jšœžœ˜—J˜Jšœžœ˜ Jšœžœ˜ Jšœžœ™!Jšœžœ™"Jšœ ˜ Jšžœ˜—šœžœžœž˜+Jšœ˜Jšœž˜JšœQ˜QJšœ$˜$Jšœ9˜9Jšžœ ˜——J˜šœ™J˜Jšœ2˜2Jš œžœ žœžœ žœ ˜CJšœ,˜,Jšœžœ˜šžœ ˜J˜š Ÿœžœžœžœžœ˜7Jš œ žœžœžœžœ˜8Jšœžœ žœžœ˜KJšœ<˜J˜šžœžœž˜Jšœ@žœ˜E—šžœžœž˜Jšœ>žœ˜C—J˜J˜J˜JšΡbkl™šžœ%ž˜)šœ5žœž˜?Jšœžœžœ˜(——J˜Jšœ6˜6Jšœ.˜.Jšœžœ˜J˜šžœžœ 7˜VJ˜šžœ žœž˜7šžœ.˜2Jšœ5žœ˜<——šžœžœž˜5šžœ-˜1Jšœ3žœ˜:——J˜Jšœžœžœ˜&Jšœ8žœ˜>Jšœ˜Jšœ!˜!J˜šœ˜Jšœ&˜&Jšœ?žœ˜EJšœA˜AJšœ=žœ˜BJšœ@žœ˜EJšœ@žœ˜EJšœ@žœ˜FJšœ@žœ˜FJšœAžœ˜GJšœ?žœ˜DJšœ?žœ˜DJšœ@žœ˜FJšœ@žœ˜FJšœ@žœ˜FJ˜—J˜šžœžœžœž˜šœ˜Jšœ"žœ˜)Jš œžœžœžœžœžœžœ˜`Jšœžœ˜&—šœ˜Jšœ"žœ˜)Jš œžœžœžœžœžœžœ˜`Jšœžœ˜&—Jšžœ˜—šœ˜Jšœ&˜&JšœAžœ˜GJšœAžœ˜GJšœ@žœ˜FJšœ@žœ˜FJ˜—J˜ J˜Jšžœžœž˜˜šœžœ˜šœžœ ˜3Jš œžœžœžœžœ ˜5—Jšœ1˜1Jš œžœžœžœžœ˜ZJ˜—šœ!˜!Jšœžœ"žœ"˜YJšœ˜Jš œžœžœžœžœ˜ZJ˜—šžœžœ˜J˜——Jšœžœ˜Jšœ˜Jšžœžœžœ ˜>Jšœ˜Jšžœžœžœ ˜>J˜Jšžœ"žœ'˜OJ˜Jšœ˜Jšœžœ˜J˜šœJ˜JJšžœ˜ Jšžœ˜—J˜šžœžœ9ž˜`J˜šžœ˜šœ˜šœJ˜JJšžœ˜ Jšžœ˜Jšžœ!˜#Jšžœ˜—šžœžœž˜Jšœ%žœ˜,Jšœžœžœ˜#Jšžœžœ˜——J˜—šžœ!žœ˜)Jšœ˜Jšœ-˜-Jšœ"žœ˜)—J˜Jšœ˜Jšžœžœžœ ˜>Jšœ˜šžœžœ˜šœG˜GJšžœ˜ Jšžœ˜Jšžœ!˜#Jšžœ˜—Jšœžœ˜Jšžœ˜—šžœžœžœ ˜>J˜—Jšœ0˜0š žœžœ žœžœž˜DJšœ@žœ˜E—š žœžœžœžœž˜BJšœ>žœ˜C—Jšžœ ˜$—J˜Jšžœ ˜"J˜—šžœžœž˜šœžœ˜Jšœžœ˜J˜šžœ!ž˜'Jšœ8˜8——šœ!˜!Jšœ:˜:—Jšžœžœ˜J˜—Jšžœ 1˜:—Jšœ ˜—Jšœ)˜)—J˜šŸ œžœžœžœ žœžœžœ˜Qšžœžœž˜šœ žœžœ˜Jšœr˜r—Jšžœžœ˜—J˜—š Ÿ œžœžœžœ žœ˜JJšœžœžœ ˜+J˜—šŸœžœžœžœ žœžœžœ˜ZJšœ˜šœ&˜&Jš œžœžœ'žœžœžœžœ˜R—Jšœ(žœ˜/J˜—š Ÿ œžœžœžœžœ žœ˜RJšœq˜q—šŸœžœžœžœ˜BJšœžœžœ ˜4J˜—šŸœžœžœ žœ˜DJšœžœžœ˜CJ˜—šŸ œžœ žœžœ)˜KJš ™Jšœžœ˜Jšœžœžœ?žœ*˜ˆJ˜—Jšœ&˜&Jšœžœ˜%šœžœ˜6J˜—šŸœžœ˜4šŸœžœ˜+Jšœ˜JšœAžœžœ žœ˜nJšœL˜Lšžœžœž˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšžœžœ˜—JšœK˜KJšœ˜—šœžœ ˜3Jš œžœžœžœžœ ˜3—Jšœ*˜*Jšœ0˜0šœ&˜&Jšœ"˜"Jšœ)˜)Jšœ˜Jšœ˜—Jšœ+ '˜RJ˜—šŸœž˜š œ=žœ žœ žœžœžœGžœ˜ΐJšœ™—Jšœžœ ˜*šœL˜LJšœV˜V—šœžœ˜šžœ˜Jšœ(˜(Jšœ  )˜5Jšœ)˜)Jšœ)˜)šœžœž˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšžœžœ˜——Jšœ˜—J˜—šŸœž˜JšœUžœ žœ˜išžœFžœ˜UJšœ™—Jšœžœ ˜*šœ8˜8Jšœ[˜[—šœžœ˜šžœ˜Jšœ(˜(Jšœ ˜ Jšœ)˜)Jšœ)˜)šœžœž˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšžœžœ˜——Jšœ˜—J˜—šŸœžœžœh˜†Jš ™Jšœžœ˜%šœžœ˜šžœ˜Jšœ(˜(Jšœ ˜ Jšœ+˜+—Jšœ˜—J˜—š Ÿ œžœžœkžœ ˜¬Jšœžœ˜>J˜—š Ÿœžœžœžœ œ˜8Jšžœ˜%š Ÿ œžœ-žœžœžœžœ˜dJšœy˜y—Jšœ˜Jšœ'˜'Jšœ žœ˜*Jšœ#˜#Jšœ/˜/Jšœ/ ˜LJšœ4˜4šœ*˜*Jšœ/˜/šœ žœ˜)Jšœ ˜ Jšœ ˜ Jšœ#˜#Jšœ˜Jšœ˜—šœžœ ˜+Jšœ ˜ Jšœ˜Jšœ˜——J˜—Jšœ žœžœ˜JšŸœžœžœžœ˜>Jš Ÿœžœžœžœžœžœ˜BJ˜šŸ œžœžœžœ˜!J˜—š Ÿ œžœžœ:žœžœ œ˜”Jšœžœžœ˜šžœž˜Jšœžœ˜JšœE #˜hJšžœ $˜*Jšžœ˜ —J˜—šŸœžœ˜2Jšœžœ˜ J˜—šœ žœ)˜:J˜—šŸœžœ˜-Jšžœžœžœžœ˜IJšœ>™>JšœL™Lšœ˜J˜——šŸ œžœ˜&šžœžœžœ˜šœžœ˜2Jšœ˜Jšœ žœ˜Jšœ ˜ Jšœ!˜!Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜—Jšœ>˜>šœ˜Jšœ˜šœ.žœ˜3Jšœžœ žœ žœ˜9Jšœžœ žœ žœ˜9Jšœžœ žœ žœ ˜E——J˜——Jšžœ˜J˜—J˜—…—zΘ §