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:
parent
351e610191
commit
2e8cf49e13
@ -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
48
include/gdb/sim-aarch64.h
Normal 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
|
@ -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
36
sim/aarch64/Makefile.in
Normal 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
110
sim/aarch64/aclocal.m4
vendored
Normal 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
160
sim/aarch64/config.in
Normal 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
15689
sim/aarch64/configure
vendored
Executable file
File diff suppressed because it is too large
Load Diff
39
sim/aarch64/configure.ac
Normal file
39
sim/aarch64/configure.ac
Normal 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
557
sim/aarch64/cpustate.c
Normal 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
333
sim/aarch64/cpustate.h
Normal 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
418
sim/aarch64/decode.h
Normal 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
483
sim/aarch64/interp.c
Normal 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
196
sim/aarch64/memory.c
Normal 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
64
sim/aarch64/memory.h
Normal 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
68
sim/aarch64/sim-main.h
Normal 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
13047
sim/aarch64/simulator.c
Normal file
File diff suppressed because it is too large
Load Diff
57
sim/aarch64/simulator.h
Normal file
57
sim/aarch64/simulator.h
Normal 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
16
sim/configure
vendored
@ -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"
|
||||
|
||||
|
||||
;;
|
||||
|
@ -15,6 +15,9 @@ sim_common=yes
|
||||
sim_igen=no
|
||||
sim_arch=
|
||||
case "${target}" in
|
||||
aarch64*-*-*)
|
||||
SIM_ARCH(aarch64)
|
||||
;;
|
||||
arm*-*-*)
|
||||
SIM_ARCH(arm)
|
||||
;;
|
||||
|
@ -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.
|
||||
|
3
sim/testsuite/configure
vendored
3
sim/testsuite/configure
vendored
@ -1827,6 +1827,9 @@ sim_common=yes
|
||||
sim_igen=no
|
||||
sim_arch=
|
||||
case "${target}" in
|
||||
aarch64*-*-*)
|
||||
sim_arch=aarch64
|
||||
;;
|
||||
arm*-*-*)
|
||||
sim_arch=arm
|
||||
;;
|
||||
|
3
sim/testsuite/sim/aarch64/ChangeLog
Normal file
3
sim/testsuite/sim/aarch64/ChangeLog
Normal file
@ -0,0 +1,3 @@
|
||||
2015-11-24 Nick Clifton <nickc@redhat.com>
|
||||
|
||||
* pass.s, allinsn.exp, testutils.inc: New files.
|
15
sim/testsuite/sim/aarch64/allinsn.exp
Normal file
15
sim/testsuite/sim/aarch64/allinsn.exp
Normal 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
|
||||
}
|
||||
}
|
7
sim/testsuite/sim/aarch64/pass.s
Normal file
7
sim/testsuite/sim/aarch64/pass.s
Normal file
@ -0,0 +1,7 @@
|
||||
# check that the sim doesn't die immediately.
|
||||
# mach: aarch64
|
||||
|
||||
.include "testutils.inc"
|
||||
|
||||
start
|
||||
pass
|
72
sim/testsuite/sim/aarch64/testutils.inc
Normal file
72
sim/testsuite/sim/aarch64/testutils.inc
Normal 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
|
Loading…
Reference in New Issue
Block a user