DynaSeerImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Written By: Pradeep Sindhu September 18, 1986 4:52:07 pm PDT
Pradeep Sindhu September 26, 1986 11:28:42 pm PDT
Last Edited by: Louis Monier September 24, 1986 2:02:42 pm PDT
Russ Atkinson (RRA) September 25, 1986 6:22:55 pm PDT
DIRECTORY CacheModel, DisplayModel, DynaStats, DynaSeer, IO, MemoryModel, ViewerIO;
DynaSeerImpl: CEDAR PROGRAM
IMPORTS CacheModel, DisplayModel, DynaStats, IO, MemoryModel
EXPORTS DynaSeer =
BEGIN OPEN DynaSeer;
oneDataCycles: Cycles ← LIST [MakeCycle[DataCycle]];
fourDataCycles: Cycles ← LIST [MakeCycle[DataCycle], MakeCycle[DataCycle], MakeCycle[DataCycle], MakeCycle[DataCycle]];
Device and Bus Procs
CreateDevice: PUBLIC PROC [] RETURNS [device: Device] = {
device ← NEW [DeviceRec];
};
MakeCycle: PUBLIC PROC [cmd: Cmd, deviceId, master: DeviceId ← 0, data: INT ← 0] RETURNS [cycle: Cycle] = {
cycle ← NEW [CycleRec ← [cmd: cmd, deviceId: deviceId, master: master, data: data, grantLatency: 0]];
};
MakeNoOp: PUBLIC PROC [] RETURNS [cycle: Cycle] = {
cycle ← MakeCycle[NoOp];
};
MakeDataCycles: PUBLIC PROC [length: Length] RETURNS [Cycles] = {
SELECT length FROM
One => RETURN [NIL];
Two => RETURN [oneDataCycles];
Five => RETURN [fourDataCycles]
ENDCASE => ERROR;
};
MakeBubble: PUBLIC PROC [] RETURNS [cycle: Cycle] = {
cycle ← MakeCycle[Bubble];
};
MakeRequest: PUBLIC PROC [length: Length, header: Cycle, priority: Priority ← Low] RETURNS [request: Request] = {
cycles: Cycles ← CONS [header, MakeDataCycles[length]];
request ← NEW [RequestRec ← [length, cycles, priority]];
};
IsDataCycle: PUBLIC PROC [cycle: Cycle] RETURNS [BOOLFALSE] ~ {RETURN[cycle.cmd=DataCycle]};
IsUsefulCycle: PUBLIC PROC [cycle: Cycle] RETURNS [BOOLFALSE] ~ {
RETURN[cycle.cmd#NoOp AND cycle.cmd#Bubble]};
IsHeaderCycle: PUBLIC PROC [cycle: Cycle] RETURNS [BOOLFALSE] ~ {
RETURN[IsUsefulCycle[cycle] AND NOT IsDataCycle[cycle]]};
IsReplyCycle: PUBLIC PROC [cycle: Cycle] RETURNS [BOOLFALSE] ~ {
RETURN[cycle.cmd=RBRply OR cycle.cmd=WBRply OR cycle.cmd=WSRply]};
IsRequestCycle: PUBLIC PROC [cycle: Cycle] RETURNS [BOOLFALSE] ~ {
RETURN[cycle.cmd=RBRqst OR cycle.cmd=WBRqst OR cycle.cmd=WSRqst]};
IsDisplay: PUBLIC PROC [handle: Handle, deviceId: DeviceId] RETURNS [BOOLFALSE] ~ {
RETURN[deviceId=handle.display]};
IsCache: PUBLIC PROC [handle: Handle, deviceId: DeviceId] RETURNS [BOOLFALSE] ~ {
RETURN[deviceId>=handle.firstcache AND deviceId<=handle.lastcache]};
IsMemory: PUBLIC PROC [handle: Handle, deviceId: DeviceId] RETURNS [BOOLFALSE] ~ {
RETURN[deviceId>=handle.firstmem AND deviceId<=handle.lastmem]};
Simulation Procs
CreateSimulation: PUBLIC PROC [in, out: IO.STREAM, numCycles, numMemories, numCaches, arbLatency: INT] RETURNS [handle: Handle] = {
deviceId: DeviceId ← 0;
handle ← NEW [HandleRec];
handle.numCycles ← numCycles;
Memories must have consecutive device numbers starting with 0
handle.firstmem ← handle.memPtr ← deviceId;
FOR i: INT IN [1..numMemories] DO
handle.devices ← CONS[MemoryModel.CreateMemory[deviceId], handle.devices]; deviceId ← deviceId+1;
ENDLOOP;
handle.lastmem ← deviceId-1;
Caches must have consecutive device numbers
handle.firstcache ← handle.cacheLPPtr ← handle.cacheHPPtr ← deviceId;
FOR i: INT IN [1..numCaches] DO
handle.devices ← CONS[CacheModel.CreateCache[deviceId], handle.devices]; deviceId ← deviceId+1;
ENDLOOP;
handle.lastcache ← deviceId-1;
Display automatically gets the highest device id
handle.display ← deviceId;
handle.devices ← CONS[DisplayModel.CreateDisplay[deviceId], handle.devices];
handle.history ← NIL;
handle.in ← in;
handle.out ← out;
handle.arbLatency ← arbLatency
};
RunSimulation: PUBLIC PROC [handle: Handle] = {
currentRequest: Request;
currentCycle: Cycle;
Initialize modules
IF handle.lastcache >= handle.firstcache THEN CacheModel.Init[handle];
IF handle.lastmem >= handle.firstmem THEN MemoryModel.Init[handle];
DisplayModel.Init[handle];
DynaStats.Init[handle];
Initialize all devices
FOR dl: LIST OF Device ← handle.devices, dl.rest WHILE dl#NIL DO
dl.first.init[handle, dl.first];
ENDLOOP;
Run for the appropriate number of cycles
handle.cycleNumber ← 1;
handle.lastNonDataCycle ← MakeNoOp[];
WHILE handle.cycleNumber <= handle.numCycles DO
currentRequest ← Arbitrate[handle];
IF IsBubble[handle, currentRequest.cycles.first] THEN
THROUGH [1..handle.bubblesPerSwitch] DO
currentRequest.cycles ← CONS[MakeBubble[], currentRequest.cycles];
ENDLOOP;
FOR cl: LIST OF Cycle ← currentRequest.cycles, cl.rest WHILE cl#NIL DO
currentCycle ← cl.first;
FOR dl: LIST OF Device ← handle.devices, dl.rest WHILE dl#NIL DO
dl.first.cycle[handle, dl.first, currentCycle];
ENDLOOP;
DynaStats.AddToHistory[handle, currentCycle];
handle.cycleNumber ← handle.cycleNumber+1;
ENDLOOP;
ENDLOOP;
};
GetIntParm: PUBLIC PROC [in, out: IO.STREAM, prompt: ROPE, default: INT] RETURNS [val: INT] = {
IO.PutF[out, "%g ( %g ): ", IO.rope[prompt], IO.int[default]];
IF IO.PeekChar[in] = '\n THEN val ← default ELSE val ← IO.GetInt[in];
[] ← IO.GetChar[in];
};
GetRealParm: PUBLIC PROC [in, out: IO.STREAM, prompt: ROPE, default: REAL] RETURNS [val: REAL] = {
IO.PutF[out, "%g ( %g ): ", IO.rope[prompt], IO.real[default]];
IF IO.PeekChar[in] = '\n THEN val ← default ELSE val ← IO.GetReal[in];
[] ← IO.GetChar[in];
};
Internal Utilities
OnSameBoard: PROC [handle: Handle, one, two: DeviceId] RETURNS [BOOL] ~ {
RETURN [
(one IN [handle.firstmem .. handle.lastmem] AND two IN [handle.firstmem .. handle.lastmem]) OR
(one IN [handle.firstcache .. handle.lastcache] AND two IN [handle.firstcache .. handle.lastcache]) OR
(one > handle.lastcache AND two > handle.lastcache)];
};
IsBubble: PROC [handle: Handle, cycle: Cycle] RETURNS [BOOLFALSE] ~ {
RETURN [IsUsefulCycle[handle.lastNonDataCycle] AND IsHeaderCycle[cycle] AND NOT OnSameBoard[handle, handle.lastNonDataCycle.master, cycle.master]];
};
Arbitrate: PROC [handle: Handle] RETURNS [request: Request] = {
ptr: DeviceId;
Incr: PROC [val, first, last: DeviceId] RETURNS[newVal: DeviceId] = {
newVal ← IF val+1>last THEN first ELSE val+1
};
If any high-priority cache requests then select one
ptr ← handle.cacheHPPtr;
WHILE TRUE DO
request ← handle.cacheHPRequests[ptr];
IF request#NIL AND request.cycles.first.grantLatency >= handle.arbLatency THEN {
handle.cacheHPPtr ← Incr[ptr, handle.firstcache, handle.lastcache];
handle.cacheHPRequests[ptr] ← NIL;
RETURN;
};
ptr ← Incr[ptr, handle.firstcache, handle.lastcache];
IF ptr=handle.cacheHPPtr THEN EXIT;
ENDLOOP;
If any memory requests then select one
ptr ← handle.memPtr;
WHILE TRUE DO
request ← handle.memRequests[ptr];
IF request#NIL AND request.cycles.first.grantLatency >= handle.arbLatency THEN {
handle.memPtr ← Incr[ptr, handle.firstmem, handle.lastmem];
handle.memRequests[ptr] ← NIL;
RETURN;
};
ptr ← Incr[ptr, handle.firstmem, handle.lastmem];
IF ptr=handle.memPtr THEN EXIT;
ENDLOOP;
If any displayHP request then select it
request ← handle.displayHPRequest;
IF request#NIL AND request.cycles.first.grantLatency >= handle.arbLatency THEN {handle.displayHPRequest ← NIL; RETURN};
If any low-priority cache requests then select one
ptr ← handle.cacheLPPtr;
WHILE TRUE DO
request ← handle.cacheLPRequests[ptr];
IF request#NIL AND request.cycles.first.grantLatency >= handle.arbLatency THEN {
handle.cacheLPPtr ← Incr[ptr, handle.firstcache, handle.lastcache];
handle.cacheLPRequests[ptr] ← NIL;
RETURN;
};
ptr ← Incr[ptr, handle.firstcache, handle.lastcache];
IF ptr=handle.cacheLPPtr THEN EXIT;
ENDLOOP;
If any low-priority display request then select it
request ← handle.displayLPRequest;
IF request#NIL AND request.cycles.first.grantLatency >= handle.arbLatency THEN {handle.displayLPRequest ← NIL; RETURN};
No request found!
request ← MakeRequest[One, MakeNoOp[]];
};
END.