Module Type MEM.
(** The abstract type of memory states. *)
Parameter mem: Type.
(** * Operations on memory states *)
(** [empty] is the initial memory state. *)
Parameter empty: mem.
(** [alloc m lo hi] allocates a fresh block of size [hi - lo] bytes. Valid offsets in this block are between [lo] included and [hi] excluded. These offsets are writable in the returned memory state. This block is not initialized: its contents are initially undefined. Returns a pair [(m', b)] of the updated memory state [m'] and the identifier [b] of the newly-allocated block. Note that [alloc] never fails: we are modeling an infinite memory. *)
Parameter alloc: forall (m: mem) (lo hi: Z), mem * block.
(** [free m b lo hi] frees (deallocates) the range of offsets from [lo] included to [hi] excluded in block [b].  Returns the updated memory state, or [None] if the freed addresses are not freeable. *)
Parameter free: forall (m: mem) (b: block) (lo hi: Z), option mem.
(** [load chunk m b ofs] reads a memory quantity [chunk] from addresses [b, ofs] to [b, ofs + size_chunk chunk - 1] in memory state [m].  Returns the value read, or [None] if the accessed addresses are not readable. *)
Parameter load: forall (chunk: memory_chunk) (m: mem) (b: block) (ofs: Z), option val.
(** [store chunk m b ofs v] writes value [v] as memory quantity [chunk] from addresses [b, ofs] to [b, ofs + size_chunk chunk - 1] in memory state [m].  Returns the updated memory state, or [None] if the accessed addresses are not writable. *)
Parameter store: forall (chunk: memory_chunk) (m: mem) (b: block) (ofs: Z) (v: val), option mem.
(** [loadv] and [storev] are variants of [load] and [store] where the address being accessed is passed as a value (of the [Vptr] kind). *)
Definition loadv (chunk: memory_chunk) (m: mem) (addr: val) : option val :=
match addr with
| Vptr b ofs => load chunk m b (Ptrofs.unsigned ofs)
| _ => None
end.
Definition storev (chunk: memory_chunk) (m: mem) (addr v: val) : option mem :=
match addr with
| Vptr b ofs => store chunk m b (Ptrofs.unsigned ofs) v
| _ => None
end.
(** [loadbytes m b ofs n] reads and returns the byte-level representation of the values contained at offsets [ofs] to [ofs + n - 1] within block [b] in memory state [m]. [None] is returned if the accessed addresses are not readable. *)
Parameter loadbytes: forall (m: mem) (b: block) (ofs n: Z), option (list memval).
(** [storebytes m b ofs bytes] stores the given list of bytes [bytes] starting at location [(b, ofs)].  Returns updated memory state or [None] if the accessed locations are not writable. *)
Parameter storebytes: forall (m: mem) (b: block) (ofs: Z) (bytes: list memval), option mem.
(** [free_list] frees all the given (block, lo, hi) triples. *)
Fixpoint free_list (m: mem) (l: list (block * Z * Z)) {struct l}: option mem :=
match l with
| nil => Some m
| (b, lo, hi) :: l' =>
match free m b lo hi with
| None => None
| Some m' => free_list m' l'
end
end.
(** [drop_perm m b lo hi p] sets the permissions of the byte range [(b, lo) ... (b, hi - 1)] to [p].  These bytes must have [Freeable] permissions in the initial memory state [m]. Returns updated memory state, or [None] if insufficient permissions. *)
Parameter drop_perm: forall (m: mem) (b: block) (lo hi: Z) (p: permission), option mem.
(** * Permissions, block validity, access validity, and bounds *)
(** The next block of a memory state is the block identifier for the next allocation.  It increases by one at each allocation. Block identifiers below [nextblock] are said to be valid, meaning that they have been allocated previously.  Block identifiers above [nextblock] are fresh or invalid, i.e. not yet allocated.  Note that a block identifier remains valid after a [free] operation over this block. *)
Parameter nextblock: mem -> block.
Definition valid_block (m: mem) (b: block) := Plt b (nextblock m).

Axiom valid_not_valid_diff:
forall m b b', valid_block m b -> ~(valid_block m b') -> b <> b'.