<* M2EXTENSIONS + *>

DEFINITION MODULE (*["C"]*) Arith64;

    (* Use the "C" specification iff Arith64.obj has been produced by   *)
    (* a C compiler.  At present this option is not working, because    *)
    (* the linker can't find the functions in Arith64.obj.  But maybe   *)
    (* that's because I forgot to specify "extern" for those functions. *)

        (********************************************************)
        (*                                                      *)
        (*            Support for 64-bit integers               *)
        (*                                                      *)
        (*  Programmer:         P. Moylan                       *)
        (*  Started:            17 October 2001                 *)
        (*  Last edited:        4 June 2024                     *)
        (*  Status:             OK                              *)
        (*                                                      *)
        (********************************************************)


FROM SYSTEM IMPORT CARD32, INT32;

(* Big-endian procedures have now been moved to module Arith64BE.    *)

TYPE
    CARD64LE =  RECORD
                    low, high: CARD32;
                END (*RECORD*);

    CARD64 = CARD64LE;

    CARD64API = CARD64LE;

    INT64LE =   RECORD
                    low: CARD32;
                    high: INT32;
                END (*RECORD*);

    INT64 = INT64LE;

CONST
    Zero64LE = CARD64LE{0, 0};
    Max64LE = CARD64LE{MAX(CARDINAL), MAX(CARDINAL)};
    Zero64 = CARD64{0, 0};
    Max64 = CARD64{MAX(CARDINAL), MAX(CARDINAL)};



PROCEDURE ToAPI64 (val: CARD64): CARD64API;

    (* Converts a CARD64 value to a CARD64API value. *)

PROCEDURE FromAPI64 (val: CARD64API): CARD64;

    (* Converts a CARD64API value to a CARD64 value. *)

PROCEDURE IsZeroLE (val: CARD64LE): BOOLEAN;

    (* Returns TRUE iff val = 0 *)

PROCEDURE ABS64 (A: INT64LE): CARD64LE;

    (* Absolute value.  *)

PROCEDURE Compare64LE (A, B: CARD64LE): INTEGER;

    (* Returns >0 if A>B, =0 if A=B, <0 if A<B.  *)

PROCEDURE Add64LE (VAR (*INOUT*) A: CARD64LE;  B: CARDINAL);

    (* Computes  A := A + B.  This differs from Sum64 (below) in the    *)
    (* type of B, and in the way the result is returned.                *)

PROCEDURE Sub64LE (VAR (*INOUT*) A: CARD64LE;  B: CARDINAL);

    (* Computes  A := A - B.  This differs from Diff64 (below) in the   *)
    (* type of B, and in the way the result is returned.                *)

PROCEDURE INC64LE (VAR (*INOUT*) A: CARD64LE);

    (* Increments A by 1.  *)

PROCEDURE DEC64LE (VAR (*INOUT*) A: CARD64LE);

    (* Decrements A by 1.  *)

PROCEDURE ShortSubLE (A, B: CARD64LE): CARDINAL;

    (* Returns A-B as a CARDINAL value, or MAX(CARDINAL) in the case of *)
    (* overflow.                                                        *)

PROCEDURE Sum64LE (A, B: CARD64LE): CARD64LE;

    (* Returns A+B. *)

PROCEDURE Diff64LE (A, B: CARD64LE): INT64LE;

    (* Returns A-B. *)

PROCEDURE Mul32LE (A, B: CARDINAL): CARD64LE;

    (* Returns A*B. *)

PROCEDURE Mul64LE (A, B: CARD64LE): CARD64LE;

    (* Returns A*B. *)

PROCEDURE ShortMul64LE (A: CARD64LE;  B: CARDINAL): CARD64LE;

    (* Returns A*B, for the case where the second operand is a CARDINAL. *)

PROCEDURE LongDiv64LE (A: CARD64LE;  B: CARDINAL;  VAR (*OUT*) quotient: CARD64LE;
                                  VAR (*OUT*) remainder: CARDINAL);

    (* Divides A by B, returns quotient and remainder. *)

PROCEDURE ShortDivLE (A: CARD64LE;  B: CARDINAL): CARDINAL;

    (* Returns A DIV B as a CARDINAL value, or MAX(CARDINAL) if the     *)
    (* result overflows.                                                *)

PROCEDURE ShortModLE (A: CARD64LE;  B: CARDINAL): CARDINAL;

    (* Returns A MOD B as a CARDINAL value.  *)

PROCEDURE Div10LE (number: CARD64LE;  VAR (*OUT*) quotient: CARD64LE;
                                  VAR (*OUT*) remainder: CARDINAL);

    (* Divides number by 10, returns quotient and remainder. *)

PROCEDURE RS64LE (VAR (*INOUT*) number: CARD64LE;  N: CARDINAL;
                                         VAR (*OUT*) remainder: CARDINAL);

    (* Right shift by N bits, i.e. division by 2^N, with remainder      *)
    (* holding the lost bits.  N must be in range [0..32].              *)

PROCEDURE FLOAT64LE (number: CARD64LE): REAL;

    (* Converts CARD64 to REAL. *)

PROCEDURE ORDL (number: INT64): CARDINAL;

    (* Converts INT64 to CARDINAL. *)

END Arith64.

