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