-- 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...