-- NonResident.mesa; edited by Sandman, July 1, 1980  8:23 AM
-- Copyright  Xerox Corporation 1979, 1980

DIRECTORY
  AltoDefs USING [BYTE],
  ControlDefs USING [
    ControlLink, FrameHandle, GFTItem, GFT, GlobalFrameHandle, StateVector],
  FrameDefs USING [SwapInCode],
  FrameOps USING [GetReturnFrame, GetReturnLink, ReleaseCode],
  InlineDefs USING [
    BITSHIFT, BITXOR, COPY, DIVMOD, LongCOPY, LongDiv, LongDivMod, LongMult,
    LongNumber],
  Mopcodes USING [zRBL, zWBL],
  NucleusOps USING [],
  Runtime USING [],
  SDDefs USING [SD, sGFTLength],
  SDOps USING [];

NonResident: PROGRAM
  IMPORTS FrameDefs, FrameOps, InlineDefs
  EXPORTS FrameDefs, FrameOps, NucleusOps, Runtime, SDOps
  SHARES ControlDefs =PUBLIC

  BEGIN OPEN ControlDefs;

  -- Frame validation

  InvalidGlobalFrame: SIGNAL [frame: GlobalFrameHandle] = CODE;

  ValidateGlobalFrame: PROCEDURE [g: GlobalFrameHandle] =
    BEGIN IF ~ValidGlobalFrame[g] THEN SIGNAL InvalidGlobalFrame[g]; END;

  ValidGlobalFrame: PROCEDURE [g: GlobalFrameHandle] RETURNS [BOOLEAN] =
    BEGIN
    gft: POINTER TO ARRAY [0..0) OF GFTItem ← GFT;
    IF LOOPHOLE[g, ControlLink].tag # frame OR g.gfi >= SDDefs.SD[
      SDDefs.sGFTLength] THEN RETURN[FALSE];
    RETURN[gft[g.gfi].frame = g]
    END;

  InvalidFrame: SIGNAL [frame: FrameHandle] = CODE;

  ValidateFrame: PROCEDURE [f: FrameHandle] =
    BEGIN IF ~ValidFrame[f] THEN SIGNAL InvalidFrame[f]; END;

  ValidFrame: PROCEDURE [f: FrameHandle] RETURNS [BOOLEAN] =
    BEGIN
    RETURN[
      LOOPHOLE[f, ControlLink].tag = frame AND ValidGlobalFrame[f.accesslink]]
    END;

  -- unimplemented instructions


  BlockEqual: PROCEDURE [p1: POINTER, n: CARDINAL, p2: POINTER]
    RETURNS [BOOLEAN] =
    BEGIN
    i: CARDINAL;
    FOR i IN [0..n) DO IF (p1 + i)↑ # (p2 + i)↑ THEN RETURN[FALSE]; ENDLOOP;
    RETURN[TRUE]
    END;

  PPA: TYPE = POINTER TO PACKED ARRAY [0..0) OF AltoDefs.BYTE;

  ByteBlockEqual: PROCEDURE [p1: PPA, n: CARDINAL, p2: PPA] RETURNS [BOOLEAN] =
    BEGIN
    RETURN[BlockEqual[p1: p1, p2: p2, n: n/2] AND p1[n - 1] = p2[n - 1]]
    END;

  BlockEqualCode: PROCEDURE [p1: POINTER, n: CARDINAL, offset: CARDINAL]
    RETURNS [BOOLEAN] =
    BEGIN
    result: BOOLEAN;
    frame: GlobalFrameHandle = FrameOps.GetReturnFrame[].accesslink;
    FrameDefs.SwapInCode[frame];
    result ←
      IF frame.code.highByte = 0 THEN BlockEqualLong[
      p1: p1, n: n, p2: frame.code.longbase + offset]
      ELSE BlockEqual[p1: p1, n: n, p2: frame.code.shortbase + offset];
    FrameOps.ReleaseCode[frame];
    RETURN[result]
    END;

  ByteBlockEqualCode: PROCEDURE [p1: POINTER, n: CARDINAL, offset: CARDINAL]
    RETURNS [BOOLEAN] =
    BEGIN
    result: BOOLEAN;
    frame: GlobalFrameHandle = FrameOps.GetReturnFrame[].accesslink;
    FrameDefs.SwapInCode[frame];
    result ←
      IF frame.code.highByte = 0 THEN ByteBlockEqualLong[
      p1: p1, n: n, p2: frame.code.longbase + offset]
      ELSE ByteBlockEqual[p1: p1, n: n, p2: frame.code.shortbase + offset];
    FrameOps.ReleaseCode[frame];
    RETURN[result]
    END;

  ReadLongWord: PROCEDURE [LONG POINTER] RETURNS [CARDINAL] = MACHINE CODE
    BEGIN Mopcodes.zRBL, 0 END;

  BlockEqualLong: PROCEDURE [p1: LONG POINTER, n: CARDINAL, p2: LONG POINTER]
    RETURNS [BOOLEAN] =
    BEGIN
    i: CARDINAL;
    FOR i IN [0..n) DO
      IF ReadLongWord[p1 + i] # ReadLongWord[p2 + i] THEN RETURN[FALSE]; ENDLOOP;
    RETURN[TRUE]
    END;

  ByteBlockEqualLong: PROCEDURE [p1: LONG PPA, n: CARDINAL, p2: LONG PPA]
    RETURNS [BOOLEAN] =
    BEGIN
    w1, w2: RECORD [odd, ignore: [0..377B]];
    IF ~BlockEqualLong[p1: p1, p2: p2, n: n/2] THEN RETURN[FALSE];
    w1 ← LOOPHOLE[ReadLongWord[p1 + n/2]];
    w2 ← LOOPHOLE[ReadLongWord[p2 + n/2]];
    RETURN[w1.odd = w2.odd];
    END;

  -- data shuffling


  LongReadWord: PROCEDURE [LONG POINTER] RETURNS [UNSPECIFIED] = MACHINE CODE
    BEGIN Mopcodes.zRBL, 0 END;

  LongWriteWord: PROCEDURE [UNSPECIFIED, LONG POINTER] = MACHINE CODE
    BEGIN Mopcodes.zWBL, 0 END;

  StringInit: PROCEDURE [coffset, n: CARDINAL, reloc, dest: POINTER] =
    BEGIN OPEN ControlDefs;
    g: GlobalFrameHandle = FrameOps.GetReturnFrame[].accesslink;
    i, j: CARDINAL;
    FrameDefs.SwapInCode[g];
    IF g.code.highByte = 0 THEN
      BEGIN
      InlineDefs.LongCOPY[from: g.code.longbase + coffset, to: dest, nwords: n];
      FOR i IN [0..n) DO
	j ← LongReadWord[dest + i]; LongWriteWord[j + reloc, dest + i]; ENDLOOP;
      END
    ELSE
      BEGIN
      InlineDefs.COPY[from: g.code.shortbase + coffset, to: dest, nwords: n];
      FOR i IN [0..n) DO (dest + i)↑ ← (dest + i)↑ + reloc; ENDLOOP;
      END;
    FrameOps.ReleaseCode[g];
    RETURN
    END;

  -- long, signed and mixed mode arithmetic


  DIVMOD: PROCEDURE [n, d: CARDINAL] RETURNS [QR] = LOOPHOLE[InlineDefs.DIVMOD];
  QR: TYPE = RECORD [q, r: INTEGER];
  PQR: TYPE = POINTER TO QR;

  SignDivide: PROCEDURE =
    BEGIN
    state: ControlDefs.StateVector;
    p: PQR;
    t: CARDINAL;
    negnum, negden: BOOLEAN;
    state ← STATE;
    state.stkptr ← t ← state.stkptr - 1;
    state.dest ← FrameOps.GetReturnLink[];
    p ← @state.stk[t - 1];
    IF negden ← (p.r < 0) THEN p.r ← -p.r;
    IF negnum ← (p.q < 0) THEN p.q ← -p.q;
    p↑ ← DIVMOD[n: p.q, d: p.r]; -- following assumes TRUE = 1; FALSE = 0
    IF InlineDefs.BITXOR[negnum, negden] # 0 THEN p.q ← -p.q;
    IF negnum THEN p.r ← -p.r;
    RETURN WITH state
    END;

  DDivMod: PROCEDURE [num, den: Number] RETURNS [quotient, remainder: Number] =
    BEGIN
    negNum, negDen: BOOLEAN ← FALSE;
    IF LOOPHOLE[num.highbits, INTEGER] < 0 THEN
      BEGIN negNum ← TRUE; num.li ← -num.li; END;
    IF LOOPHOLE[den.highbits, INTEGER] < 0 THEN
      BEGIN negDen ← TRUE; den.li ← -den.li; END;
    [quotient: quotient, remainder: remainder] ← DUnsignedDivMod[
      num: num, den: den];
    IF InlineDefs.BITXOR[negNum, negDen] # 0 THEN quotient.li ← -quotient.li;
    IF negNum THEN remainder.li ← -remainder.li;
    RETURN
    END;

  DDiv: PROCEDURE [a, b: Number] RETURNS [Number] =
    BEGIN RETURN[DDivMod[a, b].quotient] END;

  DMod: PROCEDURE [a, b: Number] RETURNS [r: Number] =
    BEGIN [remainder: r] ← DDivMod[a, b]; RETURN END;

  DMultiply: PROCEDURE [a, b: Number] RETURNS [product: Number] =
    BEGIN
    product.lc ← InlineDefs.LongMult[a.lowbits, b.lowbits];
    product.highbits ←
      product.highbits + a.lowbits*b.highbits + a.highbits*b.lowbits;
    RETURN
    END;

  Number: PRIVATE TYPE = InlineDefs.LongNumber;

  DUnsignedDivMod: PROCEDURE [num, den: Number]
    RETURNS [quotient, remainder: Number] =
    BEGIN OPEN InlineDefs;
    qq: CARDINAL;
    count: [0..31);
    lTemp: Number;
    IF den.highbits = 0 THEN
      BEGIN
      [quotient.highbits, qq] ← LongDivMod[
	LOOPHOLE[Number[num[lowbits: num.highbits, highbits: 0]]], den.lowbits];
      [quotient.lowbits, remainder.lowbits] ← LongDivMod[
	LOOPHOLE[Number[num[lowbits: num.lowbits, highbits: qq]]], den.lowbits];
      remainder.highbits ← 0;
      END
    ELSE
      BEGIN
      count ← 0;
      quotient.highbits ← 0;
      lTemp ← den;
      WHILE lTemp.highbits # 0 DO
	-- normalize
	lTemp.lowbits ←
	  BITSHIFT[lTemp.lowbits, -1] + BITSHIFT[lTemp.highbits, 15];
	lTemp.highbits ← BITSHIFT[lTemp.highbits, -1];
	count ← count + 1;
	ENDLOOP;
      IF num.highbits >= lTemp.lowbits THEN
	BEGIN -- subtract off 2↑16*divisor and fix up count
	div: Number ← Number[num[lowbits: 0, highbits: lTemp.lowbits]];
	qq ← LongDiv[num.lc - div.lc, lTemp.lowbits]/2 + 100000B;
	count ← count - 1;
	END
      ELSE qq ← LongDiv[num.lc, lTemp.lowbits]; -- trial quotient
      qq ← BITSHIFT[qq, -count];
      lTemp.lc ← LongMult[den.lowbits, qq]; -- multiply by trial quotient
      lTemp.highbits ← lTemp.highbits + den.highbits*qq;
      UNTIL lTemp.lc <= num.lc DO
	-- decrease quotient until product is small enough
	lTemp.lc ← lTemp.lc - den.lc;
	qq ← qq - 1;
	ENDLOOP;
      quotient.lowbits ← qq;
      remainder.lc ← num.lc - lTemp.lc;
      END;
    RETURN
    END;

  DUnsignedDiv: PROCEDURE [a, b: Number] RETURNS [Number] =
    BEGIN RETURN[DUnsignedDivMod[a, b].quotient] END;

  DUnsignedMod: PROCEDURE [a, b: Number] RETURNS [r: Number] =
    BEGIN [remainder: r] ← DUnsignedDivMod[a, b]; RETURN END;


  END...