| /* cpustate.h -- Prototypes for AArch64 cpu state functions. |
| |
| Copyright (C) 2015-2021 Free Software Foundation, Inc. |
| |
| Contributed by Red Hat. |
| |
| This file is part of GDB. |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
| |
| #ifndef _CPU_STATE_H |
| #define _CPU_STATE_H |
| |
| #include <sys/types.h> |
| #include <stdint.h> |
| #include <inttypes.h> |
| |
| #include "sim/sim.h" |
| |
| /* Symbolic names used to identify general registers which also match |
| the registers indices in machine code. |
| |
| We have 32 general registers which can be read/written as 32 bit or |
| 64 bit sources/sinks and are appropriately referred to as Wn or Xn |
| in the assembly code. Some instructions mix these access modes |
| (e.g. ADD X0, X1, W2) so the implementation of the instruction |
| needs to *know* which type of read or write access is required. */ |
| typedef enum GReg |
| { |
| R0, |
| R1, |
| R2, |
| R3, |
| R4, |
| R5, |
| R6, |
| R7, |
| R8, |
| R9, |
| R10, |
| R11, |
| R12, |
| R13, |
| R14, |
| R15, |
| R16, |
| R17, |
| R18, |
| R19, |
| R20, |
| R21, |
| R22, |
| R23, |
| R24, |
| R25, |
| R26, |
| R27, |
| R28, |
| R29, |
| R30, |
| R31, |
| FP = R29, |
| LR = R30, |
| SP = R31, |
| ZR = R31 |
| } GReg; |
| |
| /* Symbolic names used to refer to floating point registers which also |
| match the registers indices in machine code. |
| |
| We have 32 FP registers which can be read/written as 8, 16, 32, 64 |
| and 128 bit sources/sinks and are appropriately referred to as Bn, |
| Hn, Sn, Dn and Qn in the assembly code. Some instructions mix these |
| access modes (e.g. FCVT S0, D0) so the implementation of the |
| instruction needs to *know* which type of read or write access is |
| required. */ |
| |
| typedef enum VReg |
| { |
| V0, |
| V1, |
| V2, |
| V3, |
| V4, |
| V5, |
| V6, |
| V7, |
| V8, |
| V9, |
| V10, |
| V11, |
| V12, |
| V13, |
| V14, |
| V15, |
| V16, |
| V17, |
| V18, |
| V19, |
| V20, |
| V21, |
| V22, |
| V23, |
| V24, |
| V25, |
| V26, |
| V27, |
| V28, |
| V29, |
| V30, |
| V31, |
| } VReg; |
| |
| /* All the different integer bit patterns for the components of a |
| general register are overlaid here using a union so as to allow |
| all reading and writing of the desired bits. Note that we have |
| to take care when emulating a big-endian AArch64 as we are |
| running on a little endian host. */ |
| |
| typedef union GRegisterValue |
| { |
| #if !WORDS_BIGENDIAN |
| int8_t s8; |
| int16_t s16; |
| int32_t s32; |
| int64_t s64; |
| uint8_t u8; |
| uint16_t u16; |
| uint32_t u32; |
| uint64_t u64; |
| #else |
| struct { int64_t :56; int8_t s8; }; |
| struct { int64_t :48; int16_t s16; }; |
| struct { int64_t :32; int32_t s32; }; |
| int64_t s64; |
| struct { uint64_t :56; uint8_t u8; }; |
| struct { uint64_t :48; uint16_t u16; }; |
| struct { uint64_t :32; uint32_t u32; }; |
| uint64_t u64; |
| #endif |
| } GRegister; |
| |
| /* Float registers provide for storage of a single, double or quad |
| word format float in the same register. Single floats are not |
| paired within each double register as per 32 bit arm. Instead each |
| 128 bit register Vn embeds the bits for Sn, and Dn in the lower |
| quarter and half, respectively, of the bits for Qn. |
| |
| The upper bits can also be accessed as single or double floats by |
| the float vector operations using indexing e.g. V1.D[1], V1.S[3] |
| etc and, for SIMD operations using a horrible index range notation. |
| |
| The spec also talks about accessing float registers as half words |
| and bytes with Hn and Bn providing access to the low 16 and 8 bits |
| of Vn but it is not really clear what these bits represent. We can |
| probably ignore this for Java anyway. However, we do need to access |
| the raw bits at 32 and 64 bit resolution to load to/from integer |
| registers. |
| |
| Note - we do not use the long double type. Aliasing issues between |
| integer and float values mean that it is unreliable to use them. */ |
| |
| typedef union FRegisterValue |
| { |
| float s; |
| double d; |
| |
| uint64_t v[2]; |
| uint32_t w[4]; |
| uint16_t h[8]; |
| uint8_t b[16]; |
| |
| int64_t V[2]; |
| int32_t W[4]; |
| int16_t H[8]; |
| int8_t B[16]; |
| |
| float S[4]; |
| double D[2]; |
| |
| } FRegister; |
| |
| /* Condition register bit select values. |
| |
| The order of bits here is important because some of |
| the flag setting conditional instructions employ a |
| bit field to populate the flags when a false condition |
| bypasses execution of the operation and we want to |
| be able to assign the flags register using the |
| supplied value. */ |
| |
| typedef enum FlagIdx |
| { |
| V_IDX = 0, |
| C_IDX = 1, |
| Z_IDX = 2, |
| N_IDX = 3 |
| } FlagIdx; |
| |
| typedef enum FlagMask |
| { |
| V = 1 << V_IDX, |
| C = 1 << C_IDX, |
| Z = 1 << Z_IDX, |
| N = 1 << N_IDX |
| } FlagMask; |
| |
| #define CPSR_ALL_FLAGS (V | C | Z | N) |
| |
| typedef uint32_t FlagsRegister; |
| |
| /* FPSR register -- floating point status register |
| |
| This register includes IDC, IXC, UFC, OFC, DZC, IOC and QC bits, |
| and the floating point N, Z, C, V bits but the latter are unused in |
| aarch64 mode. The sim ignores QC for now. |
| |
| Bit positions are as per the ARMv7 FPSCR register |
| |
| IDC : 7 ==> Input Denormal (cumulative exception bit) |
| IXC : 4 ==> Inexact |
| UFC : 3 ==> Underflow |
| OFC : 2 ==> Overflow |
| DZC : 1 ==> Division by Zero |
| IOC : 0 ==> Invalid Operation |
| |
| The rounding mode is held in bits [23,22] defined as follows: |
| |
| 0b00 Round to Nearest (RN) mode |
| 0b01 Round towards Plus Infinity (RP) mode |
| 0b10 Round towards Minus Infinity (RM) mode |
| 0b11 Round towards Zero (RZ) mode. */ |
| |
| /* Indices for bits in the FPSR register value. */ |
| typedef enum FPSRIdx |
| { |
| IO_IDX = 0, |
| DZ_IDX = 1, |
| OF_IDX = 2, |
| UF_IDX = 3, |
| IX_IDX = 4, |
| ID_IDX = 7 |
| } FPSRIdx; |
| |
| /* Corresponding bits as numeric values. */ |
| typedef enum FPSRMask |
| { |
| IO = (1 << IO_IDX), |
| DZ = (1 << DZ_IDX), |
| OF = (1 << OF_IDX), |
| UF = (1 << UF_IDX), |
| IX = (1 << IX_IDX), |
| ID = (1 << ID_IDX) |
| } FPSRMask; |
| |
| #define FPSR_ALL_FPSRS (IO | DZ | OF | UF | IX | ID) |
| |
| /* General Register access functions. */ |
| extern uint64_t aarch64_get_reg_u64 (sim_cpu *, GReg, int); |
| extern int64_t aarch64_get_reg_s64 (sim_cpu *, GReg, int); |
| extern uint32_t aarch64_get_reg_u32 (sim_cpu *, GReg, int); |
| extern int32_t aarch64_get_reg_s32 (sim_cpu *, GReg, int); |
| extern uint32_t aarch64_get_reg_u16 (sim_cpu *, GReg, int); |
| extern int32_t aarch64_get_reg_s16 (sim_cpu *, GReg, int); |
| extern uint32_t aarch64_get_reg_u8 (sim_cpu *, GReg, int); |
| extern int32_t aarch64_get_reg_s8 (sim_cpu *, GReg, int); |
| |
| extern void aarch64_set_reg_u64 (sim_cpu *, GReg, int, uint64_t); |
| extern void aarch64_set_reg_u32 (sim_cpu *, GReg, int, uint32_t); |
| extern void aarch64_set_reg_s64 (sim_cpu *, GReg, int, int64_t); |
| extern void aarch64_set_reg_s32 (sim_cpu *, GReg, int, int32_t); |
| |
| /* FP Register access functions. */ |
| extern float aarch64_get_FP_half (sim_cpu *, VReg); |
| extern float aarch64_get_FP_float (sim_cpu *, VReg); |
| extern double aarch64_get_FP_double (sim_cpu *, VReg); |
| extern void aarch64_get_FP_long_double (sim_cpu *, VReg, FRegister *); |
| |
| extern void aarch64_set_FP_half (sim_cpu *, VReg, float); |
| extern void aarch64_set_FP_float (sim_cpu *, VReg, float); |
| extern void aarch64_set_FP_double (sim_cpu *, VReg, double); |
| extern void aarch64_set_FP_long_double (sim_cpu *, VReg, FRegister); |
| |
| /* PC register accessors. */ |
| extern uint64_t aarch64_get_PC (sim_cpu *); |
| extern uint64_t aarch64_get_next_PC (sim_cpu *); |
| extern void aarch64_set_next_PC (sim_cpu *, uint64_t); |
| extern void aarch64_set_next_PC_by_offset (sim_cpu *, int64_t); |
| extern void aarch64_update_PC (sim_cpu *); |
| extern void aarch64_save_LR (sim_cpu *); |
| |
| /* Instruction accessor - implemented as a |
| macro as we do not need to annotate it. */ |
| #define aarch64_get_instr(cpu) ((cpu)->instr) |
| |
| /* Flag register accessors. */ |
| extern uint32_t aarch64_get_CPSR (sim_cpu *); |
| extern void aarch64_set_CPSR (sim_cpu *, uint32_t); |
| extern uint32_t aarch64_get_CPSR_bits (sim_cpu *, uint32_t); |
| extern void aarch64_set_CPSR_bits (sim_cpu *, uint32_t, uint32_t); |
| extern uint32_t aarch64_test_CPSR_bit (sim_cpu *, FlagMask); |
| extern void aarch64_set_CPSR_bit (sim_cpu *, FlagMask); |
| extern void aarch64_clear_CPSR_bit (sim_cpu *, FlagMask); |
| |
| extern void aarch64_set_FPSR (sim_cpu *, uint32_t); |
| extern uint32_t aarch64_get_FPSR (sim_cpu *); |
| extern void aarch64_set_FPSR_bits (sim_cpu *, uint32_t, uint32_t); |
| extern uint32_t aarch64_get_FPSR_bits (sim_cpu *, uint32_t); |
| extern int aarch64_test_FPSR_bit (sim_cpu *, FPSRMask); |
| |
| /* Vector register accessors. */ |
| extern uint64_t aarch64_get_vec_u64 (sim_cpu *, VReg, unsigned); |
| extern uint32_t aarch64_get_vec_u32 (sim_cpu *, VReg, unsigned); |
| extern uint16_t aarch64_get_vec_u16 (sim_cpu *, VReg, unsigned); |
| extern uint8_t aarch64_get_vec_u8 (sim_cpu *, VReg, unsigned); |
| extern void aarch64_set_vec_u64 (sim_cpu *, VReg, unsigned, uint64_t); |
| extern void aarch64_set_vec_u32 (sim_cpu *, VReg, unsigned, uint32_t); |
| extern void aarch64_set_vec_u16 (sim_cpu *, VReg, unsigned, uint16_t); |
| extern void aarch64_set_vec_u8 (sim_cpu *, VReg, unsigned, uint8_t); |
| |
| extern int64_t aarch64_get_vec_s64 (sim_cpu *, VReg, unsigned); |
| extern int32_t aarch64_get_vec_s32 (sim_cpu *, VReg, unsigned); |
| extern int16_t aarch64_get_vec_s16 (sim_cpu *, VReg, unsigned); |
| extern int8_t aarch64_get_vec_s8 (sim_cpu *, VReg, unsigned); |
| extern void aarch64_set_vec_s64 (sim_cpu *, VReg, unsigned, int64_t); |
| extern void aarch64_set_vec_s32 (sim_cpu *, VReg, unsigned, int32_t); |
| extern void aarch64_set_vec_s16 (sim_cpu *, VReg, unsigned, int16_t); |
| extern void aarch64_set_vec_s8 (sim_cpu *, VReg, unsigned, int8_t); |
| |
| extern float aarch64_get_vec_float (sim_cpu *, VReg, unsigned); |
| extern double aarch64_get_vec_double (sim_cpu *, VReg, unsigned); |
| extern void aarch64_set_vec_float (sim_cpu *, VReg, unsigned, float); |
| extern void aarch64_set_vec_double (sim_cpu *, VReg, unsigned, double); |
| |
| /* System register accessors. */ |
| extern uint64_t aarch64_get_thread_id (sim_cpu *); |
| extern uint32_t aarch64_get_FPCR (sim_cpu *); |
| extern void aarch64_set_FPCR (sim_cpu *, uint32_t); |
| |
| #endif /* _CPU_STATE_H */ |