ClusterImpl.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, 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
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;
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] = {
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, "NotPhA",   1, force],  -- IFU no longer uses. Does EU?
IFUPublic.PortWire[TRUE, "NotPhB",   1, force],  -- IFU no longer uses. Does EU?
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"]]];
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]};
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.ROPENIL] = {
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)
THENREJECT
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
THENREJECT
ELSE {TerminalIO.PutF["%g\n", IO.rope[msg]]; RESUME}]};
IF ks.controlPanel.reset THEN ks.controlPanel.instrCount ← -1;
IF ks.ifuVectors#NILTHEN RosemaryVector.WriteVector[ks.ifuVectors, inhibitExpects];
IF ks.euVectors#NILTHEN RosemaryVector.WriteVector[ks.euVectors, inhibitExpects];
Process.Yield[];
ks.controlPanel.continueTestFromAbort ← FALSE};
LogSettle: PROC [handle: RosemaryUser.RoseDisplay, time: INT, memory: BOOLTRUE] = {
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: BOOLTRUE;
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  [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];
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};
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 ] = {
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[];
Main LOOP EXIT
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 ANYNIL ] = {
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 ANYNIL ] = {
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 ] = {
EU.NoteRegStoreProc
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: BOOLFALSE] RETURNS [data: LizardCache.Word, status: LizardCache.TrapIndex, rejectCycles: INT] = {
Lizard.CacheFetchProc
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] = {
Lizard.CacheStoreProc
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] = {
LizardHeart.RegChangeProc
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: BOOLFALSE, privateData: REFNIL ] =
{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: BOOLFALSE;
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: 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};
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];
ViewRec.SetBehavior[newBehavior: [delayParms: [min: 2000.0]]];
[] ← ViewRec.ViewRef[agg: ks.ifuScanBuffer, label: "IFU Debug Scan Record"];
};
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.