MODULE; (* TInt but with specified precision, in bytes *) IMPORT Fmt, TInt, Word, Target; FROM Target IMPORT Int; CONST Mask = 16_FF; SignMask = 16_80; PROCEDURE TIntN Init () = BEGIN TargetIntegerMin := T{x := Target.Integer.min}; TargetIntegerMax := T{x := Target.Integer.max}; END Init; PROCEDURESignExtend (VAR a: Int; n: CARDINAL) =
sign extend from n to the precision of Int
VAR extend := 0; BEGIN IF Word.And(a[n - 1], SignMask) # 0 THEN extend := Mask; END; FOR i := n TO LAST(a) DO a[i] := extend; END; END SignExtend; PROCEDURESignedTruncate (VAR a: Int; n: CARDINAL): BOOLEAN =
truncate to n bytes return FALSE if the value did not previously fit
VAR result := TRUE; extend := 0; BEGIN <* ASSERT n # 0 *> <* ASSERT n <= NUMBER(a) *> IF Word.And(a[LAST(a)], SignMask) # 0 THEN extend := Mask; END; FOR i := n TO LAST(a) DO IF a[i] # extend THEN result := FALSE; a[i] := extend; END; END; RETURN result; END SignedTruncate; PROCEDUREZeroExtend (VAR a: Int; n: CARDINAL) =
zero extend from n bytes to the precision of Int
BEGIN <*ASSERT n # 0*> FOR i := n TO LAST(a) DO a[i] := 0; END; END ZeroExtend; PROCEDUREUnsignedTruncate (VAR a: Int; n: CARDINAL): BOOLEAN =
truncate to n bytes return FALSE if the value did not previously fit
VAR result := TRUE; BEGIN <*ASSERT n # 0*> FOR i := n TO LAST(a) DO IF a[i] # 0 THEN result := FALSE; a[i] := 0; END; END; RETURN result; END UnsignedTruncate; PROCEDUREToInt (READONLY a: T): Int = VAR b: Int; BEGIN b := a.x; SignExtend(b, a.n); RETURN b; END ToInt; PROCEDUREFromInt (VAR a: T; n: CARDINAL): BOOLEAN = BEGIN <* ASSERT n # 0 *> <* ASSERT n <= NUMBER(Int) *> a.n := n; RETURN SignedTruncate(a.x, n); END FromInt; PROCEDUREFromHostInteger (x: INTEGER; n: CARDINAL; VAR r: T): BOOLEAN = BEGIN RETURN TInt.FromInt(x, r.x) AND FromInt(r, n); END FromHostInteger; PROCEDUREToHostInteger (READONLY r: T; VAR x: INTEGER): BOOLEAN = VAR i := r; BEGIN i.n := BYTESIZE(INTEGER); RETURN TInt.ToInt(ToInt(i), x); END ToHostInteger; PROCEDUREAdd (READONLY a, b: T; VAR r: T): BOOLEAN = BEGIN RETURN TInt.Add(ToInt(a), ToInt(b), r.x) AND FromInt(r, MIN(a.n, b.n)); END Add; PROCEDURESubtract (READONLY a, b: T; VAR r: T): BOOLEAN = BEGIN RETURN TInt.Subtract(ToInt(a), ToInt(b), r.x) AND FromInt(r, MIN(a.n, b.n)); END Subtract; PROCEDURENegate (READONLY a: T; VAR r: T): BOOLEAN = BEGIN RETURN Subtract(Zero, a, r); END Negate; PROCEDUREAbs (READONLY a: T; VAR r: T): BOOLEAN = BEGIN IF GE(a, Zero) THEN r := a; RETURN TRUE; END; RETURN Negate(a, r); END Abs; PROCEDUREMultiply (READONLY a, b: T; VAR r: T): BOOLEAN = BEGIN RETURN TInt.Multiply(ToInt(a), ToInt(b), r.x) AND FromInt(r, MIN(a.n, b.n)); END Multiply; PROCEDUREDiv (READONLY num, den: T; VAR q: T): BOOLEAN = BEGIN RETURN TInt.Div(ToInt(num), ToInt(den), q.x) AND FromInt(q, MIN(num.n, den.n)); END Div; PROCEDUREMod (READONLY num, den: T; VAR r: T): BOOLEAN = BEGIN RETURN TInt.Mod(ToInt(num), ToInt(den), r.x) AND FromInt(r, MIN(num.n, den.n)); END Mod; PROCEDUREEQ (READONLY a, b: T): BOOLEAN = BEGIN RETURN TInt.EQ(ToInt(a), ToInt(b)); END EQ; PROCEDURELT (READONLY a, b: T): BOOLEAN = BEGIN RETURN TInt.LT(ToInt(a), ToInt(b)); END LT; PROCEDURELE (READONLY a, b: T): BOOLEAN = BEGIN RETURN TInt.LE(ToInt(a), ToInt(b)); END LE; PROCEDURENE (READONLY a, b: T): BOOLEAN = BEGIN RETURN TInt.NE(ToInt(a), ToInt(b)); END NE; PROCEDUREGT (READONLY a, b: T): BOOLEAN = BEGIN RETURN TInt.GT(ToInt(a), ToInt(b)); END GT; PROCEDUREGE (READONLY a, b: T): BOOLEAN = BEGIN RETURN TInt.GE(ToInt(a), ToInt(b)); END GE; PROCEDUREToText (READONLY r: T): TEXT = BEGIN RETURN TInt.ToText(ToInt(r)); END ToText; PROCEDUREToChars (READONLY r: T; VAR buf: ARRAY OF CHAR): INTEGER = BEGIN RETURN TInt.ToChars(ToInt(r), buf); END ToChars; PROCEDUREFromTargetInt (READONLY i: Int; byteSize: CARDINAL): T = BEGIN RETURN T{n := byteSize, x := i}; END FromTargetInt; PROCEDUREToDiagnosticText (a: T): TEXT = BEGIN RETURN "n:" & Fmt.Unsigned(a.n) & ",x:" & TargetIntToDiagnosticText(a.x); END ToDiagnosticText; PROCEDURETargetIntToDiagnosticText (a: Int): TEXT = VAR t := ""; BEGIN FOR i := FIRST(a) TO LAST(a) DO t := t & Fmt.Unsigned(a[i]); IF i # LAST(a) THEN t := t & ","; END; END; RETURN t; END TargetIntToDiagnosticText; BEGIN END TIntN.