| /* |
| * Constants for memory operations |
| * |
| * Authors: |
| * Richard Henderson <rth@twiddle.net> |
| * |
| * This work is licensed under the terms of the GNU GPL, version 2 or later. |
| * See the COPYING file in the top-level directory. |
| * |
| */ |
| |
| #ifndef MEMOP_H |
| #define MEMOP_H |
| |
| #include "qemu/host-utils.h" |
| |
| typedef enum MemOp { |
| MO_8 = 0, |
| MO_16 = 1, |
| MO_32 = 2, |
| MO_64 = 3, |
| MO_SIZE = 3, /* Mask for the above. */ |
| |
| MO_SIGN = 4, /* Sign-extended, otherwise zero-extended. */ |
| |
| MO_BSWAP = 8, /* Host reverse endian. */ |
| #ifdef HOST_WORDS_BIGENDIAN |
| MO_LE = MO_BSWAP, |
| MO_BE = 0, |
| #else |
| MO_LE = 0, |
| MO_BE = MO_BSWAP, |
| #endif |
| #ifdef NEED_CPU_H |
| #ifdef TARGET_WORDS_BIGENDIAN |
| MO_TE = MO_BE, |
| #else |
| MO_TE = MO_LE, |
| #endif |
| #endif |
| |
| /* |
| * MO_UNALN accesses are never checked for alignment. |
| * MO_ALIGN accesses will result in a call to the CPU's |
| * do_unaligned_access hook if the guest address is not aligned. |
| * The default depends on whether the target CPU defines |
| * TARGET_ALIGNED_ONLY. |
| * |
| * Some architectures (e.g. ARMv8) need the address which is aligned |
| * to a size more than the size of the memory access. |
| * Some architectures (e.g. SPARCv9) need an address which is aligned, |
| * but less strictly than the natural alignment. |
| * |
| * MO_ALIGN supposes the alignment size is the size of a memory access. |
| * |
| * There are three options: |
| * - unaligned access permitted (MO_UNALN). |
| * - an alignment to the size of an access (MO_ALIGN); |
| * - an alignment to a specified size, which may be more or less than |
| * the access size (MO_ALIGN_x where 'x' is a size in bytes); |
| */ |
| MO_ASHIFT = 4, |
| MO_AMASK = 7 << MO_ASHIFT, |
| #ifdef NEED_CPU_H |
| #ifdef TARGET_ALIGNED_ONLY |
| MO_ALIGN = 0, |
| MO_UNALN = MO_AMASK, |
| #else |
| MO_ALIGN = MO_AMASK, |
| MO_UNALN = 0, |
| #endif |
| #endif |
| MO_ALIGN_2 = 1 << MO_ASHIFT, |
| MO_ALIGN_4 = 2 << MO_ASHIFT, |
| MO_ALIGN_8 = 3 << MO_ASHIFT, |
| MO_ALIGN_16 = 4 << MO_ASHIFT, |
| MO_ALIGN_32 = 5 << MO_ASHIFT, |
| MO_ALIGN_64 = 6 << MO_ASHIFT, |
| |
| /* Combinations of the above, for ease of use. */ |
| MO_UB = MO_8, |
| MO_UW = MO_16, |
| MO_UL = MO_32, |
| MO_SB = MO_SIGN | MO_8, |
| MO_SW = MO_SIGN | MO_16, |
| MO_SL = MO_SIGN | MO_32, |
| MO_Q = MO_64, |
| |
| MO_LEUW = MO_LE | MO_UW, |
| MO_LEUL = MO_LE | MO_UL, |
| MO_LESW = MO_LE | MO_SW, |
| MO_LESL = MO_LE | MO_SL, |
| MO_LEQ = MO_LE | MO_Q, |
| |
| MO_BEUW = MO_BE | MO_UW, |
| MO_BEUL = MO_BE | MO_UL, |
| MO_BESW = MO_BE | MO_SW, |
| MO_BESL = MO_BE | MO_SL, |
| MO_BEQ = MO_BE | MO_Q, |
| |
| #ifdef NEED_CPU_H |
| MO_TEUW = MO_TE | MO_UW, |
| MO_TEUL = MO_TE | MO_UL, |
| MO_TESW = MO_TE | MO_SW, |
| MO_TESL = MO_TE | MO_SL, |
| MO_TEQ = MO_TE | MO_Q, |
| #endif |
| |
| MO_SSIZE = MO_SIZE | MO_SIGN, |
| } MemOp; |
| |
| /* MemOp to size in bytes. */ |
| static inline unsigned memop_size(MemOp op) |
| { |
| return 1 << (op & MO_SIZE); |
| } |
| |
| /* Size in bytes to MemOp. */ |
| static inline MemOp size_memop(unsigned size) |
| { |
| #ifdef CONFIG_DEBUG_TCG |
| /* Power of 2 up to 8. */ |
| assert((size & (size - 1)) == 0 && size >= 1 && size <= 8); |
| #endif |
| return ctz32(size); |
| } |
| |
| /* Big endianness from MemOp. */ |
| static inline bool memop_big_endian(MemOp op) |
| { |
| return (op & MO_BSWAP) == MO_BE; |
| } |
| |
| #endif |