DIRECTORY
Atom, Basics, Cache2, CacheOps, Cluster2, Core, CoreClasses, CoreCreate, CoreFlat, CoreOps, Dragon, DragonRosemary, DragOpsCross, DragOpsCrossUtils, EU2, FileNames, IFU2, IFUTest, IO, LizardCache, LizardHeart, Ports, Process, RandomCode, Rope, Rosemary, RosemaryUser, SparseMemory, TerminalIO, TypeScript, ViewerClasses, ViewerIO, ViewRec;

Cluster2Impl: CEDAR PROGRAM
IMPORTS Atom, Cache2, CacheOps, CoreCreate, CoreFlat, CoreOps, DragonRosemary, DragOpsCrossUtils, EU2, FileNames, IFU2, IFUTest, IO, LizardCache, LizardHeart, Ports, Process, RandomCode, Rope, Rosemary, RosemaryUser, SparseMemory, TerminalIO, TypeScript, ViewerIO, ViewRec
EXPORTS Cluster2 =
BEGIN

KitchenSink:				TYPE = Cluster2.KitchenSink;
OpaqueKitchenSink:		TYPE = Cluster2.OpaqueKitchenSink;
LizardSimulation:		TYPE = Cluster2.LizardSimulation;
Instances:					TYPE = Cluster2.Instances;
ClusterState:				TYPE = Cluster2.ClusterState;
IFUState:					TYPE = IFU2.IFUState;
EUState:					TYPE = EU2.EU2State;
CacheSt:					TYPE = REF Cache2.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;
lastKs:					PUBLIC KitchenSink			_ NIL;

MakeCluster: PUBLIC PROC RETURNS [ks: KitchenSink] = {

ifuRoseInst, euRoseInst, iCacheRoseInst, eCacheRoseInst: CoreClasses.CellInstance _ NIL;

DStateAddress: CoreCreate.WR _ CoreCreate.Seq["DStateAddress", 4];

publicOutputName:	CoreCreate.WR _ "DShOut";		-- IFU debug
publicInputNames:	LIST OF CoreCreate.WR _ LIST[
"ResetAB", "RescheduleAB",
"PhA", "PhB", "NotPhA", "NotPhB",
"DShA", "DShB", "DShRd", "DShWt", "DShIn",
CoreCreate.Seq["DStAd", 4], "DHold",									-- EU debug
"Vdd", "Gnd", "PadVdd", "PadGnd", "VRef" ];
public:				CoreCreate.Wire = CoreCreate.WireList[CONS[DStateAddress, CONS
[publicOutputName, publicInputNames]]];
tempInstances: CoreClasses.CellInstances _ NIL;

internalOnly: CoreCreate.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" ]  ];

ks _ lastKs _ NEW[Cluster2.KitchenSinkRec _ [
log:	ViewerIO.CreateViewerStreams["Rosemary Cluster Simulation"].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:	Cache2.Cache[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:	Cache2.Cache[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: IFU2.CreateIFU[NEW[IFU2.IFUTypeData _
[data: ks, getLog: GetLog, checkSynch: CheckSynch, getCycle: GetCycle ]],
fullIFU, quickIFU],
l1: "TopLevel" ],
pas: LIST[] ];
ks.coreInsts[eu] _ CoreCreate.InstanceList[
type: CoreFlat.CellTypeCutLabels[
on: EU2.CreateEU2[NEW[EU2.EUTypeData _
[data: ks, storeNoted: FALSE, noteStore: NoteRegStore ]],
fullEU ],
l1: "TopLevel" ],
pas: LIST[ ] ];
FOR inst: Instances DECREASING IN Instances DO
tempInstances _ CONS[ks.coreInsts[inst], tempInstances] ENDLOOP;
ks.cluster _ CoreCreate.Cell[
public:			public,
onlyInternal:		internalOnly,
instances:			tempInstances,
name:				"Cluster" ];

[] _ Rosemary.SetFixedWire[public[CoreOps.GetWireIndex[public, "Vdd"	]], H];
[] _ Rosemary.SetFixedWire[public[CoreOps.GetWireIndex[public, "Gnd"	]], L];
[] _ Rosemary.SetFixedWire[public[CoreOps.GetWireIndex[public, "PadVdd"	]], H];
[] _ Rosemary.SetFixedWire[public[CoreOps.GetWireIndex[public, "PadGnd"	]], L];
[] _ Rosemary.SetFixedWire[public[CoreOps.GetWireIndex[public, "VRef"	]], H];

[] _ Ports.InitPort[wire: CoreCreate.FindWire[ks.cluster.public, DStateAddress], levelType: c, initDrive: force];
[] _ Ports.InitPort[wire: CoreCreate.FindWire[ks.cluster.public, publicOutputName], levelType: b, initDrive: none];
FOR rl: LIST OF CoreCreate.WR _ publicInputNames, rl.rest WHILE rl # NIL DO
[] _ Ports.InitPort[wire: CoreCreate.FindWire[ks.cluster.public, rl.first], levelType: b, initDrive: force];
ENDLOOP;

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..Cluster2.historySize) DO
ks.stateTop[i].refCy	_ NEW[INT				_ 0];
ks.stateTop[i].refPh	_ NEW[Dragon.Phase	_ a];
ks.stateTop[i].data _ [
ifu:		NEW[IFU2.IFUStateRec],
eu:		NEW[EU2.EU2StateRec],
iCache:	NEW[Cache2.CacheState],
eCache:	NEW[Cache2.CacheState]];
ENDLOOP;
FOR i: NAT IN [0..Cluster2.historySize) DO
ks.stateFull[i].refCy	_ NEW[INT				_ 0];
ks.stateFull[i].refPh	_ NEW[Dragon.Phase	_ a];
ks.stateFull[i].data _ [
ifu:		NEW[IFU2.IFUStateRec],
eu:		NEW[EU2.EU2StateRec],
iCache:	NEW[Cache2.CacheState],
eCache:	NEW[Cache2.CacheState]];
ENDLOOP;

ks.euReject _ NEW[CoreFlat.FlatWireRec _ CoreFlat.ParseWirePath[ks.cluster, "DPRejectB"]];

IF fullIFU THEN {
ifuCellType: Core.CellType _ ks.coreInsts[ifu].type;
TerminalIO.WriteF["Make IFU Simulation %g\n", IO.time[]];
ks.ifuSimulationTruthPort	_ Ports.CreatePort[ifuCellType, TRUE];
ks.ifuSimulationTestPort	_ Ports.CreatePort[ifuCellType, TRUE];
ks.ifuSimulation				_ Rosemary.Instantiate[
ifuCellType,
ks.ifuSimulationTestPort,
CoreFlat.CreateCutSet[labels: fullIFUCuts]];
ks.ifuDisplay					_ RosemaryUser.DisplayViewer[ks.ifuSimulation, ifuCellType, "IFU2", RosemaryUser.DisplayPortLeafWires[ifuCellType]];
Rosemary.Initialize[ks.ifuSimulation, FALSE];
RosemaryUser.InitializeDeltas[ks.ifuDisplay];
TerminalIO.WriteF["IFU Instantiated %g\n", IO.time[]]};
IF fullEU THEN {
euCellType: Core.CellType	_ ks.coreInsts[eu].type;
TerminalIO.WriteF["Make EU Simulation %g\n", IO.time[]];
ks.euSimulationTruthPort	_ Ports.CreatePort[euCellType, TRUE];
ks.euSimulationTestPort		_ Ports.CreatePort[euCellType, TRUE];
ks.euSimulation				_ Rosemary.Instantiate[
euCellType,
ks.euSimulationTestPort,
CoreFlat.CreateCutSet[labels: LIST["AlpsCell", "EU2Ram"]]];
ks.euDisplay					_ RosemaryUser.DisplayViewer[ks.euSimulation, euCellType, "EU2", RosemaryUser.DisplayPortLeafWires[euCellType]];
Rosemary.Initialize[ks.euSimulation, FALSE]};

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 = {
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]];
IF fullIFU THEN {
Rosemary.SettleToTest[simulation: ks.rosemarySimulation, flatCell: ks.flatCT[ifu], test: ks.ifuSimulationTruthPort];
Ports.CopyPortValue[from: ks.ifuSimulationTruthPort, to: ks.ifuSimulationTestPort];
RosemaryUser.LogSettle[ks.ifuDisplay, time
! Rosemary.Stop => IF reason # $BoolWireHasX
THEN REJECT ELSE IF ks.controlPanel.reset OR ks.protCyclesAfterReject>0
THEN RESUME ELSE {
TerminalIO.WriteF["%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.WriteF["%g\n", IO.rope[msg]]; RESUME}] };
IF fullEU THEN {
Rosemary.SettleToTest[simulation: ks.rosemarySimulation, flatCell: ks.flatCT[eu], test: ks.euSimulationTruthPort];
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.WriteF["%g\n", IO.rope[msg]]; RESUME}]};
IF ks.controlPanel.reset THEN ks.controlPanel.instrCount _ -1;
Process.Yield[];
ks.controlPanel.continueTestFromAbort _ FALSE};

UpdateIFUState: IFUTest.UpdateProc = {
comp:			IFUState _ NARROW[ks.stateTop[0].data[ifu]];
atom:			ATOM _ IFUTest.ifuUpdateProc;
updateProc:	REF IFUTest.UpdateProc _ NARROW[Atom.GetProp[atom, atom]];
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.WriteF["#\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[];
};

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];
SetPublicBool[ks, $NotPhA, ph#a];
SetPublicBool[ks, $NotPhB, 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		[Cluster2.historySize-1];
lastFull:	ClusterState _ ks.stateFull	[Cluster2.historySize-1];
FOR i: NAT DECREASING IN (1..Cluster2.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];
SetPublicBool[ks, $NotPhA,	TRUE];
SetPublicBool[ks, $NotPhB,		TRUE];
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]};

diagnosticFileName: Core.ROPE _ diagnosticName _ Chop[].first;

IF Rope.Length[diagnosticFileName] = 0 OR
(Rope.Equal[s1: diagnosticFileName, s2: "END", case: FALSE] AND
ks.controlPanel.randomSeed=0)
THEN EXIT;

ks.controlPanel.reset			_ TRUE;

WHILE ks.controlPanel.reset DO -- as often as RESET is asserted in the same diagnostic

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, "DShA"]].b				_ TRUE;
ks.clusterIOPort[CoreOps.GetWireIndex[public, "DShB"]].b				_ TRUE;
ks.clusterIOPort[CoreOps.GetWireIndex[public, "DShRd"]].b			_ FALSE;
ks.clusterIOPort[CoreOps.GetWireIndex[public, "DShWt"]].b			_ FALSE;
ks.clusterIOPort[CoreOps.GetWireIndex[public, "DShIn"]].b				_ FALSE;
};

FOR j: NAT IN [0..3) DO
DoPh[a !
DragonRosemary.AssertionFailed => RESUME;
Rosemary.Stop => IF reason = $FailedAssertion OR reason = $BoolWireHasX THEN RESUME ELSE REJECT;
IFU2.IFUInconsistent => CONTINUE  ];
DoPh[b !
DragonRosemary.AssertionFailed => RESUME;
Rosemary.Stop => IF reason = $FailedAssertion OR reason = $BoolWireHasX THEN RESUME ELSE REJECT;
IFU2.IFUInconsistent => CONTINUE  ];
ENDLOOP;
{
public: Core.Wire _ ks.cluster.public;
ks.clusterIOPort[CoreOps.GetWireIndex[public, "DShA"]].b				_ FALSE;
ks.clusterIOPort[CoreOps.GetWireIndex[public, "DShB"]].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 {
SuccessHalt => {
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]];
EXIT };
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 } };

DoPh[a];
IF ks.controlPanel.reset THEN EXIT; -- restart this diagnostic
DoPh[b];
IF ks.controlPanel.reset THEN EXIT; -- restart this diagnostic

ks.controlPanel.cycle _ ks.controlPanel.cycle+1;
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, writeProtect: 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,
EUPageFault			=> page,
EUWriteFault		=> write,
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,
EUPageFault			=> page,
EUWriteFault		=> write,
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[Cluster2.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: PUBLIC ERROR = CODE;
Breakpoint: PUBLIC SIGNAL = CODE;

CheckSynch: PUBLIC PROC [ data: OpaqueKitchenSink, basicInst: IFU2.BasicInst ] RETURNS [deltaInstrCount: INT _ 1] -- IFU2.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 IFU2.CheckSynchProc  =
{RETURN[1]};

csProcRec: PUBLIC Cluster2.CSProcRec _ [DefaultCheckSynch];

StartPanel: PROC [ks: KitchenSink] = {
IF ks.controlPanel = NIL THEN {
ks.controlPanel _ NEW[Cluster2.ControlPanelRec _ [ 
msg: "Initialized...",
enaIFULog: TRUE,
diagnostic: ks.diagnostics 
]];
ViewRec.SetBehavior[newBehavior: [delayParms: [min: 2000.0]]];
[] _ ViewRec.ViewRef[
agg:	ks.controlPanel,
label: "Dragon Cluster2 Rosemary5 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.


���"��Cluster2Impl.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 November 1, 1986 10:33:42 am 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 ...
Main body of Inner
EU2.NoteRegStoreProc
Lizard.CacheFetchProc
Lizard.CacheStoreProc
LizardHeart.RegChangeProc
Êp��˜�šœ™Jšœ
Ïmœ1™<Jšœ&™&J™*J™$J™&Icode™*J™�—šÏk	˜	Jšœ´žœ˜ÓJ˜�—šÏnœžœž˜Jšžœxžœ˜Jšžœ˜Jšž˜J˜�Jšœžœ˜,Jšœžœ˜6Jšœžœ˜4Jšœžœ˜)Jšœžœ˜.Jšœžœ˜#Jšœ
žœ˜!Jšœ
žœžœ˜*Jšœžœžœ˜$Jšœžœžœžœ˜*Jšœžœžœžœ˜)Jšœžœžœžœ˜$Jšœ
žœžœžœ˜%Jš	œžœžœžœžœ˜/Jšœžœžœžœ˜&šœžœžœ˜'Jšœ”™”—J˜�šŸœžœžœžœ˜6J˜�JšœTžœ˜XJ˜�JšŸ
œ
žœ&˜BJ˜�JšœžœÏc˜9š	œžœžœžœžœ˜/Jšœ˜Jšœ!˜!Jšœ*˜*Jšœ- ˜8Jšœ+˜+—šœ1žœž˜IJšœ'˜'—Jšœ+žœ˜/J˜�šœ4žœ˜9Jšœ˜Jšœ˜Jšœ˜Jšœ"˜"Jšœ˜Jšœ˜Jšœ!˜!Jšœ˜Jšœ!˜!Jšœ#˜#Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜J˜�—šœžœ˜-JšœE˜EJšœ#˜#J˜�—JšœA˜AJ˜�Jšœ?˜?Jšœ?˜?J˜�šœ/˜/šœŸœ˜!Jšœ=˜=Jšœ˜—šœžœ˜
Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ"˜"Jšœ"˜"Jšœ&˜&——šœ/˜/šœŸœ˜!Jšœ<˜<Jšœ˜—šœžœ˜
Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜——šœ,˜,šœŸœ˜!šœžœ˜)JšœI˜IJšœ˜—J˜—Jšœžœ˜—šœ+˜+šœŸœ˜!šœžœ˜&Jšœžœ˜9Jšœ	˜	—J˜—Jšœžœ˜—šžœž
œžœž˜.Jšœžœ$žœ˜@—šœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜—J˜�JšœL˜LJšœL˜LJšœO˜OJšœO˜OJšœM˜MJ˜�Jšœq˜qJšœs˜sš
žœžœžœžœžœžœž˜KJšœl˜lJšžœ˜J˜�—Jšœ0˜0šœ-˜-Jšœ˜Jšœ˜Jšœ&žœ˜;—J˜�šžœžœž˜#Jš	œžœCžœžœžœ˜‡Jšœžœžœ	˜'Jšœžœ˜-JšœV˜VJšžœ˜—šžœžœžœž˜*Jšœžœžœ	˜'Jšœžœ˜-šœ˜Jšœžœ˜Jšœžœ˜Jšœžœ˜Jšœžœ˜ —Jšžœ˜—šžœžœžœž˜*Jšœžœžœ	˜(Jšœžœ˜.šœ˜Jšœžœ˜Jšœžœ˜Jšœžœ˜Jšœžœ˜ —Jšžœ˜J˜�—JšœžœI˜ZJ˜�šžœ	žœ˜Jšœ4˜4Jšœ.žœ	˜9Jšœ:žœ˜@Jšœ9žœ˜?šœ+˜+Jšœ˜Jšœ˜Jšœ,˜,—JšœcŸœ˜†Jšœ&žœ˜-Jšœ-˜-Jšœ+žœ
˜7—šžœžœ˜Jšœ2˜2Jšœ-žœ	˜8Jšœ8žœ˜>Jšœ8žœ˜>šœ*˜*Jšœ˜Jšœ˜Jšœžœ˜;—Jšœ_Ÿœ˜Jšœ%žœ˜-—J˜�Jšœ˜J˜�—J˜�š
Ÿ	œžœžœ$žœžœ˜IJšœ;˜;Jšœžœ
˜&Jšžœžœžœ˜"šœ˜šžœžœ˜Jšœ.žœ˜GJšœ˜Jšœ*˜*J˜�——Jšœžœ˜J˜�šŸœžœ˜Jšœ˜Jšœ(žœ˜.šžœžœ˜!Jšœ:˜:Jšœ5˜5—šœ&˜&Jš
œžœžœ&žœžœžœžœ˜Q—Jšœ:˜:šžœ	žœ˜Jšœt˜tJšœS˜Sšœ*˜*šœžœ˜,š
žœžœžœžœžœ˜Gšžœžœžœ˜šœžœ˜&Jšœžœ"˜A—Jšœ*˜*Jšžœ˜	————šžœžœžœ˜PJšœžœ7˜P—šžœžœžœ˜PJšœžœ7˜P—Jšœ*˜*šœ•˜•šžœžœ'žœ˜KJšžœž˜Jšžœžœ
žœ˜:———šžœžœ˜Jšœr˜rJšœQ˜Qšœ)˜)šœžœžœ˜KJšžœžœžœ,žœ˜E——Jšœ)˜)šœ’˜’šžœžœ%˜+Jšžœž˜Jšžœžœ
žœ˜9———Jšžœžœ!˜>Jšœ˜Jšœ(žœ˜/J˜�—šŸœ˜&Jšœžœ˜4Jšœžœ˜%Jšœžœžœ˜FJšœ#˜#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šœG˜GJšœG˜Gšžœ˜Jšžœ-˜1šžœ	žœ!˜0Jšžœ$žœ˜C——šžœžœ˜Jšžœ˜šžœž˜Jšœž˜ šœžœ%ž˜;šœžœ ˜)Jš
žœžœžœžœžœ˜5———šžœžœ&˜4Jš
žœžœžœžœžœ˜B——J˜�šžœžœ "˜2Jšœ>˜>Jšœ?˜?š	žœžœž
œžœž˜5Jšœ%˜%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šœžœ!˜>J˜�šžœ%ž˜)šœ5žœž˜?Jšœ˜—Jšžœžœ˜
—J˜�Jšœžœ˜J˜�šžœžœ 7˜VJ˜�Jšœžœžœ˜&Jšœ8žœ˜>Jšœ˜Jšœ!˜!J˜�šœ˜Jšœ&˜&Jšœ?žœ˜EJšœA˜AJšœ>žœ˜CJšœ>žœ˜CJšœ>žœ˜DJšœ>žœ˜DJšœ?žœ˜EJ˜—J˜�šžœžœžœž˜šœ˜Jšœ"žœ˜)Jš
œžœžœžœžœžœžœ˜`Jšœžœ˜$—šœ˜Jšœ"žœ˜)Jš
œžœžœžœžœžœžœ˜`Jšœžœ˜$—Jšžœ˜—šœ˜Jšœ&˜&Jšœ>žœ˜DJšœ>žœ˜DJ˜—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˜�šžœ˜šœ˜šœG˜GJšžœ˜
Jšžœ˜Jšžœ!˜#Jšžœ˜—Jšžœ˜—šœ˜šœJ˜JJšžœ˜
Jšžœ˜Jšžœ!˜#Jšžœ˜—šžœžœž˜Jšœ%žœ˜,Jšœžœžœ˜#Jšžœžœ˜——J˜�—Jšœ˜Jšžœžœžœ ˜>Jšœ˜šžœžœžœ ˜>J˜�—Jšœ0˜0Jšžœ ˜$—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žœžœ	žœ˜jJšœ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šœUžœžœ˜išžœFžœ˜UJšœ™—Jšœžœ˜*šœ8˜8Jšœ[˜[—šœžœ˜šžœ˜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˜�—šŸ
œžœžœ8žœžœ œ˜Jšœžœžœ˜šžœž˜Jšœžœ˜JšœE #˜hJšžœ $˜*Jšžœ˜	—J˜�—šŸœžœ˜0Jšœžœ˜J˜�—šœžœ*˜;J˜�—šŸ
œžœ˜&šžœžœžœ˜šœžœ˜3Jšœ˜Jšœžœ˜Jšœ˜Jšœ˜—Jšœ>˜>šœ˜Jšœ˜šœ9žœ˜>Jšœžœ
žœ
žœ˜9Jšœžœ
žœ
žœ˜9Jšœžœ
žœ
žœ
˜E——J˜�——Jšžœ˜J˜�—J˜�—�…—����a¾��}P��