Cluster2Impl.mesa
Copyright © 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, August 22, 1986 9:40:44 am PDT
DIRECTORY
Atom, Basics, Cache2, CacheOps, Cluster2, Core, CoreClasses, CoreCreate, CoreFlat, CoreOps, Dragon, DragonRosemary, DragOpsCross, DragOpsCrossUtils, EU2, IFU2, IO, LizardCache, LizardHeart, Ports, Process, RandomCode, Rope, Rosemary, RosemaryUser, SparseMemory, TypeScript, ViewerClasses, ViewerIO, ViewRec;
Cluster2Impl: CEDAR PROGRAM
IMPORTS Atom, Cache2, CacheOps, CoreCreate, CoreOps, DragonRosemary, DragOpsCrossUtils, EU2, IFU2, IO, LizardCache, LizardHeart, Ports, Process, RandomCode, Rope, Rosemary, RosemaryUser, SparseMemory, TypeScript, ViewerIO, ViewRec
EXPORTS Cluster2 =
BEGIN OPEN Cluster2;
nCacheLines: NAT ← 200;
skipIFURejects: BOOLFALSE;
skipEURejects: BOOLFALSE;
fullEU: BOOLFALSE;
lastKs: KitchenSink ← NIL; -- 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 ...
MakeCluster: PUBLIC PROC RETURNS [ks: KitchenSink] =
BEGIN
ifuRoseInst, euRoseInst, iCacheRoseInst, eCacheRoseInst: CoreClasses.CellInstance ← NIL;
DStateAddress: CoreCreate.WR ← CoreCreate.Seq["DStateAddress", 4];
publicInputNames: LIST OF CoreCreate.WRLIST[
"PhA", "PhB", "ResetAB", "RescheduleAB",
"Vdd", "Gnd", "PadVdd", "PadGnd",
"DExecuteAB", "DNSelectAB", "DHoldAB",
"DrShA", "DrShB", "DrShRd", "DrShWt", "DrShIn" -- IFU's debugging shifter
and implicitly the MBus --
];
publicOutputName: CoreCreate.WR ← "DrShOut"; -- IFU's debugging shifter
public: CoreCreate.Wire = CoreCreate.WireList[CONS[DStateAddress, CONS[publicOutputName, publicInputNames]]];
internal: CoreCreate.Wire = CoreCreate.WireList[LIST[
CoreCreate.Seq["KBus", 32],
CoreCreate.Seq["EUAluOp2AB", 4],
CoreCreate.Seq["EUCondSel2AB", 4],
"EUCondition2B", "EURes3BisPBus3AB", "EUWriteToPBus3AB",
CoreCreate.Seq["IPData", 32],
CoreCreate.Seq["IPCmdA", 8],
"IPRejectB",
CoreCreate.Seq["IPFaultB", 5],
CoreCreate.Seq["DPData", 32],
CoreCreate.Seq["DPCmdA", 8],
"DPRejectB",
CoreCreate.Seq["DPFaultB",5]
]];
flatInstance: CoreFlat.FlatInstance ← NEW[CoreFlat.FlatInstanceRec];
ks ← lastKs ← NEW[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: Cache2.Cache[vm: ks.iCache, skipRejects: skipIFURejects],
pas: LIST[
[public: "PData", actual: "IPData"],
["PCmdA", "IPCmdA"],
["PRejectB", "IPRejectB"],
["PFaultB", "IPFaultB"]
]
];
ks.coreInsts[eCache] ← CoreCreate.InstanceList[
type: Cache2.Cache[vm: ks.eCache, skipRejects: skipEURejects],
pas: LIST[
[public: "PData", actual: "DPData"],
["PCmdA", "DPCmdA"],
["PRejectB", "DPRejectB"],
["PFaultB", "DPFaultB"]
]
];
ks.coreInsts[ifu] ← CoreCreate.InstanceList[
type: IFU2.IFU[NEW[IFU2.IFUTypeData ← [
data: ks, getLog: GetLog, checkSynch: CheckSynch, getCycle: GetCycle
]]],
pas: LIST[]
];
ks.coreInsts[eu] ← CoreCreate.InstanceList[
type: Rosemary.AddCutSets[
cellType: EU2.CreateEU2[NEW[EU2.EUTypeData ← [
data: ks, storeNoted: FALSE, noteStore: NoteRegStore
]],
fullEU],
cs1: "TopLevel"
],
pas: LIST[]
];
ks.cluster ← CoreCreate.Cell[
public: public,
onlyInternal: internal,
instances: LIST[ks.coreInsts[ifu], ks.coreInsts[eu], ks.coreInsts[iCache], ks.coreInsts[eCache]],
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];
[] ← 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.public];
ks.rosemarySimulation ← Rosemary.InstantiateInstances[
cellType: ks.cluster,
testPort: ks.clusterIOPort,
cutSets: LIST["TopLevel"]
];
FOR inst: Instances IN Instances DO
flatInstance.instance ← ks.coreInsts[inst];
ks.state[0].data[inst] ← Rosemary.GetInstanceState[ks.rosemarySimulation, flatInstance];
ENDLOOP;
FOR i: NAT IN [1..historySize) DO
ks.state[i].data ← [
ifu: IFU2.NewIFUState[NARROW[ks.state[0].data[ifu]]],
eu: NEW[EU2.EU2StateRec],
iCache: NEW[Cache2.CacheState],
eCache: NEW[Cache2.CacheState]];
ENDLOOP;
ks.euReject ← NEW[CoreFlat.FlatWireRec];
ks.euReject.wire ← CoreCreate.FindWire[internal, "DPRejectB"];
IF fullEU THEN {
euCellType: Core.CellType ← ks.coreInsts[eu].type;
ks.euSimulationTruthPort ← Ports.CreatePort[euCellType.public, TRUE];
ks.euSimulationTestPort ← Ports.CreatePort[euCellType.public, TRUE];
ks.euSimulation ← Rosemary.InstantiateInstances[euCellType, ks.euSimulationTestPort, LIST["AlpsCell", "EU2Ram"]];
ks.euFlatInstance ← NEW[CoreFlat.FlatInstanceRec];
ks.euFlatInstance.instance ← ks.coreInsts[eu];
ks.euDisplay ← RosemaryUser.DisplayViewer[ks.euSimulation, euCellType, "EU2", RosemaryUser.DisplayCellTypePortLeafWires[euCellType]];
Rosemary.Initialize[ks.euSimulation, FALSE];
};
StartPanel[ks];
END;
runningMsg: Core.ROPE ← "Running...";
SetPublic: PUBLIC PROC [ks: KitchenSink, signal: ATOM, value: REF ANYNIL ] =
BEGIN
WITH value SELECT FROM
refBool: REF BOOL =>
ks.clusterIOPort[CoreOps.GetWireIndex[ks.rosemarySimulation.coreCellType.public, Atom.GetPName[signal]]].b ← refBool^;
ENDCASE => ERROR;
END;
SetPublicBool: PUBLIC PROC [ks: KitchenSink, signal: ATOM, value: BOOL ] =
BEGIN
SetPublic[ks, signal, NEW[BOOL ← value]];
END;
SetPublicAndSettle: PUBLIC PROC [ks: KitchenSink, signal: ATOM, value: REF ANY ← NIL ] =
BEGIN
SetPublic[ks, signal, value];
Rosemary.Settle[ ks.rosemarySimulation
! ABORTED => IF ks.controlPanel.continueTestFromAbort
THEN CONTINUE ELSE REJECT;
];
ks.controlPanel.continueTestFromAbort ← FALSE;
END;
GetPublicBool: PUBLIC PROC [ks: KitchenSink, signal: ATOM] RETURNS [value: BOOL] =
{value ← ks.clusterIOPort[CoreOps.GetWireIndex[ks.rosemarySimulation.coreCellType.public, Atom.GetPName[signal]]].b};
DoCluster: PUBLIC PROC [ks: KitchenSink, diagnostic: Core.ROPENIL] =
BEGIN
originalPriority: Process.Priority = Process.GetPriority[];
diagnosticName: Core.ROPE ← "unknown";
{
ENABLE UNWIND => {
ks.log.PutF["\nSimulation of %g aborted\n\n", IO.rope[diagnosticName]];
ks.log.Flush[];
Process.SetPriority[ originalPriority ] };
DoEval: PROC = {
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;
];
IF fullEU THEN {
Rosemary.SettleToTest[simulation: ks.rosemarySimulation, instance: ks.euFlatInstance, test: ks.euSimulationTruthPort];
Ports.CopyPortValue[from: ks.euSimulationTruthPort, to: ks.euSimulationTestPort];
Rosemary.Settle[ks.euSimulation ! Rosemary.Stop => IF ks.euCyclesFromReject>0 AND data = $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];
};
IF ks.controlPanel.reset THEN ks.controlPanel.instrCount ← -1;
Process.Yield[];
ks.controlPanel.continueTestFromAbort ← FALSE
};
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: BOOLTRUE;
ks.controlPanel.phase ← ph;
WHILE first OR ks.controlPanel.repeatPhase DO
SetPublicBool[ks, $PhB, ph=b];
SetPublicBool[ks, $PhA, ph=a];
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 {
IF (ks.controlPanel.cycle >= ks.controlPanel.slowFromCycle OR
(ks.controlPanel.cycle>=0 AND ks.controlPanel.instrCount >= ks.controlPanel.slowFromInstr)) AND
ks.controlPanel.stopInPh[ph] THEN
Remark[IO.PutFR["Doing cycle %g Ph%g...",
IO.int[ks.controlPanel.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 the history buffer
s: ClusterState ← ks.state[historySize-1];
FOR i: NAT DECREASING IN (1..historySize) DO
ks.state[i] ← ks.state[i-1];
ENDLOOP;
s.cycle ← ks.controlPanel.cycle;
s.phase ← ks.controlPanel.phase;
NARROW[s.data[ifu], REF IFU2.IFUState]^ ← NARROW[ks.state[0].data[ifu], REF IFU2.IFUState]^;
NARROW[s.data[eu], REF EU2.EU2StateRec]^ ← NARROW[ks.state[0].data[eu], REF EU2.EU2StateRec]^;
NARROW[s.data[iCache], REF Cache2.CacheState]^ ← NARROW[ks.state[0].data[iCache], REF Cache2.CacheState]^;
NARROW[s.data[eCache], REF Cache2.CacheState]^ ← NARROW[ks.state[0].data[eCache], REF Cache2.CacheState]^;
ks.state[1] ← s;
first ← FALSE;
};
SetPublicBool[ks, $PhB, FALSE];
SetPublicBool[ks, $PhA, FALSE];
DoEval[];
ENDLOOP;
ks.euCyclesFromReject ← SELECT TRUE FROM
ks.controlPanel.reset => 3,
ph=a OR Rosemary.WireValue[simulation: ks.rosemarySimulation, wire: ks.euReject][0]=H => ks.euCyclesFromReject,
ks.euCyclesFromReject>0 => ks.euCyclesFromReject-1,
ENDCASE => 0;
};
Main body of Inner
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.ROPENIL ] =
BEGIN
dStream: IO.STREAM = IO.RIS[ks.controlPanel.diagnostic];
first ← dStream.GetTokenRope[IO.IDProc ! IO.EndOfStream => CONTINUE].token;
rest ← ks.controlPanel.diagnostic.Substr[dStream.GetIndex];
END;
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, "DExecuteAB"]].b ← FALSE;
ks.clusterIOPort[CoreOps.GetWireIndex[public, "DNSelectAB"]].b ← FALSE;
ks.clusterIOPort[CoreOps.GetWireIndex[public, "DHoldAB"]].b ← FALSE;
ks.clusterIOPort[CoreOps.GetWireIndex[public, "DStateAddress"]].c ← 0;
ks.clusterIOPort[CoreOps.GetWireIndex[public, "DrShA"]].b ← FALSE;
ks.clusterIOPort[CoreOps.GetWireIndex[public, "DrShB"]].b ← FALSE;
ks.clusterIOPort[CoreOps.GetWireIndex[public, "DrShRd"]].b ← FALSE;
ks.clusterIOPort[CoreOps.GetWireIndex[public, "DrShWt"]].b ← FALSE;
ks.clusterIOPort[CoreOps.GetWireIndex[public, "DrShIn"]].b ← FALSE;
};
FOR j: NAT IN [0..3) DO
DoPh[a !
DragonRosemary.AssertionFailed => RESUME;
Rosemary.Stop => IF data = $FailedAssertion OR data = $BoolWireHasX THEN RESUME ELSE REJECT;
IFU2.IFUInconsistent => CONTINUE
];
DoPh[b !
DragonRosemary.AssertionFailed => RESUME;
Rosemary.Stop => IF data = $FailedAssertion OR data = $BoolWireHasX THEN RESUME ELSE REJECT;
IFU2.IFUInconsistent => CONTINUE
];
ENDLOOP;
Cycles[2];
SELECT TRUE FROM
diagnosticFileName # NIL =>
BEGIN
CacheOps.VirtualMemoryFromFile[ks.vm, diagnosticFileName ];
ks.lizardSimulation ← (IF ks.controlPanel.lizardToo THEN StartNewLizard[ks.vm] ELSE NIL);
END;
ks.controlPanel.randomSeed#0 =>
BEGIN
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);
END;
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 =>
BEGIN
first, rest: Rope.ROPE;
[first, rest] ← Chop[];
IF first.Equal[diagnosticFileName] THEN
ks.controlPanel.diagnostic ← Rope.Cat[rest, " ",first];
END;
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 ];
END;
GetLog: PROC [ data: OpaqueKitchenSink ] RETURNS [ Core.STREAM ] =
BEGIN
ks: KitchenSink = NARROW[data];
RETURN [ ks.log ];
END;
GetCycle: PROC [ data: OpaqueKitchenSink ] RETURNS [ cycle: INT ] =
BEGIN
ks: KitchenSink = NARROW[data];
RETURN [ ks.controlPanel.cycle ];
END;
NoteRegStore: PROC [ data: REF ANY, reg: [0..256), value: Dragon.Word ] -- EU2.NoteRegStoreProc -- =
BEGIN
ks: KitchenSink = NARROW[data];
ks.rosemaryStores ← CONS[NEW[Dragon.RegStoreRec ← [instr: ks.controlPanel.instrCount, reg: VAL[reg], data: value]], ks.rosemaryStores];
END;
randomStartPC: Dragon.Word ← 102000H;
randomBackground: Core.ROPE ← "RandomBackground.quad";
InsertRandomProgramInVM: PROC[ ks: KitchenSink ] = {
WriteOneCodeByte: PROC [byte: [0..255]] =
BEGIN
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;
END;
nextByteAddr: Dragon.Word ← randomStartPC;
CacheOps.VirtualMemoryFromFile[ks.vm, randomBackground];
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, noEffect: BOOLFALSE] RETURNS [data: LizardCache.Word, status: LizardCache.TrapIndex, rejectCycles: INT] -- Lizard.CacheFetchProc -- =
BEGIN
sim: LizardSimulation = NARROW[base.data];
[data: data, status: status, rejectCycles: rejectCycles] ←
sim.euCache.fetch[base: sim.euCache, addr: addr, cycle: cycle, 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,
EUPageFault => page,
EUWriteFault => write,
ENDCASE => ERROR
]],
sim.lastInstrOps];
END;
LizardEUCacheStoreTrap: PROC [base: LizardCache.CacheBase, addr: LizardCache.Word, data: LizardCache.Word, cycle: INT]
RETURNS [old: LizardCache.Word, status: LizardCache.TrapIndex, rejectCycles: INT] -- Lizard.CacheStoreProc -- =
BEGIN
sim: LizardSimulation = NARROW[base.data];
[old: old, status: status, rejectCycles: rejectCycles] ←
sim.euCache.store[base: sim.euCache, addr: addr, data: data, cycle: cycle];
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,
EUPageFault => page,
EUWriteFault => write,
ENDCASE => ERROR
]],
sim.lastInstrOps];
END;
NoteChangedReg: PROC [data: REF, processor: LizardHeart.Processor, reg: DragOpsCross.ProcessorRegister, old,new: DragOpsCross.Word] -- LizardHeart.RegChangeProc -- =
BEGIN
sim: LizardSimulation = NARROW[data];
sim.lastInstrOps ← CONS[
NEW[Dragon.RegStoreRec ← [
instr: sim.processor.stats.instructions,
reg: reg,
data: DragOpsCrossUtils.WordToCard[new]
]],
sim.lastInstrOps];
END;
NoteInstDone: PROC [data: REF, processor: LizardHeart.Processor, newPC, rtnPC: DragOpsCross.Word, control: LizardHeart.Control, cycles: INT] -- LizardHeart.InstDoneProc -- =
BEGIN
sim: LizardSimulation = NARROW[data];
sim.control ← control;
END;
StartNewLizard: PUBLIC PROC [ m: REF -- CacheOps.VM -- ] RETURNS [ sim: LizardSimulation ] =
BEGIN
StoreWord: PROC [ addr, data: Dragon.Word, readOnly, dirty: BOOLFALSE, privateData: REFNIL ] =
{SparseMemory.Store[base: lizardVM, index: DragOpsCrossUtils.CardToWord[addr], new: DragOpsCrossUtils.CardToWord[data]]};
lizardVM: SparseMemory.Base;
lizardSharedVM: LizardCache.SharedBase;
sim ← NEW[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,
data: sim
]],
logger: NEW[LizardHeart.ChangeLoggerRep ← [
data: sim,
regChange: NoteChangedReg,
instDone: NoteInstDone
]]
];
END;
SuccessHalt: PUBLIC ERROR = CODE;
Breakpoint: PUBLIC SIGNAL = CODE;
CheckSynch: PUBLIC PROC [ data: OpaqueKitchenSink, basicInst: IFU2.BasicInst ] RETURNS [deltaInstrCount: INT ← 1] -- IFU2.CheckSynchProc -- =
BEGIN
retry: BOOLTRUE;
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;
END;
DefaultCheckSynch: PUBLIC IFU2.CheckSynchProc =
{RETURN[1]};
csProcRec: PUBLIC CSProcRec ← [DefaultCheckSynch];
StartPanel: PROC [ks: KitchenSink] = {
IF ks.controlPanel = NIL THEN {
ks.controlPanel ← NEW[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.}