MODULE Builtins; (** AUTHOR ""; PURPOSE ""; *) (** @concept The module [[TRMRuntime]] provides run-time services implemented as procedures. The compiler \ emits procedure calls for all invocations of the runtime. **) IMPORT SYSTEM; CONST expo = 7F800000H; bias = 3F800000H; mant = 7FFFFFH; mant1 = LONGINT(0FFC00000H); mant2 = 0FFFFFFH; LimE = 0C800000H; C = 800000H; S = LONGINT(80000000H); M= LONGINT(7FFFFFFFH); VAR lastDataAddress-: ADDRESS; emptyVariable: RECORD END; (* always linked to top of used memory *) (* for testing test with intel VAR high: LONGINT; PROCEDURE SimulatedMul(l,r: LONGINT): LONGINT; VAR h: HUGEINT; BEGIN h := HUGEINT(l)*r; high := LONGINT(h DIV 100000000H); RETURN LONGINT(h MOD 100000000H); END SimulatedMul; PROCEDURE H(): LONGINT; RETURN high END H; *) PROCEDURE H(): LONGINT; CODE LDH R0 END H; (* helper functions *) PROCEDURE MSK(x,bits: LONGINT): LONGINT; BEGIN RETURN SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET,x)*SYSTEM.VAL(SET,bits)) END MSK; PROCEDURE NULLF(x: LONGINT): BOOLEAN; BEGIN RETURN SYSTEM.VAL(SET,x) * SYSTEM.VAL(SET,M) = {} END NULLF; PROCEDURE ConvertIR*(x: LONGINT): REAL; (* Float 32 bit *) VAR xe, s: LONGINT; odd,odd1: BOOLEAN; odds: LONGINT; BEGIN s := x; IF x # 0 THEN x := ABS(x); xe := 4B000000H; IF x >= 2*C THEN odd := FALSE; odd1 := FALSE; REPEAT odd1 := odd1 OR odd; odd := ODD(x); (* rounding bit *) x := ROT(MSK(x, -2),-1); (*ASH(x,-1);*) INC(xe,C); (*D.Hex(x,10); D.Ln;*) UNTIL x <2*C; (* round half to even, standard in IEEE 754 *) IF odd & (ODD(x) OR odd1) & (x<2*C) THEN INC(x) END; (* rounding *) ELSIF x < C THEN REPEAT x := x+x; xe := xe - C UNTIL x >= C END ; x := xe - C + x; IF s < 0 THEN x := x+S END END ; RETURN SYSTEM.VAL(REAL,x) END ConvertIR; PROCEDURE ConvertHR*(x: HUGEINT): REAL; BEGIN HALT(200); END ConvertHR; PROCEDURE ConvertRI*(l: REAL): LONGINT; (* Floor 32bit *) VAR x,xe, n, sign: LONGINT; BEGIN x := SYSTEM.VAL(LONGINT,l); IF ~NULLF(x) THEN sign := MSK(x, S); xe := MSK(x, expo) - bias; x := MSK(x, mant) + C; IF xe >= 0 THEN xe := ROT(xe, -23) ELSE xe := -1 END ; IF sign < 0 THEN x := -x END ; IF xe < 24 THEN n := 23 - xe; WHILE n > 0 DO x := ROT(MSK(x, -2), -1) + sign; DEC(n) END ELSIF xe >= 31 THEN x := MIN(LONGINT) ELSE n := xe - 23; WHILE n > 0 DO x := x+x; DEC(n) END END ELSE x := 0 END ; RETURN x END ConvertRI; PROCEDURE ConvertRH*(x: REAL): HUGEINT ; BEGIN HALT(200); END ConvertRH; (* 32 bit float instructions *) PROCEDURE AddR*(l,r: REAL): REAL; VAR x,y,xe, ye, xm, ym, sign: LONGINT; odd, odd1: BOOLEAN; BEGIN x := SYSTEM.VAL(LONGINT,l); y := SYSTEM.VAL(LONGINT,r); IF NULLF(x) THEN x := y ELSIF ~NULLF(y) THEN xe := MSK(x, expo) - bias; xm := MSK(x, mant) + C; ye := MSK(y, expo) - bias; ym := MSK(y, mant) + C; IF xe < ye THEN (*denorm x*) IF ye - xe > LimE THEN xm := 0; xe := ye ELSE odd1 := FALSE; odd := FALSE; REPEAT odd1 := odd1 OR odd; odd := ODD(xm); xe := xe + C; xm := ROT(MSK(xm, -2), -1) UNTIL xe = ye; (* half even rounding *) IF odd & (odd1 OR ODD(xm)) THEN INC(xm) END; END ELSIF ye < xe THEN (*denorm y*) IF xe - ye > LimE THEN ym := 0 ELSE odd := FALSE; odd1 := FALSE; REPEAT odd1 := odd1 OR odd; odd := ODD(ym); ye := ye + C; ym := ROT(MSK(ym, -2), -1) UNTIL ye = xe; (* half even rounding *) IF odd & (odd1 OR ODD(ym)) THEN INC(xm) END; END END ; IF x < 0 THEN xm := -xm END ; IF y < 0 THEN ym := -ym END ; x := xm + ym; sign := MSK(x, S); IF x # 0 THEN IF x < 0 THEN x := -x END ; IF x >= 2*C THEN odd := ODD(x); x := ROT(MSK(x, -2), -1); (* half even rounding *) IF odd & ODD(x) THEN INC(x) END; xe := xe + C ELSE (*normalize*) WHILE x < C DO x := ROT(x, -31); xe := xe - C END END ; IF xe < -bias THEN x := 0 (*underflow*) ELSIF (xe <= bias) THEN x := (x-C) + xe + bias + sign ELSE xe := M END END END ; RETURN SYSTEM.VAL(REAL,x) END AddR; PROCEDURE SubR*(l,r: REAL): REAL; BEGIN RETURN AddR(l,-r) END SubR; PROCEDURE MulR*(l,r: REAL): REAL; (* float 32 * float 32 => float 32 *) VAR x,y,xe, ye, sign: LONGINT; BEGIN x := SYSTEM.VAL(LONGINT,l); y := SYSTEM.VAL(LONGINT,r); IF NULLF(y) THEN x := 0 ELSIF ~NULLF(x) THEN sign := MSK(x, S) + MSK(y, S); xe := MSK(x, expo) - bias; x := MSK(x, mant) + C; ye := MSK(y, expo) - bias; y := MSK(y, mant) + C; xe := xe + ye; x := x * y (*testing: SimulatedMul(x,y) *); IF xe < -bias THEN x := 0 (*underflow*) ELSIF (xe <= bias) THEN x := ROT(MSK(x, mant1),-24)+ROT(H(),8); IF MSK(x, C) = 0 THEN (*normalize*) x := ROT(x, -31); xe := xe - C END; IF x < 0 THEN x := x + 1 (*round*) END; x := MSK(x, mant2) + xe + bias + sign; ELSE x := M; END ELSE x := 0; END ; RETURN SYSTEM.VAL(REAL,x) END MulR; PROCEDURE DivR*(l,r: REAL): REAL; (* float 32 / float 32 => float 32 *) VAR x,y,xe, ye, q, n, sign: LONGINT; BEGIN x := SYSTEM.VAL(LONGINT,l); y := SYSTEM.VAL(LONGINT,r); ASSERT(ABS(y) # 0,26); IF ~NULLF(x) THEN sign := MSK(x, S) + MSK(y, S); xe := MSK(x, expo) - bias; x := MSK(x, mant) + C; ye := MSK(y, expo) - bias; y := MSK(y, mant) + C; xe := xe - ye; IF x < y THEN x := ROT(x, -31); xe := xe - C END ; n := 25; q := 0; REPEAT q := ROT(q, -31); IF x >= y THEN x := x - y; INC(q) END ; x := ROT(x, -31); DEC(n) UNTIL n = 0; q := ROT(MSK(q+1, -2), -1); (*round*) IF xe < -bias THEN x := 0 (*underflow*) ELSIF (xe <= bias) THEN x := q - C + xe + bias + sign ELSE x := M; END ELSE x := 0 END ; RETURN SYSTEM.VAL(REAL,x) END DivR; PROCEDURE AbsR*(x: REAL): REAL; BEGIN IF x < 0 THEN RETURN -x ELSE RETURN x END END AbsR; PROCEDURE DivModL(dividend, divisor: LONGINT; VAR quotient, remainder: LONGINT); VAR d: LONGINT; BEGIN ASSERT(dividend >=0); ASSERT(divisor > 0); remainder := dividend; quotient := 0; d := divisor; REPEAT d := ASH(d,1) UNTIL (d > dividend) OR (d < 0); REPEAT d := LSH(d,-1); quotient := ASH(quotient,1); IF remainder >= d THEN remainder := remainder - d; quotient := quotient+1 END UNTIL d = divisor; END DivModL; (* 32 bit integer instructions *) PROCEDURE DivL*(l,r: LONGINT): LONGINT; VAR quotient, remainder: LONGINT; BEGIN IF l < 0 THEN DivModL(-l,r,quotient,remainder); RETURN -quotient-1; ELSE DivModL(l,r,quotient,remainder); RETURN quotient END; END DivL; PROCEDURE ModL*(l,r: LONGINT): LONGINT; VAR quotient, remainder: LONGINT; BEGIN IF l < 0 THEN DivModL(-l,r,quotient,remainder); RETURN r - remainder; ELSE DivModL(l,r,quotient,remainder); RETURN remainder END; END ModL; (* 64 bit integer instructions *) PROCEDURE DivH*(l,r: HUGEINT): HUGEINT ; BEGIN HALT(200); END DivH; PROCEDURE ModH*(l,r: HUGEINT): HUGEINT ; BEGIN HALT(200); END ModH; PROCEDURE AbsH*(x: HUGEINT): HUGEINT; BEGIN IF x < 0 THEN RETURN -x ELSE RETURN x END; END AbsH; PROCEDURE AslH*(l,r: HUGEINT): HUGEINT ; BEGIN HALT(200); END AslH; PROCEDURE LslH*(l,r: HUGEINT): HUGEINT ; BEGIN HALT(200); END LslH; PROCEDURE AsrH*(l,r: HUGEINT): HUGEINT; BEGIN HALT(200); END AsrH; PROCEDURE LsrH*(l,r: HUGEINT): HUGEINT ; BEGIN HALT(200); END LsrH; PROCEDURE RorH*(l,r: HUGEINT): HUGEINT; BEGIN HALT(200); END RorH; PROCEDURE RolH*(l,r: HUGEINT): HUGEINT; BEGIN HALT(200); END RolH; (* currently unused 64 bit float support (* conversions such as ENTIER, SHORT or implicit *) PROCEDURE ConvertXR*(x: LONGREAL): REAL; BEGIN HALT(200); END ConvertXR; PROCEDURE ConvertRX*(x: REAL): LONGREAL ; BEGIN HALT(200); END ConvertRX; PROCEDURE ConvertIX*(x: LONGINT): LONGREAL; VAR xe: LONGINT; h: HUGEINT; CONST B = 1023; C=10000000000000H; BEGIN IF x # 0 THEN h := ABS(x); xe := 52; IF h >= 2*C THEN REPEAT h := h DIV 2; INC(xe) UNTIL h < 2*C ELSIF h < C THEN REPEAT h := 2*h; DEC(xe) UNTIL h >= C END ; h := (xe + B -1)*C + h; IF x < 0 THEN h := -h END END ; RETURN SYSTEM.VAL(LONGREAL,h) END ConvertIX; PROCEDURE ConvertXI*(x: LONGREAL): LONGINT ; BEGIN HALT(200); END ConvertXI; PROCEDURE ConvertXH*(x: LONGREAL): HUGEINT ; BEGIN HALT(200); END ConvertXH; (* 64 bit float instructions *) PROCEDURE AddX*(l,r: LONGREAL): LONGREAL ; BEGIN HALT(200); END AddX; PROCEDURE SubX*(l,r: LONGREAL): LONGREAL ; BEGIN HALT(200); END SubX; PROCEDURE MulX*(l,r: LONGREAL): LONGREAL; BEGIN HALT(200); END MulX; PROCEDURE DivX*(l,r: LONGREAL): LONGREAL; BEGIN HALT(200); END DivX; PROCEDURE AbsX*(x: LONGREAL): LONGREAL; BEGIN IF x < 0 THEN RETURN -x ELSE RETURN x END END AbsX; PROCEDURE ConvertHX*(x: HUGEINT): LONGREAL; BEGIN HALT(200); END ConvertHX; *) (* compare strings, returns 0 if strings are equal, returns +1 if left is lexicographic greater than right, returns -1 if left is lexicographics smaller than right traps if src or destination is not 0X terminated and comparison is not finished *) PROCEDURE CompareString*(CONST left,right: ARRAY OF CHAR): SHORTINT; VAR i: LONGINT; res: SHORTINT; l,r: CHAR; BEGIN i := 0; res := 0; LOOP l := left[i]; (* index check included *) r := right[i]; (* index check included *) IF (l > r) THEN res := 1; EXIT ELSIF (l