Module Make(WS: WORDSIZE).
Definition wordsize: nat := WS.wordsize.
Definition zwordsize: Z := Z.of_nat wordsize.
Definition modulus : Z := two_power_nat wordsize.
Definition half_modulus : Z := modulus / 2.
Definition max_unsigned : Z := modulus - 1.
Definition max_signed : Z := half_modulus - 1.
Definition min_signed : Z := - half_modulus.
Remark wordsize_pos: zwordsize > 0.
Remark modulus_power: modulus = two_p zwordsize.
Remark modulus_gt_one: modulus > 1.
Remark modulus_pos: modulus > 0.
Hint Resolve modulus_pos: ints.
(** * Representation of machine integers *)
(** A machine integer (type [int]) is represented as a Coq arbitrary-precision integer (type [Z]) plus a proof that it is in the range 0 (included) to [modulus] (excluded). *)
Record int: Type := mkint { intval: Z; intrange: -1 < intval < modulus }.
(** Fast normalization modulo [2^wordsize] *)
Definition Z_mod_modulus (x: Z) : Z :=
match x with
| Z0 => 0
| Zpos p => P_mod_two_p p wordsize
| Zneg p => let r := P_mod_two_p p wordsize in if zeq r 0 then 0 else modulus - r
end.
Proof (Z_mod_two_p_range wordsize).
Proof (Z_mod_two_p_eq wordsize).
(** The [unsigned] and [signed] functions return the Coq integer corresponding to the given machine integer, interpreted as unsigned or signed respectively. *)
Definition unsigned (n: int) : Z := intval n.
Definition signed (n: int) : Z :=
let x := unsigned n in
if zlt x half_modulus then x else x - modulus.
(** Conversely, [repr] takes a Coq integer and returns the corresponding machine integer.  The argument is treated modulo [modulus]. *)
Definition repr (x: Z) : int :=
mkint (Z_mod_modulus x) (Z_mod_modulus_range' x).
Definition zero := repr 0.
Definition one  := repr 1.
Definition mone := repr (-1).
Definition iwordsize := repr zwordsize.
Remark half_modulus_modulus: modulus = 2 * half_modulus.
(** Relative positions, from greatest to smallest: << max_unsigned max_signed 2*wordsize-1 wordsize 0 min_signed >> *)
Remark half_modulus_pos: half_modulus > 0.
Remark min_signed_neg: min_signed < 0.
Remark max_signed_pos: max_signed >= 0.
Remark wordsize_max_unsigned: zwordsize <= max_unsigned.
Remark two_wordsize_max_unsigned: 2 * zwordsize - 1 <= max_unsigned.
Remark max_signed_unsigned: max_signed < max_unsigned.
(** ** Modulo arithmetic *)
(** [eqm] is equality modulo $2^{wordsize}$ #2<sup>wordsize</sup>#. *)
Definition eqm := eqmod modulus.
Proof (eqmod_refl modulus).
Hint Resolve eqm_refl: ints.
Proof (eqmod_refl2 modulus).
Hint Resolve eqm_refl2: ints.
Proof (eqmod_sym modulus).
Hint Resolve eqm_sym: ints.
Proof (eqmod_trans modulus).
Hint Resolve eqm_trans: ints.
Proof (eqmod_small_eq modulus).
Hint Resolve eqm_small_eq: ints.
Proof (eqmod_add modulus).
Hint Resolve eqm_add: ints.
Proof (eqmod_neg modulus).
Hint Resolve eqm_neg: ints.
Proof (eqmod_sub modulus).
Hint Resolve eqm_sub: ints.
Proof (eqmod_mult modulus).
Hint Resolve eqm_mult: ints.
Proof (eqmod_same_bits wordsize).
Proof (same_bits_eqmod wordsize).
(** ** Properties of the coercions between [Z] and [int] *)
Hint Resolve eqm_unsigned_repr: ints.
Hint Resolve eqm_unsigned_repr_l: ints.

Lemma eqm_unsigned_repr_r:
forall a b, eqm a b -> eqm a (unsigned (repr b)).