aboutsummaryrefslogtreecommitdiff
path: root/sim/aarch64/cpustate.h
blob: 368c75915d0316463eb4aa8388d98538237ab901 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
/* cpustate.h -- Prototypes for AArch64 cpu state functions.

   Copyright (C) 2015-2023 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"
#include "sim-main.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)  (AARCH64_SIM_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 *, FlagMask);
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  */