Add an AArch64 simulator to GDB.

sim	* configure.tgt: Add aarch64 entry.
	* configure: Regenerate.
	* sim/aarch64/configure.ac: New configure template.
	* sim/aarch64/aclocal.m4: Generate.
	* sim/aarch64/config.in: Generate.
	* sim/aarch64/configure: Generate.
	* sim/aarch64/cpustate.c: New file - functions for accessing
	AArch64 registers.
	* sim/aarch64/cpustate.h: New header.
	* sim/aarch64/decode.h: New header.
	* sim/aarch64/interp.c: New file - interface between GDB and
	simulator.
	* sim/aarch64/Makefile.in: New makefile template.
	* sim/aarch64/memory.c: New file - functions for simulating
	aarch64 memory accesses.
	* sim/aarch64/memory.h: New header.
	* sim/aarch64/sim-main.h: New header.
	* sim/aarch64/simulator.c: New file - aarch64 simulator
	functions.
	* sim/aarch64/simulator.h: New header.

include/gdb * sim-aarch64.h: New file.

sim/test * configure: Regenerate.
	* sim/aarch64: New directory.
This commit is contained in:
Nick Clifton 2015-11-24 08:47:59 +00:00
parent 351e610191
commit 2e8cf49e13
25 changed files with 31452 additions and 4 deletions

View File

@ -1,3 +1,7 @@
2015-11-24 Nick Clifton <nickc@redhat.com>
* sim-aarch64.h: New file.
2015-11-15 Mike Frysinger <vapier@gentoo.org>
* sim-cr16.h (SIM_CR16_MEMORY_UNIFIED, SIM_CR16_MEMORY_INSN,

48
include/gdb/sim-aarch64.h Normal file
View File

@ -0,0 +1,48 @@
/* sim-aarch64.h --- interface between AArch64 simulator and GDB.
Copyright (C) 2015 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/>. */
#if !defined (SIM_AARCH64_H)
#define SIM_AARCH64_H
enum sim_aarch64_regnum
{
SIM_AARCH64_R0_REGNUM,
SIM_AARCH64_R1_REGNUM,
SIM_AARCH64_R2_REGNUM,
SIM_AARCH64_R3_REGNUM,
SIM_AARCH64_R4_REGNUM,
SIM_AARCH64_R5_REGNUM,
SIM_AARCH64_R6_REGNUM,
SIM_AARCH64_R7_REGNUM,
SIM_AARCH64_R8_REGNUM,
SIM_AARCH64_R9_REGNUM,
SIM_AARCH64_R10_REGNUM,
SIM_AARCH64_R11_REGNUM,
SIM_AARCH64_R12_REGNUM,
SIM_AARCH64_R13_REGNUM,
SIM_AARCH64_R14_REGNUM,
SIM_AARCH64_R15_REGNUM,
SIM_AARCH64_SP_REGNUM,
SIM_AARCH64_PC_REGNUM,
SIM_AARCH64_NUM_REGS
};
#endif

View File

@ -1,3 +1,26 @@
2015-11-24 Nick Clifton <nickc@redhat.com>
* configure.tgt: Add aarch64 entry.
* configure: Regenerate.
* sim/aarch64/configure.ac: New configure template.
* sim/aarch64/aclocal.m4: Generate.
* sim/aarch64/config.in: Generate.
* sim/aarch64/configure: Generate.
* sim/aarch64/cpustate.c: New file - functions for accessing
AArch64 registers.
* sim/aarch64/cpustate.h: New header.
* sim/aarch64/decode.h: New header.
* sim/aarch64/interp.c: New file - interface between GDB and
simulator.
* sim/aarch64/Makefile.in: New makefile template.
* sim/aarch64/memory.c: New file - functions for simulating
aarch64 memory accesses.
* sim/aarch64/memory.h: New header.
* sim/aarch64/sim-main.h: New header.
* sim/aarch64/simulator.c: New file - aarch64 simulator
functions.
* sim/aarch64/simulator.h: New header.
2015-06-23 Mike Frysinger <vapier@gentoo.org>
* configure.ac (AC_ARG_ENABLE(sim)): Call AS_HELP_STRING.

36
sim/aarch64/Makefile.in Normal file
View File

@ -0,0 +1,36 @@
#### Makefile.in --- Makefile template for the AArch64 simulator
### Copyright (C) 2015 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/>. */
## COMMON_PRE_CONFIG_FRAG
SIM_EXTRA_LIBS = -lm
SIM_OBJS = \
$(SIM_NEW_COMMON_OBJS) \
interp.o \
cpustate.o \
simulator.o \
memory.o \
sim-hload.o \
sim-resume.o \
## COMMON_POST_CONFIG_FRAG

110
sim/aarch64/aclocal.m4 vendored Normal file
View File

@ -0,0 +1,110 @@
# generated automatically by aclocal 1.11.6 -*- Autoconf -*-
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
# 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
# Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
# AM_CONDITIONAL -*- Autoconf -*-
# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008
# Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 9
# AM_CONDITIONAL(NAME, SHELL-CONDITION)
# -------------------------------------
# Define a conditional.
AC_DEFUN([AM_CONDITIONAL],
[AC_PREREQ(2.52)dnl
ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
[$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
AC_SUBST([$1_TRUE])dnl
AC_SUBST([$1_FALSE])dnl
_AM_SUBST_NOTMAKE([$1_TRUE])dnl
_AM_SUBST_NOTMAKE([$1_FALSE])dnl
m4_define([_AM_COND_VALUE_$1], [$2])dnl
if $2; then
$1_TRUE=
$1_FALSE='#'
else
$1_TRUE='#'
$1_FALSE=
fi
AC_CONFIG_COMMANDS_PRE(
[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
AC_MSG_ERROR([[conditional "$1" was never defined.
Usually this means the macro was only invoked conditionally.]])
fi])])
# Add --enable-maintainer-mode option to configure. -*- Autoconf -*-
# From Jim Meyering
# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008,
# 2011 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 5
# AM_MAINTAINER_MODE([DEFAULT-MODE])
# ----------------------------------
# Control maintainer-specific portions of Makefiles.
# Default is to disable them, unless `enable' is passed literally.
# For symmetry, `disable' may be passed as well. Anyway, the user
# can override the default with the --enable/--disable switch.
AC_DEFUN([AM_MAINTAINER_MODE],
[m4_case(m4_default([$1], [disable]),
[enable], [m4_define([am_maintainer_other], [disable])],
[disable], [m4_define([am_maintainer_other], [enable])],
[m4_define([am_maintainer_other], [enable])
m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])])
AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
dnl maintainer-mode's default is 'disable' unless 'enable' is passed
AC_ARG_ENABLE([maintainer-mode],
[ --][am_maintainer_other][-maintainer-mode am_maintainer_other make rules and dependencies not useful
(and sometimes confusing) to the casual installer],
[USE_MAINTAINER_MODE=$enableval],
[USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes]))
AC_MSG_RESULT([$USE_MAINTAINER_MODE])
AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes])
MAINT=$MAINTAINER_MODE_TRUE
AC_SUBST([MAINT])dnl
]
)
AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE])
# Copyright (C) 2006, 2008, 2010 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 3
# _AM_SUBST_NOTMAKE(VARIABLE)
# ---------------------------
# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
# This macro is traced by Automake.
AC_DEFUN([_AM_SUBST_NOTMAKE])
# AM_SUBST_NOTMAKE(VARIABLE)
# --------------------------
# Public sister of _AM_SUBST_NOTMAKE.
AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
m4_include([../../config/lead-dot.m4])

160
sim/aarch64/config.in Normal file
View File

@ -0,0 +1,160 @@
/* config.in. Generated from configure.ac by autoheader. */
/* Define if building universal (internal helper macro) */
#undef AC_APPLE_UNIVERSAL_BUILD
/* Define to 1 if translation of program messages to the user's native
language is requested. */
#undef ENABLE_NLS
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
/* Define to 1 if you have the <errno.h> header file. */
#undef HAVE_ERRNO_H
/* Define to 1 if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H
/* Define to 1 if you have the <fpu_control.h> header file. */
#undef HAVE_FPU_CONTROL_H
/* Define to 1 if you have the `getrusage' function. */
#undef HAVE_GETRUSAGE
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the `nsl' library (-lnsl). */
#undef HAVE_LIBNSL
/* Define to 1 if you have the `socket' library (-lsocket). */
#undef HAVE_LIBSOCKET
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the `sigaction' function. */
#undef HAVE_SIGACTION
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the <sys/resource.h> header file. */
#undef HAVE_SYS_RESOURCE_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/time.h> header file. */
#undef HAVE_SYS_TIME_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the `time' function. */
#undef HAVE_TIME
/* Define to 1 if you have the <time.h> header file. */
#undef HAVE_TIME_H
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define to 1 if you have the <windows.h> header file. */
#undef HAVE_WINDOWS_H
/* Define to 1 if you have the `__setfpucw' function. */
#undef HAVE___SETFPUCW
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#undef LT_OBJDIR
/* Name of this package. */
#undef PACKAGE
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Additional package description */
#undef PKGVERSION
/* Bug reporting address */
#undef REPORT_BUGS_TO
/* Define as the return type of signal handlers (`int' or `void'). */
#undef RETSIGTYPE
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Enable extensions on AIX 3, Interix. */
#ifndef _ALL_SOURCE
# undef _ALL_SOURCE
#endif
/* Enable GNU extensions on systems that have them. */
#ifndef _GNU_SOURCE
# undef _GNU_SOURCE
#endif
/* Enable threading extensions on Solaris. */
#ifndef _POSIX_PTHREAD_SEMANTICS
# undef _POSIX_PTHREAD_SEMANTICS
#endif
/* Enable extensions on HP NonStop. */
#ifndef _TANDEM_SOURCE
# undef _TANDEM_SOURCE
#endif
/* Enable general extensions on Solaris. */
#ifndef __EXTENSIONS__
# undef __EXTENSIONS__
#endif
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
significant byte first (like Motorola and SPARC, unlike Intel). */
#if defined AC_APPLE_UNIVERSAL_BUILD
# if defined __BIG_ENDIAN__
# define WORDS_BIGENDIAN 1
# endif
#else
# ifndef WORDS_BIGENDIAN
# undef WORDS_BIGENDIAN
# endif
#endif
/* Define to 1 if on MINIX. */
#undef _MINIX
/* Define to 2 if the system does not provide POSIX.1 features except with
this defined. */
#undef _POSIX_1_SOURCE
/* Define to 1 if you need to in order for `stat' and other things to work. */
#undef _POSIX_SOURCE
#include "tconfig.h"

15689
sim/aarch64/configure vendored Executable file

File diff suppressed because it is too large Load Diff

39
sim/aarch64/configure.ac Normal file
View File

@ -0,0 +1,39 @@
dnl Process this file with autoconf to produce a configure script.
dnl Copyright (C) 2015 Free Software Foundation, Inc.
dnl
dnl Contributed by Red Hat.
dnl
dnl This file is part of GDB.
dnl This program is free software; you can redistribute it and/or modify
dnl it under the terms of the GNU General Public License as published by
dnl the Free Software Foundation; either version 3 of the License, or
dnl (at your option) any later version.
dnl
dnl This program is distributed in the hope that it will be useful,
dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
dnl GNU General Public License for more details.
dnl
dnl You should have received a copy of the GNU General Public License
dnl along with this program. If not, see <http://www.gnu.org/licenses/>. */
AC_PREREQ(2.64)dnl
AC_INIT(Makefile.in)
sinclude(../common/acinclude.m4)
SIM_AC_COMMON
SIM_AC_OPTION_ENDIAN
## We use NONSTRICT_ALIGNMENT as the default because AArch64 only
## enforces 4-byte alignment, even for 8-byte reads/writes. The
## common core does not support this, so we opt for non-strict
## alignment instead.
SIM_AC_OPTION_ALIGNMENT(NONSTRICT_ALIGNMENT,NONSTRICT_ALIGNMENT)
SIM_AC_OPTION_HOSTENDIAN
SIM_AC_OPTION_ENVIRONMENT
SIM_AC_OPTION_INLINE
SIM_AC_OPTION_WARNINGS
SIM_AC_OUTPUT

557
sim/aarch64/cpustate.c Normal file
View File

@ -0,0 +1,557 @@
/* cpustate.h -- Prototypes for AArch64 simulator functions.
Copyright (C) 2015 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/>. */
#include <stdio.h>
#include "sim-main.h"
#include "cpustate.h"
#include "simulator.h"
/* Some operands are allowed to access the stack pointer (reg 31).
For others a read from r31 always returns 0, and a write to r31 is ignored. */
#define reg_num(reg) (((reg) == R31 && !r31_is_sp) ? 32 : (reg))
void
aarch64_set_reg_u64 (sim_cpu *cpu, GReg reg, int r31_is_sp, uint64_t val)
{
if (reg == R31 && ! r31_is_sp)
{
TRACE_REGISTER (cpu, " GR[31] NOT CHANGED!");
return;
}
if (val != cpu->gr[reg].u64)
TRACE_REGISTER (cpu,
" GR[%2d] changes from %16" PRIx64 " to %16" PRIx64,
reg, cpu->gr[reg].u64, val);
cpu->gr[reg].u64 = val;
}
void
aarch64_set_reg_s64 (sim_cpu *cpu, GReg reg, int r31_is_sp, int64_t val)
{
if (reg == R31 && ! r31_is_sp)
{
TRACE_REGISTER (cpu, " GR[31] NOT CHANGED!");
return;
}
if (val != cpu->gr[reg].s64)
TRACE_REGISTER (cpu,
" GR[%2d] changes from %16" PRIx64 " to %16" PRIx64,
reg, cpu->gr[reg].s64, val);
cpu->gr[reg].s64 = val;
}
uint64_t
aarch64_get_reg_u64 (sim_cpu *cpu, GReg reg, int r31_is_sp)
{
return cpu->gr[reg_num(reg)].u64;
}
int64_t
aarch64_get_reg_s64 (sim_cpu *cpu, GReg reg, int r31_is_sp)
{
return cpu->gr[reg_num(reg)].s64;
}
uint32_t
aarch64_get_reg_u32 (sim_cpu *cpu, GReg reg, int r31_is_sp)
{
return cpu->gr[reg_num(reg)].u32;
}
int32_t
aarch64_get_reg_s32 (sim_cpu *cpu, GReg reg, int r31_is_sp)
{
return cpu->gr[reg_num(reg)].s32;
}
uint32_t
aarch64_get_reg_u16 (sim_cpu *cpu, GReg reg, int r31_is_sp)
{
return cpu->gr[reg_num(reg)].u16;
}
int32_t
aarch64_get_reg_s16 (sim_cpu *cpu, GReg reg, int r31_is_sp)
{
return cpu->gr[reg_num(reg)].s16;
}
uint32_t
aarch64_get_reg_u8 (sim_cpu *cpu, GReg reg, int r31_is_sp)
{
return cpu->gr[reg_num(reg)].u8;
}
int32_t
aarch64_get_reg_s8 (sim_cpu *cpu, GReg reg, int r31_is_sp)
{
return cpu->gr[reg_num(reg)].s8;
}
uint64_t
aarch64_get_PC (sim_cpu *cpu)
{
return cpu->pc;
}
uint64_t
aarch64_get_next_PC (sim_cpu *cpu)
{
return cpu->nextpc;
}
void
aarch64_set_next_PC (sim_cpu *cpu, uint64_t next)
{
if (next != cpu->nextpc + 4)
TRACE_REGISTER (cpu,
" NextPC changes from %16" PRIx64 " to %16" PRIx64,
cpu->nextpc, next);
cpu->nextpc = next;
}
void
aarch64_set_next_PC_by_offset (sim_cpu *cpu, int64_t offset)
{
if (cpu->pc + offset != cpu->nextpc + 4)
TRACE_REGISTER (cpu,
" NextPC changes from %16" PRIx64 " to %16" PRIx64,
cpu->nextpc, cpu->pc + offset);
cpu->nextpc = cpu->pc + offset;
}
/* Install nextpc as current pc. */
void
aarch64_update_PC (sim_cpu *cpu)
{
cpu->pc = cpu->nextpc;
/* Rezero the register we hand out when asked for ZR just in case it
was used as the destination for a write by the previous
instruction. */
cpu->gr[32].u64 = 0UL;
}
/* This instruction can be used to save the next PC to LR
just before installing a branch PC. */
void
aarch64_save_LR (sim_cpu *cpu)
{
if (cpu->gr[LR].u64 != cpu->nextpc)
TRACE_REGISTER (cpu,
" LR changes from %16" PRIx64 " to %16" PRIx64,
cpu->gr[LR].u64, cpu->nextpc);
cpu->gr[LR].u64 = cpu->nextpc;
}
static const char *
decode_cpsr (FlagMask flags)
{
switch (flags & CPSR_ALL_FLAGS)
{
default:
case 0: return "----";
case 1: return "---V";
case 2: return "--C-";
case 3: return "--CV";
case 4: return "-Z--";
case 5: return "-Z-V";
case 6: return "-ZC-";
case 7: return "-ZCV";
case 8: return "N---";
case 9: return "N--V";
case 10: return "N-C-";
case 11: return "N-CV";
case 12: return "NZ--";
case 13: return "NZ-V";
case 14: return "NZC-";
case 15: return "NZCV";
}
}
/* Retrieve the CPSR register as an int. */
uint32_t
aarch64_get_CPSR (sim_cpu *cpu)
{
return cpu->CPSR;
}
/* Set the CPSR register as an int. */
void
aarch64_set_CPSR (sim_cpu *cpu, uint32_t new_flags)
{
if (TRACE_REGISTER_P (cpu))
{
if (cpu->CPSR != new_flags)
TRACE_REGISTER (cpu,
" CPSR changes from %s to %s",
decode_cpsr (cpu->CPSR), decode_cpsr (new_flags));
else
TRACE_REGISTER (cpu,
" CPSR stays at %s", decode_cpsr (cpu->CPSR));
}
cpu->CPSR = new_flags & CPSR_ALL_FLAGS;
}
/* Read a specific subset of the CPSR as a bit pattern. */
uint32_t
aarch64_get_CPSR_bits (sim_cpu *cpu, FlagMask mask)
{
return cpu->CPSR & mask;
}
/* Assign a specific subset of the CPSR as a bit pattern. */
void
aarch64_set_CPSR_bits (sim_cpu *cpu, uint32_t mask, uint32_t value)
{
uint32_t old_flags = cpu->CPSR;
mask &= CPSR_ALL_FLAGS;
cpu->CPSR &= ~ mask;
cpu->CPSR |= (value & mask);
if (old_flags != cpu->CPSR)
TRACE_REGISTER (cpu,
" CPSR changes from %s to %s",
decode_cpsr (old_flags), decode_cpsr (cpu->CPSR));
}
/* Test the value of a single CPSR returned as non-zero or zero. */
uint32_t
aarch64_test_CPSR_bit (sim_cpu *cpu, FlagMask bit)
{
return cpu->CPSR & bit;
}
/* Set a single flag in the CPSR. */
void
aarch64_set_CPSR_bit (sim_cpu *cpu, FlagMask bit)
{
uint32_t old_flags = cpu->CPSR;
cpu->CPSR |= (bit & CPSR_ALL_FLAGS);
if (old_flags != cpu->CPSR)
TRACE_REGISTER (cpu,
" CPSR changes from %s to %s",
decode_cpsr (old_flags), decode_cpsr (cpu->CPSR));
}
/* Clear a single flag in the CPSR. */
void
aarch64_clear_CPSR_bit (sim_cpu *cpu, FlagMask bit)
{
uint32_t old_flags = cpu->CPSR;
cpu->CPSR &= ~(bit & CPSR_ALL_FLAGS);
if (old_flags != cpu->CPSR)
TRACE_REGISTER (cpu,
" CPSR changes from %s to %s",
decode_cpsr (old_flags), decode_cpsr (cpu->CPSR));
}
float
aarch64_get_FP_float (sim_cpu *cpu, VReg reg)
{
return cpu->fr[reg].s;
}
double
aarch64_get_FP_double (sim_cpu *cpu, VReg reg)
{
return cpu->fr[reg].d;
}
void
aarch64_get_FP_long_double (sim_cpu *cpu, VReg reg, FRegister *a)
{
a->v[0] = cpu->fr[reg].v[0];
a->v[1] = cpu->fr[reg].v[1];
}
void
aarch64_set_FP_float (sim_cpu *cpu, VReg reg, float val)
{
if (val != cpu->fr[reg].s)
TRACE_REGISTER (cpu,
" FR[%d] changes from %f to %f",
reg, cpu->fr[reg].s, val);
cpu->fr[reg].s = val;
}
void
aarch64_set_FP_double (sim_cpu *cpu, VReg reg, double val)
{
if (val != cpu->fr[reg].d)
TRACE_REGISTER (cpu,
" FR[%d] changes from %f to %f",
reg, cpu->fr[reg].d, val);
cpu->fr[reg].d = val;
}
void
aarch64_set_FP_long_double (sim_cpu *cpu, VReg reg, FRegister a)
{
if (cpu->fr[reg].v[0] != a.v[0]
|| cpu->fr[reg].v[1] != a.v[1])
TRACE_REGISTER (cpu,
" FR[%d] changes from [%0lx %0lx] to [%lx %lx] ",
reg,
cpu->fr[reg].v[0], cpu->fr[reg].v[1],
a.v[0], a.v[1]);
cpu->fr[reg].v[0] = a.v[0];
cpu->fr[reg].v[1] = a.v[1];
}
uint64_t
aarch64_get_vec_u64 (sim_cpu *cpu, VReg reg, unsigned element)
{
return cpu->fr[reg].v[element];
}
uint32_t
aarch64_get_vec_u32 (sim_cpu *cpu, VReg regno, unsigned element)
{
return cpu->fr[regno].w[element];
}
uint16_t
aarch64_get_vec_u16 (sim_cpu *cpu, VReg regno, unsigned element)
{
return cpu->fr[regno].h[element];
}
uint8_t
aarch64_get_vec_u8 (sim_cpu *cpu, VReg regno, unsigned element)
{
return cpu->fr[regno].b[element];
}
void
aarch64_set_vec_u64 (sim_cpu * cpu,
VReg regno,
unsigned element,
uint64_t value)
{
if (value != cpu->fr[regno].v[element])
TRACE_REGISTER (cpu,
" VR[%2d].<long>[%d] changes from %16" PRIx64
" to %16" PRIx64,
regno, element, cpu->fr[regno].v[element], value);
cpu->fr[regno].v[element] = value;
}
void
aarch64_set_vec_u32 (sim_cpu * cpu,
VReg regno,
unsigned element,
uint32_t value)
{
if (value != cpu->fr[regno].w[element])
TRACE_REGISTER (cpu,
" VR[%2d].<word>[%d] changes from %8x to %8x",
regno, element, cpu->fr[regno].w[element], value);
cpu->fr[regno].w[element] = value;
}
void
aarch64_set_vec_u16 (sim_cpu * cpu,
VReg regno,
unsigned element,
uint16_t value)
{
if (value != cpu->fr[regno].h[element])
TRACE_REGISTER (cpu,
" VR[%2d].<half>[%d] changes from %4x to %4x",
regno, element, cpu->fr[regno].h[element], value);
cpu->fr[regno].h[element] = value;
}
void
aarch64_set_vec_u8 (sim_cpu *cpu, VReg regno, unsigned element, uint8_t value)
{
if (value != cpu->fr[regno].b[element])
TRACE_REGISTER (cpu,
" VR[%2d].<byte>[%d] changes from %x to %x",
regno, element, cpu->fr[regno].b[element], value);
cpu->fr[regno].b[element] = value;
}
void
aarch64_set_FPSR (sim_cpu *cpu, uint32_t value)
{
if (cpu->FPSR != value)
TRACE_REGISTER (cpu,
" FPSR changes from %x to %x", cpu->FPSR, value);
cpu->FPSR = value & FPSR_ALL_FPSRS;
}
uint32_t
aarch64_get_FPSR (sim_cpu *cpu)
{
return cpu->FPSR;
}
void
aarch64_set_FPSR_bits (sim_cpu *cpu, uint32_t mask, uint32_t value)
{
uint32_t old_FPSR = cpu->FPSR;
mask &= FPSR_ALL_FPSRS;
cpu->FPSR &= ~mask;
cpu->FPSR |= (value & mask);
if (cpu->FPSR != old_FPSR)
TRACE_REGISTER (cpu,
" FPSR changes from %x to %x", old_FPSR, cpu->FPSR);
}
uint32_t
aarch64_get_FPSR_bits (sim_cpu *cpu, uint32_t mask)
{
mask &= FPSR_ALL_FPSRS;
return cpu->FPSR & mask;
}
int
aarch64_test_FPSR_bit (sim_cpu *cpu, FPSRMask flag)
{
return cpu->FPSR & flag;
}
float
aarch64_get_vec_float (sim_cpu *cpu, VReg v, unsigned e)
{
return cpu->fr[v].S[e];
}
double
aarch64_get_vec_double (sim_cpu *cpu, VReg v, unsigned e)
{
return cpu->fr[v].D[e];
}
void
aarch64_set_vec_float (sim_cpu *cpu, VReg v, unsigned e, float f)
{
if (f != cpu->fr[v].S[e])
TRACE_REGISTER (cpu,
" VR[%2d].<float>[%d] changes from %f to %f",
v, e, cpu->fr[v].S[e], f);
cpu->fr[v].S[e] = f;
}
void
aarch64_set_vec_double (sim_cpu *cpu, VReg v, unsigned e, double d)
{
if (d != cpu->fr[v].D[e])
TRACE_REGISTER (cpu,
" VR[%2d].<double>[%d] changes from %f to %f",
v, e, cpu->fr[v].D[e], d);
cpu->fr[v].D[e] = d;
}
int64_t
aarch64_get_vec_s64 (sim_cpu *cpu, VReg regno, unsigned element)
{
return cpu->fr[regno].V[element];
}
int32_t
aarch64_get_vec_s32 (sim_cpu *cpu, VReg regno, unsigned element)
{
return cpu->fr[regno].W[element];
}
int16_t
aarch64_get_vec_s16 (sim_cpu *cpu, VReg regno, unsigned element)
{
return cpu->fr[regno].H[element];
}
int8_t
aarch64_get_vec_s8 (sim_cpu *cpu, VReg regno, unsigned element)
{
return cpu->fr[regno].B[element];
}
void
aarch64_set_vec_s64 (sim_cpu *cpu, VReg regno, unsigned element, int64_t value)
{
if (value != cpu->fr[regno].V[element])
TRACE_REGISTER (cpu,
" VR[%2d].<long>[%d] changes from %16" PRIx64 " to %16" PRIx64,
regno, element, cpu->fr[regno].V[element], value);
cpu->fr[regno].V[element] = value;
}
void
aarch64_set_vec_s32 (sim_cpu *cpu, VReg regno, unsigned element, int32_t value)
{
if (value != cpu->fr[regno].W[element])
TRACE_REGISTER (cpu,
" VR[%2d].<word>[%d] changes from %8x to %8x",
regno, element, cpu->fr[regno].W[element], value);
cpu->fr[regno].W[element] = value;
}
void
aarch64_set_vec_s16 (sim_cpu *cpu, VReg regno, unsigned element, int16_t value)
{
if (value != cpu->fr[regno].H[element])
TRACE_REGISTER (cpu,
" VR[%2d].<half>[%d] changes from %4x to %4x",
regno, element, cpu->fr[regno].H[element], value);
cpu->fr[regno].H[element] = value;
}
void
aarch64_set_vec_s8 (sim_cpu *cpu, VReg regno, unsigned element, int8_t value)
{
if (value != cpu->fr[regno].B[element])
TRACE_REGISTER (cpu,
" VR[%2d].<byte>[%d] changes from %x to %x",
regno, element, cpu->fr[regno].B[element], value);
cpu->fr[regno].B[element] = value;
}

333
sim/aarch64/cpustate.h Normal file
View File

@ -0,0 +1,333 @@
/* cpustate.h -- Prototypes for AArch64 cpu state functions.
Copyright (C) 2015 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 "gdb/remote-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.
N.B. the ARM spec says that when you write a 32 bit register you
are supposed to write the low 32 bits and zero the high 32
bits. But we don't actually have to care about this because Java
will only ever consume the 32 bits value as a 64 bit quantity after
an explicit extend. */
typedef union GRegisterValue
{
int8_t s8;
int16_t s16;
int32_t s32;
int64_t s64;
uint8_t u8;
uint16_t u16;
uint32_t u32;
uint64_t u64;
} 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,
C_IDX,
Z_IDX,
N_IDX
} 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_s64 (sim_cpu *, GReg, int, int64_t);
/* FP Register access functions. */
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_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);
#endif /* _CPU_STATE_H */

418
sim/aarch64/decode.h Normal file
View File

@ -0,0 +1,418 @@
/* decode.h -- Prototypes for AArch64 simulator decoder functions.
Copyright (C) 2015 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 _DECODE_H
#define _DECODE_H
#include <sys/types.h>
#include "cpustate.h"
/* Codes used in conditional instructions
These are passed to conditional operations to identify which
condition to test for. */
typedef enum CondCode
{
EQ = 0x0, /* meaning Z == 1 */
NE = 0x1, /* meaning Z == 0 */
HS = 0x2, /* meaning C == 1 */
CS = HS,
LO = 0x3, /* meaning C == 0 */
CC = LO,
MI = 0x4, /* meaning N == 1 */
PL = 0x5, /* meaning N == 0 */
VS = 0x6, /* meaning V == 1 */
VC = 0x7, /* meaning V == 0 */
HI = 0x8, /* meaning C == 1 && Z == 0 */
LS = 0x9, /* meaning !(C == 1 && Z == 0) */
GE = 0xa, /* meaning N == V */
LT = 0xb, /* meaning N != V */
GT = 0xc, /* meaning Z == 0 && N == V */
LE = 0xd, /* meaning !(Z == 0 && N == V) */
AL = 0xe, /* meaning ANY */
NV = 0xf /* ditto */
} CondCode;
/* Certain addressing modes for load require pre or post writeback of
the computed address to a base register. */
typedef enum WriteBack
{
Post = 0,
Pre = 1,
NoWriteBack = -1
} WriteBack;
/* Certain addressing modes for load require an offset to
be optionally scaled so the decode needs to pass that
through to the execute routine. */
typedef enum Scaling
{
Unscaled = 0,
Scaled = 1,
NoScaling = -1
} Scaling;
/* When we do have to scale we do so by shifting using
log(bytes in data element - 1) as the shift count.
so we don't have to scale offsets when loading
bytes. */
typedef enum ScaleShift
{
ScaleShift16 = 1,
ScaleShift32 = 2,
ScaleShift64 = 3,
ScaleShift128 = 4
} ScaleShift;
/* One of the addressing modes for load requires a 32-bit register
value to be either zero- or sign-extended for these instructions
UXTW or SXTW should be passed.
Arithmetic register data processing operations can optionally
extend a portion of the second register value for these
instructions the value supplied must identify the portion of the
register which is to be zero- or sign-exended. */
typedef enum Extension
{
UXTB = 0,
UXTH = 1,
UXTW = 2,
UXTX = 3,
SXTB = 4,
SXTH = 5,
SXTW = 6,
SXTX = 7,
NoExtension = -1
} Extension;
/* Arithmetic and logical register data processing operations
optionally perform a shift on the second register value. */
typedef enum Shift
{
LSL = 0,
LSR = 1,
ASR = 2,
ROR = 3
} Shift;
/* Bit twiddling helpers for instruction decode. */
/* 32 bit mask with bits [hi,...,lo] set. */
static inline uint32_t
mask32 (int hi, int lo)
{
int nbits = (hi + 1) - lo;
return ((1 << nbits) - 1) << lo;
}
/* 64 bit mask with bits [hi,...,lo] set. */
static inline uint64_t
mask64 (int hi, int lo)
{
int nbits = (hi + 1) - lo;
return ((1L << nbits) - 1) << lo;
}
/* Pick bits [hi,...,lo] from val. */
static inline uint32_t
pick32 (uint32_t val, int hi, int lo)
{
return val & mask32 (hi, lo);
}
/* Pick bits [hi,...,lo] from val. */
static inline uint64_t
pick64 (uint64_t val, int hi, int lo)
{
return val & mask64 (hi, lo);
}
/* Pick bits [hi,...,lo] from val and shift to [(hi-(newlo - lo)),newlo]. */
static inline uint32_t
pickshift32 (uint32_t val, int hi, int lo, int newlo)
{
uint32_t bits = pick32 (val, hi, lo);
if (lo < newlo)
return bits << (newlo - lo);
return bits >> (lo - newlo);
}
/* Mask [hi,lo] and shift down to start at bit 0. */
static inline uint32_t
pickbits32 (uint32_t val, int hi, int lo)
{
return pick32 (val, hi, lo) >> lo;
}
/* Mask [hi,lo] and shift down to start at bit 0. */
static inline uint64_t
pickbits64 (uint64_t val, int hi, int lo)
{
return pick64 (val, hi, lo) >> lo;
}
/* Decode registers, immediates and constants of various types. */
static inline GReg
greg (uint32_t val, int lo)
{
return (GReg) pickbits32 (val, lo + 4, lo);
}
static inline VReg
vreg (uint32_t val, int lo)
{
return (VReg) pickbits32 (val, lo + 4, lo);
}
static inline uint32_t
uimm (uint32_t val, int hi, int lo)
{
return pickbits32 (val, hi, lo);
}
static inline int32_t
simm32 (uint32_t val, int hi, int lo)
{
union
{
uint32_t u;
int32_t n;
} x;
x.u = val << (31 - hi);
return x.n >> (31 - hi + lo);
}
static inline int64_t
simm64 (uint64_t val, int hi, int lo)
{
union
{
uint64_t u;
int64_t n;
} x;
x.u = val << (63 - hi);
return x.n >> (63 - hi + lo);
}
static inline Shift
shift (uint32_t val, int lo)
{
return (Shift) pickbits32 (val, lo + 1, lo);
}
static inline Extension
extension (uint32_t val, int lo)
{
return (Extension) pickbits32 (val, lo + 2, lo);
}
static inline Scaling
scaling (uint32_t val, int lo)
{
return (Scaling) pickbits32 (val, lo, lo);
}
static inline WriteBack
writeback (uint32_t val, int lo)
{
return (WriteBack) pickbits32 (val, lo, lo);
}
static inline CondCode
condcode (uint32_t val, int lo)
{
return (CondCode) pickbits32 (val, lo + 3, lo);
}
/* Operation decode.
Bits [28,24] are the primary dispatch vector. */
static inline uint32_t
dispatchGroup (uint32_t val)
{
return pickshift32 (val, 28, 25, 0);
}
/* The 16 possible values for bits [28,25] identified by tags which
map them to the 5 main instruction groups LDST, DPREG, ADVSIMD,
BREXSYS and DPIMM.
An extra group PSEUDO is included in one of the unallocated ranges
for simulator-specific pseudo-instructions. */
enum DispatchGroup
{
GROUP_PSEUDO_0000,
GROUP_UNALLOC_0001,
GROUP_UNALLOC_0010,
GROUP_UNALLOC_0011,
GROUP_LDST_0100,
GROUP_DPREG_0101,
GROUP_LDST_0110,
GROUP_ADVSIMD_0111,
GROUP_DPIMM_1000,
GROUP_DPIMM_1001,
GROUP_BREXSYS_1010,
GROUP_BREXSYS_1011,
GROUP_LDST_1100,
GROUP_DPREG_1101,
GROUP_LDST_1110,
GROUP_ADVSIMD_1111
};
/* Bits [31, 29] of a Pseudo are the secondary dispatch vector. */
static inline uint32_t
dispatchPseudo (uint32_t val)
{
return pickshift32 (val, 31, 29, 0);
}
/* The 8 possible values for bits [31,29] in a Pseudo Instruction.
Bits [28,25] are always 0000. */
enum DispatchPseudo
{
PSEUDO_UNALLOC_000, /* Unallocated. */
PSEUDO_UNALLOC_001, /* Ditto. */
PSEUDO_UNALLOC_010, /* Ditto. */
PSEUDO_UNALLOC_011, /* Ditto. */
PSEUDO_UNALLOC_100, /* Ditto. */
PSEUDO_UNALLOC_101, /* Ditto. */
PSEUDO_CALLOUT_110, /* CALLOUT -- bits [24,0] identify call/ret sig. */
PSEUDO_HALT_111 /* HALT -- bits [24, 0] identify halt code. */
};
/* Bits [25, 23] of a DPImm are the secondary dispatch vector. */
static inline uint32_t
dispatchDPImm (uint32_t instr)
{
return pickshift32 (instr, 25, 23, 0);
}
/* The 8 possible values for bits [25,23] in a Data Processing Immediate
Instruction. Bits [28,25] are always 100_. */
enum DispatchDPImm
{
DPIMM_PCADR_000, /* PC-rel-addressing. */
DPIMM_PCADR_001, /* Ditto. */
DPIMM_ADDSUB_010, /* Add/Subtract (immediate). */
DPIMM_ADDSUB_011, /* Ditto. */
DPIMM_LOG_100, /* Logical (immediate). */
DPIMM_MOV_101, /* Move Wide (immediate). */
DPIMM_BITF_110, /* Bitfield. */
DPIMM_EXTR_111 /* Extract. */
};
/* Bits [29,28:26] of a LS are the secondary dispatch vector. */
static inline uint32_t
dispatchLS (uint32_t instr)
{
return ( pickshift32 (instr, 29, 28, 1)
| pickshift32 (instr, 26, 26, 0));
}
/* The 8 possible values for bits [29,28:26] in a Load/Store
Instruction. Bits [28,25] are always _1_0. */
enum DispatchLS
{
LS_EXCL_000, /* Load/store exclusive (includes some unallocated). */
LS_ADVSIMD_001, /* AdvSIMD load/store (various -- includes some unallocated). */
LS_LIT_010, /* Load register literal (includes some unallocated). */
LS_LIT_011, /* Ditto. */
LS_PAIR_100, /* Load/store register pair (various). */
LS_PAIR_101, /* Ditto. */
LS_OTHER_110, /* Other load/store formats. */
LS_OTHER_111 /* Ditto. */
};
/* Bits [28:24:21] of a DPReg are the secondary dispatch vector. */
static inline uint32_t
dispatchDPReg (uint32_t instr)
{
return ( pickshift32 (instr, 28, 28, 2)
| pickshift32 (instr, 24, 24, 1)
| pickshift32 (instr, 21, 21, 0));
}
/* The 8 possible values for bits [28:24:21] in a Data Processing
Register Instruction. Bits [28,25] are always _101. */
enum DispatchDPReg
{
DPREG_LOG_000, /* Logical (shifted register). */
DPREG_LOG_001, /* Ditto. */
DPREG_ADDSHF_010, /* Add/subtract (shifted register). */
DPREG_ADDEXT_011, /* Add/subtract (extended register). */
DPREG_ADDCOND_100, /* Add/subtract (with carry) AND
Cond compare/select AND
Data Processing (1/2 source). */
DPREG_UNALLOC_101, /* Unallocated. */
DPREG_3SRC_110, /* Data Processing (3 source). */
DPREG_3SRC_111 /* Data Processing (3 source). */
};
/* bits [31,29] of a BrExSys are the secondary dispatch vector. */
static inline uint32_t
dispatchBrExSys (uint32_t instr)
{
return pickbits32 (instr, 31, 29);
}
/* The 8 possible values for bits [31,29] in a Branch/Exception/System
Instruction. Bits [28,25] are always 101_. */
enum DispatchBr
{
BR_IMM_000, /* Unconditional branch (immediate). */
BR_IMMCMP_001, /* Compare & branch (immediate) AND
Test & branch (immediate). */
BR_IMMCOND_010, /* Conditional branch (immediate) AND Unallocated. */
BR_UNALLOC_011, /* Unallocated. */
BR_IMM_100, /* Unconditional branch (immediate). */
BR_IMMCMP_101, /* Compare & branch (immediate) AND
Test & branch (immediate). */
BR_REG_110, /* Unconditional branch (register) AND System AND
Excn gen AND Unallocated. */
BR_UNALLOC_111 /* Unallocated. */
};
/* TODO still need to provide secondary decode and dispatch for
AdvSIMD Insructions with instr[28,25] = 0111 or 1111. */
#endif /* _DECODE_H */

483
sim/aarch64/interp.c Normal file
View File

@ -0,0 +1,483 @@
/* interp.c -- AArch64 sim interface to GDB.
Copyright (C) 2015 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/>. */
#include "config.h"
#include <stdio.h>
#include <assert.h>
#include <signal.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include "ansidecl.h"
#include "gdb/callback.h"
#include "gdb/remote-sim.h"
#include "gdb/signals.h"
#include "gdb/sim-aarch64.h"
#include "sim-main.h"
#include "sim-options.h"
#include "memory.h"
#include "simulator.h"
#include "dis-asm.h"
static struct disassemble_info info;
static unsigned long symcount = 0;
static asymbol ** symtab = NULL;
/* FIXME: 1000 characters should be enough to hold the disassembled
instruction plus any comments that come after it. But maybe with
C++ programs this might not be enough. Not sure if it is worth
adding logic to dynamically grow the buffer though. */
static char opbuf[1000];
static int op_printf (void *, const char *, ...) ATTRIBUTE_FPTR_PRINTF_2;
static int
op_printf (void *stream ATTRIBUTE_UNUSED, const char *fmt, ...)
{
size_t space_remaining;
int ret;
va_list ap;
space_remaining = sizeof (opbuf) - strlen (opbuf);
va_start (ap, fmt);
/* Instead of printing to stream we store the text in opbuf.
This allows us to use the sim_io_eprintf routine to output
the text in aarch64_print_insn. */
ret = vsnprintf (opbuf + strlen (opbuf), space_remaining, fmt, ap);
va_end (ap);
return ret;
}
void
aarch64_print_insn (SIM_DESC sd, uint64_t addr)
{
int size;
opbuf[0] = 0;
size = print_insn_aarch64 (addr, & info);
sim_io_eprintf (sd, " %*s\n", size, opbuf);
}
static int
sim_dis_read (bfd_vma memaddr,
bfd_byte * ptr,
unsigned int length,
struct disassemble_info * info)
{
aarch64_get_mem_blk (info->private_data, memaddr, (char *) ptr, length);
return 0;
}
/* Filter out (in place) symbols that are useless for disassembly.
COUNT is the number of elements in SYMBOLS.
Return the number of useful symbols. */
static unsigned long
remove_useless_symbols (asymbol **symbols, unsigned long count)
{
asymbol **in_ptr = symbols;
asymbol **out_ptr = symbols;
while (count-- > 0)
{
asymbol *sym = *in_ptr++;
if (strstr (sym->name, "gcc2_compiled"))
continue;
if (sym->name == NULL || sym->name[0] == '\0')
continue;
if (sym->flags & (BSF_DEBUGGING))
continue;
if ( bfd_is_und_section (sym->section)
|| bfd_is_com_section (sym->section))
continue;
if (sym->name[0] == '$')
continue;
*out_ptr++ = sym;
}
return out_ptr - symbols;
}
static signed int
compare_symbols (const void *ap, const void *bp)
{
const asymbol *a = * (const asymbol **) ap;
const asymbol *b = * (const asymbol **) bp;
if (bfd_asymbol_value (a) > bfd_asymbol_value (b))
return 1;
if (bfd_asymbol_value (a) < bfd_asymbol_value (b))
return -1;
return 0;
}
/* Find the name of the function at ADDR. */
const char *
aarch64_get_func (uint64_t addr)
{
int min, max;
min = -1;
max = symcount;
while (min < max - 1)
{
int sym;
bfd_vma sa;
sym = (min + max) / 2;
sa = bfd_asymbol_value (symtab[sym]);
if (sa > addr)
max = sym;
else if (sa < addr)
min = sym;
else
{
min = sym;
break;
}
}
if (min != -1)
return bfd_asymbol_name (symtab [min]);
return "";
}
uint64_t
aarch64_get_sym_value (const char *name)
{
unsigned long i;
for (i = 0; i < symcount; i++)
if (strcmp (bfd_asymbol_name (symtab[i]), name) == 0)
return bfd_asymbol_value (symtab[i]);
return 0;
}
SIM_RC
sim_create_inferior (SIM_DESC sd, struct bfd *abfd, char **argv, char **env)
{
sim_cpu *cpu = STATE_CPU (sd, 0);
long storage;
bfd_vma addr = 0;
if (abfd != NULL)
addr = bfd_get_start_address (abfd);
aarch64_set_next_PC (cpu, addr);
aarch64_update_PC (cpu);
/* Standalone mode (ie aarch64-elf-run) will take care of the argv
for us in sim_open() -> sim_parse_args(). But in debug mode (i.e.
'target sim' with `aarch64-...-gdb`), we need to handle it. */
if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG)
{
freeargv (STATE_PROG_ARGV (sd));
STATE_PROG_ARGV (sd) = dupargv (argv);
}
memset (& info, 0, sizeof (info));
init_disassemble_info (& info, NULL, op_printf);
info.read_memory_func = sim_dis_read;
info.arch = bfd_get_arch (abfd);
info.mach = bfd_get_mach (abfd);
info.private_data = cpu;
if (info.mach == 0)
info.arch = bfd_arch_aarch64;
disassemble_init_for_target (& info);
storage = bfd_get_symtab_upper_bound (abfd);
if (storage > 0)
{
symtab = (asymbol **) xmalloc (storage);
symcount = bfd_canonicalize_symtab (abfd, symtab);
symcount = remove_useless_symbols (symtab, symcount);
qsort (symtab, symcount, sizeof (asymbol *), compare_symbols);
}
aarch64_init (cpu, bfd_get_start_address (abfd));
return SIM_RC_OK;
}
/* Read the LENGTH bytes at BUF as a little-endian value. */
static bfd_vma
get_le (unsigned char *buf, unsigned int length)
{
bfd_vma acc = 0;
while (length -- > 0)
acc = (acc << 8) + buf[length];
return acc;
}
/* Store VAL as a little-endian value in the LENGTH bytes at BUF. */
static void
put_le (unsigned char *buf, unsigned int length, bfd_vma val)
{
int i;
for (i = 0; i < length; i++)
{
buf[i] = val & 0xff;
val >>= 8;
}
}
static int
check_regno (int regno)
{
return 0 <= regno && regno < AARCH64_MAX_REGNO;
}
static size_t
reg_size (int regno)
{
if (regno == AARCH64_CPSR_REGNO || regno == AARCH64_FPSR_REGNO)
return 32;
return 64;
}
static int
aarch64_reg_get (SIM_CPU *cpu, int regno, unsigned char *buf, int length)
{
size_t size;
bfd_vma val;
if (!check_regno (regno))
return 0;
size = reg_size (regno);
if (length != size)
return 0;
switch (regno)
{
case AARCH64_MIN_GR ... AARCH64_MAX_GR:
val = aarch64_get_reg_u64 (cpu, regno, 0);
break;
case AARCH64_MIN_FR ... AARCH64_MAX_FR:
val = aarch64_get_FP_double (cpu, regno - 32);
break;
case AARCH64_PC_REGNO:
val = aarch64_get_PC (cpu);
break;
case AARCH64_CPSR_REGNO:
val = aarch64_get_CPSR (cpu);
break;
case AARCH64_FPSR_REGNO:
val = aarch64_get_FPSR (cpu);
break;
default:
sim_io_eprintf (CPU_STATE (cpu),
"sim: unrecognized register number: %d\n", regno);
return -1;
}
put_le (buf, length, val);
return size;
}
static int
aarch64_reg_set (SIM_CPU *cpu, int regno, unsigned char *buf, int length)
{
size_t size;
bfd_vma val;
if (!check_regno (regno))
return -1;
size = reg_size (regno);
if (length != size)
return -1;
val = get_le (buf, length);
switch (regno)
{
case AARCH64_MIN_GR ... AARCH64_MAX_GR:
aarch64_set_reg_u64 (cpu, regno, 1, val);
break;
case AARCH64_MIN_FR ... AARCH64_MAX_FR:
aarch64_set_FP_double (cpu, regno - 32, (double) val);
break;
case AARCH64_PC_REGNO:
aarch64_set_next_PC (cpu, val);
aarch64_update_PC (cpu);
break;
case AARCH64_CPSR_REGNO:
aarch64_set_CPSR (cpu, val);
break;
case AARCH64_FPSR_REGNO:
aarch64_set_FPSR (cpu, val);
break;
default:
sim_io_eprintf (CPU_STATE (cpu),
"sim: unrecognized register number: %d\n", regno);
return 0;
}
return size;
}
static sim_cia
aarch64_pc_get (sim_cpu *cpu)
{
return aarch64_get_PC (cpu);
}
static void
aarch64_pc_set (sim_cpu *cpu, sim_cia pc)
{
aarch64_set_next_PC (cpu, pc);
aarch64_update_PC (cpu);
}
static void
free_state (SIM_DESC sd)
{
if (STATE_MODULES (sd) != NULL)
sim_module_uninstall (sd);
sim_cpu_free_all (sd);
sim_state_free (sd);
}
enum
{
OPTION_DISAS = OPTION_START,
};
static SIM_RC
aarch64_option_handler (SIM_DESC sd ATTRIBUTE_UNUSED,
sim_cpu * current_cpu ATTRIBUTE_UNUSED,
int opt,
char * arg ATTRIBUTE_UNUSED,
int is_command ATTRIBUTE_UNUSED)
{
switch (opt)
{
case OPTION_DISAS:
disas = TRUE;
return SIM_RC_OK;
default:
sim_io_eprintf (sd, "Unknown AArch64 option %d\n", opt);
return SIM_RC_FAIL;
}
}
static DECLARE_OPTION_HANDLER (aarch64_option_handler);
const OPTION aarch64_options[] =
{
{ {"disas", no_argument, NULL, OPTION_DISAS },
'\0', NULL, "Enable instruction disassembly",
aarch64_option_handler, NULL },
{ {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL, NULL }
};
SIM_DESC
sim_open (SIM_OPEN_KIND kind,
struct host_callback_struct * callback,
struct bfd * abfd,
char ** argv)
{
int i;
sim_cpu *cpu;
SIM_DESC sd = sim_state_alloc (kind, callback);
if (sd == NULL)
return sd;
SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
sim_add_option_table (sd, NULL, aarch64_options);
/* Perform the initialization steps one by one. */
if (sim_cpu_alloc_all (sd, 1, 0) != SIM_RC_OK
|| sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK
|| sim_parse_args (sd, argv) != SIM_RC_OK
|| sim_analyze_program (sd,
(STATE_PROG_ARGV (sd) != NULL
? *STATE_PROG_ARGV (sd)
: NULL), abfd) != SIM_RC_OK
|| sim_config (sd) != SIM_RC_OK
|| sim_post_argv_init (sd) != SIM_RC_OK)
{
free_state (sd);
return NULL;
}
aarch64_init_LIT_table ();
assert (MAX_NR_PROCESSORS == 1);
cpu = STATE_CPU (sd, 0);
CPU_PC_FETCH (cpu) = aarch64_pc_get;
CPU_PC_STORE (cpu) = aarch64_pc_set;
CPU_REG_FETCH (cpu) = aarch64_reg_get;
CPU_REG_STORE (cpu) = aarch64_reg_set;
/* Set SP, FP and PC to 0 and set LR to -1
so we can detect a top-level return. */
aarch64_set_reg_u64 (cpu, SP, 1, 0);
aarch64_set_reg_u64 (cpu, FP, 1, 0);
aarch64_set_reg_u64 (cpu, LR, 1, TOP_LEVEL_RETURN_PC);
aarch64_set_next_PC (cpu, 0);
aarch64_update_PC (cpu);
/* Default to a 128 Mbyte (== 2^27) memory space. */
sim_do_commandf (sd, "memory-size 0x8000000");
return sd;
}
void
sim_engine_run (SIM_DESC sd,
int next_cpu_nr ATTRIBUTE_UNUSED,
int nr_cpus ATTRIBUTE_UNUSED,
int siggnal ATTRIBUTE_UNUSED)
{
aarch64_run (sd);
}

196
sim/aarch64/memory.c Normal file
View File

@ -0,0 +1,196 @@
/* memory.c -- Memory accessor functions for the AArch64 simulator
Copyright (C) 2015 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/>. */
#include "config.h"
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "bfd.h"
#include "libbfd.h"
#include "libiberty.h"
#include "elf/internal.h"
#include "elf/common.h"
#include "memory.h"
#include "simulator.h"
#include "sim-core.h"
static inline void
mem_error (sim_cpu *cpu, const char *message, uint64_t addr)
{
if (disas)
sim_io_eprintf (CPU_STATE (cpu), "\n");
TRACE_MEMORY (cpu, "ERROR: %s: %" PRIx64, message, addr);
}
#define FETCH_FUNC(RETURN_TYPE, ACCESS_TYPE, NAME, N) \
RETURN_TYPE \
aarch64_get_mem_##NAME (sim_cpu *cpu, uint64_t address) \
{ \
return (RETURN_TYPE) sim_core_read_##N (cpu, 0, read_map, address); \
}
/* A variant of the FETCH_FUNC macro that uses unaligned reads.
The AArch64 only requires 4-byte alignment for 8-byte quantities
but the sim common core does not support this. */
#define FETCH_FUNC_U(RETURN_TYPE, ACCESS_TYPE, NAME) \
RETURN_TYPE \
aarch64_get_mem_##NAME (sim_cpu *cpu, uint64_t address) \
{ \
return (RETURN_TYPE) sim_core_read_unaligned_8 (cpu, 0, read_map, address); \
}
FETCH_FUNC_U (uint64_t, uint64_t, u64)
FETCH_FUNC_U (int64_t, int64_t, s64)
FETCH_FUNC (uint32_t, uint32_t, u32, 4)
FETCH_FUNC (int32_t, int32_t, s32, 4)
FETCH_FUNC (uint32_t, uint16_t, u16, 2)
FETCH_FUNC (int32_t, int16_t, s16, 2)
FETCH_FUNC (uint32_t, uint8_t, u8, 1)
FETCH_FUNC (int32_t, int8_t, s8, 1)
FETCH_FUNC (float, float, float, 4)
FETCH_FUNC_U (double, double, double)
void
aarch64_get_mem_long_double (sim_cpu *cpu, uint64_t address, FRegister *a)
{
a->v[0] = sim_core_read_unaligned_8 (cpu, 0, read_map, address);
a->v[1] = sim_core_read_unaligned_8 (cpu, 0, read_map, address + 8);
}
#define STORE_FUNC(TYPE, NAME, N) \
void \
aarch64_set_mem_##NAME (sim_cpu *cpu, uint64_t address, TYPE value) \
{ \
TRACE_MEMORY (cpu, \
"write of %" PRIx64 " (%d bytes) to %" PRIx64, \
(uint64_t) value, N, address); \
\
sim_core_write_unaligned_##N (cpu, 0, write_map, address, value); \
}
/* A variant of the STORE_FUNC macro that uses unaligned writes.
The AArch64 only requires 4-byte alignment for 8-byte quantities
but the sim common core does not support this. */
#define STORE_FUNC_U(TYPE, NAME) \
void \
aarch64_set_mem_##NAME (sim_cpu *cpu, uint64_t address, TYPE value) \
{ \
TRACE_MEMORY (cpu, \
"write of %" PRIx64 " (8 bytes) to %" PRIx64, \
(uint64_t) value, address); \
\
sim_core_write_unaligned_8 (cpu, 0, write_map, address, value); \
}
STORE_FUNC_U (uint64_t, u64)
STORE_FUNC_U (int64_t, s64)
STORE_FUNC (uint32_t, u32, 4)
STORE_FUNC (int32_t, s32, 4)
STORE_FUNC (uint16_t, u16, 2)
STORE_FUNC (int16_t, s16, 2)
STORE_FUNC (uint8_t, u8, 1)
STORE_FUNC (int8_t, s8, 1)
STORE_FUNC (float, float, 4)
STORE_FUNC_U (double, double)
void
aarch64_set_mem_long_double (sim_cpu *cpu, uint64_t address, FRegister a)
{
TRACE_MEMORY (cpu,
"write of long double %" PRIx64 " %" PRIx64 " to %" PRIx64,
a.v[0], a.v[1], address);
sim_core_write_unaligned_8 (cpu, 0, write_map, address, a.v[0]);
sim_core_write_unaligned_8 (cpu, 0, write_map, address + 8, a.v[1]);
}
void
aarch64_get_mem_blk (sim_cpu * cpu,
uint64_t address,
char * buffer,
unsigned length)
{
unsigned len;
len = sim_core_read_buffer (CPU_STATE (cpu), cpu, read_map,
buffer, address, length);
if (len == length)
return;
memset (buffer, 0, length);
if (cpu)
mem_error (cpu, "read of non-existant mem block at", address);
sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
sim_stopped, SIM_SIGBUS);
}
const char *
aarch64_get_mem_ptr (sim_cpu *cpu, uint64_t address)
{
char *addr = sim_core_trans_addr (CPU_STATE (cpu), cpu, read_map, address);
if (addr == NULL)
{
mem_error (cpu, "request for non-existant mem addr of", address);
sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
sim_stopped, SIM_SIGBUS);
}
return addr;
}
/* We implement a combined stack and heap. That way the sbrk()
function in libgloss/aarch64/syscalls.c has a chance to detect
an out-of-memory condition by noticing a stack/heap collision.
The heap starts at the end of loaded memory and carries on up
to an arbitary 2Gb limit. */
uint64_t
aarch64_get_heap_start (sim_cpu *cpu)
{
uint64_t heap = aarch64_get_sym_value ("end");
if (heap == 0)
heap = aarch64_get_sym_value ("_end");
if (heap == 0)
{
heap = STACK_TOP - 0x100000;
sim_io_eprintf (CPU_STATE (cpu),
"Unable to find 'end' symbol - using addr based "
"upon stack instead %" PRIx64 "\n",
heap);
}
return heap;
}
uint64_t
aarch64_get_stack_start (sim_cpu *cpu)
{
if (aarch64_get_heap_start (cpu) >= STACK_TOP)
mem_error (cpu, "executable is too big", aarch64_get_heap_start (cpu));
return STACK_TOP;
}

64
sim/aarch64/memory.h Normal file
View File

@ -0,0 +1,64 @@
/* memory.h -- Prototypes for AArch64 memory accessor functions.
Copyright (C) 2015 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 _MEMORY_H
#define _MEMORY_H
#include <sys/types.h>
#include "bfd.h"
#include "simulator.h"
extern float aarch64_get_mem_float (sim_cpu *, uint64_t);
extern double aarch64_get_mem_double (sim_cpu *, uint64_t);
extern void aarch64_get_mem_long_double (sim_cpu *, uint64_t, FRegister *);
extern uint64_t aarch64_get_mem_u64 (sim_cpu *, uint64_t);
extern int64_t aarch64_get_mem_s64 (sim_cpu *, uint64_t);
extern uint32_t aarch64_get_mem_u32 (sim_cpu *, uint64_t);
extern int32_t aarch64_get_mem_s32 (sim_cpu *, uint64_t);
extern uint32_t aarch64_get_mem_u16 (sim_cpu *, uint64_t);
extern int32_t aarch64_get_mem_s16 (sim_cpu *, uint64_t);
extern uint32_t aarch64_get_mem_u8 (sim_cpu *, uint64_t);
extern int32_t aarch64_get_mem_s8 (sim_cpu *, uint64_t);
extern void aarch64_get_mem_blk (sim_cpu *, uint64_t, char *, unsigned);
extern const char * aarch64_get_mem_ptr (sim_cpu *, uint64_t);
extern void aarch64_set_mem_float (sim_cpu *, uint64_t, float);
extern void aarch64_set_mem_double (sim_cpu *, uint64_t, double);
extern void aarch64_set_mem_long_double (sim_cpu *, uint64_t, FRegister);
extern void aarch64_set_mem_u64 (sim_cpu *, uint64_t, uint64_t);
extern void aarch64_set_mem_s64 (sim_cpu *, uint64_t, int64_t);
extern void aarch64_set_mem_u32 (sim_cpu *, uint64_t, uint32_t);
extern void aarch64_set_mem_s32 (sim_cpu *, uint64_t, int32_t);
extern void aarch64_set_mem_u16 (sim_cpu *, uint64_t, uint16_t);
extern void aarch64_set_mem_s16 (sim_cpu *, uint64_t, int16_t);
extern void aarch64_set_mem_u8 (sim_cpu *, uint64_t, uint8_t);
extern void aarch64_set_mem_s8 (sim_cpu *, uint64_t, int8_t);
#define STACK_TOP 0x07FFFF00
extern uint64_t aarch64_get_heap_start (sim_cpu *);
extern uint64_t aarch64_get_stack_start (sim_cpu *);
extern void mem_add_blk (sim_cpu *, uint64_t, char *, uint64_t, bfd_boolean);
#endif /* _MEMORY_H */

68
sim/aarch64/sim-main.h Normal file
View File

@ -0,0 +1,68 @@
/* sim-main.h -- Interface with sim/common.
Copyright (C) 2015 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 _SIM_MAIN_H
#define _SIM_MAIN_H
#include "sim-basics.h"
#include "sim-types.h"
#include "sim-base.h"
#include "sim-base.h"
#include "sim-io.h"
#include "cpustate.h"
/* A per-core state structure. */
struct _sim_cpu
{
GRegister gr[33]; /* Extra register at index 32 is used to hold zero value. */
FRegister fr[32];
uint64_t pc;
uint32_t CPSR;
uint32_t FPSR;
uint64_t nextpc;
uint32_t instr;
sim_cpu_base base;
};
typedef enum
{
AARCH64_MIN_GR = 0,
AARCH64_MAX_GR = 31,
AARCH64_MIN_FR = 32,
AARCH64_MAX_FR = 63,
AARCH64_PC_REGNO = 64,
AARCH64_CPSR_REGNO = 65,
AARCH64_FPSR_REGNO = 66,
AARCH64_MAX_REGNO = 67
} aarch64_regno;
/* The simulator state structure used to hold all global variables. */
struct sim_state
{
sim_cpu * cpu[MAX_NR_PROCESSORS];
sim_state_base base;
};
#endif /* _SIM_MAIN_H */

13047
sim/aarch64/simulator.c Normal file

File diff suppressed because it is too large Load Diff

57
sim/aarch64/simulator.h Normal file
View File

@ -0,0 +1,57 @@
/* simulator.h -- Prototypes for AArch64 simulator functions.
Copyright (C) 2015 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 _SIMULATOR_H
#define _SIMULATOR_H
#include "config.h"
#include <sys/types.h>
#include <setjmp.h>
#include "sim-main.h"
#include "decode.h"
extern bfd_boolean disas;
#define TOP_LEVEL_RETURN_PC 0xffffffffffffffecULL
/* Call this to set the start stack pointer, frame pointer and pc
before calling run or step. Also sets link register to a special
value (-20) so we can detect a top level return. This function
should be called from the sim setup routine running on the alt
stack, and should pass in the current top of C stack for SP and
the FP of the caller for fp. PC should be sthe start of the
AARCH64 code segment to be executed. */
extern void aarch64_init (sim_cpu *, uint64_t);
/* Call this to run from the current PC without stopping until we
either return from the top frame, execute a halt or break or we
hit an error. */
extern void aarch64_run (SIM_DESC);
extern const char * aarch64_get_func (uint64_t);
extern void aarch64_print_insn (SIM_DESC, uint64_t);
extern uint64_t aarch64_get_sym_value (const char *);
extern void aarch64_init_LIT_table (void);
#endif /* _SIMULATOR_H */

16
sim/configure vendored
View File

@ -634,7 +634,8 @@ CFLAGS
LDFLAGS
LIBS
CPPFLAGS'
ac_subdirs_all='arm
ac_subdirs_all='aarch64
arm
avr
bfin
cr16
@ -3625,12 +3626,19 @@ sim_common=yes
sim_igen=no
sim_arch=
case "${target}" in
aarch64*-*-*)
sim_arch=aarch64
subdirs="$subdirs aarch64"
;;
arm*-*-*)
sim_arch=arm
subdirs="$subdirs arm"
subdirs="$subdirs arm"
;;

View File

@ -15,6 +15,9 @@ sim_common=yes
sim_igen=no
sim_arch=
case "${target}" in
aarch64*-*-*)
SIM_ARCH(aarch64)
;;
arm*-*-*)
SIM_ARCH(arm)
;;

View File

@ -1,3 +1,8 @@
2015-11-24 Nick Clifton <nickc@redhat.com>
* configure: Regenerate.
* sim/aarch64: New directory.
2015-11-14 Mike Frysinger <vapier@gentoo.org>
* lib/sim-defs.exp (slurp_options): Pull in global subdir/srcdir.

View File

@ -1827,6 +1827,9 @@ sim_common=yes
sim_igen=no
sim_arch=
case "${target}" in
aarch64*-*-*)
sim_arch=aarch64
;;
arm*-*-*)
sim_arch=arm
;;

View File

@ -0,0 +1,3 @@
2015-11-24 Nick Clifton <nickc@redhat.com>
* pass.s, allinsn.exp, testutils.inc: New files.

View File

@ -0,0 +1,15 @@
# AArch64 simulator testsuite
if [istarget aarch64*-*] {
# all machines
set all_machs "aarch64"
foreach src [lsort [glob -nocomplain $srcdir/$subdir/*.s]] {
# If we're only testing specific files and this isn't one of them,
# skip it.
if ![runtest_file_p $runtests $src] {
continue
}
run_sim_test $src $all_machs
}
}

View File

@ -0,0 +1,7 @@
# check that the sim doesn't die immediately.
# mach: aarch64
.include "testutils.inc"
start
pass

View File

@ -0,0 +1,72 @@
# MACRO: exit
# Terminates execution.
.macro exit nr
stp x29, x30, [sp,#-32]!
mov x4, #0x26
mov x7, #\nr
mov x29, sp
movk x4, #0x2, lsl #16
add x1, x29, #0x10
str x4, [x29,#16]
str x7, [x29,#24]
mov w0, #0x18
hlt #0xf000
.endm
# MACRO: swiwrite
# Writes the string in X1 to stdout
.macro swiwrite len
stp x29, x30, [sp,#-48]!
mov x0, #1
mov x2, #\len
mov x29, sp
str x0, [x29,#24]
str x1, [x29,#32]
str x2, [x29,#40]
mov w0, #0x5
add x1, x29, #0x18
hlt #0xf000
ldp x29, x30, [sp],#48
ret
.endm
# MACRO: pass
# Write 'pass' to stdout and quit
.macro pass
adrp x1, .Lpass
add x1, x1, :lo12:.Lpass
swiwrite 5
exit 0
.data
.Lpass:
.asciz "pass\n"
.endm
# MACRO: fail
# Write 'fail' to stdout and quit
.macro fail
adrp x1, .Lfail
add x1, x1, :lo12:.Lfail
swiwrite 5
exit 0
.data
.Lfail:
.asciz "fail\n"
.endm
# MACRO: start
# All assembler tests should start with a call to "start"
.macro start
.text
.global _start
_start:
.endm