-- Miscellaneous.mesa; edited by Sandman, September 7, 1980 3:29 PM
-- Copyright Xerox Corporation 1979, 1980
DIRECTORY
AltoFileDefs USING [TIME],
BcdDefs USING [NullVersion, VersionID, VersionStamp],
BitBltDefs USING [AlignedBBTable, BBptr, BBTableSpace, BITBLT],
ControlDefs USING [
ControlLink, FrameHandle, GFT, GFTIndex, GlobalFrameHandle, NullEpBase,
NullGlobalFrame, NullLink, UnboundLink],
FrameDefs USING [GlobalFrame, SwapInCode, SwapOutCode, UnNew],
FrameOps USING [CodeHandle, Free, GetReturnFrame, ReleaseCode, SetReturnLink],
ImageDefs USING [
AbortMesa, CleanupItem, CleanupMask, CleanupProcedure, StopMesa],
ImageFormat USING [ImageHeader, VersionID],
InlineDefs USING [BITAND, COPY, LongNumber],
MiscDefs USING [DAYTIME],
NucleusOps USING [Resident],
ProcessDefs USING [DisableInterrupts, EnableInterrupts],
Runtime USING [],
SDDefs USING [SD, sGoingAway],
SDOps USING [BlockEqualLong, ByteBlockEqualLong, Signal],
SegmentDefs USING [
DefaultANYBase, DeleteFileSegment, FileSegmentAddress, FileSegmentHandle,
MakeSwappedIn, MoveFileSegment, NewFileSegment, Read, SwapIn, SwapOut,
Unlock],
SwapperOps USING [UpdateCodebases],
SystemDefs USING [],
TrapDefs USING [ResumeError];
Miscellaneous: PROGRAM
IMPORTS
BitBltDefs, FrameDefs, FrameOps, ImageDefs, InlineDefs, MiscDefs, NucleusOps,
ProcessDefs, SDOps, SegmentDefs, SwapperOps, TrapDefs
EXPORTS FrameDefs, ImageDefs, MiscDefs, NucleusOps, Runtime, SDOps, SystemDefs
SHARES ControlDefs =PUBLIC
BEGIN OPEN ControlDefs;
DeletedFrame: PROCEDURE [gfi: GFTIndex] RETURNS [BOOLEAN] =
BEGIN RETURN[GFT[gfi] = [frame: NullGlobalFrame, epbase: NullEpBase]]; END;
SwapOutCode: PROCEDURE [f: GlobalFrameHandle] =
BEGIN
seg: SegmentDefs.FileSegmentHandle = FrameOps.CodeHandle[f];
IF seg # NIL THEN {
OPEN SwapperOps, SegmentDefs;
ProcessDefs.DisableInterrupts[];
IF seg.swappedin THEN {
SwapIn[seg]; UpdateCodebases[seg]; Unlock[seg]; SwapOut[seg]};
ProcessDefs.EnableInterrupts[]};
RETURN
END;
LockCode: PROCEDURE [link: UNSPECIFIED] =
BEGIN FrameDefs.SwapInCode[FrameDefs.GlobalFrame[link]]; RETURN END;
UnlockCode: PROCEDURE [link: UNSPECIFIED] =
BEGIN OPEN FrameDefs;
seg: SegmentDefs.FileSegmentHandle ← FrameOps.CodeHandle[GlobalFrame[link]];
IF seg # NIL AND seg.lock # 0 THEN SegmentDefs.Unlock[seg];
RETURN
END;
MakeCodeResident: PROCEDURE [f: GlobalFrameHandle] =
BEGIN OPEN SegmentDefs;
seg: FileSegmentHandle;
IF (seg ← FrameOps.CodeHandle[f]) = NIL THEN RETURN;
IF seg.lock = 0 THEN FrameDefs.SwapOutCode[f];
MakeSwappedIn[seg, DefaultANYBase, [hard, bottomup, code]];
RETURN
END;
GetCaller: PROCEDURE RETURNS [PROGRAM] =
BEGIN
RETURN[LOOPHOLE[FrameOps.GetReturnFrame[].returnlink.frame.accesslink]];
END;
IsBound: PROCEDURE [link: UNSPECIFIED] RETURNS [BOOLEAN] =
BEGIN
RETURN[link # ControlDefs.UnboundLink AND link # ControlDefs.NullLink];
END;
SelfDestruct: PROCEDURE =
BEGIN
destructee: FrameHandle ← FrameOps.GetReturnFrame[];
FrameOps.SetReturnLink[destructee.returnlink];
FrameDefs.UnNew[FrameDefs.GlobalFrame[destructee]];
FrameOps.Free[destructee];
RETURN
END;
-- Bcd Version and Time
Version: PROCEDURE [frame: GlobalFrameHandle, type: {bcd, image}]
RETURNS [version: BcdDefs.VersionStamp] =
BEGIN OPEN SegmentDefs;
codeseg: FileSegmentHandle ← FrameOps.CodeHandle[frame];
seg: FileSegmentHandle;
image: POINTER TO ImageFormat.ImageHeader;
id: CARDINAL;
p: POINTER TO RECORD [a, pages: CARDINAL];
IF codeseg = NIL THEN RETURN[BcdDefs.NullVersion];
seg ← NewFileSegment[codeseg.file, 1, 1, Read];
SwapIn[seg];
image ← p ← FileSegmentAddress[seg];
IF type = image AND image.prefix.versionident # ImageFormat.VersionID THEN
BEGIN
base: CARDINAL ← p.pages + 1;
Unlock[seg];
MoveFileSegment[seg, base, 1];
SwapIn[seg];
image ← FileSegmentAddress[seg];
END;
id ← image.prefix.versionident;
version ←
IF (id = ImageFormat.VersionID) OR (type = bcd AND id = BcdDefs.VersionID)
THEN image.prefix.version ELSE BcdDefs.NullVersion;
Unlock[seg];
DeleteFileSegment[seg];
RETURN
END;
BcdVersion: PROCEDURE RETURNS [version: BcdDefs.VersionStamp] =
BEGIN OPEN FrameDefs, FrameOps;
RETURN[Version[frame: GlobalFrame[GetReturnFrame[]], type: bcd]]
END;
GetBcdTime, BcdTime: PROCEDURE RETURNS [LONG CARDINAL] = {
OPEN FrameDefs, FrameOps;
RETURN[Version[frame: GlobalFrame[GetReturnFrame[]], type: bcd].time]};
-- Image Version and Time
ImageVersion: PROCEDURE RETURNS [version: BcdDefs.VersionStamp] =
BEGIN OPEN FrameDefs;
RETURN[Version[frame: GlobalFrame[NucleusOps.Resident], type: image]]
END;
GetBuildTime, ImageTime: PROCEDURE RETURNS [LONG CARDINAL] = {
OPEN FrameDefs;
RETURN[Version[frame: GlobalFrame[NucleusOps.Resident], type: image].time]};
CurrentTime: PROCEDURE RETURNS [LONG CARDINAL] =
BEGIN
time: AltoFileDefs.TIME ← MiscDefs.DAYTIME[];
RETURN[
LOOPHOLE[InlineDefs.LongNumber[
num[highbits: time.high, lowbits: time.low]]]];
END;
Even: PROCEDURE [n: CARDINAL] RETURNS [CARDINAL] = {RETURN[n + (n MOD 2)]};
Quad: PROCEDURE [n: CARDINAL] RETURNS [CARDINAL] = {
RETURN[n + InlineDefs.BITAND[-n, 3B]]};
SetBlock: PROCEDURE [p: POINTER, v: UNSPECIFIED, l: CARDINAL] =
BEGIN
IF l = 0 THEN RETURN;
p↑ ← v;
InlineDefs.COPY[from: p, to: p + 1, nwords: l - 1];
RETURN
END;
PPA: TYPE = POINTER TO PACKED ARRAY [0..0) OF [0..377B];
BlockEqualCodeLong: PUBLIC PROCEDURE [
p1: LONG POINTER, n: CARDINAL, offset: CARDINAL] RETURNS [BOOLEAN] =
BEGIN
result: BOOLEAN;
p2: LONG POINTER;
frame: GlobalFrameHandle = FrameOps.GetReturnFrame[].accesslink;
FrameDefs.SwapInCode[frame];
p2 ←
IF frame.code.highByte = 0 THEN frame.code.longbase + offset
ELSE frame.code.shortbase + offset;
result ← SDOps.BlockEqualLong[p1: p1, n: n, p2: p2];
FrameOps.ReleaseCode[frame];
RETURN[result]
END;
ByteBlockEqualCodeLong: PUBLIC PROCEDURE [
p1: LONG POINTER, n: CARDINAL, offset: CARDINAL] RETURNS [BOOLEAN] =
BEGIN
result: BOOLEAN;
p2: LONG POINTER;
frame: GlobalFrameHandle = FrameOps.GetReturnFrame[].accesslink;
FrameDefs.SwapInCode[frame];
p2 ←
IF frame.code.highByte = 0 THEN frame.code.longbase + offset
ELSE frame.code.shortbase + offset;
result ← SDOps.ByteBlockEqualLong[p1: p1, n: n, p2: p2];
FrameOps.ReleaseCode[frame];
RETURN[result]
END;
ByteBlt: PUBLIC PROCEDURE [to, from: PPA, toByte, fromByte, nBytes: CARDINAL] =
BEGIN
IF nBytes = 0 THEN RETURN;
IF (toByte MOD 2) # 0 THEN
BEGIN
to[toByte] ← from[fromByte];
toByte ← toByte + 1;
fromByte ← fromByte + 1;
nBytes ← nBytes - 1;
END;
IF (fromByte MOD 2) = 0 THEN -- fast case: both are word aligned
BEGIN
words: CARDINAL = nBytes/2;
InlineDefs.COPY[to: to + toByte/2, from: from + fromByte/2, nwords: words];
IF 2*words # nBytes THEN to[toByte + 2*words] ← from[fromByte + 2*words];
-- move the last byte
END
ELSE -- slow case: have to ripple things
BEGIN
lineWidth: CARDINAL = 16; -- words per line: controls interrupt latency
bba: BitBltDefs.BBTableSpace;
bbt: BitBltDefs.BBptr ← BitBltDefs.AlignedBBTable[@bba];
lines, tail: CARDINAL;
bbt↑ ←
[sourcetype: block, function: replace, dbca: to + toByte/2,
dbmr: lineWidth, dlx: 0, dw: 16*lineWidth, sbca: from + fromByte/2,
sbmr: lineWidth, slx: 8];
-- BITBLT is not interruptable except at the end of each scan line,
-- so we break things up into chunks in order to maintain reasonable
-- interrupt latency for the IO devices. It takes about 200microsec
-- to move 50 bytes with the display off.
tail ← nBytes MOD (2*lineWidth); -- bytes left to move with second BitBlt
lines ← nBytes/(2*lineWidth);
-- This "moves" a rectangle that is lineWidth words wide by as many
-- lines high as will fit. NB: It cheats and actually reads a byte
-- from beyond the edge of the rectangle. This is not really legal,
-- but works out OK for any reasonable inplementation of BitBlt.
bbt.dty ← bbt.sty ← 0;
bbt.dw ← 16*lineWidth;
bbt.dh ← lines;
BitBltDefs.BITBLT[bbt];
-- This BitBlt will move one line that is less than lineWidth words wide.
bbt.dty ← bbt.sty ← lines;
bbt.dw ← 8*tail;
bbt.dh ← 1;
BitBltDefs.BITBLT[bbt];
END;
END;
-- procedure lists
UserCleanupList: POINTER TO ImageDefs.CleanupItem ← NIL;
AddCleanupProcedure: PROCEDURE [item: POINTER TO ImageDefs.CleanupItem] =
BEGIN
ProcessDefs.DisableInterrupts[];
RemoveCleanupProcedure[item];
item.link ← UserCleanupList;
UserCleanupList ← item;
ProcessDefs.EnableInterrupts[];
END;
RemoveCleanupProcedure: PROCEDURE [item: POINTER TO ImageDefs.CleanupItem] =
BEGIN
prev, this: POINTER TO ImageDefs.CleanupItem;
IF UserCleanupList = NIL THEN RETURN;
ProcessDefs.DisableInterrupts[];
prev ← this ← UserCleanupList;
IF this = item THEN UserCleanupList ← this.link
ELSE
UNTIL (this ← this.link) = NIL DO
IF this = item THEN BEGIN prev.link ← this.link; EXIT END;
prev ← this;
ENDLOOP;
ProcessDefs.EnableInterrupts[];
END;
UserCleanupProc: ImageDefs.CleanupProcedure =
BEGIN -- all interrupts off if why = finish or abort
this, next: POINTER TO ImageDefs.CleanupItem;
this ← UserCleanupList;
UserCleanupList ← NIL;
WHILE this # NIL DO
next ← this.link;
IF InlineDefs.BITAND[ImageDefs.CleanupMask[why], this.mask] # 0 THEN
this.proc[why ! ANY => IF why = Abort OR why = Finish THEN CONTINUE];
AddCleanupProcedure[this];
this ← next;
ENDLOOP;
SELECT why FROM
Finish => ImageDefs.StopMesa[];
Abort => ImageDefs.AbortMesa[];
ENDCASE;
END;
-- Signaller Overflow routines; known not to be called in resident stuff
ReturnError: PROCEDURE [signal: SIGNAL, message: UNSPECIFIED] =
BEGIN
caller: FrameHandle = FrameOps.GetReturnFrame[];
FrameOps.SetReturnLink[caller.returnlink];
SDOps.Signal[signal, message ! UNWIND => FrameOps.Free[caller]];
FrameOps.Free[caller];
ERROR TrapDefs.ResumeError
END;
ReturnErrorList: PROCEDURE [signal: SIGNAL, message: POINTER TO UNSPECIFIED] =
BEGIN
caller: FrameHandle = FrameOps.GetReturnFrame[];
FrameOps.SetReturnLink[caller.returnlink];
SDOps.Signal[
signal, message !
UNWIND => BEGIN FrameOps.Free[caller]; FrameOps.Free[message]; END];
FrameOps.Free[caller];
FrameOps.Free[message];
ERROR TrapDefs.ResumeError
END;
-- Main Body;
SDDefs.SD[SDDefs.sGoingAway] ← UserCleanupProc;
END...