Home | History | Annotate | Line # | Download | only in aarch64
cpustate.c revision 1.1.1.1
      1 /* cpustate.h -- Prototypes for AArch64 simulator functions.
      2 
      3    Copyright (C) 2015-2016 Free Software Foundation, Inc.
      4 
      5    Contributed by Red Hat.
      6 
      7    This file is part of GDB.
      8 
      9    This program is free software; you can redistribute it and/or modify
     10    it under the terms of the GNU General Public License as published by
     11    the Free Software Foundation; either version 3 of the License, or
     12    (at your option) any later version.
     13 
     14    This program is distributed in the hope that it will be useful,
     15    but WITHOUT ANY WARRANTY; without even the implied warranty of
     16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17    GNU General Public License for more details.
     18 
     19    You should have received a copy of the GNU General Public License
     20    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     21 
     22 #include <stdio.h>
     23 
     24 #include "sim-main.h"
     25 #include "cpustate.h"
     26 #include "simulator.h"
     27 
     28 /* Some operands are allowed to access the stack pointer (reg 31).
     29    For others a read from r31 always returns 0, and a write to r31 is ignored.  */
     30 #define reg_num(reg) (((reg) == R31 && !r31_is_sp) ? 32 : (reg))
     31 
     32 void
     33 aarch64_set_reg_u64 (sim_cpu *cpu, GReg reg, int r31_is_sp, uint64_t val)
     34 {
     35   if (reg == R31 && ! r31_is_sp)
     36     {
     37       TRACE_REGISTER (cpu, "GR[31] NOT CHANGED!");
     38       return;
     39     }
     40 
     41   if (val != cpu->gr[reg].u64)
     42     TRACE_REGISTER (cpu,
     43 		    "GR[%2d] changes from %16" PRIx64 " to %16" PRIx64,
     44 		    reg, cpu->gr[reg].u64, val);
     45 
     46   cpu->gr[reg].u64 = val;
     47 }
     48 
     49 void
     50 aarch64_set_reg_s64 (sim_cpu *cpu, GReg reg, int r31_is_sp, int64_t val)
     51 {
     52   if (reg == R31 && ! r31_is_sp)
     53     {
     54       TRACE_REGISTER (cpu, "GR[31] NOT CHANGED!");
     55       return;
     56     }
     57 
     58   if (val != cpu->gr[reg].s64)
     59     TRACE_REGISTER (cpu,
     60 		    "GR[%2d] changes from %16" PRIx64 " to %16" PRIx64,
     61 		    reg, cpu->gr[reg].s64, val);
     62 
     63   cpu->gr[reg].s64 = val;
     64 }
     65 
     66 uint64_t
     67 aarch64_get_reg_u64 (sim_cpu *cpu, GReg reg, int r31_is_sp)
     68 {
     69   return cpu->gr[reg_num(reg)].u64;
     70 }
     71 
     72 int64_t
     73 aarch64_get_reg_s64 (sim_cpu *cpu, GReg reg, int r31_is_sp)
     74 {
     75   return cpu->gr[reg_num(reg)].s64;
     76 }
     77 
     78 uint32_t
     79 aarch64_get_reg_u32 (sim_cpu *cpu, GReg reg, int r31_is_sp)
     80 {
     81   return cpu->gr[reg_num(reg)].u32;
     82 }
     83 
     84 int32_t
     85 aarch64_get_reg_s32 (sim_cpu *cpu, GReg reg, int r31_is_sp)
     86 {
     87   return cpu->gr[reg_num(reg)].s32;
     88 }
     89 
     90 void
     91 aarch64_set_reg_s32 (sim_cpu *cpu, GReg reg, int r31_is_sp, int32_t val)
     92 {
     93   if (reg == R31 && ! r31_is_sp)
     94     {
     95       TRACE_REGISTER (cpu, "GR[31] NOT CHANGED!");
     96       return;
     97     }
     98 
     99   if (val != cpu->gr[reg].s32)
    100     TRACE_REGISTER (cpu, "GR[%2d] changes from %8x to %8x",
    101 		    reg, cpu->gr[reg].s32, val);
    102 
    103   /* The ARM ARM states that (C1.2.4):
    104         When the data size is 32 bits, the lower 32 bits of the
    105 	register are used and the upper 32 bits are ignored on
    106 	a read and cleared to zero on a write.
    107      We simulate this by first clearing the whole 64-bits and
    108      then writing to the 32-bit value in the GRegister union.  */
    109   cpu->gr[reg].s64 = 0;
    110   cpu->gr[reg].s32 = val;
    111 }
    112 
    113 void
    114 aarch64_set_reg_u32 (sim_cpu *cpu, GReg reg, int r31_is_sp, uint32_t val)
    115 {
    116   if (reg == R31 && ! r31_is_sp)
    117     {
    118       TRACE_REGISTER (cpu, "GR[31] NOT CHANGED!");
    119       return;
    120     }
    121 
    122   if (val != cpu->gr[reg].u32)
    123     TRACE_REGISTER (cpu, "GR[%2d] changes from %8x to %8x",
    124 		    reg, cpu->gr[reg].u32, val);
    125 
    126   cpu->gr[reg].u64 = 0;
    127   cpu->gr[reg].u32 = val;
    128 }
    129 
    130 uint32_t
    131 aarch64_get_reg_u16 (sim_cpu *cpu, GReg reg, int r31_is_sp)
    132 {
    133   return cpu->gr[reg_num(reg)].u16;
    134 }
    135 
    136 int32_t
    137 aarch64_get_reg_s16 (sim_cpu *cpu, GReg reg, int r31_is_sp)
    138 {
    139   return cpu->gr[reg_num(reg)].s16;
    140 }
    141 
    142 uint32_t
    143 aarch64_get_reg_u8 (sim_cpu *cpu, GReg reg, int r31_is_sp)
    144 {
    145   return cpu->gr[reg_num(reg)].u8;
    146 }
    147 
    148 int32_t
    149 aarch64_get_reg_s8 (sim_cpu *cpu, GReg reg, int r31_is_sp)
    150 {
    151   return cpu->gr[reg_num(reg)].s8;
    152 }
    153 
    154 uint64_t
    155 aarch64_get_PC (sim_cpu *cpu)
    156 {
    157   return cpu->pc;
    158 }
    159 
    160 uint64_t
    161 aarch64_get_next_PC (sim_cpu *cpu)
    162 {
    163   return cpu->nextpc;
    164 }
    165 
    166 void
    167 aarch64_set_next_PC (sim_cpu *cpu, uint64_t next)
    168 {
    169   if (next != cpu->nextpc + 4)
    170     TRACE_REGISTER (cpu,
    171 		    "NextPC changes from %16" PRIx64 " to %16" PRIx64,
    172 		    cpu->nextpc, next);
    173 
    174   cpu->nextpc = next;
    175 }
    176 
    177 void
    178 aarch64_set_next_PC_by_offset (sim_cpu *cpu, int64_t offset)
    179 {
    180   if (cpu->pc + offset != cpu->nextpc + 4)
    181     TRACE_REGISTER (cpu,
    182 		    "NextPC changes from %16" PRIx64 " to %16" PRIx64,
    183 		    cpu->nextpc, cpu->pc + offset);
    184 
    185   cpu->nextpc = cpu->pc + offset;
    186 }
    187 
    188 /* Install nextpc as current pc.  */
    189 void
    190 aarch64_update_PC (sim_cpu *cpu)
    191 {
    192   cpu->pc = cpu->nextpc;
    193   /* Rezero the register we hand out when asked for ZR just in case it
    194      was used as the destination for a write by the previous
    195      instruction.  */
    196   cpu->gr[32].u64 = 0UL;
    197 }
    198 
    199 /* This instruction can be used to save the next PC to LR
    200    just before installing a branch PC.  */
    201 void
    202 aarch64_save_LR (sim_cpu *cpu)
    203 {
    204   if (cpu->gr[LR].u64 != cpu->nextpc)
    205     TRACE_REGISTER (cpu,
    206 		    "LR    changes from %16" PRIx64 " to %16" PRIx64,
    207 		    cpu->gr[LR].u64, cpu->nextpc);
    208 
    209   cpu->gr[LR].u64 = cpu->nextpc;
    210 }
    211 
    212 static const char *
    213 decode_cpsr (FlagMask flags)
    214 {
    215   switch (flags & CPSR_ALL_FLAGS)
    216     {
    217     default:
    218     case 0:  return "----";
    219     case 1:  return "---V";
    220     case 2:  return "--C-";
    221     case 3:  return "--CV";
    222     case 4:  return "-Z--";
    223     case 5:  return "-Z-V";
    224     case 6:  return "-ZC-";
    225     case 7:  return "-ZCV";
    226     case 8:  return "N---";
    227     case 9:  return "N--V";
    228     case 10: return "N-C-";
    229     case 11: return "N-CV";
    230     case 12: return "NZ--";
    231     case 13: return "NZ-V";
    232     case 14: return "NZC-";
    233     case 15: return "NZCV";
    234     }
    235 }
    236 
    237 /* Retrieve the CPSR register as an int.  */
    238 uint32_t
    239 aarch64_get_CPSR (sim_cpu *cpu)
    240 {
    241   return cpu->CPSR;
    242 }
    243 
    244 /* Set the CPSR register as an int.  */
    245 void
    246 aarch64_set_CPSR (sim_cpu *cpu, uint32_t new_flags)
    247 {
    248   if (TRACE_REGISTER_P (cpu))
    249     {
    250       if (cpu->CPSR != new_flags)
    251 	TRACE_REGISTER (cpu,
    252 			"CPSR changes from %s to %s",
    253 			decode_cpsr (cpu->CPSR), decode_cpsr (new_flags));
    254       else
    255 	TRACE_REGISTER (cpu,
    256 			"CPSR stays at %s", decode_cpsr (cpu->CPSR));
    257     }
    258 
    259   cpu->CPSR = new_flags & CPSR_ALL_FLAGS;
    260 }
    261 
    262 /* Read a specific subset of the CPSR as a bit pattern.  */
    263 uint32_t
    264 aarch64_get_CPSR_bits (sim_cpu *cpu, FlagMask mask)
    265 {
    266   return cpu->CPSR & mask;
    267 }
    268 
    269 /* Assign a specific subset of the CPSR as a bit pattern.  */
    270 void
    271 aarch64_set_CPSR_bits (sim_cpu *cpu, uint32_t mask, uint32_t value)
    272 {
    273   uint32_t old_flags = cpu->CPSR;
    274 
    275   mask &= CPSR_ALL_FLAGS;
    276   cpu->CPSR &= ~ mask;
    277   cpu->CPSR |= (value & mask);
    278 
    279   if (old_flags != cpu->CPSR)
    280     TRACE_REGISTER (cpu,
    281 		    "CPSR changes from %s to %s",
    282 		    decode_cpsr (old_flags), decode_cpsr (cpu->CPSR));
    283 }
    284 
    285 /* Test the value of a single CPSR returned as non-zero or zero.  */
    286 uint32_t
    287 aarch64_test_CPSR_bit (sim_cpu *cpu, FlagMask bit)
    288 {
    289   return cpu->CPSR & bit;
    290 }
    291 
    292 /* Set a single flag in the CPSR.  */
    293 void
    294 aarch64_set_CPSR_bit (sim_cpu *cpu, FlagMask bit)
    295 {
    296   uint32_t old_flags = cpu->CPSR;
    297 
    298   cpu->CPSR |= (bit & CPSR_ALL_FLAGS);
    299 
    300   if (old_flags != cpu->CPSR)
    301     TRACE_REGISTER (cpu,
    302 		    "CPSR changes from %s to %s",
    303 		    decode_cpsr (old_flags), decode_cpsr (cpu->CPSR));
    304 }
    305 
    306 /* Clear a single flag in the CPSR.  */
    307 void
    308 aarch64_clear_CPSR_bit (sim_cpu *cpu, FlagMask bit)
    309 {
    310   uint32_t old_flags = cpu->CPSR;
    311 
    312   cpu->CPSR &= ~(bit & CPSR_ALL_FLAGS);
    313 
    314   if (old_flags != cpu->CPSR)
    315     TRACE_REGISTER (cpu,
    316 		    "CPSR changes from %s to %s",
    317 		    decode_cpsr (old_flags), decode_cpsr (cpu->CPSR));
    318 }
    319 
    320 float
    321 aarch64_get_FP_half (sim_cpu *cpu, VReg reg)
    322 {
    323   union
    324   {
    325     uint16_t h[2];
    326     float    f;
    327   } u;
    328 
    329   u.h[0] = 0;
    330   u.h[1] = cpu->fr[reg].h[0];
    331   return u.f;
    332 }
    333 
    334 
    335 float
    336 aarch64_get_FP_float (sim_cpu *cpu, VReg reg)
    337 {
    338   return cpu->fr[reg].s;
    339 }
    340 
    341 double
    342 aarch64_get_FP_double (sim_cpu *cpu, VReg reg)
    343 {
    344   return cpu->fr[reg].d;
    345 }
    346 
    347 void
    348 aarch64_get_FP_long_double (sim_cpu *cpu, VReg reg, FRegister *a)
    349 {
    350   a->v[0] = cpu->fr[reg].v[0];
    351   a->v[1] = cpu->fr[reg].v[1];
    352 }
    353 
    354 void
    355 aarch64_set_FP_half (sim_cpu *cpu, VReg reg, float val)
    356 {
    357   union
    358   {
    359     uint16_t h[2];
    360     float    f;
    361   } u;
    362 
    363   u.f = val;
    364   cpu->fr[reg].h[0] = u.h[1];
    365   cpu->fr[reg].h[1] = 0;
    366 }
    367 
    368 
    369 void
    370 aarch64_set_FP_float (sim_cpu *cpu, VReg reg, float val)
    371 {
    372   if (val != cpu->fr[reg].s)
    373     {
    374       FRegister v;
    375 
    376       v.s = val;
    377       TRACE_REGISTER (cpu,
    378 		      "FR[%d].s changes from %f to %f [hex: %0lx]",
    379 		      reg, cpu->fr[reg].s, val, v.v[0]);
    380     }
    381 
    382   cpu->fr[reg].s = val;
    383 }
    384 
    385 void
    386 aarch64_set_FP_double (sim_cpu *cpu, VReg reg, double val)
    387 {
    388   if (val != cpu->fr[reg].d)
    389     {
    390       FRegister v;
    391 
    392       v.d = val;
    393       TRACE_REGISTER (cpu,
    394 		      "FR[%d].d changes from %f to %f [hex: %0lx]",
    395 		      reg, cpu->fr[reg].d, val, v.v[0]);
    396     }
    397   cpu->fr[reg].d = val;
    398 }
    399 
    400 void
    401 aarch64_set_FP_long_double (sim_cpu *cpu, VReg reg, FRegister a)
    402 {
    403   if (cpu->fr[reg].v[0] != a.v[0]
    404       || cpu->fr[reg].v[1] != a.v[1])
    405     TRACE_REGISTER (cpu,
    406 		    "FR[%d].q changes from [%0lx %0lx] to [%0lx %0lx] ",
    407 		    reg,
    408 		    cpu->fr[reg].v[0], cpu->fr[reg].v[1],
    409 		    a.v[0], a.v[1]);
    410 
    411   cpu->fr[reg].v[0] = a.v[0];
    412   cpu->fr[reg].v[1] = a.v[1];
    413 }
    414 
    415 #define GET_VEC_ELEMENT(REG, ELEMENT, FIELD)	   \
    416   do						   \
    417     {						   \
    418       if (ELEMENT >= ARRAY_SIZE (cpu->fr[0].FIELD)) \
    419 	{								\
    420 	  TRACE_REGISTER (cpu, \
    421 			  "Internal SIM error: invalid element number: %d ",\
    422 			  ELEMENT);					\
    423 	  sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu), \
    424 			   sim_stopped, SIM_SIGBUS);			\
    425 	}								\
    426       return cpu->fr[REG].FIELD [ELEMENT];				\
    427     }									\
    428   while (0)
    429 
    430 uint64_t
    431 aarch64_get_vec_u64 (sim_cpu *cpu, VReg reg, unsigned element)
    432 {
    433   GET_VEC_ELEMENT (reg, element, v);
    434 }
    435 
    436 uint32_t
    437 aarch64_get_vec_u32 (sim_cpu *cpu, VReg reg, unsigned element)
    438 {
    439   GET_VEC_ELEMENT (reg, element, w);
    440 }
    441 
    442 uint16_t
    443 aarch64_get_vec_u16 (sim_cpu *cpu, VReg reg, unsigned element)
    444 {
    445   GET_VEC_ELEMENT (reg, element, h);
    446 }
    447 
    448 uint8_t
    449 aarch64_get_vec_u8 (sim_cpu *cpu, VReg reg, unsigned element)
    450 {
    451   GET_VEC_ELEMENT (reg, element, b);
    452 }
    453 
    454 int64_t
    455 aarch64_get_vec_s64 (sim_cpu *cpu, VReg reg, unsigned element)
    456 {
    457   GET_VEC_ELEMENT (reg, element, V);
    458 }
    459 
    460 int32_t
    461 aarch64_get_vec_s32 (sim_cpu *cpu, VReg reg, unsigned element)
    462 {
    463   GET_VEC_ELEMENT (reg, element, W);
    464 }
    465 
    466 int16_t
    467 aarch64_get_vec_s16 (sim_cpu *cpu, VReg reg, unsigned element)
    468 {
    469   GET_VEC_ELEMENT (reg, element, H);
    470 }
    471 
    472 int8_t
    473 aarch64_get_vec_s8 (sim_cpu *cpu, VReg reg, unsigned element)
    474 {
    475   GET_VEC_ELEMENT (reg, element, B);
    476 }
    477 
    478 float
    479 aarch64_get_vec_float (sim_cpu *cpu, VReg reg, unsigned element)
    480 {
    481   GET_VEC_ELEMENT (reg, element, S);
    482 }
    483 
    484 double
    485 aarch64_get_vec_double (sim_cpu *cpu, VReg reg, unsigned element)
    486 {
    487   GET_VEC_ELEMENT (reg, element, D);
    488 }
    489 
    490 
    491 #define SET_VEC_ELEMENT(REG, ELEMENT, VAL, FIELD, PRINTER)		\
    492   do									\
    493     {									\
    494       if (ELEMENT >= ARRAY_SIZE (cpu->fr[0].FIELD))			\
    495 	{								\
    496 	  TRACE_REGISTER (cpu,						\
    497 			  "Internal SIM error: invalid element number: %d ",\
    498 			  ELEMENT);					\
    499 	  sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu), \
    500 			   sim_stopped, SIM_SIGBUS);			\
    501 	}								\
    502       if (VAL != cpu->fr[REG].FIELD [ELEMENT])				\
    503 	TRACE_REGISTER (cpu,						\
    504 			"VR[%2d]." #FIELD " [%d] changes from " PRINTER \
    505 			" to " PRINTER , REG,				\
    506 			ELEMENT, cpu->fr[REG].FIELD [ELEMENT], VAL);	\
    507 									\
    508       cpu->fr[REG].FIELD [ELEMENT] = VAL;				\
    509     }									\
    510   while (0)
    511 
    512 void
    513 aarch64_set_vec_u64 (sim_cpu *cpu, VReg reg, unsigned element, uint64_t val)
    514 {
    515   SET_VEC_ELEMENT (reg, element, val, v, "%16lx");
    516 }
    517 
    518 void
    519 aarch64_set_vec_u32 (sim_cpu *cpu, VReg reg, unsigned element, uint32_t val)
    520 {
    521   SET_VEC_ELEMENT (reg, element, val, w, "%8x");
    522 }
    523 
    524 void
    525 aarch64_set_vec_u16 (sim_cpu *cpu, VReg reg, unsigned element, uint16_t val)
    526 {
    527   SET_VEC_ELEMENT (reg, element, val, h, "%4x");
    528 }
    529 
    530 void
    531 aarch64_set_vec_u8 (sim_cpu *cpu, VReg reg, unsigned element, uint8_t val)
    532 {
    533   SET_VEC_ELEMENT (reg, element, val, b, "%x");
    534 }
    535 
    536 void
    537 aarch64_set_vec_s64 (sim_cpu *cpu, VReg reg, unsigned element, int64_t val)
    538 {
    539   SET_VEC_ELEMENT (reg, element, val, V, "%16lx");
    540 }
    541 
    542 void
    543 aarch64_set_vec_s32 (sim_cpu *cpu, VReg reg, unsigned element, int32_t val)
    544 {
    545   SET_VEC_ELEMENT (reg, element, val, W, "%8x");
    546 }
    547 
    548 void
    549 aarch64_set_vec_s16 (sim_cpu *cpu, VReg reg, unsigned element, int16_t val)
    550 {
    551   SET_VEC_ELEMENT (reg, element, val, H, "%4x");
    552 }
    553 
    554 void
    555 aarch64_set_vec_s8 (sim_cpu *cpu, VReg reg, unsigned element, int8_t val)
    556 {
    557   SET_VEC_ELEMENT (reg, element, val, B, "%x");
    558 }
    559 
    560 void
    561 aarch64_set_vec_float (sim_cpu *cpu, VReg reg, unsigned element, float val)
    562 {
    563   SET_VEC_ELEMENT (reg, element, val, S, "%f");
    564 }
    565 
    566 void
    567 aarch64_set_vec_double (sim_cpu *cpu, VReg reg, unsigned element, double val)
    568 {
    569   SET_VEC_ELEMENT (reg, element, val, D, "%f");
    570 }
    571 
    572 void
    573 aarch64_set_FPSR (sim_cpu *cpu, uint32_t value)
    574 {
    575   if (cpu->FPSR != value)
    576     TRACE_REGISTER (cpu,
    577 		    "FPSR changes from %x to %x", cpu->FPSR, value);
    578 
    579   cpu->FPSR = value & FPSR_ALL_FPSRS;
    580 }
    581 
    582 uint32_t
    583 aarch64_get_FPSR (sim_cpu *cpu)
    584 {
    585   return cpu->FPSR;
    586 }
    587 
    588 void
    589 aarch64_set_FPSR_bits (sim_cpu *cpu, uint32_t mask, uint32_t value)
    590 {
    591   uint32_t old_FPSR = cpu->FPSR;
    592 
    593   mask &= FPSR_ALL_FPSRS;
    594   cpu->FPSR &= ~mask;
    595   cpu->FPSR |= (value & mask);
    596 
    597   if (cpu->FPSR != old_FPSR)
    598     TRACE_REGISTER (cpu,
    599 		    "FPSR changes from %x to %x", old_FPSR, cpu->FPSR);
    600 }
    601 
    602 uint32_t
    603 aarch64_get_FPSR_bits (sim_cpu *cpu, uint32_t mask)
    604 {
    605   mask &= FPSR_ALL_FPSRS;
    606   return cpu->FPSR & mask;
    607 }
    608 
    609 int
    610 aarch64_test_FPSR_bit (sim_cpu *cpu, FPSRMask flag)
    611 {
    612   return cpu->FPSR & flag;
    613 }
    614 
    615 uint64_t
    616 aarch64_get_thread_id (sim_cpu *cpu)
    617 {
    618   return cpu->tpidr;
    619 }
    620 
    621 uint32_t
    622 aarch64_get_FPCR (sim_cpu *cpu)
    623 {
    624   return cpu->FPCR;
    625 }
    626 
    627 void
    628 aarch64_set_FPCR (sim_cpu *cpu, uint32_t val)
    629 {
    630   if (cpu->FPCR != val)
    631     TRACE_REGISTER (cpu,
    632 		    "FPCR changes from %x to %x", cpu->FPCR, val);
    633   cpu->FPCR = val;
    634 }
    635