  Modern processors deploy a variety of weak memory models, which for
efficiency reasons may execute instructions in an order different to that
specified by the program text. The consequences of instruction reordering can
be complex and subtle, and can impact on ensuring correctness. In this paper we
build on extensive work elucidating the semantics of assembler-level languages
on hardware architectures with weak memory models (specifically TSO, ARM and
POWER) and lift the principles to a straightforward operational semantics which
allows reasoning at a higher level of abstraction. To this end we introduce a
wide-spectrum language that encompasses operations on abstract data types as
well as low-level assembler code, define its operational semantics using a
novel approach to allowing reordering of instructions, and derive some
refinement laws that can be used to explain behaviours of real processors. In
this framework memory models are mostly distinguished via a pair-wise static
ordering on instruction types that determines when later instructions may be
reordered before earlier instructions. In addition, memory models may use
different types of storage systems. For instance, non-multicopy atomic systems
allow sibling processes to see updates to different variables in different
orders.
  We encode the semantics in the rewriting engine Maude as a model-checking
tool, and develop confidence in our framework by validating our semantics
against existing sets of \textit{litmus tests} -- small assembler programs --
comparing our results with those observed on hardware and in existing
semantics. We also use the tool as a prototype to model check implementations
of data structures from the literature against their abstract specifications.
