-- Counter.mesa; edited by Sandman on September 21, 1980 7:29 PM
DIRECTORY
ControlDefs USING [
ControlLink, EPRange, FrameHandle, NullFrame, NullReason, Port, StateVector,
TraceNext, TraceOff, TrapParameter, TrapReason, TrapStatus],
CoreSwapDefs USING [BBHandle, ExternalStateVector, PuntInfo, UBBPointer],
CountPrivate USING [ControlRecord, GroupIndex, VersionID],
FrameDefs USING [MakeCodeResident],
FrameOps USING [
Free, GetReturnLink, MyGlobalFrame, MyLocalFrame, SetReturnFrame,
SetReturnLink],
ImageDefs USING [AbortMesa],
Inline USING [BITSHIFT, LongNumber],
KeyDefs USING [Keys],
MiscDefs USING [Zero],
OsStaticDefs USING [OsStatics],
ProcessDefs USING [DisableInterrupts, EnableInterrupts],
ProcessOps USING [CurrentPSB],
SDDefs USING [
sBreakBlock, sCoreSwap, SD, sGFTLength, sXferTrap, sXferTrapMonitor],
Storage USING [Words],
TimingDefs USING [
Fudge, Fudges, HiLo, Machine, MaxTick, Pair, ReadTime, RealTime],
TrapOps USING [ReadXTP, ReadXTS, WriteXTS],
XferCountDefs USING [];
Counter: PROGRAM
IMPORTS
FrameDefs, FrameOps, ImageDefs, Inline, MiscDefs, ProcessDefs, Storage,
TimingDefs, TrapOps
EXPORTS XferCountDefs =
BEGIN OPEN TimingDefs, Inline, CountPrivate, ControlDefs, FrameOps;
WBPort: PORT [POINTER TO CoreSwapDefs.ExternalStateVector];
machine: Machine;
fudge: TimingDefs.Fudge;
activeFudge: TimingDefs.Pair;
currentState: TimingDefs.HiLo;
cr: ControlRecord;
GetFudge: PROCEDURE RETURNS [val: CARDINAL] = INLINE
BEGIN
val ← activeFudge.value;
IF (activeFudge.factor ← activeFudge.factor - 1) = 0 THEN
BEGIN
currentState ← SELECT currentState FROM hi => lo, ENDCASE => hi;
activeFudge ← fudge[currentState];
END;
RETURN
END;
HandleTraps: PROCEDURE =
BEGIN
state: StateVector;
trapParam: TrapParameter;
status: TrapStatus;
frame: FrameHandle;
ep, i: CARDINAL;
link: ControlLink;
previousProcess: UNSPECIFIED;
exitTime, entryTime: RealTime;
finish, time, start: LONG CARDINAL;
reason: TrapReason;
state ← STATE;
state.dest ← GetReturnLink[];
SDDefs.SD[SDDefs.sXferTrap] ← state.source ← FrameOps.MyLocalFrame[];
ProcessDefs.DisableInterrupts[];
ProcessDefs.DisableInterrupts[];
DO
IF cr.trace THEN TrapOps.WriteXTS[TraceNext];
previousProcess ← ProcessOps.CurrentPSB↑;
exitTime ← ReadTime[];
ProcessDefs.EnableInterrupts[];
ProcessDefs.EnableInterrupts[];
TRANSFER WITH state;
ProcessDefs.DisableInterrupts[];
ProcessDefs.DisableInterrupts[];
state ← STATE;
entryTime ← ReadTime[];
trapParam ← TrapOps.ReadXTP[];
status ← TrapOps.ReadXTS[];
TrapOps.WriteXTS[TraceOff];
-- Fixup time
finish ←
LONG[
WITH entryTime.low SELECT machine FROM altoI => low, altoII => low,
d0 => low, ENDCASE => 0] + BITSHIFT[entryTime.high.whole, 10] +
LOOPHOLE[LongNumber[num[highbits: entryTime.high.high, lowbits: 0]],
LONG CARDINAL];
start ←
LONG[
WITH exitTime.low SELECT machine FROM altoI => low, altoII => low,
d0 => low, ENDCASE => 0] + BITSHIFT[exitTime.high.whole, 10] +
LOOPHOLE[LongNumber[num[highbits: exitTime.high.high, lowbits: 0]], LONG
CARDINAL];
i ← GetFudge[];
time ← finish - start;
IF start > finish THEN time ← time + MaxTick;
time ← IF time > i THEN time - i ELSE i;
IF cr.newMeasurement THEN {cr.newMeasurement ← FALSE; cr.gfi ← 0}
ELSE IF cr.mode = plain THEN {
cr.times.plain[cr.gfi] ← cr.times.plain[cr.gfi] + time;
IF ProcessOps.CurrentPSB↑ = previousProcess THEN
cr.counts.plain[cr.gfi] ← cr.counts.plain[cr.gfi] + 1
ELSE time ← time}
ELSE {
to, from: GroupIndex;
to ← cr.groups[cr.gfi];
from ← cr.groups[cr.prevGfi];
cr.prevGfi ← cr.gfi;
cr.times.matrix[to][from] ← cr.times.matrix[to][from] + time;
IF ProcessOps.CurrentPSB↑ = previousProcess THEN
cr.counts.matrix[to][from] ← cr.counts.matrix[to][from] + 1
ELSE time ← time};
SELECT (reason ← status.reason) FROM
other => {
SetReturnLink[
IF state.source = NullFrame THEN trapParam.link ELSE state.source];
link ← trapParam.link;
DO
SELECT link.tag FROM
procedure => BEGIN cr.gfi ← link.gfi; EXIT; END;
indirect => link ← link.link↑;
frame => BEGIN cr.gfi ← link.frame.accesslink.gfi; EXIT; END;
ENDCASE => BEGIN cr.gfi ← 0; EXIT; END;
ENDLOOP};
localCall => {
ep ← (trapParam.ep - 2)/2;
frame ← state.source;
cr.gfi ← frame.accesslink.gfi;
trapParam.link ← ControlLink[
procedure[
tag: procedure, gfi: cr.gfi + ep/EPRange, ep: ep MOD EPRange]];
SetReturnFrame[frame]};
return => {
frame ← trapParam.frame - 6;
link ← trapParam.link ← frame.returnlink;
SetReturnFrame[frame];
DO
SELECT link.tag FROM
procedure => BEGIN cr.gfi ← link.gfi; EXIT; END;
indirect => link ← link.link↑;
frame => BEGIN cr.gfi ← link.frame.accesslink.gfi; EXIT; END;
ENDCASE => BEGIN cr.gfi ← 0; EXIT; END;
ENDLOOP};
ENDCASE;
IF (cr.process # NIL AND cr.process # ProcessOps.CurrentPSB↑) THEN
cr.gfi ← 0;
state.dest ← trapParam.link;
IF reason = return THEN
BEGIN FrameOps.Free[frame]; state.source ← NullFrame; END;
ENDLOOP;
END;
TraceOn: TrapStatus = [0, NullReason, 0, on];
MonitorBreaks: PROCEDURE =
BEGIN
state: StateVector;
frame: FrameHandle;
esv: CoreSwapDefs.ExternalStateVector;
bbHandle: CoreSwapDefs.BBHandle;
ubb: CoreSwapDefs.UBBPointer;
i: CARDINAL;
state ← STATE;
cr.self ← MyLocalFrame[];
state.dest ← GetReturnLink[];
ProcessDefs.DisableInterrupts[];
DO
ProcessDefs.EnableInterrupts[];
TRANSFER WITH state;
ProcessDefs.DisableInterrupts[];
state ← STATE;
SetReturnFrame[state.dest ← frame ← state.source];
state.source ← FrameOps.MyLocalFrame[];
frame.pc ← [IF frame.pc < 0 THEN -frame.pc ELSE (1 - frame.pc)];
bbHandle ← SDDefs.SD[SDDefs.sBreakBlock];
FOR i IN [0..bbHandle.length) DO
ubb ← @bbHandle.blocks[i];
IF frame.accesslink = ubb.frame AND frame.pc = ubb.pc THEN
BEGIN
IF ubb.counterL THEN
SELECT LOOPHOLE[ubb.ptrR, CARDINAL] FROM
0 => cr.trace ← TRUE;
1 => cr.trace ← ~cr.trace;
2 => cr.trace ← FALSE;
ENDCASE;
state.instbyte ← ubb.inst;
EXIT;
END;
REPEAT
FINISHED =>
BEGIN
esv ← CoreSwapDefs.PuntInfo↑.puntESV;
esv.state ← @state;
esv.reason ← worrybreak;
DO
WBPort[@esv];
SELECT esv.reason FROM
proceed => EXIT;
kill => ImageDefs.AbortMesa[];
showscreen => UNTIL KeyDefs.Keys.Spare3 = down DO NULL ENDLOOP;
ENDCASE;
esv.reason ← return;
ENDLOOP;
END;
ENDLOOP;
IF cr.trace THEN TrapOps.WriteXTS[TraceNext]
ELSE BEGIN cr.gfi ← 0; TrapOps.WriteXTS[TraceOff] END;
ENDLOOP;
END;
StartCounting: PUBLIC PROCEDURE =
BEGIN TrapOps.WriteXTS[TraceNext]; cr.trace ← TRUE; RETURN END;
StopCounting: PUBLIC PROCEDURE = BEGIN cr.trace ← FALSE; cr.gfi ← 0; RETURN END;
Init: PROCEDURE =
BEGIN
sd: POINTER TO ARRAY [0..0) OF UNSPECIFIED ← SDDefs.SD;
length: CARDINAL = MAX[SDDefs.SD[SDDefs.sGFTLength], 256];
words: CARDINAL = length*SIZE[LONG CARDINAL]*2 + length;
data: POINTER = Storage.Words[words];
FrameDefs.MakeCodeResident[FrameOps.MyGlobalFrame[]];
cr ←
[gfi: 0, version: VersionID, saveBreakHandler: NIL, length: length,
newSession: TRUE, trace: FALSE, counts: data, self: NIL, mode: plain,
times: data + length*SIZE[LONG CARDINAL], prevGfi: 0, process: NIL,
groups: data + 2*length*SIZE[LONG CARDINAL], pulseConversion: 3810,
newMeasurement: TRUE];
MiscDefs.Zero[data, words];
sd[SDDefs.sXferTrapMonitor] ← @cr;
LOOPHOLE[WBPort, ControlDefs.Port] ←
[representation[in: 0, out: sd[SDDefs.sCoreSwap]]];
SELECT OsStaticDefs.OsStatics.AltoVersion.engineeringnumber FROM
2, 3, 5 => BEGIN machine ← altoII; fudge ← TimingDefs.Fudges[altoII] END;
4 => BEGIN machine ← d0; fudge ← TimingDefs.Fudges[d0] END;
ENDCASE => BEGIN machine ← altoI; fudge ← TimingDefs.Fudges[altoI] END;
activeFudge ← fudge[currentState ← hi];
HandleTraps[];
MonitorBreaks[];
END;
Init[];
END...