[v6,1/3] PRU Simulator port
Commit Message
I'd like to contribute a sim port for the TI PRU I/O processor. This
is the sixth version of the patch series.
Changes since patch series v5:
- Added copyright headers to test cases.
- Regenerated using autoconf-2.69 and automake-1.5.1
- Added more comments to functions and MAC register enum.
- Updated copyright years.
v1: https://sourceware.org/ml/gdb-patches/2016-12/msg00143.html
v2: https://sourceware.org/ml/gdb-patches/2017-02/msg00397.html
v3: https://sourceware.org/ml/gdb-patches/2017-02/msg00516.html
v4: https://sourceware.org/ml/gdb-patches/2018-06/msg00484.html
v5: https://sourceware.org/ml/gdb-patches/2019-08/msg00584.html
gdb/ChangeLog:
2019-09-04 Dimitar Dimitrov <dimitar@dinux.eu>
* NEWS: Mention new simulator port for PRU.
sim/
2019-09-04 Dimitar Dimitrov <dimitar@dinux.eu>
* MAINTAINERS: Add myself as PRU maintainer.
* configure: Regenerated.
* configure.tgt: Add PRU.
sim/common/
2019-09-04 Dimitar Dimitrov <dimitar@dinux.eu>
* gennltvals.sh: Add PRU libgloss target.
* nltvals.def: Regenerate from the latest libgloss sources.
sim/pru/
2019-09-04 Dimitar Dimitrov <dimitar@dinux.eu>
* Makefile.in: New file.
* aclocal.m4: Regenerated.
* config.in: Regenerated.
* configure: Regenerated.
* configure.ac: New file.
* interp.c: New file.
* pru.h: New file.
* pru.isa: New file.
* sim-main.h: New file.
Signed-off-by: Dimitar Dimitrov <dimitar@dinux.eu>
---
gdb/NEWS | 4 +
sim/MAINTAINERS | 1 +
sim/common/gennltvals.sh | 4 +
sim/common/nltvals.def | 31 ++
sim/configure | 8 +
sim/configure.tgt | 3 +
sim/pru/Makefile.in | 29 ++
sim/pru/aclocal.m4 | 119 ++++++
sim/pru/config.in | 248 ++++++++++++
sim/pru/configure.ac | 31 ++
sim/pru/interp.c | 848 +++++++++++++++++++++++++++++++++++++++
sim/pru/pru.h | 110 +++++
sim/pru/pru.isa | 249 ++++++++++++
sim/pru/sim-main.h | 91 +++++
14 files changed, 1776 insertions(+)
create mode 100644 sim/pru/Makefile.in
create mode 100644 sim/pru/aclocal.m4
create mode 100644 sim/pru/config.in
create mode 100644 sim/pru/configure.ac
create mode 100644 sim/pru/interp.c
create mode 100644 sim/pru/pru.h
create mode 100644 sim/pru/pru.isa
create mode 100644 sim/pru/sim-main.h
Comments
Since the new file is rather big, I'm sending it as a separate bzipped patch.
Regards,
Dimitar
Ping.
On Wednesday, 4 Sep 2019, 22:40:29 EEST Dimitar Dimitrov wrote:
> I'd like to contribute a sim port for the TI PRU I/O processor. This
> is the sixth version of the patch series.
>
> Changes since patch series v5:
> - Added copyright headers to test cases.
> - Regenerated using autoconf-2.69 and automake-1.5.1
> - Added more comments to functions and MAC register enum.
> - Updated copyright years.
>
> v1: https://sourceware.org/ml/gdb-patches/2016-12/msg00143.html
> v2: https://sourceware.org/ml/gdb-patches/2017-02/msg00397.html
> v3: https://sourceware.org/ml/gdb-patches/2017-02/msg00516.html
> v4: https://sourceware.org/ml/gdb-patches/2018-06/msg00484.html
> v5: https://sourceware.org/ml/gdb-patches/2019-08/msg00584.html
>
> gdb/ChangeLog:
>
> 2019-09-04 Dimitar Dimitrov <dimitar@dinux.eu>
>
> * NEWS: Mention new simulator port for PRU.
>
> sim/
> 2019-09-04 Dimitar Dimitrov <dimitar@dinux.eu>
>
> * MAINTAINERS: Add myself as PRU maintainer.
> * configure: Regenerated.
> * configure.tgt: Add PRU.
>
> sim/common/
> 2019-09-04 Dimitar Dimitrov <dimitar@dinux.eu>
>
> * gennltvals.sh: Add PRU libgloss target.
> * nltvals.def: Regenerate from the latest libgloss sources.
>
> sim/pru/
> 2019-09-04 Dimitar Dimitrov <dimitar@dinux.eu>
>
> * Makefile.in: New file.
> * aclocal.m4: Regenerated.
> * config.in: Regenerated.
> * configure: Regenerated.
> * configure.ac: New file.
> * interp.c: New file.
> * pru.h: New file.
> * pru.isa: New file.
> * sim-main.h: New file.
>
> Signed-off-by: Dimitar Dimitrov <dimitar@dinux.eu>
> ---
> gdb/NEWS | 4 +
> sim/MAINTAINERS | 1 +
> sim/common/gennltvals.sh | 4 +
> sim/common/nltvals.def | 31 ++
> sim/configure | 8 +
> sim/configure.tgt | 3 +
> sim/pru/Makefile.in | 29 ++
> sim/pru/aclocal.m4 | 119 ++++++
> sim/pru/config.in | 248 ++++++++++++
> sim/pru/configure.ac | 31 ++
> sim/pru/interp.c | 848 +++++++++++++++++++++++++++++++++++++++
> sim/pru/pru.h | 110 +++++
> sim/pru/pru.isa | 249 ++++++++++++
> sim/pru/sim-main.h | 91 +++++
> 14 files changed, 1776 insertions(+)
> create mode 100644 sim/pru/Makefile.in
> create mode 100644 sim/pru/aclocal.m4
> create mode 100644 sim/pru/config.in
> create mode 100644 sim/pru/configure.ac
> create mode 100644 sim/pru/interp.c
> create mode 100644 sim/pru/pru.h
> create mode 100644 sim/pru/pru.isa
> create mode 100644 sim/pru/sim-main.h
>
> diff --git a/gdb/NEWS b/gdb/NEWS
> index f382e887c0..f4b5c9239c 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -318,6 +318,10 @@ maint show test-options-completion-result
> GDB now bundles GNU readline 8.0, but if you choose to use
> --with-system-readline, only readline >= 7.0 can be used.
>
> +* New Simulators
> +
> +TI PRU pru-*-elf
> +
> *** Changes in GDB 8.3
>
> * GDB and GDBserver now support access to additional registers on
> diff --git a/sim/MAINTAINERS b/sim/MAINTAINERS
> index 3b9b08c40d..4ca67cfd1d 100644
> --- a/sim/MAINTAINERS
> +++ b/sim/MAINTAINERS
> @@ -29,6 +29,7 @@ mips I-IV Maciej W. Rozycki <macro@linux-mips.org>
> moxie Anthony Green <green@moxielogic.com>
> msp430 Nick Clifton <nickc@redhat.com>
> or1k Stafford Horne <shorne@gmail.com>
> +pru Dimitar Dimitrov <dimitar@dinux.eu>
> sh (global maintainers)
> sh64 Dave Brolley <brolley@redhat.com>
> common Frank Ch. Eigler <fche@redhat.com>
> diff --git a/sim/common/gennltvals.sh b/sim/common/gennltvals.sh
> index 7027c35ad4..79180335b6 100755
> --- a/sim/common/gennltvals.sh
> +++ b/sim/common/gennltvals.sh
> @@ -95,3 +95,7 @@ $shell ${srccom}/gentvals.sh $target sys
> ${newlibroot}/$dir \ dir=libgloss target=lm32
> $shell ${srccom}/gentvals.sh $target sys ${newlibroot}/$dir \
> "syscall.h" 'SYS_[_[:alnum:]]*' "${cpp}"
> +
> +dir=libgloss target=pru
> +$shell ${srccom}/gentvals.sh $target sys ${newlibroot}/$dir \
> + "syscall.h" 'SYS_[_[:alnum:]]*' "${cpp}"
> diff --git a/sim/common/nltvals.def b/sim/common/nltvals.def
> index 3f82d47b6b..92ccc9aded 100644
> --- a/sim/common/nltvals.def
> +++ b/sim/common/nltvals.def
> @@ -574,3 +574,34 @@
> /* end lm32 sys target macros */
> #endif
> #endif
> +#ifdef NL_TARGET_pru
> +#ifdef sys_defs
> +/* from syscall.h */
> +/* begin pru sys target macros */
> + { "SYS_argc", 22 },
> + { "SYS_argn", 24 },
> + { "SYS_argnlen", 23 },
> + { "SYS_argv", 13 },
> + { "SYS_argvlen", 12 },
> + { "SYS_chdir", 14 },
> + { "SYS_chmod", 16 },
> + { "SYS_close", 3 },
> + { "SYS_exit", 1 },
> + { "SYS_fstat", 10 },
> + { "SYS_getpid", 8 },
> + { "SYS_gettimeofday", 19 },
> + { "SYS_kill", 9 },
> + { "SYS_link", 21 },
> + { "SYS_lseek", 6 },
> + { "SYS_open", 2 },
> + { "SYS_read", 4 },
> + { "SYS_reconfig", 25 },
> + { "SYS_stat", 15 },
> + { "SYS_time", 18 },
> + { "SYS_times", 20 },
> + { "SYS_unlink", 7 },
> + { "SYS_utime", 17 },
> + { "SYS_write", 5 },
> +/* end pru sys target macros */
> +#endif
> +#endif
> diff --git a/sim/configure b/sim/configure
> index ca3fd673ab..72f95cd5c7 100755
> --- a/sim/configure
> +++ b/sim/configure
> @@ -686,6 +686,7 @@ mn10300
> moxie
> msp430
> or1k
> +pru
> rl78
> rx
> sh64
> @@ -3837,6 +3838,13 @@ subdirs="$subdirs aarch64"
> subdirs="$subdirs or1k"
>
>
> + ;;
> + pru*-*-*)
> +
> + sim_arch=pru
> + subdirs="$subdirs pru"
> +
> +
> ;;
> rl78-*-*)
>
> diff --git a/sim/configure.tgt b/sim/configure.tgt
> index a6dbd1af83..8a8e03d96f 100644
> --- a/sim/configure.tgt
> +++ b/sim/configure.tgt
> @@ -79,6 +79,9 @@ case "${target}" in
> or1k-*-* | or1knd-*-*)
> SIM_ARCH(or1k)
> ;;
> + pru*-*-*)
> + SIM_ARCH(pru)
> + ;;
> rl78-*-*)
> SIM_ARCH(rl78)
> ;;
> diff --git a/sim/pru/Makefile.in b/sim/pru/Makefile.in
> new file mode 100644
> index 0000000000..5235a5ff07
> --- /dev/null
> +++ b/sim/pru/Makefile.in
> @@ -0,0 +1,29 @@
> +# Makefile template for Configure for the PRU sim library.
> +# Copyright (C) 1990-2019 Free Software Foundation, Inc.
> +# Written by Dimitar Dimitrov <dimitar@dinux.eu>
> +#
> +# Based on the MCore sim library
> +#
> +# 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_OBJS = \
> + $(SIM_NEW_COMMON_OBJS) \
> + interp.o \
> + sim-resume.o
> +
> +NL_TARGET = -DNL_TARGET_pru
> +
> +## COMMON_POST_CONFIG_FRAG
> diff --git a/sim/pru/aclocal.m4 b/sim/pru/aclocal.m4
> new file mode 100644
> index 0000000000..e9f11c775c
> --- /dev/null
> +++ b/sim/pru/aclocal.m4
> @@ -0,0 +1,119 @@
> +# generated automatically by aclocal 1.15.1 -*- Autoconf -*-
> +
> +# Copyright (C) 1996-2017 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.
> +
> +m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS],
> [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) +#
> AM_CONDITIONAL -*- Autoconf -*-
> +
> +# Copyright (C) 1997-2017 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.
> +
> +# AM_CONDITIONAL(NAME, SHELL-CONDITION)
> +# -------------------------------------
> +# Define a conditional.
> +AC_DEFUN([AM_CONDITIONAL],
> +[AC_PREREQ([2.52])dnl
> + m4_if([$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])])
> +
> +# Copyright (C) 2003-2017 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.
> +
> +# Check whether the underlying file-system supports filenames
> +# with a leading dot. For instance MS-DOS doesn't.
> +AC_DEFUN([AM_SET_LEADING_DOT],
> +[rm -rf .tst 2>/dev/null
> +mkdir .tst 2>/dev/null
> +if test -d .tst; then
> + am__leading_dot=.
> +else
> + am__leading_dot=_
> +fi
> +rmdir .tst 2>/dev/null
> +AC_SUBST([am__leading_dot])])
> +
> +# Add --enable-maintainer-mode option to configure. -*- Autoconf
> -*- +# From Jim Meyering
> +
> +# Copyright (C) 1996-2017 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.
> +
> +# 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],
> + [AS_HELP_STRING([--]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
> +]
> +)
> +
> +# Copyright (C) 2006-2017 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.
> +
> +# _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($@)])
> +
> diff --git a/sim/pru/config.in b/sim/pru/config.in
> new file mode 100644
> index 0000000000..7c667a1c0d
> --- /dev/null
> +++ b/sim/pru/config.in
> @@ -0,0 +1,248 @@
> +/* config.in. Generated from configure.ac by autoheader. */
> +
> +/* Define if building universal (internal helper macro) */
> +#undef AC_APPLE_UNIVERSAL_BUILD
> +
> +/* Sim debug setting */
> +#undef DEBUG
> +
> +/* 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 `ftruncate' function. */
> +#undef HAVE_FTRUNCATE
> +
> +/* 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 `lstat' function. */
> +#undef HAVE_LSTAT
> +
> +/* Define to 1 if you have the <memory.h> header file. */
> +#undef HAVE_MEMORY_H
> +
> +/* Define to 1 if you have the `mmap' function. */
> +#undef HAVE_MMAP
> +
> +/* Define to 1 if you have the `munmap' function. */
> +#undef HAVE_MUNMAP
> +
> +/* Define to 1 if you have the `posix_fallocate' function. */
> +#undef HAVE_POSIX_FALLOCATE
> +
> +/* Define to 1 if you have the `sigaction' function. */
> +#undef HAVE_SIGACTION
> +
> +/* Define to 1 if the system has the type `socklen_t'. */
> +#undef HAVE_SOCKLEN_T
> +
> +/* 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 `st_atime' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_ATIME
> +
> +/* Define to 1 if `st_blksize' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_BLKSIZE
> +
> +/* Define to 1 if `st_blocks' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_BLOCKS
> +
> +/* Define to 1 if `st_ctime' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_CTIME
> +
> +/* Define to 1 if `st_dev' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_DEV
> +
> +/* Define to 1 if `st_gid' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_GID
> +
> +/* Define to 1 if `st_ino' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_INO
> +
> +/* Define to 1 if `st_mode' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_MODE
> +
> +/* Define to 1 if `st_mtime' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_MTIME
> +
> +/* Define to 1 if `st_nlink' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_NLINK
> +
> +/* Define to 1 if `st_rdev' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_RDEV
> +
> +/* Define to 1 if `st_size' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_SIZE
> +
> +/* Define to 1 if `st_uid' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_UID
> +
> +/* Define to 1 if you have the <sys/mman.h> header file. */
> +#undef HAVE_SYS_MMAN_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/times.h> header file. */
> +#undef HAVE_SYS_TIMES_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 `truncate' function. */
> +#undef HAVE_TRUNCATE
> +
> +/* 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
> +
> +/* Sim profile settings */
> +#undef PROFILE
> +
> +/* 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
> +
> +
> +/* Sim assert settings */
> +#undef WITH_ASSERT
> +
> +/* Sim debug setting */
> +#undef WITH_DEBUG
> +
> +/* Sim default environment */
> +#undef WITH_ENVIRONMENT
> +
> +/* Sim profile settings */
> +#undef WITH_PROFILE
> +
> +/* How to route I/O */
> +#undef WITH_STDIO
> +
> +/* Sim trace settings */
> +#undef WITH_TRACE
> +
> +/* 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
> diff --git a/sim/pru/configure.ac b/sim/pru/configure.ac
> new file mode 100644
> index 0000000000..e7132b4493
> --- /dev/null
> +++ b/sim/pru/configure.ac
> @@ -0,0 +1,31 @@
> +dnl Process this file with autoconf to produce a configure script.
> +
> +dnl Copyright (C) 2016-2019 Free Software Foundation, Inc.
> +dnl Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
> +dnl
> +dnl This file is part of the GNU simulators.
> +dnl
> +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/>.
> +dnl
> +AC_PREREQ(2.64)dnl
> +AC_INIT(Makefile.in)
> +sinclude(../common/acinclude.m4)
> +
> +SIM_AC_COMMON
> +
> +SIM_AC_OPTION_ENDIAN(LITTLE)
> +SIM_AC_OPTION_ALIGNMENT(STRICT_ALIGNMENT,STRICT_ALIGNMENT)
> +SIM_AC_OPTION_WARNINGS
> +
> +SIM_AC_OUTPUT
> diff --git a/sim/pru/interp.c b/sim/pru/interp.c
> new file mode 100644
> index 0000000000..0e783c121c
> --- /dev/null
> +++ b/sim/pru/interp.c
> @@ -0,0 +1,848 @@
> +/* Simulator for the Texas Instruments PRU processor
> + Copyright 2009-2019 Free Software Foundation, Inc.
> + Inspired by the Microblaze simulator
> + Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
> +
> + This file is part of the simulators.
> +
> + 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 <stdbool.h>
> +#include <stdint.h>
> +#include <stddef.h>
> +#include "bfd.h"
> +#include "gdb/callback.h"
> +#include "libiberty.h"
> +#include "gdb/remote-sim.h"
> +#include "sim-main.h"
> +#include "sim-assert.h"
> +#include "sim-options.h"
> +#include "sim-syscall.h"
> +#include "pru.h"
> +
> +/* DMEM zero address is perfectly valid. But if CRT leaves the first word
> + alone, we can use it as a trap to catch NULL pointer access. */
> +static bfd_boolean abort_on_dmem_zero_access;
> +
> +enum {
> + OPTION_ERROR_NULL_DEREF = OPTION_START,
> +};
> +
> +/* Extract (from PRU endianess) and return an integer in HOST's endianness.
> */ +static uint32_t
> +pru_extract_unsigned_integer (uint8_t *addr, size_t len)
> +{
> + uint32_t retval;
> + uint8_t *p;
> + uint8_t *startaddr = addr;
> + uint8_t *endaddr = startaddr + len;
> +
> + /* Start at the most significant end of the integer, and work towards
> + the least significant. */
> + retval = 0;
> +
> + for (p = endaddr; p > startaddr;)
> + retval = (retval << 8) | * -- p;
> + return retval;
> +}
> +
> +/* Store "val" (which is in HOST's endianess) into "addr"
> + (using PRU's endianness). */
> +static void
> +pru_store_unsigned_integer (uint8_t *addr, size_t len, uint32_t val)
> +{
> + uint8_t *p;
> + uint8_t *startaddr = (uint8_t *)addr;
> + uint8_t *endaddr = startaddr + len;
> +
> + for (p = startaddr; p < endaddr;)
> + {
> + *p++ = val & 0xff;
> + val >>= 8;
> + }
> +}
> +
> +/* Extract a field value from CPU register using the given REGSEL selector.
> +
> + Byte number maps directly to first values of RSEL, so we can
> + safely use "regsel" as a register byte number (0..3). */
> +static inline uint32_t
> +extract_regval (uint32_t val, uint32_t regsel)
> +{
> + ASSERT (RSEL_7_0 == 0);
> + ASSERT (RSEL_15_8 == 1);
> + ASSERT (RSEL_23_16 == 2);
> + ASSERT (RSEL_31_24 == 3);
> +
> + switch (regsel)
> + {
> + case RSEL_7_0: return (val >> 0) & 0xff;
> + case RSEL_15_8: return (val >> 8) & 0xff;
> + case RSEL_23_16: return (val >> 16) & 0xff;
> + case RSEL_31_24: return (val >> 24) & 0xff;
> + case RSEL_15_0: return (val >> 0) & 0xffff;
> + case RSEL_23_8: return (val >> 8) & 0xffff;
> + case RSEL_31_16: return (val >> 16) & 0xffff;
> + case RSEL_31_0: return val;
> + default: sim_io_error (NULL, "invalid regsel");
> + }
> +}
> +
> +/* Write a value into CPU subregister pointed by reg and regsel. */
> +static inline void
> +write_regval (uint32_t val, uint32_t *reg, uint32_t regsel)
> +{
> + uint32_t mask, sh;
> +
> + switch (regsel)
> + {
> + case RSEL_7_0: mask = (0xffu << 0); sh = 0; break;
> + case RSEL_15_8: mask = (0xffu << 8); sh = 8; break;
> + case RSEL_23_16: mask = (0xffu << 16); sh = 16; break;
> + case RSEL_31_24: mask = (0xffu << 24); sh = 24; break;
> + case RSEL_15_0: mask = (0xffffu << 0); sh = 0; break;
> + case RSEL_23_8: mask = (0xffffu << 8); sh = 8; break;
> + case RSEL_31_16: mask = (0xffffu << 16); sh = 16; break;
> + case RSEL_31_0: mask = 0xffffffffu; sh = 0; break;
> + default: sim_io_error (NULL, "invalid regsel");
> + }
> +
> + *reg = (*reg & ~mask) | ((val << sh) & mask);
> +}
> +
> +/* Convert the given IMEM word address to a regular byte address used by
> the + GNU ELF container. */
> +static uint32_t
> +imem_wordaddr_to_byteaddr (SIM_CPU *cpu, uint16_t wa)
> +{
> + return (((uint32_t) wa << 2) & IMEM_ADDR_MASK) | PC_ADDR_SPACE_MARKER;
> +}
> +
> +/* Convert the given ELF text byte address to IMEM word address. */
> +static uint16_t
> +imem_byteaddr_to_wordaddr (SIM_CPU *cpu, uint32_t ba)
> +{
> + return (ba >> 2) & 0xffff;
> +}
> +
> +
> +/* Store "nbytes" into DMEM "addr" from CPU register file, starting with
> + register "regn", and byte "regb" within it. */
> +static inline void
> +pru_reg2dmem (SIM_CPU *cpu, uint32_t addr, unsigned int nbytes,
> + int regn, int regb)
> +{
> + /* GDB assumes unconditional access to all memories, so enable additional
> + checks only in standalone mode. */
> + bool standalone = (STATE_OPEN_KIND (CPU_STATE (cpu)) ==
> SIM_OPEN_STANDALONE); +
> + if (abort_on_dmem_zero_access && addr < 4)
> + {
> + sim_core_signal (CPU_STATE (cpu), cpu, PC_byteaddr, write_map,
> + nbytes, addr, write_transfer,
> + sim_core_unmapped_signal);
> + }
> + else if (standalone && ((addr >= PC_ADDR_SPACE_MARKER)
> + || (addr + nbytes > PC_ADDR_SPACE_MARKER)))
> + {
> + sim_core_signal (CPU_STATE (cpu), cpu, PC_byteaddr, write_map,
> + nbytes, addr, write_transfer,
> + sim_core_unmapped_signal);
> + }
> + else if ((regn * 4 + regb + nbytes) > (32 * 4))
> + {
> + sim_io_eprintf (CPU_STATE (cpu),
> + "SBBO/SBCO with invalid store data length\n");
> + RAISE_SIGILL (CPU_STATE (cpu));
> + }
> + else
> + {
> + TRACE_MEMORY (cpu, "write of %d bytes to %08x", nbytes, addr);
> + while (nbytes--)
> + {
> + sim_core_write_1 (cpu,
> + PC_byteaddr,
> + write_map,
> + addr++,
> + extract_regval (CPU.regs[regn], regb));
> +
> + if (++regb >= 4)
> + {
> + regb = 0;
> + regn++;
> + }
> + }
> + }
> +}
> +
> +/* Load "nbytes" from DMEM "addr" into CPU register file, starting with
> + register "regn", and byte "regb" within it. */
> +static inline void
> +pru_dmem2reg (SIM_CPU *cpu, uint32_t addr, unsigned int nbytes,
> + int regn, int regb)
> +{
> + /* GDB assumes unconditional access to all memories, so enable additional
> + checks only in standalone mode. */
> + bool standalone = (STATE_OPEN_KIND (CPU_STATE (cpu)) ==
> SIM_OPEN_STANDALONE); +
> + if (abort_on_dmem_zero_access && addr < 4)
> + {
> + sim_core_signal (CPU_STATE (cpu), cpu, PC_byteaddr, read_map,
> + nbytes, addr, read_transfer,
> + sim_core_unmapped_signal);
> + }
> + else if (standalone && ((addr >= PC_ADDR_SPACE_MARKER)
> + || (addr + nbytes > PC_ADDR_SPACE_MARKER)))
> + {
> + /* This check is necessary because our IMEM "address space"
> + is not really accessible, yet we have mapped it as a generic
> + memory space. */
> + sim_core_signal (CPU_STATE (cpu), cpu, PC_byteaddr, read_map,
> + nbytes, addr, read_transfer,
> + sim_core_unmapped_signal);
> + }
> + else if ((regn * 4 + regb + nbytes) > (32 * 4))
> + {
> + sim_io_eprintf (CPU_STATE (cpu),
> + "LBBO/LBCO with invalid load data length\n");
> + RAISE_SIGILL (CPU_STATE (cpu));
> + }
> + else
> + {
> + unsigned int b;
> + TRACE_MEMORY (cpu, "read of %d bytes from %08x", nbytes, addr);
> + while (nbytes--)
> + {
> + b = sim_core_read_1 (cpu, PC_byteaddr, read_map, addr++);
> +
> + /* Reuse the fact the Register Byte Number maps directly to RSEL. */
> + ASSERT (RSEL_7_0 == 0);
> + write_regval (b, &CPU.regs[regn], regb);
> +
> + if (++regb >= 4)
> + {
> + regb = 0;
> + regn++;
> + }
> + }
> + }
> +}
> +
> +/* Set reset values of general-purpose registers. */
> +static void
> +set_initial_gprs (SIM_CPU *cpu)
> +{
> + int i;
> +
> + /* Set up machine just out of reset. */
> + CPU_PC_SET (cpu, 0);
> + PC_ADDR_SPACE_MARKER = IMEM_ADDR_DEFAULT; /* from default linker script?
> */ +
> + /* Clean out the GPRs. */
> + for (i = 0; i < ARRAY_SIZE (CPU.regs); i++)
> + CPU.regs[i] = 0;
> + for (i = 0; i < ARRAY_SIZE (CPU.macregs); i++)
> + CPU.macregs[i] = 0;
> +
> + CPU.loop.looptop = CPU.loop.loopend = 0;
> + CPU.loop.loop_in_progress = 0;
> + CPU.loop.loop_counter = 0;
> +
> + CPU.carry = 0;
> + CPU.insts = 0;
> + CPU.cycles = 0;
> +
> + /* AM335x should provide sane defaults. */
> + CPU.ctable[0] = 0x00020000;
> + CPU.ctable[1] = 0x48040000;
> + CPU.ctable[2] = 0x4802a000;
> + CPU.ctable[3] = 0x00030000;
> + CPU.ctable[4] = 0x00026000;
> + CPU.ctable[5] = 0x48060000;
> + CPU.ctable[6] = 0x48030000;
> + CPU.ctable[7] = 0x00028000;
> + CPU.ctable[8] = 0x46000000;
> + CPU.ctable[9] = 0x4a100000;
> + CPU.ctable[10] = 0x48318000;
> + CPU.ctable[11] = 0x48022000;
> + CPU.ctable[12] = 0x48024000;
> + CPU.ctable[13] = 0x48310000;
> + CPU.ctable[14] = 0x481cc000;
> + CPU.ctable[15] = 0x481d0000;
> + CPU.ctable[16] = 0x481a0000;
> + CPU.ctable[17] = 0x4819c000;
> + CPU.ctable[18] = 0x48300000;
> + CPU.ctable[19] = 0x48302000;
> + CPU.ctable[20] = 0x48304000;
> + CPU.ctable[21] = 0x00032400;
> + CPU.ctable[22] = 0x480c8000;
> + CPU.ctable[23] = 0x480ca000;
> + CPU.ctable[24] = 0x00000000;
> + CPU.ctable[25] = 0x00002000;
> + CPU.ctable[26] = 0x0002e000;
> + CPU.ctable[27] = 0x00032000;
> + CPU.ctable[28] = 0x00000000;
> + CPU.ctable[29] = 0x49000000;
> + CPU.ctable[30] = 0x40000000;
> + CPU.ctable[31] = 0x80000000;
> +}
> +
> +/* Map regsel selector to subregister field width. */
> +static inline unsigned int
> +regsel_width (uint32_t regsel)
> +{
> + switch (regsel)
> + {
> + case RSEL_7_0: return 8;
> + case RSEL_15_8: return 8;
> + case RSEL_23_16: return 8;
> + case RSEL_31_24: return 8;
> + case RSEL_15_0: return 16;
> + case RSEL_23_8: return 16;
> + case RSEL_31_16: return 16;
> + case RSEL_31_0: return 32;
> + default: sim_io_error (NULL, "invalid regsel");
> + }
> +}
> +
> +/* Handle XIN instruction addressing the MAC peripheral. */
> +static void
> +pru_sim_xin_mac (SIM_DESC sd, SIM_CPU *cpu, unsigned int rd_regn,
> + unsigned int rdb, unsigned int length)
> +{
> + if (rd_regn < 25 || (rd_regn * 4 + rdb + length) > (27 + 1) * 4)
> + sim_io_error (sd, "XIN MAC: invalid transfer regn=%u.%u, length=%u\n",
> + rd_regn, rdb, length);
> +
> + /* Copy from MAC to PRU regs. Ranges have been validated above. */
> + while (length--)
> + {
> + write_regval (CPU.macregs[rd_regn - 25] >> (rdb * 8),
> + &CPU.regs[rd_regn],
> + rdb);
> + if (++rdb == 4)
> + {
> + rdb = 0;
> + rd_regn++;
> + }
> + }
> +}
> +
> +/* Handle XIN instruction. */
> +static void
> +pru_sim_xin (SIM_DESC sd, SIM_CPU *cpu, unsigned int wba,
> + unsigned int rd_regn, unsigned int rdb, unsigned int length)
> +{
> + if (wba == 0)
> + {
> + pru_sim_xin_mac (sd, cpu, rd_regn, rdb, length);
> + }
> + else if (wba == XFRID_SCRATCH_BANK_0 || wba == XFRID_SCRATCH_BANK_1
> + || wba == XFRID_SCRATCH_BANK_2 || wba == XFRID_SCRATCH_BANK_PEER)
> + {
> + while (length--)
> + {
> + unsigned int val;
> +
> + val = extract_regval (CPU.scratchpads[wba][rd_regn], rdb);
> + write_regval (val, &CPU.regs[rd_regn], rdb);
> + if (++rdb == 4)
> + {
> + rdb = 0;
> + rd_regn++;
> + }
> + }
> + }
> + else if (wba == 254 || wba == 255)
> + {
> + /* FILL/ZERO pseudos implemented via XIN. */
> + unsigned int fillbyte = (wba == 254) ? 0xff : 0x00;
> + while (length--)
> + {
> + write_regval (fillbyte, &CPU.regs[rd_regn], rdb);
> + if (++rdb == 4)
> + {
> + rdb = 0;
> + rd_regn++;
> + }
> + }
> + }
> + else
> + {
> + sim_io_error (sd, "XIN: XFR device %d not supported.\n", wba);
> + }
> +}
> +
> +/* Handle XOUT instruction addressing the MAC peripheral. */
> +static void
> +pru_sim_xout_mac (SIM_DESC sd, SIM_CPU *cpu, unsigned int rd_regn,
> + unsigned int rdb, unsigned int length)
> +{
> + const int modereg_accessed = (rd_regn == 25);
> +
> + /* Multiple Accumulate. */
> + if (rd_regn < 25 || (rd_regn * 4 + rdb + length) > (27 + 1) * 4)
> + sim_io_error (sd, "XOUT MAC: invalid transfer regn=%u.%u, length=%u\n",
> + rd_regn, rdb, length);
> +
> + /* Copy from PRU to MAC regs. Ranges have been validated above. */
> + while (length--)
> + {
> + write_regval (CPU.regs[rd_regn] >> (rdb * 8),
> + &CPU.macregs[rd_regn - 25],
> + rdb);
> + if (++rdb == 4)
> + {
> + rdb = 0;
> + rd_regn++;
> + }
> + }
> +
> + if (modereg_accessed
> + && (CPU.macregs[PRU_MACREG_MODE] & MAC_R25_MAC_MODE_MASK))
> + {
> + /* MUL/MAC operands are sampled every XOUT in multiply and
> + accumulate mode. */
> + uint64_t prod, oldsum, sum;
> + CPU.macregs[PRU_MACREG_OP_0] = CPU.regs[28];
> + CPU.macregs[PRU_MACREG_OP_1] = CPU.regs[29];
> +
> + prod = CPU.macregs[PRU_MACREG_OP_0];
> + prod *= (uint64_t)CPU.macregs[PRU_MACREG_OP_1];
> +
> + oldsum = CPU.macregs[PRU_MACREG_ACC_L];
> + oldsum += (uint64_t)CPU.macregs[PRU_MACREG_ACC_H] << 32;
> + sum = oldsum + prod;
> +
> + CPU.macregs[PRU_MACREG_PROD_L] = sum & 0xfffffffful;
> + CPU.macregs[PRU_MACREG_PROD_H] = sum >> 32;
> + CPU.macregs[PRU_MACREG_ACC_L] = CPU.macregs[PRU_MACREG_PROD_L];
> + CPU.macregs[PRU_MACREG_ACC_H] = CPU.macregs[PRU_MACREG_PROD_H];
> +
> + if (oldsum > sum)
> + CPU.macregs[PRU_MACREG_MODE] |= MAC_R25_ACC_CARRY_MASK;
> + }
> + if (modereg_accessed
> + && (CPU.macregs[PRU_MACREG_MODE] & MAC_R25_ACC_CARRY_MASK))
> + {
> + /* store 1 to clear. */
> + CPU.macregs[PRU_MACREG_MODE] &= ~MAC_R25_ACC_CARRY_MASK;
> + CPU.macregs[PRU_MACREG_ACC_L] = 0;
> + CPU.macregs[PRU_MACREG_ACC_H] = 0;
> + }
> +
> +}
> +
> +/* Handle XOUT instruction. */
> +static void
> +pru_sim_xout (SIM_DESC sd, SIM_CPU *cpu, unsigned int wba,
> + unsigned int rd_regn, unsigned int rdb, unsigned int length)
> +{
> + if (wba == 0)
> + {
> + pru_sim_xout_mac (sd, cpu, rd_regn, rdb, length);
> + }
> + else if (wba == XFRID_SCRATCH_BANK_0 || wba == XFRID_SCRATCH_BANK_1
> + || wba == XFRID_SCRATCH_BANK_2 || wba == XFRID_SCRATCH_BANK_PEER)
> + {
> + while (length--)
> + {
> + unsigned int val;
> +
> + val = extract_regval (CPU.regs[rd_regn], rdb);
> + write_regval (val, &CPU.scratchpads[wba][rd_regn], rdb);
> + if (++rdb == 4)
> + {
> + rdb = 0;
> + rd_regn++;
> + }
> + }
> + }
> + else
> + sim_io_error (sd, "XOUT: XFR device %d not supported.\n", wba);
> +}
> +
> +/* Handle XCHG instruction. */
> +static void
> +pru_sim_xchg (SIM_DESC sd, SIM_CPU *cpu, unsigned int wba,
> + unsigned int rd_regn, unsigned int rdb, unsigned int length)
> +{
> + if (wba == XFRID_SCRATCH_BANK_0 || wba == XFRID_SCRATCH_BANK_1
> + || wba == XFRID_SCRATCH_BANK_2 || wba == XFRID_SCRATCH_BANK_PEER)
> + {
> + while (length--)
> + {
> + unsigned int valr, vals;
> +
> + valr = extract_regval (CPU.regs[rd_regn], rdb);
> + vals = extract_regval (CPU.scratchpads[wba][rd_regn], rdb);
> + write_regval (valr, &CPU.scratchpads[wba][rd_regn], rdb);
> + write_regval (vals, &CPU.regs[rd_regn], rdb);
> + if (++rdb == 4)
> + {
> + rdb = 0;
> + rd_regn++;
> + }
> + }
> + }
> + else
> + sim_io_error (sd, "XOUT: XFR device %d not supported.\n", wba);
> +}
> +
> +/* Handle syscall simulation. Its ABI is specific to the GNU simulator.
> */ +static void
> +pru_sim_syscall (SIM_DESC sd, SIM_CPU *cpu)
> +{
> + /* If someday TI confirms that the "reserved" HALT opcode fields
> + can be used for extra arguments, then maybe we can embed
> + the syscall number there. Until then, let's use R1. */
> + const uint32_t syscall_num = CPU.regs[1];
> + long ret;
> +
> + ret = sim_syscall (cpu, syscall_num,
> + CPU.regs[14], CPU.regs[15],
> + CPU.regs[16], CPU.regs[17]);
> + CPU.regs[14] = ret;
> +}
> +
> +/* Simulate one instruction. */
> +static void
> +sim_step_once (SIM_DESC sd)
> +{
> + SIM_CPU *cpu = STATE_CPU (sd, 0);
> + const struct pru_opcode *op;
> + uint32_t inst;
> + uint32_t _RDVAL, OP2; /* intermediate values. */
> + int rd_is_modified = 0; /* RD modified and must be stored back. */
> +
> + /* Fetch the initial instruction that we'll decode. */
> + inst = sim_core_read_4 (cpu, PC_byteaddr, exec_map, PC_byteaddr);
> + TRACE_MEMORY (cpu, "read of insn 0x%08x from %08x", inst, PC_byteaddr);
> +
> + op = pru_find_opcode (inst);
> +
> + if (!op)
> + {
> + sim_io_eprintf (sd, "Unknown instruction 0x%04x\n", inst);
> + RAISE_SIGILL (sd);
> + }
> + else
> + {
> + TRACE_DISASM (cpu, PC_byteaddr);
> +
> + /* In multiply-only mode, R28/R29 operands are sampled on every clock
> + cycle. */
> + if ((CPU.macregs[PRU_MACREG_MODE] & MAC_R25_MAC_MODE_MASK) == 0)
> + {
> + CPU.macregs[PRU_MACREG_OP_0] = CPU.regs[28];
> + CPU.macregs[PRU_MACREG_OP_1] = CPU.regs[29];
> + }
> +
> + switch (op->type)
> + {
> +/* Helper macro to improve clarity of pru.isa. The empty while is a
> + guard against using RD as a left-hand side value. */
> +#define RD do { } while (0); rd_is_modified = 1; _RDVAL
> +#define INSTRUCTION(NAME, ACTION) \
> + case prui_ ## NAME: \
> + ACTION; \
> + break;
> +#include "pru.isa"
> +#undef INSTRUCTION
> +#undef RD
> +
> + default:
> + RAISE_SIGILL (sd);
> + }
> +
> + if (rd_is_modified)
> + write_regval (_RDVAL, &CPU.regs[RD_REGN], RDSEL);
> +
> + /* Don't treat r30 and r31 as regular registers, they are I/O! */
> + CPU.regs[30] = 0;
> + CPU.regs[31] = 0;
> +
> + /* Handle PC match of loop end. */
> + if (LOOP_IN_PROGRESS && (PC == LOOPEND))
> + {
> + SIM_ASSERT (LOOPCNT > 0);
> + if (--LOOPCNT == 0)
> + LOOP_IN_PROGRESS = 0;
> + else
> + PC = LOOPTOP;
> + }
> +
> + /* In multiply-only mode, MAC does multiplication every cycle. */
> + if ((CPU.macregs[PRU_MACREG_MODE] & MAC_R25_MAC_MODE_MASK) == 0)
> + {
> + uint64_t prod;
> + prod = CPU.macregs[PRU_MACREG_OP_0];
> + prod *= (uint64_t)CPU.macregs[PRU_MACREG_OP_1];
> + CPU.macregs[PRU_MACREG_PROD_L] = prod & 0xfffffffful;
> + CPU.macregs[PRU_MACREG_PROD_H] = prod >> 32;
> +
> + /* Clear the MAC accumulator when in normal mode. */
> + CPU.macregs[PRU_MACREG_ACC_L] = 0;
> + CPU.macregs[PRU_MACREG_ACC_H] = 0;
> + }
> +
> + /* Update cycle counts. */
> + CPU.insts += 1; /* One instruction completed ... */
> + CPU.cycles += 1; /* ... and it takes a single cycle. */
> +
> + /* Account for memory access latency with a reasonable estimate.
> + No distinction is currently made between SRAM, DRAM and generic
> + L3 slaves. */
> + if (op->type == prui_lbbo || op->type == prui_sbbo
> + || op->type == prui_lbco || op->type == prui_sbco)
> + CPU.cycles += 2;
> +
> + }
> +}
> +
> +/* Implement standard sim_engine_run function. */
> +void
> +sim_engine_run (SIM_DESC sd,
> + int next_cpu_nr, /* ignore */
> + int nr_cpus, /* ignore */
> + int siggnal) /* ignore */
> +{
> + while (1)
> + {
> + sim_step_once (sd);
> + if (sim_events_tick (sd))
> + sim_events_process (sd);
> + }
> +}
> +
> +
> +/* Implement callback for standard CPU_PC_FETCH routine. */
> +static sim_cia
> +pru_pc_get (sim_cpu *cpu)
> +{
> + /* Present PC as byte address. */
> + return imem_wordaddr_to_byteaddr (cpu, cpu->pru_cpu.pc);
> +}
> +
> +/* Implement callback for standard CPU_PC_STORE routine. */
> +static void
> +pru_pc_set (sim_cpu *cpu, sim_cia pc)
> +{
> + /* PC given as byte address. */
> + cpu->pru_cpu.pc = imem_byteaddr_to_wordaddr (cpu, pc);
> +}
> +
> +
> +/* Implement callback for standard CPU_REG_STORE routine. */
> +static int
> +pru_store_register (SIM_CPU *cpu, int rn, unsigned char *memory, int
> length) +{
> + if (rn < NUM_REGS && rn >= 0)
> + {
> + if (length == 4)
> + {
> + /* Misalignment safe. */
> + long ival = pru_extract_unsigned_integer (memory, 4);
> + if (rn < 32)
> + CPU.regs[rn] = ival;
> + else
> + pru_pc_set (cpu, ival);
> + return 4;
> + }
> + else
> + return 0;
> + }
> + else
> + return 0;
> +}
> +
> +/* Implement callback for standard CPU_REG_FETCH routine. */
> +static int
> +pru_fetch_register (SIM_CPU *cpu, int rn, unsigned char *memory, int
> length) +{
> + long ival;
> +
> + if (rn < NUM_REGS && rn >= 0)
> + {
> + if (length == 4)
> + {
> + if (rn < 32)
> + ival = CPU.regs[rn];
> + else
> + ival = pru_pc_get (cpu);
> +
> + /* Misalignment-safe. */
> + pru_store_unsigned_integer (memory, 4, ival);
> + return 4;
> + }
> + else
> + return 0;
> + }
> + else
> + return 0;
> +}
> +
> +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);
> +}
> +
> +/* Declare the PRU option handler. */
> +static DECLARE_OPTION_HANDLER (pru_option_handler);
> +
> +/* Implement the PRU option handler. */
> +static SIM_RC
> +pru_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt, char *arg,
> + int is_command)
> +{
> + switch (opt)
> + {
> + case OPTION_ERROR_NULL_DEREF:
> + abort_on_dmem_zero_access = TRUE;
> + return SIM_RC_OK;
> +
> + default:
> + sim_io_eprintf (sd, "Unknown PRU option %d\n", opt);
> + return SIM_RC_FAIL;
> + }
> +}
> +
> +/* List of PRU-specific options. */
> +static const OPTION pru_options[] =
> +{
> + { {"error-null-deref", no_argument, NULL, OPTION_ERROR_NULL_DEREF},
> + '\0', NULL, "Trap any access to DMEM address zero",
> + pru_option_handler, NULL },
> +
> + { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL, NULL }
> +};
> +
> +/* Implement standard sim_open function. */
> +SIM_DESC
> +sim_open (SIM_OPEN_KIND kind, host_callback *cb,
> + struct bfd *abfd, char * const *argv)
> +{
> + int i;
> + char c;
> + SIM_DESC sd = sim_state_alloc (kind, cb);
> + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
> +
> + /* The cpu data is kept in a separately allocated chunk of memory. */
> + if (sim_cpu_alloc_all (sd, 1, /*cgen_cpu_max_extra_bytes ()*/0) !=
> SIM_RC_OK) + {
> + free_state (sd);
> + return 0;
> + }
> +
> + if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
> + {
> + free_state (sd);
> + return 0;
> + }
> + sim_add_option_table (sd, NULL, pru_options);
> +
> + /* The parser will print an error message for us, so we silently return.
> */ + if (sim_parse_args (sd, argv) != SIM_RC_OK)
> + {
> + free_state (sd);
> + return 0;
> + }
> +
> + /* Check for/establish a reference program image. */
> + if (sim_analyze_program (sd,
> + (STATE_PROG_ARGV (sd) != NULL
> + ? *STATE_PROG_ARGV (sd)
> + : NULL), abfd) != SIM_RC_OK)
> + {
> + free_state (sd);
> + return 0;
> + }
> +
> + /* Configure/verify the target byte order and other runtime
> + configuration options. */
> + if (sim_config (sd) != SIM_RC_OK)
> + {
> + sim_module_uninstall (sd);
> + return 0;
> + }
> +
> + if (sim_post_argv_init (sd) != SIM_RC_OK)
> + {
> + /* Uninstall the modules to avoid memory leaks,
> + file descriptor leaks, etc. */
> + sim_module_uninstall (sd);
> + return 0;
> + }
> +
> + /* CPU specific initialization. */
> + for (i = 0; i < MAX_NR_PROCESSORS; ++i)
> + {
> + SIM_CPU *cpu = STATE_CPU (sd, i);
> +
> + CPU_REG_STORE (cpu) = pru_store_register;
> + CPU_REG_FETCH (cpu) = pru_fetch_register;
> + CPU_PC_FETCH (cpu) = pru_pc_get;
> + CPU_PC_STORE (cpu) = pru_pc_set;
> +
> + set_initial_gprs (cpu);
> + }
> +
> + /* Allocate external memory if none specified by user.
> + Use address 4 here in case the user wanted address 0 unmapped. */
> + if (sim_core_read_buffer (sd, NULL, read_map, &c, 4, 1) == 0)
> + {
> + sim_do_commandf (sd, "memory-region 0x%x,0x%x",
> + 0,
> + DMEM_DEFAULT_SIZE);
> + }
> + if (sim_core_read_buffer (sd, NULL, read_map, &c, IMEM_ADDR_DEFAULT, 1)
> == 0) + {
> + sim_do_commandf (sd, "memory-region 0x%x,0x%x",
> + IMEM_ADDR_DEFAULT,
> + IMEM_DEFAULT_SIZE);
> + }
> +
> + return sd;
> +}
> +
> +/* Implement standard sim_create_inferior function. */
> +SIM_RC
> +sim_create_inferior (SIM_DESC sd, struct bfd *prog_bfd,
> + char * const *argv, char * const *env)
> +{
> + SIM_CPU *cpu = STATE_CPU (sd, 0);
> + SIM_ADDR addr;
> +
> + addr = bfd_get_start_address (prog_bfd);
> +
> + sim_pc_set (cpu, addr);
> + PC_ADDR_SPACE_MARKER = addr & ~IMEM_ADDR_MASK;
> +
> + /* Standalone mode (i.e. `run`) will take care of the argv for us in
> + sim_open () -> sim_parse_args (). But in debug mode (i.e. 'target
> sim' + with `gdb`), we need to handle it because the user can change
> the + argv on the fly via gdb's 'run'. */
> + if (STATE_PROG_ARGV (sd) != argv)
> + {
> + freeargv (STATE_PROG_ARGV (sd));
> + STATE_PROG_ARGV (sd) = dupargv (argv);
> + }
> +
> + return SIM_RC_OK;
> +}
> diff --git a/sim/pru/pru.h b/sim/pru/pru.h
> new file mode 100644
> index 0000000000..8b005ef0b5
> --- /dev/null
> +++ b/sim/pru/pru.h
> @@ -0,0 +1,110 @@
> +/* Copyright 2016-2019 Free Software Foundation, Inc.
> + Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
> +
> + This file is part of the PRU simulator.
> +
> + This library 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 PRU_H
> +#define PRU_H
> +
> +#include "config.h"
> +#include "opcode/pru.h"
> +
> +/* NOTE: Needed for handling the dual PRU address space. */
> +#define IMEM_ADDR_MASK ((1u << 23) - 1)
> +
> +#define IMEM_ADDR_DEFAULT 0x20000000
> +
> +/* Define memory sizes to allocate for simulated target. Sizes are
> + artificially large to accommodate execution of compiler test suite.
> + Please synchronize with the linker script for prusim target. */
> +#define DMEM_DEFAULT_SIZE (64 * 1024 * 1024)
> +
> +/* 16-bit word addressable space. */
> +#define IMEM_DEFAULT_SIZE (64 * 4 * 1024)
> +
> +/* For AM335x SoCs. */
> +#define XFRID_SCRATCH_BANK_0 10
> +#define XFRID_SCRATCH_BANK_1 11
> +#define XFRID_SCRATCH_BANK_2 12
> +#define XFRID_SCRATCH_BANK_PEER 14
> +#define XFRID_MAX 255
> +
> +#define CPU (cpu->pru_cpu)
> +
> +#define PC (CPU.pc)
> +#define PC_byteaddr ((PC << 2) | PC_ADDR_SPACE_MARKER)
> +
> +/* Various opcode fields. */
> +#define RS1 extract_regval (CPU.regs[GET_INSN_FIELD (RS1, inst)], \
> + GET_INSN_FIELD (RS1SEL, inst))
> +#define RS2 extract_regval (CPU.regs[GET_INSN_FIELD (RS2, inst)], \
> + GET_INSN_FIELD (RS2SEL, inst))
> +
> +#define RS2_w0 extract_regval (CPU.regs[GET_INSN_FIELD (RS2, inst)], \
> + RSEL_15_0)
> +
> +#define XBBO_BASEREG (CPU.regs[GET_INSN_FIELD (RS1, inst)])
> +
> +#define RDSEL GET_INSN_FIELD (RDSEL, inst)
> +#define RD_WIDTH regsel_width (RDSEL)
> +#define RD_REGN GET_INSN_FIELD (RD, inst)
> +#define IO GET_INSN_FIELD (IO, inst)
> +#define IMM8 GET_INSN_FIELD (IMM8, inst)
> +#define IMM16 GET_INSN_FIELD (IMM16, inst)
> +#define WAKEONSTATUS GET_INSN_FIELD (WAKEONSTATUS, inst)
> +#define CB GET_INSN_FIELD (CB, inst)
> +#define RDB GET_INSN_FIELD (RDB, inst)
> +#define XFR_WBA GET_INSN_FIELD (XFR_WBA, inst)
> +#define LOOP_JMPOFFS GET_INSN_FIELD (LOOP_JMPOFFS, inst)
> +#define BROFF ((uint32_t) GET_BROFF_SIGNED (inst))
> +
> +#define _BURSTLEN_CALCULATE(BITFIELD) \
> + ((BITFIELD) >= LSSBBO_BYTECOUNT_R0_BITS7_0 ? \
> + (CPU.regs[0] >> ((BITFIELD) - LSSBBO_BYTECOUNT_R0_BITS7_0) * 8) & 0xff
> \ + : (BITFIELD) + 1)
> +
> +#define BURSTLEN _BURSTLEN_CALCULATE (GET_BURSTLEN (inst))
> +#define XFR_LENGTH _BURSTLEN_CALCULATE (GET_INSN_FIELD (XFR_LENGTH, inst))
> +
> +#define DO_XIN(wba,regn,rdb,l) \
> + pru_sim_xin (sd, cpu, (wba), (regn), (rdb), (l))
> +#define DO_XOUT(wba,regn,rdb,l) \
> + pru_sim_xout (sd, cpu, (wba), (regn), (rdb), (l))
> +#define DO_XCHG(wba,regn,rdb,l) \
> + pru_sim_xchg (sd, cpu, (wba), (regn), (rdb), (l))
> +
> +#define RAISE_SIGILL(sd) sim_engine_halt ((sd), NULL, NULL, PC_byteaddr, \
> + sim_stopped, SIM_SIGILL)
> +#define RAISE_SIGINT(sd) sim_engine_halt ((sd), NULL, NULL, PC_byteaddr, \
> + sim_stopped, SIM_SIGINT)
> +
> +#define MAC_R25_MAC_MODE_MASK (1u << 0)
> +#define MAC_R25_ACC_CARRY_MASK (1u << 1)
> +
> +#define CARRY CPU.carry
> +#define CTABLE CPU.ctable
> +
> +#define PC_ADDR_SPACE_MARKER CPU.pc_addr_space_marker
> +
> +#define LOOPTOP CPU.loop.looptop
> +#define LOOPEND CPU.loop.loopend
> +#define LOOP_IN_PROGRESS CPU.loop.loop_in_progress
> +#define LOOPCNT CPU.loop.loop_counter
> +
> +/* 32 GP registers plus PC. */
> +#define NUM_REGS 33
> +
> +#endif /* PRU_H */
> diff --git a/sim/pru/pru.isa b/sim/pru/pru.isa
> new file mode 100644
> index 0000000000..c906b2a169
> --- /dev/null
> +++ b/sim/pru/pru.isa
> @@ -0,0 +1,249 @@
> +/* Copyright 2016-2019 Free Software Foundation, Inc.
> + Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
> +
> + This file is part of the PRU simulator.
> +
> + This library 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/>. */
> +
> +/*
> + PRU Instruction Set Architecture
> +
> + INSTRUCTION (NAME,
> + SEMANTICS)
> + */
> +
> +INSTRUCTION (add,
> + OP2 = (IO ? IMM8 : RS2);
> + RD = RS1 + OP2;
> + CARRY = (((uint64_t) RS1 + (uint64_t) OP2) >> RD_WIDTH) & 1;
> + PC++)
> +
> +INSTRUCTION (adc,
> + OP2 = (IO ? IMM8 : RS2);
> + RD = RS1 + OP2 + CARRY;
> + CARRY = (((uint64_t) RS1 + (uint64_t) OP2 + (uint64_t) CARRY)
> + >> RD_WIDTH) & 1;
> + PC++)
> +
> +INSTRUCTION (sub,
> + OP2 = (IO ? IMM8 : RS2);
> + RD = RS1 - OP2;
> + CARRY = (((uint64_t) RS1 - (uint64_t) OP2) >> RD_WIDTH) & 1;
> + PC++)
> +
> +INSTRUCTION (suc,
> + OP2 = (IO ? IMM8 : RS2);
> + RD = RS1 - OP2 - CARRY;
> + CARRY = (((uint64_t) RS1 - (uint64_t) OP2 - (uint64_t) CARRY)
> + >> RD_WIDTH) & 1;
> + PC++)
> +
> +INSTRUCTION (rsb,
> + OP2 = (IO ? IMM8 : RS2);
> + RD = OP2 - RS1;
> + CARRY = (((uint64_t) OP2 - (uint64_t) RS1) >> RD_WIDTH) & 1;
> + PC++)
> +
> +INSTRUCTION (rsc,
> + OP2 = (IO ? IMM8 : RS2);
> + RD = OP2 - RS1 - CARRY;
> + CARRY = (((uint64_t) OP2 - (uint64_t) RS1 - (uint64_t) CARRY)
> + >> RD_WIDTH) & 1;
> + PC++)
> +
> +INSTRUCTION (lsl,
> + OP2 = (IO ? IMM8 : RS2);
> + RD = RS1 << (OP2 & 0x1f);
> + PC++)
> +
> +INSTRUCTION (lsr,
> + OP2 = (IO ? IMM8 : RS2);
> + RD = RS1 >> (OP2 & 0x1f);
> + PC++)
> +
> +INSTRUCTION (and,
> + OP2 = (IO ? IMM8 : RS2);
> + RD = RS1 & OP2;
> + PC++)
> +
> +INSTRUCTION (or,
> + OP2 = (IO ? IMM8 : RS2);
> + RD = RS1 | OP2;
> + PC++)
> +
> +INSTRUCTION (xor,
> + OP2 = (IO ? IMM8 : RS2);
> + RD = RS1 ^ OP2;
> + PC++)
> +
> +INSTRUCTION (not,
> + RD = ~RS1;
> + PC++)
> +
> +INSTRUCTION (min,
> + OP2 = (IO ? IMM8 : RS2);
> + RD = RS1 < OP2 ? RS1 : OP2;
> + PC++)
> +
> +INSTRUCTION (max,
> + OP2 = (IO ? IMM8 : RS2);
> + RD = RS1 > OP2 ? RS1 : OP2;
> + PC++)
> +
> +INSTRUCTION (clr,
> + OP2 = (IO ? IMM8 : RS2);
> + RD = RS1 & ~(1u << (OP2 & 0x1f));
> + PC++)
> +
> +INSTRUCTION (set,
> + OP2 = (IO ? IMM8 : RS2);
> + RD = RS1 | (1u << (OP2 & 0x1f));
> + PC++)
> +
> +INSTRUCTION (jmp,
> + OP2 = (IO ? IMM16 : RS2);
> + PC = OP2)
> +
> +INSTRUCTION (jal,
> + OP2 = (IO ? IMM16 : RS2);
> + RD = PC + 1;
> + PC = OP2)
> +
> +INSTRUCTION (ldi,
> + RD = IMM16;
> + PC++)
> +
> +INSTRUCTION (halt,
> + pru_sim_syscall (sd, cpu);
> + PC++)
> +
> +INSTRUCTION (slp,
> + if (!WAKEONSTATUS)
> + {
> + RAISE_SIGINT (sd);
> + }
> + else
> + {
> + PC++;
> + })
> +
> +INSTRUCTION (qbgt,
> + OP2 = (IO ? IMM8 : RS2);
> + PC = (OP2 > RS1) ? (PC + BROFF) : (PC + 1))
> +
> +INSTRUCTION (qbge,
> + OP2 = (IO ? IMM8 : RS2);
> + PC = (OP2 >= RS1) ? (PC + BROFF) : (PC + 1))
> +
> +INSTRUCTION (qblt,
> + OP2 = (IO ? IMM8 : RS2);
> + PC = (OP2 < RS1) ? (PC + BROFF) : (PC + 1))
> +
> +INSTRUCTION (qble,
> + OP2 = (IO ? IMM8 : RS2);
> + PC = (OP2 <= RS1) ? (PC + BROFF) : (PC + 1))
> +
> +INSTRUCTION (qbeq,
> + OP2 = (IO ? IMM8 : RS2);
> + PC = (OP2 == RS1) ? (PC + BROFF) : (PC + 1))
> +
> +INSTRUCTION (qbne,
> + OP2 = (IO ? IMM8 : RS2);
> + PC = (OP2 != RS1) ? (PC + BROFF) : (PC + 1))
> +
> +INSTRUCTION (qba,
> + OP2 = (IO ? IMM8 : RS2);
> + PC = PC + BROFF)
> +
> +INSTRUCTION (qbbs,
> + OP2 = (IO ? IMM8 : RS2);
> + PC = (RS1 & (1u << (OP2 & 0x1f))) ? (PC + BROFF) : (PC + 1))
> +
> +INSTRUCTION (qbbc,
> + OP2 = (IO ? IMM8 : RS2);
> + PC = !(RS1 & (1u << (OP2 & 0x1f))) ? (PC + BROFF) : (PC + 1))
> +
> +INSTRUCTION (lbbo,
> + pru_dmem2reg (cpu, XBBO_BASEREG + (IO ? IMM8 : RS2),
> + BURSTLEN, RD_REGN, RDB);
> + PC++)
> +
> +INSTRUCTION (sbbo,
> + pru_reg2dmem (cpu, XBBO_BASEREG + (IO ? IMM8 : RS2),
> + BURSTLEN, RD_REGN, RDB);
> + PC++)
> +
> +INSTRUCTION (lbco,
> + pru_dmem2reg (cpu, CTABLE[CB] + (IO ? IMM8 : RS2),
> + BURSTLEN, RD_REGN, RDB);
> + PC++)
> +
> +INSTRUCTION (sbco,
> + pru_reg2dmem (cpu, CTABLE[CB] + (IO ? IMM8 : RS2),
> + BURSTLEN, RD_REGN, RDB);
> + PC++)
> +
> +INSTRUCTION (xin,
> + DO_XIN (XFR_WBA, RD_REGN, RDB, XFR_LENGTH);
> + PC++)
> +
> +INSTRUCTION (xout,
> + DO_XOUT (XFR_WBA, RD_REGN, RDB, XFR_LENGTH);
> + PC++)
> +
> +INSTRUCTION (xchg,
> + DO_XCHG (XFR_WBA, RD_REGN, RDB, XFR_LENGTH);
> + PC++)
> +
> +INSTRUCTION (sxin,
> + sim_io_eprintf (sd, "SXIN instruction not supported by sim\n");
> + RAISE_SIGILL (sd))
> +
> +INSTRUCTION (sxout,
> + sim_io_eprintf (sd, "SXOUT instruction not supported by sim\n");
> + RAISE_SIGILL (sd))
> +
> +INSTRUCTION (sxchg,
> + sim_io_eprintf (sd, "SXCHG instruction not supported by sim\n");
> + RAISE_SIGILL (sd))
> +
> +INSTRUCTION (loop,
> + OP2 = (IO ? IMM8 + 1 : RS2_w0);
> + if (OP2 == 0)
> + {
> + PC = LOOPEND;
> + }
> + else
> + {
> + LOOPTOP = PC + 1;
> + LOOPEND = PC + LOOP_JMPOFFS;
> + LOOPCNT = OP2;
> + LOOP_IN_PROGRESS = 1;
> + PC++;
> + })
> +
> +INSTRUCTION (iloop,
> + OP2 = (IO ? IMM8 + 1 : RS2_w0);
> + if (OP2 == 0)
> + {
> + PC = LOOPEND;
> + }
> + else
> + {
> + LOOPTOP = PC + 1;
> + LOOPEND = PC + LOOP_JMPOFFS;
> + LOOPCNT = OP2;
> + LOOP_IN_PROGRESS = 1;
> + PC++;
> + })
> diff --git a/sim/pru/sim-main.h b/sim/pru/sim-main.h
> new file mode 100644
> index 0000000000..b8a2c20ea8
> --- /dev/null
> +++ b/sim/pru/sim-main.h
> @@ -0,0 +1,91 @@
> +/* Copyright 2016-2019 Free Software Foundation, Inc.
> + Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
> +
> + This file is part of the PRU simulator.
> +
> + This library 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 PRU_SIM_MAIN
> +#define PRU_SIM_MAIN
> +
> +#include <stdint.h>
> +#include <stddef.h>
> +#include "pru.h"
> +#include "sim-basics.h"
> +
> +#include "sim-base.h"
> +
> +/* The machine state.
> + This state is maintained in host byte order. The
> + fetch/store register functions must translate between host
> + byte order and the target processor byte order.
> + Keeping this data in target byte order simplifies the register
> + read/write functions. Keeping this data in host order improves
> + the performance of the simulator. Simulation speed is deemed more
> + important. */
> +
> +/* For clarity, please keep the same relative order in this enum as in the
> + corresponding group of GP registers.
> +
> + In PRU ISA, Multiplier-Accumulator-Unit's registers are like "shadows"
> of + the GP registers. MAC registers are implicitly addressed when
> executing + the XIN/XOUT instructions to access them. Transfer to/from a
> MAC register + can happen only from/to its corresponding GP peer
> register. */ +
> +enum pru_macreg_id {
> + /* MAC register CPU GP register Description. */
> + PRU_MACREG_MODE, /* r25 */ /* Mode (MUL/MAC). */
> + PRU_MACREG_PROD_L, /* r26 */ /* Lower 32 bits of product.
*/
> + PRU_MACREG_PROD_H, /* r27 */ /* Higher 32 bits of product.
*/
> + PRU_MACREG_OP_0, /* r28 */ /* First operand. */
> + PRU_MACREG_OP_1, /* r29 */ /* Second operand. */
> + PRU_MACREG_ACC_L, /* N/A */ /* Accumulator (not exposed)
*/
> + PRU_MACREG_ACC_H, /* N/A */ /* Higher 32 bits of MAC
> + accumulator. */
> + PRU_MAC_NREGS
> +};
> +
> +struct pru_regset
> +{
> + uint32_t regs[32]; /* Primary registers. */
> + uint16_t pc; /* IMEM _word_ address. */
> + uint32_t pc_addr_space_marker; /* IMEM virtual linker offset. This
> + is the artificial offset that
> + we invent in order to "separate"
> + the DMEM and IMEM memory spaces. */
> + unsigned int carry : 1;
> + uint32_t ctable[32]; /* Constant offsets table for xBCO. */
> + uint32_t macregs[PRU_MAC_NREGS];
> + uint32_t scratchpads[XFRID_MAX + 1][32];
> + struct {
> + uint16_t looptop; /* LOOP top (PC of loop instr). */
> + uint16_t loopend; /* LOOP end (PC of loop end label). */
> + int loop_in_progress; /* Whether to check for PC==loopend. */
> + uint32_t loop_counter; /* LOOP counter. */
> + } loop;
> + int cycles;
> + int insts;
> +};
> +
> +struct _sim_cpu {
> + struct pru_regset pru_cpu;
> + sim_cpu_base base;
> +};
> +
> +struct sim_state {
> + sim_cpu *cpu[MAX_NR_PROCESSORS];
> +
> + sim_state_base base;
> +};
> +#endif /* PRU_SIM_MAIN */
* Dimitar Dimitrov <dimitar@dinux.eu> [2019-09-22 11:08:41 +0300]:
> Ping.
Sorry for the delay in reviewing this. I plan to review this in the
first half of this week.
Thanks,
Andrew
>
> On Wednesday, 4 Sep 2019, 22:40:29 EEST Dimitar Dimitrov wrote:
> > I'd like to contribute a sim port for the TI PRU I/O processor. This
> > is the sixth version of the patch series.
> >
> > Changes since patch series v5:
> > - Added copyright headers to test cases.
> > - Regenerated using autoconf-2.69 and automake-1.5.1
> > - Added more comments to functions and MAC register enum.
> > - Updated copyright years.
> >
> > v1: https://sourceware.org/ml/gdb-patches/2016-12/msg00143.html
> > v2: https://sourceware.org/ml/gdb-patches/2017-02/msg00397.html
> > v3: https://sourceware.org/ml/gdb-patches/2017-02/msg00516.html
> > v4: https://sourceware.org/ml/gdb-patches/2018-06/msg00484.html
> > v5: https://sourceware.org/ml/gdb-patches/2019-08/msg00584.html
> >
> > gdb/ChangeLog:
> >
> > 2019-09-04 Dimitar Dimitrov <dimitar@dinux.eu>
> >
> > * NEWS: Mention new simulator port for PRU.
> >
> > sim/
> > 2019-09-04 Dimitar Dimitrov <dimitar@dinux.eu>
> >
> > * MAINTAINERS: Add myself as PRU maintainer.
> > * configure: Regenerated.
> > * configure.tgt: Add PRU.
> >
> > sim/common/
> > 2019-09-04 Dimitar Dimitrov <dimitar@dinux.eu>
> >
> > * gennltvals.sh: Add PRU libgloss target.
> > * nltvals.def: Regenerate from the latest libgloss sources.
> >
> > sim/pru/
> > 2019-09-04 Dimitar Dimitrov <dimitar@dinux.eu>
> >
> > * Makefile.in: New file.
> > * aclocal.m4: Regenerated.
> > * config.in: Regenerated.
> > * configure: Regenerated.
> > * configure.ac: New file.
> > * interp.c: New file.
> > * pru.h: New file.
> > * pru.isa: New file.
> > * sim-main.h: New file.
> >
> > Signed-off-by: Dimitar Dimitrov <dimitar@dinux.eu>
> > ---
> > gdb/NEWS | 4 +
> > sim/MAINTAINERS | 1 +
> > sim/common/gennltvals.sh | 4 +
> > sim/common/nltvals.def | 31 ++
> > sim/configure | 8 +
> > sim/configure.tgt | 3 +
> > sim/pru/Makefile.in | 29 ++
> > sim/pru/aclocal.m4 | 119 ++++++
> > sim/pru/config.in | 248 ++++++++++++
> > sim/pru/configure.ac | 31 ++
> > sim/pru/interp.c | 848 +++++++++++++++++++++++++++++++++++++++
> > sim/pru/pru.h | 110 +++++
> > sim/pru/pru.isa | 249 ++++++++++++
> > sim/pru/sim-main.h | 91 +++++
> > 14 files changed, 1776 insertions(+)
> > create mode 100644 sim/pru/Makefile.in
> > create mode 100644 sim/pru/aclocal.m4
> > create mode 100644 sim/pru/config.in
> > create mode 100644 sim/pru/configure.ac
> > create mode 100644 sim/pru/interp.c
> > create mode 100644 sim/pru/pru.h
> > create mode 100644 sim/pru/pru.isa
> > create mode 100644 sim/pru/sim-main.h
> >
> > diff --git a/gdb/NEWS b/gdb/NEWS
> > index f382e887c0..f4b5c9239c 100644
> > --- a/gdb/NEWS
> > +++ b/gdb/NEWS
> > @@ -318,6 +318,10 @@ maint show test-options-completion-result
> > GDB now bundles GNU readline 8.0, but if you choose to use
> > --with-system-readline, only readline >= 7.0 can be used.
> >
> > +* New Simulators
> > +
> > +TI PRU pru-*-elf
> > +
> > *** Changes in GDB 8.3
> >
> > * GDB and GDBserver now support access to additional registers on
> > diff --git a/sim/MAINTAINERS b/sim/MAINTAINERS
> > index 3b9b08c40d..4ca67cfd1d 100644
> > --- a/sim/MAINTAINERS
> > +++ b/sim/MAINTAINERS
> > @@ -29,6 +29,7 @@ mips I-IV Maciej W. Rozycki <macro@linux-mips.org>
> > moxie Anthony Green <green@moxielogic.com>
> > msp430 Nick Clifton <nickc@redhat.com>
> > or1k Stafford Horne <shorne@gmail.com>
> > +pru Dimitar Dimitrov <dimitar@dinux.eu>
> > sh (global maintainers)
> > sh64 Dave Brolley <brolley@redhat.com>
> > common Frank Ch. Eigler <fche@redhat.com>
> > diff --git a/sim/common/gennltvals.sh b/sim/common/gennltvals.sh
> > index 7027c35ad4..79180335b6 100755
> > --- a/sim/common/gennltvals.sh
> > +++ b/sim/common/gennltvals.sh
> > @@ -95,3 +95,7 @@ $shell ${srccom}/gentvals.sh $target sys
> > ${newlibroot}/$dir \ dir=libgloss target=lm32
> > $shell ${srccom}/gentvals.sh $target sys ${newlibroot}/$dir \
> > "syscall.h" 'SYS_[_[:alnum:]]*' "${cpp}"
> > +
> > +dir=libgloss target=pru
> > +$shell ${srccom}/gentvals.sh $target sys ${newlibroot}/$dir \
> > + "syscall.h" 'SYS_[_[:alnum:]]*' "${cpp}"
> > diff --git a/sim/common/nltvals.def b/sim/common/nltvals.def
> > index 3f82d47b6b..92ccc9aded 100644
> > --- a/sim/common/nltvals.def
> > +++ b/sim/common/nltvals.def
> > @@ -574,3 +574,34 @@
> > /* end lm32 sys target macros */
> > #endif
> > #endif
> > +#ifdef NL_TARGET_pru
> > +#ifdef sys_defs
> > +/* from syscall.h */
> > +/* begin pru sys target macros */
> > + { "SYS_argc", 22 },
> > + { "SYS_argn", 24 },
> > + { "SYS_argnlen", 23 },
> > + { "SYS_argv", 13 },
> > + { "SYS_argvlen", 12 },
> > + { "SYS_chdir", 14 },
> > + { "SYS_chmod", 16 },
> > + { "SYS_close", 3 },
> > + { "SYS_exit", 1 },
> > + { "SYS_fstat", 10 },
> > + { "SYS_getpid", 8 },
> > + { "SYS_gettimeofday", 19 },
> > + { "SYS_kill", 9 },
> > + { "SYS_link", 21 },
> > + { "SYS_lseek", 6 },
> > + { "SYS_open", 2 },
> > + { "SYS_read", 4 },
> > + { "SYS_reconfig", 25 },
> > + { "SYS_stat", 15 },
> > + { "SYS_time", 18 },
> > + { "SYS_times", 20 },
> > + { "SYS_unlink", 7 },
> > + { "SYS_utime", 17 },
> > + { "SYS_write", 5 },
> > +/* end pru sys target macros */
> > +#endif
> > +#endif
> > diff --git a/sim/configure b/sim/configure
> > index ca3fd673ab..72f95cd5c7 100755
> > --- a/sim/configure
> > +++ b/sim/configure
> > @@ -686,6 +686,7 @@ mn10300
> > moxie
> > msp430
> > or1k
> > +pru
> > rl78
> > rx
> > sh64
> > @@ -3837,6 +3838,13 @@ subdirs="$subdirs aarch64"
> > subdirs="$subdirs or1k"
> >
> >
> > + ;;
> > + pru*-*-*)
> > +
> > + sim_arch=pru
> > + subdirs="$subdirs pru"
> > +
> > +
> > ;;
> > rl78-*-*)
> >
> > diff --git a/sim/configure.tgt b/sim/configure.tgt
> > index a6dbd1af83..8a8e03d96f 100644
> > --- a/sim/configure.tgt
> > +++ b/sim/configure.tgt
> > @@ -79,6 +79,9 @@ case "${target}" in
> > or1k-*-* | or1knd-*-*)
> > SIM_ARCH(or1k)
> > ;;
> > + pru*-*-*)
> > + SIM_ARCH(pru)
> > + ;;
> > rl78-*-*)
> > SIM_ARCH(rl78)
> > ;;
> > diff --git a/sim/pru/Makefile.in b/sim/pru/Makefile.in
> > new file mode 100644
> > index 0000000000..5235a5ff07
> > --- /dev/null
> > +++ b/sim/pru/Makefile.in
> > @@ -0,0 +1,29 @@
> > +# Makefile template for Configure for the PRU sim library.
> > +# Copyright (C) 1990-2019 Free Software Foundation, Inc.
> > +# Written by Dimitar Dimitrov <dimitar@dinux.eu>
> > +#
> > +# Based on the MCore sim library
> > +#
> > +# 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_OBJS = \
> > + $(SIM_NEW_COMMON_OBJS) \
> > + interp.o \
> > + sim-resume.o
> > +
> > +NL_TARGET = -DNL_TARGET_pru
> > +
> > +## COMMON_POST_CONFIG_FRAG
> > diff --git a/sim/pru/aclocal.m4 b/sim/pru/aclocal.m4
> > new file mode 100644
> > index 0000000000..e9f11c775c
> > --- /dev/null
> > +++ b/sim/pru/aclocal.m4
> > @@ -0,0 +1,119 @@
> > +# generated automatically by aclocal 1.15.1 -*- Autoconf -*-
> > +
> > +# Copyright (C) 1996-2017 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.
> > +
> > +m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS],
> > [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) +#
> > AM_CONDITIONAL -*- Autoconf -*-
> > +
> > +# Copyright (C) 1997-2017 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.
> > +
> > +# AM_CONDITIONAL(NAME, SHELL-CONDITION)
> > +# -------------------------------------
> > +# Define a conditional.
> > +AC_DEFUN([AM_CONDITIONAL],
> > +[AC_PREREQ([2.52])dnl
> > + m4_if([$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])])
> > +
> > +# Copyright (C) 2003-2017 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.
> > +
> > +# Check whether the underlying file-system supports filenames
> > +# with a leading dot. For instance MS-DOS doesn't.
> > +AC_DEFUN([AM_SET_LEADING_DOT],
> > +[rm -rf .tst 2>/dev/null
> > +mkdir .tst 2>/dev/null
> > +if test -d .tst; then
> > + am__leading_dot=.
> > +else
> > + am__leading_dot=_
> > +fi
> > +rmdir .tst 2>/dev/null
> > +AC_SUBST([am__leading_dot])])
> > +
> > +# Add --enable-maintainer-mode option to configure. -*- Autoconf
> > -*- +# From Jim Meyering
> > +
> > +# Copyright (C) 1996-2017 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.
> > +
> > +# 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],
> > + [AS_HELP_STRING([--]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
> > +]
> > +)
> > +
> > +# Copyright (C) 2006-2017 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.
> > +
> > +# _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($@)])
> > +
> > diff --git a/sim/pru/config.in b/sim/pru/config.in
> > new file mode 100644
> > index 0000000000..7c667a1c0d
> > --- /dev/null
> > +++ b/sim/pru/config.in
> > @@ -0,0 +1,248 @@
> > +/* config.in. Generated from configure.ac by autoheader. */
> > +
> > +/* Define if building universal (internal helper macro) */
> > +#undef AC_APPLE_UNIVERSAL_BUILD
> > +
> > +/* Sim debug setting */
> > +#undef DEBUG
> > +
> > +/* 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 `ftruncate' function. */
> > +#undef HAVE_FTRUNCATE
> > +
> > +/* 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 `lstat' function. */
> > +#undef HAVE_LSTAT
> > +
> > +/* Define to 1 if you have the <memory.h> header file. */
> > +#undef HAVE_MEMORY_H
> > +
> > +/* Define to 1 if you have the `mmap' function. */
> > +#undef HAVE_MMAP
> > +
> > +/* Define to 1 if you have the `munmap' function. */
> > +#undef HAVE_MUNMAP
> > +
> > +/* Define to 1 if you have the `posix_fallocate' function. */
> > +#undef HAVE_POSIX_FALLOCATE
> > +
> > +/* Define to 1 if you have the `sigaction' function. */
> > +#undef HAVE_SIGACTION
> > +
> > +/* Define to 1 if the system has the type `socklen_t'. */
> > +#undef HAVE_SOCKLEN_T
> > +
> > +/* 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 `st_atime' is a member of `struct stat'. */
> > +#undef HAVE_STRUCT_STAT_ST_ATIME
> > +
> > +/* Define to 1 if `st_blksize' is a member of `struct stat'. */
> > +#undef HAVE_STRUCT_STAT_ST_BLKSIZE
> > +
> > +/* Define to 1 if `st_blocks' is a member of `struct stat'. */
> > +#undef HAVE_STRUCT_STAT_ST_BLOCKS
> > +
> > +/* Define to 1 if `st_ctime' is a member of `struct stat'. */
> > +#undef HAVE_STRUCT_STAT_ST_CTIME
> > +
> > +/* Define to 1 if `st_dev' is a member of `struct stat'. */
> > +#undef HAVE_STRUCT_STAT_ST_DEV
> > +
> > +/* Define to 1 if `st_gid' is a member of `struct stat'. */
> > +#undef HAVE_STRUCT_STAT_ST_GID
> > +
> > +/* Define to 1 if `st_ino' is a member of `struct stat'. */
> > +#undef HAVE_STRUCT_STAT_ST_INO
> > +
> > +/* Define to 1 if `st_mode' is a member of `struct stat'. */
> > +#undef HAVE_STRUCT_STAT_ST_MODE
> > +
> > +/* Define to 1 if `st_mtime' is a member of `struct stat'. */
> > +#undef HAVE_STRUCT_STAT_ST_MTIME
> > +
> > +/* Define to 1 if `st_nlink' is a member of `struct stat'. */
> > +#undef HAVE_STRUCT_STAT_ST_NLINK
> > +
> > +/* Define to 1 if `st_rdev' is a member of `struct stat'. */
> > +#undef HAVE_STRUCT_STAT_ST_RDEV
> > +
> > +/* Define to 1 if `st_size' is a member of `struct stat'. */
> > +#undef HAVE_STRUCT_STAT_ST_SIZE
> > +
> > +/* Define to 1 if `st_uid' is a member of `struct stat'. */
> > +#undef HAVE_STRUCT_STAT_ST_UID
> > +
> > +/* Define to 1 if you have the <sys/mman.h> header file. */
> > +#undef HAVE_SYS_MMAN_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/times.h> header file. */
> > +#undef HAVE_SYS_TIMES_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 `truncate' function. */
> > +#undef HAVE_TRUNCATE
> > +
> > +/* 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
> > +
> > +/* Sim profile settings */
> > +#undef PROFILE
> > +
> > +/* 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
> > +
> > +
> > +/* Sim assert settings */
> > +#undef WITH_ASSERT
> > +
> > +/* Sim debug setting */
> > +#undef WITH_DEBUG
> > +
> > +/* Sim default environment */
> > +#undef WITH_ENVIRONMENT
> > +
> > +/* Sim profile settings */
> > +#undef WITH_PROFILE
> > +
> > +/* How to route I/O */
> > +#undef WITH_STDIO
> > +
> > +/* Sim trace settings */
> > +#undef WITH_TRACE
> > +
> > +/* 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
> > diff --git a/sim/pru/configure.ac b/sim/pru/configure.ac
> > new file mode 100644
> > index 0000000000..e7132b4493
> > --- /dev/null
> > +++ b/sim/pru/configure.ac
> > @@ -0,0 +1,31 @@
> > +dnl Process this file with autoconf to produce a configure script.
> > +
> > +dnl Copyright (C) 2016-2019 Free Software Foundation, Inc.
> > +dnl Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
> > +dnl
> > +dnl This file is part of the GNU simulators.
> > +dnl
> > +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/>.
> > +dnl
> > +AC_PREREQ(2.64)dnl
> > +AC_INIT(Makefile.in)
> > +sinclude(../common/acinclude.m4)
> > +
> > +SIM_AC_COMMON
> > +
> > +SIM_AC_OPTION_ENDIAN(LITTLE)
> > +SIM_AC_OPTION_ALIGNMENT(STRICT_ALIGNMENT,STRICT_ALIGNMENT)
> > +SIM_AC_OPTION_WARNINGS
> > +
> > +SIM_AC_OUTPUT
> > diff --git a/sim/pru/interp.c b/sim/pru/interp.c
> > new file mode 100644
> > index 0000000000..0e783c121c
> > --- /dev/null
> > +++ b/sim/pru/interp.c
> > @@ -0,0 +1,848 @@
> > +/* Simulator for the Texas Instruments PRU processor
> > + Copyright 2009-2019 Free Software Foundation, Inc.
> > + Inspired by the Microblaze simulator
> > + Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
> > +
> > + This file is part of the simulators.
> > +
> > + 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 <stdbool.h>
> > +#include <stdint.h>
> > +#include <stddef.h>
> > +#include "bfd.h"
> > +#include "gdb/callback.h"
> > +#include "libiberty.h"
> > +#include "gdb/remote-sim.h"
> > +#include "sim-main.h"
> > +#include "sim-assert.h"
> > +#include "sim-options.h"
> > +#include "sim-syscall.h"
> > +#include "pru.h"
> > +
> > +/* DMEM zero address is perfectly valid. But if CRT leaves the first word
> > + alone, we can use it as a trap to catch NULL pointer access. */
> > +static bfd_boolean abort_on_dmem_zero_access;
> > +
> > +enum {
> > + OPTION_ERROR_NULL_DEREF = OPTION_START,
> > +};
> > +
> > +/* Extract (from PRU endianess) and return an integer in HOST's endianness.
> > */ +static uint32_t
> > +pru_extract_unsigned_integer (uint8_t *addr, size_t len)
> > +{
> > + uint32_t retval;
> > + uint8_t *p;
> > + uint8_t *startaddr = addr;
> > + uint8_t *endaddr = startaddr + len;
> > +
> > + /* Start at the most significant end of the integer, and work towards
> > + the least significant. */
> > + retval = 0;
> > +
> > + for (p = endaddr; p > startaddr;)
> > + retval = (retval << 8) | * -- p;
> > + return retval;
> > +}
> > +
> > +/* Store "val" (which is in HOST's endianess) into "addr"
> > + (using PRU's endianness). */
> > +static void
> > +pru_store_unsigned_integer (uint8_t *addr, size_t len, uint32_t val)
> > +{
> > + uint8_t *p;
> > + uint8_t *startaddr = (uint8_t *)addr;
> > + uint8_t *endaddr = startaddr + len;
> > +
> > + for (p = startaddr; p < endaddr;)
> > + {
> > + *p++ = val & 0xff;
> > + val >>= 8;
> > + }
> > +}
> > +
> > +/* Extract a field value from CPU register using the given REGSEL selector.
> > +
> > + Byte number maps directly to first values of RSEL, so we can
> > + safely use "regsel" as a register byte number (0..3). */
> > +static inline uint32_t
> > +extract_regval (uint32_t val, uint32_t regsel)
> > +{
> > + ASSERT (RSEL_7_0 == 0);
> > + ASSERT (RSEL_15_8 == 1);
> > + ASSERT (RSEL_23_16 == 2);
> > + ASSERT (RSEL_31_24 == 3);
> > +
> > + switch (regsel)
> > + {
> > + case RSEL_7_0: return (val >> 0) & 0xff;
> > + case RSEL_15_8: return (val >> 8) & 0xff;
> > + case RSEL_23_16: return (val >> 16) & 0xff;
> > + case RSEL_31_24: return (val >> 24) & 0xff;
> > + case RSEL_15_0: return (val >> 0) & 0xffff;
> > + case RSEL_23_8: return (val >> 8) & 0xffff;
> > + case RSEL_31_16: return (val >> 16) & 0xffff;
> > + case RSEL_31_0: return val;
> > + default: sim_io_error (NULL, "invalid regsel");
> > + }
> > +}
> > +
> > +/* Write a value into CPU subregister pointed by reg and regsel. */
> > +static inline void
> > +write_regval (uint32_t val, uint32_t *reg, uint32_t regsel)
> > +{
> > + uint32_t mask, sh;
> > +
> > + switch (regsel)
> > + {
> > + case RSEL_7_0: mask = (0xffu << 0); sh = 0; break;
> > + case RSEL_15_8: mask = (0xffu << 8); sh = 8; break;
> > + case RSEL_23_16: mask = (0xffu << 16); sh = 16; break;
> > + case RSEL_31_24: mask = (0xffu << 24); sh = 24; break;
> > + case RSEL_15_0: mask = (0xffffu << 0); sh = 0; break;
> > + case RSEL_23_8: mask = (0xffffu << 8); sh = 8; break;
> > + case RSEL_31_16: mask = (0xffffu << 16); sh = 16; break;
> > + case RSEL_31_0: mask = 0xffffffffu; sh = 0; break;
> > + default: sim_io_error (NULL, "invalid regsel");
> > + }
> > +
> > + *reg = (*reg & ~mask) | ((val << sh) & mask);
> > +}
> > +
> > +/* Convert the given IMEM word address to a regular byte address used by
> > the + GNU ELF container. */
> > +static uint32_t
> > +imem_wordaddr_to_byteaddr (SIM_CPU *cpu, uint16_t wa)
> > +{
> > + return (((uint32_t) wa << 2) & IMEM_ADDR_MASK) | PC_ADDR_SPACE_MARKER;
> > +}
> > +
> > +/* Convert the given ELF text byte address to IMEM word address. */
> > +static uint16_t
> > +imem_byteaddr_to_wordaddr (SIM_CPU *cpu, uint32_t ba)
> > +{
> > + return (ba >> 2) & 0xffff;
> > +}
> > +
> > +
> > +/* Store "nbytes" into DMEM "addr" from CPU register file, starting with
> > + register "regn", and byte "regb" within it. */
> > +static inline void
> > +pru_reg2dmem (SIM_CPU *cpu, uint32_t addr, unsigned int nbytes,
> > + int regn, int regb)
> > +{
> > + /* GDB assumes unconditional access to all memories, so enable additional
> > + checks only in standalone mode. */
> > + bool standalone = (STATE_OPEN_KIND (CPU_STATE (cpu)) ==
> > SIM_OPEN_STANDALONE); +
> > + if (abort_on_dmem_zero_access && addr < 4)
> > + {
> > + sim_core_signal (CPU_STATE (cpu), cpu, PC_byteaddr, write_map,
> > + nbytes, addr, write_transfer,
> > + sim_core_unmapped_signal);
> > + }
> > + else if (standalone && ((addr >= PC_ADDR_SPACE_MARKER)
> > + || (addr + nbytes > PC_ADDR_SPACE_MARKER)))
> > + {
> > + sim_core_signal (CPU_STATE (cpu), cpu, PC_byteaddr, write_map,
> > + nbytes, addr, write_transfer,
> > + sim_core_unmapped_signal);
> > + }
> > + else if ((regn * 4 + regb + nbytes) > (32 * 4))
> > + {
> > + sim_io_eprintf (CPU_STATE (cpu),
> > + "SBBO/SBCO with invalid store data length\n");
> > + RAISE_SIGILL (CPU_STATE (cpu));
> > + }
> > + else
> > + {
> > + TRACE_MEMORY (cpu, "write of %d bytes to %08x", nbytes, addr);
> > + while (nbytes--)
> > + {
> > + sim_core_write_1 (cpu,
> > + PC_byteaddr,
> > + write_map,
> > + addr++,
> > + extract_regval (CPU.regs[regn], regb));
> > +
> > + if (++regb >= 4)
> > + {
> > + regb = 0;
> > + regn++;
> > + }
> > + }
> > + }
> > +}
> > +
> > +/* Load "nbytes" from DMEM "addr" into CPU register file, starting with
> > + register "regn", and byte "regb" within it. */
> > +static inline void
> > +pru_dmem2reg (SIM_CPU *cpu, uint32_t addr, unsigned int nbytes,
> > + int regn, int regb)
> > +{
> > + /* GDB assumes unconditional access to all memories, so enable additional
> > + checks only in standalone mode. */
> > + bool standalone = (STATE_OPEN_KIND (CPU_STATE (cpu)) ==
> > SIM_OPEN_STANDALONE); +
> > + if (abort_on_dmem_zero_access && addr < 4)
> > + {
> > + sim_core_signal (CPU_STATE (cpu), cpu, PC_byteaddr, read_map,
> > + nbytes, addr, read_transfer,
> > + sim_core_unmapped_signal);
> > + }
> > + else if (standalone && ((addr >= PC_ADDR_SPACE_MARKER)
> > + || (addr + nbytes > PC_ADDR_SPACE_MARKER)))
> > + {
> > + /* This check is necessary because our IMEM "address space"
> > + is not really accessible, yet we have mapped it as a generic
> > + memory space. */
> > + sim_core_signal (CPU_STATE (cpu), cpu, PC_byteaddr, read_map,
> > + nbytes, addr, read_transfer,
> > + sim_core_unmapped_signal);
> > + }
> > + else if ((regn * 4 + regb + nbytes) > (32 * 4))
> > + {
> > + sim_io_eprintf (CPU_STATE (cpu),
> > + "LBBO/LBCO with invalid load data length\n");
> > + RAISE_SIGILL (CPU_STATE (cpu));
> > + }
> > + else
> > + {
> > + unsigned int b;
> > + TRACE_MEMORY (cpu, "read of %d bytes from %08x", nbytes, addr);
> > + while (nbytes--)
> > + {
> > + b = sim_core_read_1 (cpu, PC_byteaddr, read_map, addr++);
> > +
> > + /* Reuse the fact the Register Byte Number maps directly to RSEL. */
> > + ASSERT (RSEL_7_0 == 0);
> > + write_regval (b, &CPU.regs[regn], regb);
> > +
> > + if (++regb >= 4)
> > + {
> > + regb = 0;
> > + regn++;
> > + }
> > + }
> > + }
> > +}
> > +
> > +/* Set reset values of general-purpose registers. */
> > +static void
> > +set_initial_gprs (SIM_CPU *cpu)
> > +{
> > + int i;
> > +
> > + /* Set up machine just out of reset. */
> > + CPU_PC_SET (cpu, 0);
> > + PC_ADDR_SPACE_MARKER = IMEM_ADDR_DEFAULT; /* from default linker script?
> > */ +
> > + /* Clean out the GPRs. */
> > + for (i = 0; i < ARRAY_SIZE (CPU.regs); i++)
> > + CPU.regs[i] = 0;
> > + for (i = 0; i < ARRAY_SIZE (CPU.macregs); i++)
> > + CPU.macregs[i] = 0;
> > +
> > + CPU.loop.looptop = CPU.loop.loopend = 0;
> > + CPU.loop.loop_in_progress = 0;
> > + CPU.loop.loop_counter = 0;
> > +
> > + CPU.carry = 0;
> > + CPU.insts = 0;
> > + CPU.cycles = 0;
> > +
> > + /* AM335x should provide sane defaults. */
> > + CPU.ctable[0] = 0x00020000;
> > + CPU.ctable[1] = 0x48040000;
> > + CPU.ctable[2] = 0x4802a000;
> > + CPU.ctable[3] = 0x00030000;
> > + CPU.ctable[4] = 0x00026000;
> > + CPU.ctable[5] = 0x48060000;
> > + CPU.ctable[6] = 0x48030000;
> > + CPU.ctable[7] = 0x00028000;
> > + CPU.ctable[8] = 0x46000000;
> > + CPU.ctable[9] = 0x4a100000;
> > + CPU.ctable[10] = 0x48318000;
> > + CPU.ctable[11] = 0x48022000;
> > + CPU.ctable[12] = 0x48024000;
> > + CPU.ctable[13] = 0x48310000;
> > + CPU.ctable[14] = 0x481cc000;
> > + CPU.ctable[15] = 0x481d0000;
> > + CPU.ctable[16] = 0x481a0000;
> > + CPU.ctable[17] = 0x4819c000;
> > + CPU.ctable[18] = 0x48300000;
> > + CPU.ctable[19] = 0x48302000;
> > + CPU.ctable[20] = 0x48304000;
> > + CPU.ctable[21] = 0x00032400;
> > + CPU.ctable[22] = 0x480c8000;
> > + CPU.ctable[23] = 0x480ca000;
> > + CPU.ctable[24] = 0x00000000;
> > + CPU.ctable[25] = 0x00002000;
> > + CPU.ctable[26] = 0x0002e000;
> > + CPU.ctable[27] = 0x00032000;
> > + CPU.ctable[28] = 0x00000000;
> > + CPU.ctable[29] = 0x49000000;
> > + CPU.ctable[30] = 0x40000000;
> > + CPU.ctable[31] = 0x80000000;
> > +}
> > +
> > +/* Map regsel selector to subregister field width. */
> > +static inline unsigned int
> > +regsel_width (uint32_t regsel)
> > +{
> > + switch (regsel)
> > + {
> > + case RSEL_7_0: return 8;
> > + case RSEL_15_8: return 8;
> > + case RSEL_23_16: return 8;
> > + case RSEL_31_24: return 8;
> > + case RSEL_15_0: return 16;
> > + case RSEL_23_8: return 16;
> > + case RSEL_31_16: return 16;
> > + case RSEL_31_0: return 32;
> > + default: sim_io_error (NULL, "invalid regsel");
> > + }
> > +}
> > +
> > +/* Handle XIN instruction addressing the MAC peripheral. */
> > +static void
> > +pru_sim_xin_mac (SIM_DESC sd, SIM_CPU *cpu, unsigned int rd_regn,
> > + unsigned int rdb, unsigned int length)
> > +{
> > + if (rd_regn < 25 || (rd_regn * 4 + rdb + length) > (27 + 1) * 4)
> > + sim_io_error (sd, "XIN MAC: invalid transfer regn=%u.%u, length=%u\n",
> > + rd_regn, rdb, length);
> > +
> > + /* Copy from MAC to PRU regs. Ranges have been validated above. */
> > + while (length--)
> > + {
> > + write_regval (CPU.macregs[rd_regn - 25] >> (rdb * 8),
> > + &CPU.regs[rd_regn],
> > + rdb);
> > + if (++rdb == 4)
> > + {
> > + rdb = 0;
> > + rd_regn++;
> > + }
> > + }
> > +}
> > +
> > +/* Handle XIN instruction. */
> > +static void
> > +pru_sim_xin (SIM_DESC sd, SIM_CPU *cpu, unsigned int wba,
> > + unsigned int rd_regn, unsigned int rdb, unsigned int length)
> > +{
> > + if (wba == 0)
> > + {
> > + pru_sim_xin_mac (sd, cpu, rd_regn, rdb, length);
> > + }
> > + else if (wba == XFRID_SCRATCH_BANK_0 || wba == XFRID_SCRATCH_BANK_1
> > + || wba == XFRID_SCRATCH_BANK_2 || wba == XFRID_SCRATCH_BANK_PEER)
> > + {
> > + while (length--)
> > + {
> > + unsigned int val;
> > +
> > + val = extract_regval (CPU.scratchpads[wba][rd_regn], rdb);
> > + write_regval (val, &CPU.regs[rd_regn], rdb);
> > + if (++rdb == 4)
> > + {
> > + rdb = 0;
> > + rd_regn++;
> > + }
> > + }
> > + }
> > + else if (wba == 254 || wba == 255)
> > + {
> > + /* FILL/ZERO pseudos implemented via XIN. */
> > + unsigned int fillbyte = (wba == 254) ? 0xff : 0x00;
> > + while (length--)
> > + {
> > + write_regval (fillbyte, &CPU.regs[rd_regn], rdb);
> > + if (++rdb == 4)
> > + {
> > + rdb = 0;
> > + rd_regn++;
> > + }
> > + }
> > + }
> > + else
> > + {
> > + sim_io_error (sd, "XIN: XFR device %d not supported.\n", wba);
> > + }
> > +}
> > +
> > +/* Handle XOUT instruction addressing the MAC peripheral. */
> > +static void
> > +pru_sim_xout_mac (SIM_DESC sd, SIM_CPU *cpu, unsigned int rd_regn,
> > + unsigned int rdb, unsigned int length)
> > +{
> > + const int modereg_accessed = (rd_regn == 25);
> > +
> > + /* Multiple Accumulate. */
> > + if (rd_regn < 25 || (rd_regn * 4 + rdb + length) > (27 + 1) * 4)
> > + sim_io_error (sd, "XOUT MAC: invalid transfer regn=%u.%u, length=%u\n",
> > + rd_regn, rdb, length);
> > +
> > + /* Copy from PRU to MAC regs. Ranges have been validated above. */
> > + while (length--)
> > + {
> > + write_regval (CPU.regs[rd_regn] >> (rdb * 8),
> > + &CPU.macregs[rd_regn - 25],
> > + rdb);
> > + if (++rdb == 4)
> > + {
> > + rdb = 0;
> > + rd_regn++;
> > + }
> > + }
> > +
> > + if (modereg_accessed
> > + && (CPU.macregs[PRU_MACREG_MODE] & MAC_R25_MAC_MODE_MASK))
> > + {
> > + /* MUL/MAC operands are sampled every XOUT in multiply and
> > + accumulate mode. */
> > + uint64_t prod, oldsum, sum;
> > + CPU.macregs[PRU_MACREG_OP_0] = CPU.regs[28];
> > + CPU.macregs[PRU_MACREG_OP_1] = CPU.regs[29];
> > +
> > + prod = CPU.macregs[PRU_MACREG_OP_0];
> > + prod *= (uint64_t)CPU.macregs[PRU_MACREG_OP_1];
> > +
> > + oldsum = CPU.macregs[PRU_MACREG_ACC_L];
> > + oldsum += (uint64_t)CPU.macregs[PRU_MACREG_ACC_H] << 32;
> > + sum = oldsum + prod;
> > +
> > + CPU.macregs[PRU_MACREG_PROD_L] = sum & 0xfffffffful;
> > + CPU.macregs[PRU_MACREG_PROD_H] = sum >> 32;
> > + CPU.macregs[PRU_MACREG_ACC_L] = CPU.macregs[PRU_MACREG_PROD_L];
> > + CPU.macregs[PRU_MACREG_ACC_H] = CPU.macregs[PRU_MACREG_PROD_H];
> > +
> > + if (oldsum > sum)
> > + CPU.macregs[PRU_MACREG_MODE] |= MAC_R25_ACC_CARRY_MASK;
> > + }
> > + if (modereg_accessed
> > + && (CPU.macregs[PRU_MACREG_MODE] & MAC_R25_ACC_CARRY_MASK))
> > + {
> > + /* store 1 to clear. */
> > + CPU.macregs[PRU_MACREG_MODE] &= ~MAC_R25_ACC_CARRY_MASK;
> > + CPU.macregs[PRU_MACREG_ACC_L] = 0;
> > + CPU.macregs[PRU_MACREG_ACC_H] = 0;
> > + }
> > +
> > +}
> > +
> > +/* Handle XOUT instruction. */
> > +static void
> > +pru_sim_xout (SIM_DESC sd, SIM_CPU *cpu, unsigned int wba,
> > + unsigned int rd_regn, unsigned int rdb, unsigned int length)
> > +{
> > + if (wba == 0)
> > + {
> > + pru_sim_xout_mac (sd, cpu, rd_regn, rdb, length);
> > + }
> > + else if (wba == XFRID_SCRATCH_BANK_0 || wba == XFRID_SCRATCH_BANK_1
> > + || wba == XFRID_SCRATCH_BANK_2 || wba == XFRID_SCRATCH_BANK_PEER)
> > + {
> > + while (length--)
> > + {
> > + unsigned int val;
> > +
> > + val = extract_regval (CPU.regs[rd_regn], rdb);
> > + write_regval (val, &CPU.scratchpads[wba][rd_regn], rdb);
> > + if (++rdb == 4)
> > + {
> > + rdb = 0;
> > + rd_regn++;
> > + }
> > + }
> > + }
> > + else
> > + sim_io_error (sd, "XOUT: XFR device %d not supported.\n", wba);
> > +}
> > +
> > +/* Handle XCHG instruction. */
> > +static void
> > +pru_sim_xchg (SIM_DESC sd, SIM_CPU *cpu, unsigned int wba,
> > + unsigned int rd_regn, unsigned int rdb, unsigned int length)
> > +{
> > + if (wba == XFRID_SCRATCH_BANK_0 || wba == XFRID_SCRATCH_BANK_1
> > + || wba == XFRID_SCRATCH_BANK_2 || wba == XFRID_SCRATCH_BANK_PEER)
> > + {
> > + while (length--)
> > + {
> > + unsigned int valr, vals;
> > +
> > + valr = extract_regval (CPU.regs[rd_regn], rdb);
> > + vals = extract_regval (CPU.scratchpads[wba][rd_regn], rdb);
> > + write_regval (valr, &CPU.scratchpads[wba][rd_regn], rdb);
> > + write_regval (vals, &CPU.regs[rd_regn], rdb);
> > + if (++rdb == 4)
> > + {
> > + rdb = 0;
> > + rd_regn++;
> > + }
> > + }
> > + }
> > + else
> > + sim_io_error (sd, "XOUT: XFR device %d not supported.\n", wba);
> > +}
> > +
> > +/* Handle syscall simulation. Its ABI is specific to the GNU simulator.
> > */ +static void
> > +pru_sim_syscall (SIM_DESC sd, SIM_CPU *cpu)
> > +{
> > + /* If someday TI confirms that the "reserved" HALT opcode fields
> > + can be used for extra arguments, then maybe we can embed
> > + the syscall number there. Until then, let's use R1. */
> > + const uint32_t syscall_num = CPU.regs[1];
> > + long ret;
> > +
> > + ret = sim_syscall (cpu, syscall_num,
> > + CPU.regs[14], CPU.regs[15],
> > + CPU.regs[16], CPU.regs[17]);
> > + CPU.regs[14] = ret;
> > +}
> > +
> > +/* Simulate one instruction. */
> > +static void
> > +sim_step_once (SIM_DESC sd)
> > +{
> > + SIM_CPU *cpu = STATE_CPU (sd, 0);
> > + const struct pru_opcode *op;
> > + uint32_t inst;
> > + uint32_t _RDVAL, OP2; /* intermediate values. */
> > + int rd_is_modified = 0; /* RD modified and must be stored back. */
> > +
> > + /* Fetch the initial instruction that we'll decode. */
> > + inst = sim_core_read_4 (cpu, PC_byteaddr, exec_map, PC_byteaddr);
> > + TRACE_MEMORY (cpu, "read of insn 0x%08x from %08x", inst, PC_byteaddr);
> > +
> > + op = pru_find_opcode (inst);
> > +
> > + if (!op)
> > + {
> > + sim_io_eprintf (sd, "Unknown instruction 0x%04x\n", inst);
> > + RAISE_SIGILL (sd);
> > + }
> > + else
> > + {
> > + TRACE_DISASM (cpu, PC_byteaddr);
> > +
> > + /* In multiply-only mode, R28/R29 operands are sampled on every clock
> > + cycle. */
> > + if ((CPU.macregs[PRU_MACREG_MODE] & MAC_R25_MAC_MODE_MASK) == 0)
> > + {
> > + CPU.macregs[PRU_MACREG_OP_0] = CPU.regs[28];
> > + CPU.macregs[PRU_MACREG_OP_1] = CPU.regs[29];
> > + }
> > +
> > + switch (op->type)
> > + {
> > +/* Helper macro to improve clarity of pru.isa. The empty while is a
> > + guard against using RD as a left-hand side value. */
> > +#define RD do { } while (0); rd_is_modified = 1; _RDVAL
> > +#define INSTRUCTION(NAME, ACTION) \
> > + case prui_ ## NAME: \
> > + ACTION; \
> > + break;
> > +#include "pru.isa"
> > +#undef INSTRUCTION
> > +#undef RD
> > +
> > + default:
> > + RAISE_SIGILL (sd);
> > + }
> > +
> > + if (rd_is_modified)
> > + write_regval (_RDVAL, &CPU.regs[RD_REGN], RDSEL);
> > +
> > + /* Don't treat r30 and r31 as regular registers, they are I/O! */
> > + CPU.regs[30] = 0;
> > + CPU.regs[31] = 0;
> > +
> > + /* Handle PC match of loop end. */
> > + if (LOOP_IN_PROGRESS && (PC == LOOPEND))
> > + {
> > + SIM_ASSERT (LOOPCNT > 0);
> > + if (--LOOPCNT == 0)
> > + LOOP_IN_PROGRESS = 0;
> > + else
> > + PC = LOOPTOP;
> > + }
> > +
> > + /* In multiply-only mode, MAC does multiplication every cycle. */
> > + if ((CPU.macregs[PRU_MACREG_MODE] & MAC_R25_MAC_MODE_MASK) == 0)
> > + {
> > + uint64_t prod;
> > + prod = CPU.macregs[PRU_MACREG_OP_0];
> > + prod *= (uint64_t)CPU.macregs[PRU_MACREG_OP_1];
> > + CPU.macregs[PRU_MACREG_PROD_L] = prod & 0xfffffffful;
> > + CPU.macregs[PRU_MACREG_PROD_H] = prod >> 32;
> > +
> > + /* Clear the MAC accumulator when in normal mode. */
> > + CPU.macregs[PRU_MACREG_ACC_L] = 0;
> > + CPU.macregs[PRU_MACREG_ACC_H] = 0;
> > + }
> > +
> > + /* Update cycle counts. */
> > + CPU.insts += 1; /* One instruction completed ... */
> > + CPU.cycles += 1; /* ... and it takes a single cycle. */
> > +
> > + /* Account for memory access latency with a reasonable estimate.
> > + No distinction is currently made between SRAM, DRAM and generic
> > + L3 slaves. */
> > + if (op->type == prui_lbbo || op->type == prui_sbbo
> > + || op->type == prui_lbco || op->type == prui_sbco)
> > + CPU.cycles += 2;
> > +
> > + }
> > +}
> > +
> > +/* Implement standard sim_engine_run function. */
> > +void
> > +sim_engine_run (SIM_DESC sd,
> > + int next_cpu_nr, /* ignore */
> > + int nr_cpus, /* ignore */
> > + int siggnal) /* ignore */
> > +{
> > + while (1)
> > + {
> > + sim_step_once (sd);
> > + if (sim_events_tick (sd))
> > + sim_events_process (sd);
> > + }
> > +}
> > +
> > +
> > +/* Implement callback for standard CPU_PC_FETCH routine. */
> > +static sim_cia
> > +pru_pc_get (sim_cpu *cpu)
> > +{
> > + /* Present PC as byte address. */
> > + return imem_wordaddr_to_byteaddr (cpu, cpu->pru_cpu.pc);
> > +}
> > +
> > +/* Implement callback for standard CPU_PC_STORE routine. */
> > +static void
> > +pru_pc_set (sim_cpu *cpu, sim_cia pc)
> > +{
> > + /* PC given as byte address. */
> > + cpu->pru_cpu.pc = imem_byteaddr_to_wordaddr (cpu, pc);
> > +}
> > +
> > +
> > +/* Implement callback for standard CPU_REG_STORE routine. */
> > +static int
> > +pru_store_register (SIM_CPU *cpu, int rn, unsigned char *memory, int
> > length) +{
> > + if (rn < NUM_REGS && rn >= 0)
> > + {
> > + if (length == 4)
> > + {
> > + /* Misalignment safe. */
> > + long ival = pru_extract_unsigned_integer (memory, 4);
> > + if (rn < 32)
> > + CPU.regs[rn] = ival;
> > + else
> > + pru_pc_set (cpu, ival);
> > + return 4;
> > + }
> > + else
> > + return 0;
> > + }
> > + else
> > + return 0;
> > +}
> > +
> > +/* Implement callback for standard CPU_REG_FETCH routine. */
> > +static int
> > +pru_fetch_register (SIM_CPU *cpu, int rn, unsigned char *memory, int
> > length) +{
> > + long ival;
> > +
> > + if (rn < NUM_REGS && rn >= 0)
> > + {
> > + if (length == 4)
> > + {
> > + if (rn < 32)
> > + ival = CPU.regs[rn];
> > + else
> > + ival = pru_pc_get (cpu);
> > +
> > + /* Misalignment-safe. */
> > + pru_store_unsigned_integer (memory, 4, ival);
> > + return 4;
> > + }
> > + else
> > + return 0;
> > + }
> > + else
> > + return 0;
> > +}
> > +
> > +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);
> > +}
> > +
> > +/* Declare the PRU option handler. */
> > +static DECLARE_OPTION_HANDLER (pru_option_handler);
> > +
> > +/* Implement the PRU option handler. */
> > +static SIM_RC
> > +pru_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt, char *arg,
> > + int is_command)
> > +{
> > + switch (opt)
> > + {
> > + case OPTION_ERROR_NULL_DEREF:
> > + abort_on_dmem_zero_access = TRUE;
> > + return SIM_RC_OK;
> > +
> > + default:
> > + sim_io_eprintf (sd, "Unknown PRU option %d\n", opt);
> > + return SIM_RC_FAIL;
> > + }
> > +}
> > +
> > +/* List of PRU-specific options. */
> > +static const OPTION pru_options[] =
> > +{
> > + { {"error-null-deref", no_argument, NULL, OPTION_ERROR_NULL_DEREF},
> > + '\0', NULL, "Trap any access to DMEM address zero",
> > + pru_option_handler, NULL },
> > +
> > + { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL, NULL }
> > +};
> > +
> > +/* Implement standard sim_open function. */
> > +SIM_DESC
> > +sim_open (SIM_OPEN_KIND kind, host_callback *cb,
> > + struct bfd *abfd, char * const *argv)
> > +{
> > + int i;
> > + char c;
> > + SIM_DESC sd = sim_state_alloc (kind, cb);
> > + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
> > +
> > + /* The cpu data is kept in a separately allocated chunk of memory. */
> > + if (sim_cpu_alloc_all (sd, 1, /*cgen_cpu_max_extra_bytes ()*/0) !=
> > SIM_RC_OK) + {
> > + free_state (sd);
> > + return 0;
> > + }
> > +
> > + if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
> > + {
> > + free_state (sd);
> > + return 0;
> > + }
> > + sim_add_option_table (sd, NULL, pru_options);
> > +
> > + /* The parser will print an error message for us, so we silently return.
> > */ + if (sim_parse_args (sd, argv) != SIM_RC_OK)
> > + {
> > + free_state (sd);
> > + return 0;
> > + }
> > +
> > + /* Check for/establish a reference program image. */
> > + if (sim_analyze_program (sd,
> > + (STATE_PROG_ARGV (sd) != NULL
> > + ? *STATE_PROG_ARGV (sd)
> > + : NULL), abfd) != SIM_RC_OK)
> > + {
> > + free_state (sd);
> > + return 0;
> > + }
> > +
> > + /* Configure/verify the target byte order and other runtime
> > + configuration options. */
> > + if (sim_config (sd) != SIM_RC_OK)
> > + {
> > + sim_module_uninstall (sd);
> > + return 0;
> > + }
> > +
> > + if (sim_post_argv_init (sd) != SIM_RC_OK)
> > + {
> > + /* Uninstall the modules to avoid memory leaks,
> > + file descriptor leaks, etc. */
> > + sim_module_uninstall (sd);
> > + return 0;
> > + }
> > +
> > + /* CPU specific initialization. */
> > + for (i = 0; i < MAX_NR_PROCESSORS; ++i)
> > + {
> > + SIM_CPU *cpu = STATE_CPU (sd, i);
> > +
> > + CPU_REG_STORE (cpu) = pru_store_register;
> > + CPU_REG_FETCH (cpu) = pru_fetch_register;
> > + CPU_PC_FETCH (cpu) = pru_pc_get;
> > + CPU_PC_STORE (cpu) = pru_pc_set;
> > +
> > + set_initial_gprs (cpu);
> > + }
> > +
> > + /* Allocate external memory if none specified by user.
> > + Use address 4 here in case the user wanted address 0 unmapped. */
> > + if (sim_core_read_buffer (sd, NULL, read_map, &c, 4, 1) == 0)
> > + {
> > + sim_do_commandf (sd, "memory-region 0x%x,0x%x",
> > + 0,
> > + DMEM_DEFAULT_SIZE);
> > + }
> > + if (sim_core_read_buffer (sd, NULL, read_map, &c, IMEM_ADDR_DEFAULT, 1)
> > == 0) + {
> > + sim_do_commandf (sd, "memory-region 0x%x,0x%x",
> > + IMEM_ADDR_DEFAULT,
> > + IMEM_DEFAULT_SIZE);
> > + }
> > +
> > + return sd;
> > +}
> > +
> > +/* Implement standard sim_create_inferior function. */
> > +SIM_RC
> > +sim_create_inferior (SIM_DESC sd, struct bfd *prog_bfd,
> > + char * const *argv, char * const *env)
> > +{
> > + SIM_CPU *cpu = STATE_CPU (sd, 0);
> > + SIM_ADDR addr;
> > +
> > + addr = bfd_get_start_address (prog_bfd);
> > +
> > + sim_pc_set (cpu, addr);
> > + PC_ADDR_SPACE_MARKER = addr & ~IMEM_ADDR_MASK;
> > +
> > + /* Standalone mode (i.e. `run`) will take care of the argv for us in
> > + sim_open () -> sim_parse_args (). But in debug mode (i.e. 'target
> > sim' + with `gdb`), we need to handle it because the user can change
> > the + argv on the fly via gdb's 'run'. */
> > + if (STATE_PROG_ARGV (sd) != argv)
> > + {
> > + freeargv (STATE_PROG_ARGV (sd));
> > + STATE_PROG_ARGV (sd) = dupargv (argv);
> > + }
> > +
> > + return SIM_RC_OK;
> > +}
> > diff --git a/sim/pru/pru.h b/sim/pru/pru.h
> > new file mode 100644
> > index 0000000000..8b005ef0b5
> > --- /dev/null
> > +++ b/sim/pru/pru.h
> > @@ -0,0 +1,110 @@
> > +/* Copyright 2016-2019 Free Software Foundation, Inc.
> > + Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
> > +
> > + This file is part of the PRU simulator.
> > +
> > + This library 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 PRU_H
> > +#define PRU_H
> > +
> > +#include "config.h"
> > +#include "opcode/pru.h"
> > +
> > +/* NOTE: Needed for handling the dual PRU address space. */
> > +#define IMEM_ADDR_MASK ((1u << 23) - 1)
> > +
> > +#define IMEM_ADDR_DEFAULT 0x20000000
> > +
> > +/* Define memory sizes to allocate for simulated target. Sizes are
> > + artificially large to accommodate execution of compiler test suite.
> > + Please synchronize with the linker script for prusim target. */
> > +#define DMEM_DEFAULT_SIZE (64 * 1024 * 1024)
> > +
> > +/* 16-bit word addressable space. */
> > +#define IMEM_DEFAULT_SIZE (64 * 4 * 1024)
> > +
> > +/* For AM335x SoCs. */
> > +#define XFRID_SCRATCH_BANK_0 10
> > +#define XFRID_SCRATCH_BANK_1 11
> > +#define XFRID_SCRATCH_BANK_2 12
> > +#define XFRID_SCRATCH_BANK_PEER 14
> > +#define XFRID_MAX 255
> > +
> > +#define CPU (cpu->pru_cpu)
> > +
> > +#define PC (CPU.pc)
> > +#define PC_byteaddr ((PC << 2) | PC_ADDR_SPACE_MARKER)
> > +
> > +/* Various opcode fields. */
> > +#define RS1 extract_regval (CPU.regs[GET_INSN_FIELD (RS1, inst)], \
> > + GET_INSN_FIELD (RS1SEL, inst))
> > +#define RS2 extract_regval (CPU.regs[GET_INSN_FIELD (RS2, inst)], \
> > + GET_INSN_FIELD (RS2SEL, inst))
> > +
> > +#define RS2_w0 extract_regval (CPU.regs[GET_INSN_FIELD (RS2, inst)], \
> > + RSEL_15_0)
> > +
> > +#define XBBO_BASEREG (CPU.regs[GET_INSN_FIELD (RS1, inst)])
> > +
> > +#define RDSEL GET_INSN_FIELD (RDSEL, inst)
> > +#define RD_WIDTH regsel_width (RDSEL)
> > +#define RD_REGN GET_INSN_FIELD (RD, inst)
> > +#define IO GET_INSN_FIELD (IO, inst)
> > +#define IMM8 GET_INSN_FIELD (IMM8, inst)
> > +#define IMM16 GET_INSN_FIELD (IMM16, inst)
> > +#define WAKEONSTATUS GET_INSN_FIELD (WAKEONSTATUS, inst)
> > +#define CB GET_INSN_FIELD (CB, inst)
> > +#define RDB GET_INSN_FIELD (RDB, inst)
> > +#define XFR_WBA GET_INSN_FIELD (XFR_WBA, inst)
> > +#define LOOP_JMPOFFS GET_INSN_FIELD (LOOP_JMPOFFS, inst)
> > +#define BROFF ((uint32_t) GET_BROFF_SIGNED (inst))
> > +
> > +#define _BURSTLEN_CALCULATE(BITFIELD) \
> > + ((BITFIELD) >= LSSBBO_BYTECOUNT_R0_BITS7_0 ? \
> > + (CPU.regs[0] >> ((BITFIELD) - LSSBBO_BYTECOUNT_R0_BITS7_0) * 8) & 0xff
> > \ + : (BITFIELD) + 1)
> > +
> > +#define BURSTLEN _BURSTLEN_CALCULATE (GET_BURSTLEN (inst))
> > +#define XFR_LENGTH _BURSTLEN_CALCULATE (GET_INSN_FIELD (XFR_LENGTH, inst))
> > +
> > +#define DO_XIN(wba,regn,rdb,l) \
> > + pru_sim_xin (sd, cpu, (wba), (regn), (rdb), (l))
> > +#define DO_XOUT(wba,regn,rdb,l) \
> > + pru_sim_xout (sd, cpu, (wba), (regn), (rdb), (l))
> > +#define DO_XCHG(wba,regn,rdb,l) \
> > + pru_sim_xchg (sd, cpu, (wba), (regn), (rdb), (l))
> > +
> > +#define RAISE_SIGILL(sd) sim_engine_halt ((sd), NULL, NULL, PC_byteaddr, \
> > + sim_stopped, SIM_SIGILL)
> > +#define RAISE_SIGINT(sd) sim_engine_halt ((sd), NULL, NULL, PC_byteaddr, \
> > + sim_stopped, SIM_SIGINT)
> > +
> > +#define MAC_R25_MAC_MODE_MASK (1u << 0)
> > +#define MAC_R25_ACC_CARRY_MASK (1u << 1)
> > +
> > +#define CARRY CPU.carry
> > +#define CTABLE CPU.ctable
> > +
> > +#define PC_ADDR_SPACE_MARKER CPU.pc_addr_space_marker
> > +
> > +#define LOOPTOP CPU.loop.looptop
> > +#define LOOPEND CPU.loop.loopend
> > +#define LOOP_IN_PROGRESS CPU.loop.loop_in_progress
> > +#define LOOPCNT CPU.loop.loop_counter
> > +
> > +/* 32 GP registers plus PC. */
> > +#define NUM_REGS 33
> > +
> > +#endif /* PRU_H */
> > diff --git a/sim/pru/pru.isa b/sim/pru/pru.isa
> > new file mode 100644
> > index 0000000000..c906b2a169
> > --- /dev/null
> > +++ b/sim/pru/pru.isa
> > @@ -0,0 +1,249 @@
> > +/* Copyright 2016-2019 Free Software Foundation, Inc.
> > + Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
> > +
> > + This file is part of the PRU simulator.
> > +
> > + This library 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/>. */
> > +
> > +/*
> > + PRU Instruction Set Architecture
> > +
> > + INSTRUCTION (NAME,
> > + SEMANTICS)
> > + */
> > +
> > +INSTRUCTION (add,
> > + OP2 = (IO ? IMM8 : RS2);
> > + RD = RS1 + OP2;
> > + CARRY = (((uint64_t) RS1 + (uint64_t) OP2) >> RD_WIDTH) & 1;
> > + PC++)
> > +
> > +INSTRUCTION (adc,
> > + OP2 = (IO ? IMM8 : RS2);
> > + RD = RS1 + OP2 + CARRY;
> > + CARRY = (((uint64_t) RS1 + (uint64_t) OP2 + (uint64_t) CARRY)
> > + >> RD_WIDTH) & 1;
> > + PC++)
> > +
> > +INSTRUCTION (sub,
> > + OP2 = (IO ? IMM8 : RS2);
> > + RD = RS1 - OP2;
> > + CARRY = (((uint64_t) RS1 - (uint64_t) OP2) >> RD_WIDTH) & 1;
> > + PC++)
> > +
> > +INSTRUCTION (suc,
> > + OP2 = (IO ? IMM8 : RS2);
> > + RD = RS1 - OP2 - CARRY;
> > + CARRY = (((uint64_t) RS1 - (uint64_t) OP2 - (uint64_t) CARRY)
> > + >> RD_WIDTH) & 1;
> > + PC++)
> > +
> > +INSTRUCTION (rsb,
> > + OP2 = (IO ? IMM8 : RS2);
> > + RD = OP2 - RS1;
> > + CARRY = (((uint64_t) OP2 - (uint64_t) RS1) >> RD_WIDTH) & 1;
> > + PC++)
> > +
> > +INSTRUCTION (rsc,
> > + OP2 = (IO ? IMM8 : RS2);
> > + RD = OP2 - RS1 - CARRY;
> > + CARRY = (((uint64_t) OP2 - (uint64_t) RS1 - (uint64_t) CARRY)
> > + >> RD_WIDTH) & 1;
> > + PC++)
> > +
> > +INSTRUCTION (lsl,
> > + OP2 = (IO ? IMM8 : RS2);
> > + RD = RS1 << (OP2 & 0x1f);
> > + PC++)
> > +
> > +INSTRUCTION (lsr,
> > + OP2 = (IO ? IMM8 : RS2);
> > + RD = RS1 >> (OP2 & 0x1f);
> > + PC++)
> > +
> > +INSTRUCTION (and,
> > + OP2 = (IO ? IMM8 : RS2);
> > + RD = RS1 & OP2;
> > + PC++)
> > +
> > +INSTRUCTION (or,
> > + OP2 = (IO ? IMM8 : RS2);
> > + RD = RS1 | OP2;
> > + PC++)
> > +
> > +INSTRUCTION (xor,
> > + OP2 = (IO ? IMM8 : RS2);
> > + RD = RS1 ^ OP2;
> > + PC++)
> > +
> > +INSTRUCTION (not,
> > + RD = ~RS1;
> > + PC++)
> > +
> > +INSTRUCTION (min,
> > + OP2 = (IO ? IMM8 : RS2);
> > + RD = RS1 < OP2 ? RS1 : OP2;
> > + PC++)
> > +
> > +INSTRUCTION (max,
> > + OP2 = (IO ? IMM8 : RS2);
> > + RD = RS1 > OP2 ? RS1 : OP2;
> > + PC++)
> > +
> > +INSTRUCTION (clr,
> > + OP2 = (IO ? IMM8 : RS2);
> > + RD = RS1 & ~(1u << (OP2 & 0x1f));
> > + PC++)
> > +
> > +INSTRUCTION (set,
> > + OP2 = (IO ? IMM8 : RS2);
> > + RD = RS1 | (1u << (OP2 & 0x1f));
> > + PC++)
> > +
> > +INSTRUCTION (jmp,
> > + OP2 = (IO ? IMM16 : RS2);
> > + PC = OP2)
> > +
> > +INSTRUCTION (jal,
> > + OP2 = (IO ? IMM16 : RS2);
> > + RD = PC + 1;
> > + PC = OP2)
> > +
> > +INSTRUCTION (ldi,
> > + RD = IMM16;
> > + PC++)
> > +
> > +INSTRUCTION (halt,
> > + pru_sim_syscall (sd, cpu);
> > + PC++)
> > +
> > +INSTRUCTION (slp,
> > + if (!WAKEONSTATUS)
> > + {
> > + RAISE_SIGINT (sd);
> > + }
> > + else
> > + {
> > + PC++;
> > + })
> > +
> > +INSTRUCTION (qbgt,
> > + OP2 = (IO ? IMM8 : RS2);
> > + PC = (OP2 > RS1) ? (PC + BROFF) : (PC + 1))
> > +
> > +INSTRUCTION (qbge,
> > + OP2 = (IO ? IMM8 : RS2);
> > + PC = (OP2 >= RS1) ? (PC + BROFF) : (PC + 1))
> > +
> > +INSTRUCTION (qblt,
> > + OP2 = (IO ? IMM8 : RS2);
> > + PC = (OP2 < RS1) ? (PC + BROFF) : (PC + 1))
> > +
> > +INSTRUCTION (qble,
> > + OP2 = (IO ? IMM8 : RS2);
> > + PC = (OP2 <= RS1) ? (PC + BROFF) : (PC + 1))
> > +
> > +INSTRUCTION (qbeq,
> > + OP2 = (IO ? IMM8 : RS2);
> > + PC = (OP2 == RS1) ? (PC + BROFF) : (PC + 1))
> > +
> > +INSTRUCTION (qbne,
> > + OP2 = (IO ? IMM8 : RS2);
> > + PC = (OP2 != RS1) ? (PC + BROFF) : (PC + 1))
> > +
> > +INSTRUCTION (qba,
> > + OP2 = (IO ? IMM8 : RS2);
> > + PC = PC + BROFF)
> > +
> > +INSTRUCTION (qbbs,
> > + OP2 = (IO ? IMM8 : RS2);
> > + PC = (RS1 & (1u << (OP2 & 0x1f))) ? (PC + BROFF) : (PC + 1))
> > +
> > +INSTRUCTION (qbbc,
> > + OP2 = (IO ? IMM8 : RS2);
> > + PC = !(RS1 & (1u << (OP2 & 0x1f))) ? (PC + BROFF) : (PC + 1))
> > +
> > +INSTRUCTION (lbbo,
> > + pru_dmem2reg (cpu, XBBO_BASEREG + (IO ? IMM8 : RS2),
> > + BURSTLEN, RD_REGN, RDB);
> > + PC++)
> > +
> > +INSTRUCTION (sbbo,
> > + pru_reg2dmem (cpu, XBBO_BASEREG + (IO ? IMM8 : RS2),
> > + BURSTLEN, RD_REGN, RDB);
> > + PC++)
> > +
> > +INSTRUCTION (lbco,
> > + pru_dmem2reg (cpu, CTABLE[CB] + (IO ? IMM8 : RS2),
> > + BURSTLEN, RD_REGN, RDB);
> > + PC++)
> > +
> > +INSTRUCTION (sbco,
> > + pru_reg2dmem (cpu, CTABLE[CB] + (IO ? IMM8 : RS2),
> > + BURSTLEN, RD_REGN, RDB);
> > + PC++)
> > +
> > +INSTRUCTION (xin,
> > + DO_XIN (XFR_WBA, RD_REGN, RDB, XFR_LENGTH);
> > + PC++)
> > +
> > +INSTRUCTION (xout,
> > + DO_XOUT (XFR_WBA, RD_REGN, RDB, XFR_LENGTH);
> > + PC++)
> > +
> > +INSTRUCTION (xchg,
> > + DO_XCHG (XFR_WBA, RD_REGN, RDB, XFR_LENGTH);
> > + PC++)
> > +
> > +INSTRUCTION (sxin,
> > + sim_io_eprintf (sd, "SXIN instruction not supported by sim\n");
> > + RAISE_SIGILL (sd))
> > +
> > +INSTRUCTION (sxout,
> > + sim_io_eprintf (sd, "SXOUT instruction not supported by sim\n");
> > + RAISE_SIGILL (sd))
> > +
> > +INSTRUCTION (sxchg,
> > + sim_io_eprintf (sd, "SXCHG instruction not supported by sim\n");
> > + RAISE_SIGILL (sd))
> > +
> > +INSTRUCTION (loop,
> > + OP2 = (IO ? IMM8 + 1 : RS2_w0);
> > + if (OP2 == 0)
> > + {
> > + PC = LOOPEND;
> > + }
> > + else
> > + {
> > + LOOPTOP = PC + 1;
> > + LOOPEND = PC + LOOP_JMPOFFS;
> > + LOOPCNT = OP2;
> > + LOOP_IN_PROGRESS = 1;
> > + PC++;
> > + })
> > +
> > +INSTRUCTION (iloop,
> > + OP2 = (IO ? IMM8 + 1 : RS2_w0);
> > + if (OP2 == 0)
> > + {
> > + PC = LOOPEND;
> > + }
> > + else
> > + {
> > + LOOPTOP = PC + 1;
> > + LOOPEND = PC + LOOP_JMPOFFS;
> > + LOOPCNT = OP2;
> > + LOOP_IN_PROGRESS = 1;
> > + PC++;
> > + })
> > diff --git a/sim/pru/sim-main.h b/sim/pru/sim-main.h
> > new file mode 100644
> > index 0000000000..b8a2c20ea8
> > --- /dev/null
> > +++ b/sim/pru/sim-main.h
> > @@ -0,0 +1,91 @@
> > +/* Copyright 2016-2019 Free Software Foundation, Inc.
> > + Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
> > +
> > + This file is part of the PRU simulator.
> > +
> > + This library 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 PRU_SIM_MAIN
> > +#define PRU_SIM_MAIN
> > +
> > +#include <stdint.h>
> > +#include <stddef.h>
> > +#include "pru.h"
> > +#include "sim-basics.h"
> > +
> > +#include "sim-base.h"
> > +
> > +/* The machine state.
> > + This state is maintained in host byte order. The
> > + fetch/store register functions must translate between host
> > + byte order and the target processor byte order.
> > + Keeping this data in target byte order simplifies the register
> > + read/write functions. Keeping this data in host order improves
> > + the performance of the simulator. Simulation speed is deemed more
> > + important. */
> > +
> > +/* For clarity, please keep the same relative order in this enum as in the
> > + corresponding group of GP registers.
> > +
> > + In PRU ISA, Multiplier-Accumulator-Unit's registers are like "shadows"
> > of + the GP registers. MAC registers are implicitly addressed when
> > executing + the XIN/XOUT instructions to access them. Transfer to/from a
> > MAC register + can happen only from/to its corresponding GP peer
> > register. */ +
> > +enum pru_macreg_id {
> > + /* MAC register CPU GP register Description. */
> > + PRU_MACREG_MODE, /* r25 */ /* Mode (MUL/MAC). */
> > + PRU_MACREG_PROD_L, /* r26 */ /* Lower 32 bits of product.
> */
> > + PRU_MACREG_PROD_H, /* r27 */ /* Higher 32 bits of product.
> */
> > + PRU_MACREG_OP_0, /* r28 */ /* First operand. */
> > + PRU_MACREG_OP_1, /* r29 */ /* Second operand. */
> > + PRU_MACREG_ACC_L, /* N/A */ /* Accumulator (not exposed)
> */
> > + PRU_MACREG_ACC_H, /* N/A */ /* Higher 32 bits of MAC
> > + accumulator. */
> > + PRU_MAC_NREGS
> > +};
> > +
> > +struct pru_regset
> > +{
> > + uint32_t regs[32]; /* Primary registers. */
> > + uint16_t pc; /* IMEM _word_ address. */
> > + uint32_t pc_addr_space_marker; /* IMEM virtual linker offset. This
> > + is the artificial offset that
> > + we invent in order to "separate"
> > + the DMEM and IMEM memory spaces. */
> > + unsigned int carry : 1;
> > + uint32_t ctable[32]; /* Constant offsets table for xBCO. */
> > + uint32_t macregs[PRU_MAC_NREGS];
> > + uint32_t scratchpads[XFRID_MAX + 1][32];
> > + struct {
> > + uint16_t looptop; /* LOOP top (PC of loop instr). */
> > + uint16_t loopend; /* LOOP end (PC of loop end label). */
> > + int loop_in_progress; /* Whether to check for PC==loopend. */
> > + uint32_t loop_counter; /* LOOP counter. */
> > + } loop;
> > + int cycles;
> > + int insts;
> > +};
> > +
> > +struct _sim_cpu {
> > + struct pru_regset pru_cpu;
> > + sim_cpu_base base;
> > +};
> > +
> > +struct sim_state {
> > + sim_cpu *cpu[MAX_NR_PROCESSORS];
> > +
> > + sim_state_base base;
> > +};
> > +#endif /* PRU_SIM_MAIN */
>
>
>
>
* Dimitar Dimitrov <dimitar@dinux.eu> [2019-09-04 22:40:29 +0300]:
> I'd like to contribute a sim port for the TI PRU I/O processor. This
> is the sixth version of the patch series.
>
> Changes since patch series v5:
> - Added copyright headers to test cases.
> - Regenerated using autoconf-2.69 and automake-1.5.1
> - Added more comments to functions and MAC register enum.
> - Updated copyright years.
Thanks for all this effort over the years!
I merged together patch #3 with #1 and pushed this to master.
Thanks,
Andrew
>
> v1: https://sourceware.org/ml/gdb-patches/2016-12/msg00143.html
> v2: https://sourceware.org/ml/gdb-patches/2017-02/msg00397.html
> v3: https://sourceware.org/ml/gdb-patches/2017-02/msg00516.html
> v4: https://sourceware.org/ml/gdb-patches/2018-06/msg00484.html
> v5: https://sourceware.org/ml/gdb-patches/2019-08/msg00584.html
>
> gdb/ChangeLog:
>
> 2019-09-04 Dimitar Dimitrov <dimitar@dinux.eu>
>
> * NEWS: Mention new simulator port for PRU.
>
> sim/
> 2019-09-04 Dimitar Dimitrov <dimitar@dinux.eu>
>
> * MAINTAINERS: Add myself as PRU maintainer.
> * configure: Regenerated.
> * configure.tgt: Add PRU.
>
> sim/common/
> 2019-09-04 Dimitar Dimitrov <dimitar@dinux.eu>
>
> * gennltvals.sh: Add PRU libgloss target.
> * nltvals.def: Regenerate from the latest libgloss sources.
>
> sim/pru/
> 2019-09-04 Dimitar Dimitrov <dimitar@dinux.eu>
>
> * Makefile.in: New file.
> * aclocal.m4: Regenerated.
> * config.in: Regenerated.
> * configure: Regenerated.
> * configure.ac: New file.
> * interp.c: New file.
> * pru.h: New file.
> * pru.isa: New file.
> * sim-main.h: New file.
>
> Signed-off-by: Dimitar Dimitrov <dimitar@dinux.eu>
> ---
> gdb/NEWS | 4 +
> sim/MAINTAINERS | 1 +
> sim/common/gennltvals.sh | 4 +
> sim/common/nltvals.def | 31 ++
> sim/configure | 8 +
> sim/configure.tgt | 3 +
> sim/pru/Makefile.in | 29 ++
> sim/pru/aclocal.m4 | 119 ++++++
> sim/pru/config.in | 248 ++++++++++++
> sim/pru/configure.ac | 31 ++
> sim/pru/interp.c | 848 +++++++++++++++++++++++++++++++++++++++
> sim/pru/pru.h | 110 +++++
> sim/pru/pru.isa | 249 ++++++++++++
> sim/pru/sim-main.h | 91 +++++
> 14 files changed, 1776 insertions(+)
> create mode 100644 sim/pru/Makefile.in
> create mode 100644 sim/pru/aclocal.m4
> create mode 100644 sim/pru/config.in
> create mode 100644 sim/pru/configure.ac
> create mode 100644 sim/pru/interp.c
> create mode 100644 sim/pru/pru.h
> create mode 100644 sim/pru/pru.isa
> create mode 100644 sim/pru/sim-main.h
>
> diff --git a/gdb/NEWS b/gdb/NEWS
> index f382e887c0..f4b5c9239c 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -318,6 +318,10 @@ maint show test-options-completion-result
> GDB now bundles GNU readline 8.0, but if you choose to use
> --with-system-readline, only readline >= 7.0 can be used.
>
> +* New Simulators
> +
> +TI PRU pru-*-elf
> +
> *** Changes in GDB 8.3
>
> * GDB and GDBserver now support access to additional registers on
> diff --git a/sim/MAINTAINERS b/sim/MAINTAINERS
> index 3b9b08c40d..4ca67cfd1d 100644
> --- a/sim/MAINTAINERS
> +++ b/sim/MAINTAINERS
> @@ -29,6 +29,7 @@ mips I-IV Maciej W. Rozycki <macro@linux-mips.org>
> moxie Anthony Green <green@moxielogic.com>
> msp430 Nick Clifton <nickc@redhat.com>
> or1k Stafford Horne <shorne@gmail.com>
> +pru Dimitar Dimitrov <dimitar@dinux.eu>
> sh (global maintainers)
> sh64 Dave Brolley <brolley@redhat.com>
> common Frank Ch. Eigler <fche@redhat.com>
> diff --git a/sim/common/gennltvals.sh b/sim/common/gennltvals.sh
> index 7027c35ad4..79180335b6 100755
> --- a/sim/common/gennltvals.sh
> +++ b/sim/common/gennltvals.sh
> @@ -95,3 +95,7 @@ $shell ${srccom}/gentvals.sh $target sys ${newlibroot}/$dir \
> dir=libgloss target=lm32
> $shell ${srccom}/gentvals.sh $target sys ${newlibroot}/$dir \
> "syscall.h" 'SYS_[_[:alnum:]]*' "${cpp}"
> +
> +dir=libgloss target=pru
> +$shell ${srccom}/gentvals.sh $target sys ${newlibroot}/$dir \
> + "syscall.h" 'SYS_[_[:alnum:]]*' "${cpp}"
> diff --git a/sim/common/nltvals.def b/sim/common/nltvals.def
> index 3f82d47b6b..92ccc9aded 100644
> --- a/sim/common/nltvals.def
> +++ b/sim/common/nltvals.def
> @@ -574,3 +574,34 @@
> /* end lm32 sys target macros */
> #endif
> #endif
> +#ifdef NL_TARGET_pru
> +#ifdef sys_defs
> +/* from syscall.h */
> +/* begin pru sys target macros */
> + { "SYS_argc", 22 },
> + { "SYS_argn", 24 },
> + { "SYS_argnlen", 23 },
> + { "SYS_argv", 13 },
> + { "SYS_argvlen", 12 },
> + { "SYS_chdir", 14 },
> + { "SYS_chmod", 16 },
> + { "SYS_close", 3 },
> + { "SYS_exit", 1 },
> + { "SYS_fstat", 10 },
> + { "SYS_getpid", 8 },
> + { "SYS_gettimeofday", 19 },
> + { "SYS_kill", 9 },
> + { "SYS_link", 21 },
> + { "SYS_lseek", 6 },
> + { "SYS_open", 2 },
> + { "SYS_read", 4 },
> + { "SYS_reconfig", 25 },
> + { "SYS_stat", 15 },
> + { "SYS_time", 18 },
> + { "SYS_times", 20 },
> + { "SYS_unlink", 7 },
> + { "SYS_utime", 17 },
> + { "SYS_write", 5 },
> +/* end pru sys target macros */
> +#endif
> +#endif
> diff --git a/sim/configure b/sim/configure
> index ca3fd673ab..72f95cd5c7 100755
> --- a/sim/configure
> +++ b/sim/configure
> @@ -686,6 +686,7 @@ mn10300
> moxie
> msp430
> or1k
> +pru
> rl78
> rx
> sh64
> @@ -3837,6 +3838,13 @@ subdirs="$subdirs aarch64"
> subdirs="$subdirs or1k"
>
>
> + ;;
> + pru*-*-*)
> +
> + sim_arch=pru
> + subdirs="$subdirs pru"
> +
> +
> ;;
> rl78-*-*)
>
> diff --git a/sim/configure.tgt b/sim/configure.tgt
> index a6dbd1af83..8a8e03d96f 100644
> --- a/sim/configure.tgt
> +++ b/sim/configure.tgt
> @@ -79,6 +79,9 @@ case "${target}" in
> or1k-*-* | or1knd-*-*)
> SIM_ARCH(or1k)
> ;;
> + pru*-*-*)
> + SIM_ARCH(pru)
> + ;;
> rl78-*-*)
> SIM_ARCH(rl78)
> ;;
> diff --git a/sim/pru/Makefile.in b/sim/pru/Makefile.in
> new file mode 100644
> index 0000000000..5235a5ff07
> --- /dev/null
> +++ b/sim/pru/Makefile.in
> @@ -0,0 +1,29 @@
> +# Makefile template for Configure for the PRU sim library.
> +# Copyright (C) 1990-2019 Free Software Foundation, Inc.
> +# Written by Dimitar Dimitrov <dimitar@dinux.eu>
> +#
> +# Based on the MCore sim library
> +#
> +# 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_OBJS = \
> + $(SIM_NEW_COMMON_OBJS) \
> + interp.o \
> + sim-resume.o
> +
> +NL_TARGET = -DNL_TARGET_pru
> +
> +## COMMON_POST_CONFIG_FRAG
> diff --git a/sim/pru/aclocal.m4 b/sim/pru/aclocal.m4
> new file mode 100644
> index 0000000000..e9f11c775c
> --- /dev/null
> +++ b/sim/pru/aclocal.m4
> @@ -0,0 +1,119 @@
> +# generated automatically by aclocal 1.15.1 -*- Autoconf -*-
> +
> +# Copyright (C) 1996-2017 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.
> +
> +m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
> +# AM_CONDITIONAL -*- Autoconf -*-
> +
> +# Copyright (C) 1997-2017 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.
> +
> +# AM_CONDITIONAL(NAME, SHELL-CONDITION)
> +# -------------------------------------
> +# Define a conditional.
> +AC_DEFUN([AM_CONDITIONAL],
> +[AC_PREREQ([2.52])dnl
> + m4_if([$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])])
> +
> +# Copyright (C) 2003-2017 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.
> +
> +# Check whether the underlying file-system supports filenames
> +# with a leading dot. For instance MS-DOS doesn't.
> +AC_DEFUN([AM_SET_LEADING_DOT],
> +[rm -rf .tst 2>/dev/null
> +mkdir .tst 2>/dev/null
> +if test -d .tst; then
> + am__leading_dot=.
> +else
> + am__leading_dot=_
> +fi
> +rmdir .tst 2>/dev/null
> +AC_SUBST([am__leading_dot])])
> +
> +# Add --enable-maintainer-mode option to configure. -*- Autoconf -*-
> +# From Jim Meyering
> +
> +# Copyright (C) 1996-2017 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.
> +
> +# 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],
> + [AS_HELP_STRING([--]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
> +]
> +)
> +
> +# Copyright (C) 2006-2017 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.
> +
> +# _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($@)])
> +
> diff --git a/sim/pru/config.in b/sim/pru/config.in
> new file mode 100644
> index 0000000000..7c667a1c0d
> --- /dev/null
> +++ b/sim/pru/config.in
> @@ -0,0 +1,248 @@
> +/* config.in. Generated from configure.ac by autoheader. */
> +
> +/* Define if building universal (internal helper macro) */
> +#undef AC_APPLE_UNIVERSAL_BUILD
> +
> +/* Sim debug setting */
> +#undef DEBUG
> +
> +/* 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 `ftruncate' function. */
> +#undef HAVE_FTRUNCATE
> +
> +/* 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 `lstat' function. */
> +#undef HAVE_LSTAT
> +
> +/* Define to 1 if you have the <memory.h> header file. */
> +#undef HAVE_MEMORY_H
> +
> +/* Define to 1 if you have the `mmap' function. */
> +#undef HAVE_MMAP
> +
> +/* Define to 1 if you have the `munmap' function. */
> +#undef HAVE_MUNMAP
> +
> +/* Define to 1 if you have the `posix_fallocate' function. */
> +#undef HAVE_POSIX_FALLOCATE
> +
> +/* Define to 1 if you have the `sigaction' function. */
> +#undef HAVE_SIGACTION
> +
> +/* Define to 1 if the system has the type `socklen_t'. */
> +#undef HAVE_SOCKLEN_T
> +
> +/* 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 `st_atime' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_ATIME
> +
> +/* Define to 1 if `st_blksize' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_BLKSIZE
> +
> +/* Define to 1 if `st_blocks' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_BLOCKS
> +
> +/* Define to 1 if `st_ctime' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_CTIME
> +
> +/* Define to 1 if `st_dev' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_DEV
> +
> +/* Define to 1 if `st_gid' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_GID
> +
> +/* Define to 1 if `st_ino' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_INO
> +
> +/* Define to 1 if `st_mode' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_MODE
> +
> +/* Define to 1 if `st_mtime' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_MTIME
> +
> +/* Define to 1 if `st_nlink' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_NLINK
> +
> +/* Define to 1 if `st_rdev' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_RDEV
> +
> +/* Define to 1 if `st_size' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_SIZE
> +
> +/* Define to 1 if `st_uid' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_UID
> +
> +/* Define to 1 if you have the <sys/mman.h> header file. */
> +#undef HAVE_SYS_MMAN_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/times.h> header file. */
> +#undef HAVE_SYS_TIMES_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 `truncate' function. */
> +#undef HAVE_TRUNCATE
> +
> +/* 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
> +
> +/* Sim profile settings */
> +#undef PROFILE
> +
> +/* 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
> +
> +
> +/* Sim assert settings */
> +#undef WITH_ASSERT
> +
> +/* Sim debug setting */
> +#undef WITH_DEBUG
> +
> +/* Sim default environment */
> +#undef WITH_ENVIRONMENT
> +
> +/* Sim profile settings */
> +#undef WITH_PROFILE
> +
> +/* How to route I/O */
> +#undef WITH_STDIO
> +
> +/* Sim trace settings */
> +#undef WITH_TRACE
> +
> +/* 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
> diff --git a/sim/pru/configure.ac b/sim/pru/configure.ac
> new file mode 100644
> index 0000000000..e7132b4493
> --- /dev/null
> +++ b/sim/pru/configure.ac
> @@ -0,0 +1,31 @@
> +dnl Process this file with autoconf to produce a configure script.
> +
> +dnl Copyright (C) 2016-2019 Free Software Foundation, Inc.
> +dnl Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
> +dnl
> +dnl This file is part of the GNU simulators.
> +dnl
> +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/>.
> +dnl
> +AC_PREREQ(2.64)dnl
> +AC_INIT(Makefile.in)
> +sinclude(../common/acinclude.m4)
> +
> +SIM_AC_COMMON
> +
> +SIM_AC_OPTION_ENDIAN(LITTLE)
> +SIM_AC_OPTION_ALIGNMENT(STRICT_ALIGNMENT,STRICT_ALIGNMENT)
> +SIM_AC_OPTION_WARNINGS
> +
> +SIM_AC_OUTPUT
> diff --git a/sim/pru/interp.c b/sim/pru/interp.c
> new file mode 100644
> index 0000000000..0e783c121c
> --- /dev/null
> +++ b/sim/pru/interp.c
> @@ -0,0 +1,848 @@
> +/* Simulator for the Texas Instruments PRU processor
> + Copyright 2009-2019 Free Software Foundation, Inc.
> + Inspired by the Microblaze simulator
> + Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
> +
> + This file is part of the simulators.
> +
> + 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 <stdbool.h>
> +#include <stdint.h>
> +#include <stddef.h>
> +#include "bfd.h"
> +#include "gdb/callback.h"
> +#include "libiberty.h"
> +#include "gdb/remote-sim.h"
> +#include "sim-main.h"
> +#include "sim-assert.h"
> +#include "sim-options.h"
> +#include "sim-syscall.h"
> +#include "pru.h"
> +
> +/* DMEM zero address is perfectly valid. But if CRT leaves the first word
> + alone, we can use it as a trap to catch NULL pointer access. */
> +static bfd_boolean abort_on_dmem_zero_access;
> +
> +enum {
> + OPTION_ERROR_NULL_DEREF = OPTION_START,
> +};
> +
> +/* Extract (from PRU endianess) and return an integer in HOST's endianness. */
> +static uint32_t
> +pru_extract_unsigned_integer (uint8_t *addr, size_t len)
> +{
> + uint32_t retval;
> + uint8_t *p;
> + uint8_t *startaddr = addr;
> + uint8_t *endaddr = startaddr + len;
> +
> + /* Start at the most significant end of the integer, and work towards
> + the least significant. */
> + retval = 0;
> +
> + for (p = endaddr; p > startaddr;)
> + retval = (retval << 8) | * -- p;
> + return retval;
> +}
> +
> +/* Store "val" (which is in HOST's endianess) into "addr"
> + (using PRU's endianness). */
> +static void
> +pru_store_unsigned_integer (uint8_t *addr, size_t len, uint32_t val)
> +{
> + uint8_t *p;
> + uint8_t *startaddr = (uint8_t *)addr;
> + uint8_t *endaddr = startaddr + len;
> +
> + for (p = startaddr; p < endaddr;)
> + {
> + *p++ = val & 0xff;
> + val >>= 8;
> + }
> +}
> +
> +/* Extract a field value from CPU register using the given REGSEL selector.
> +
> + Byte number maps directly to first values of RSEL, so we can
> + safely use "regsel" as a register byte number (0..3). */
> +static inline uint32_t
> +extract_regval (uint32_t val, uint32_t regsel)
> +{
> + ASSERT (RSEL_7_0 == 0);
> + ASSERT (RSEL_15_8 == 1);
> + ASSERT (RSEL_23_16 == 2);
> + ASSERT (RSEL_31_24 == 3);
> +
> + switch (regsel)
> + {
> + case RSEL_7_0: return (val >> 0) & 0xff;
> + case RSEL_15_8: return (val >> 8) & 0xff;
> + case RSEL_23_16: return (val >> 16) & 0xff;
> + case RSEL_31_24: return (val >> 24) & 0xff;
> + case RSEL_15_0: return (val >> 0) & 0xffff;
> + case RSEL_23_8: return (val >> 8) & 0xffff;
> + case RSEL_31_16: return (val >> 16) & 0xffff;
> + case RSEL_31_0: return val;
> + default: sim_io_error (NULL, "invalid regsel");
> + }
> +}
> +
> +/* Write a value into CPU subregister pointed by reg and regsel. */
> +static inline void
> +write_regval (uint32_t val, uint32_t *reg, uint32_t regsel)
> +{
> + uint32_t mask, sh;
> +
> + switch (regsel)
> + {
> + case RSEL_7_0: mask = (0xffu << 0); sh = 0; break;
> + case RSEL_15_8: mask = (0xffu << 8); sh = 8; break;
> + case RSEL_23_16: mask = (0xffu << 16); sh = 16; break;
> + case RSEL_31_24: mask = (0xffu << 24); sh = 24; break;
> + case RSEL_15_0: mask = (0xffffu << 0); sh = 0; break;
> + case RSEL_23_8: mask = (0xffffu << 8); sh = 8; break;
> + case RSEL_31_16: mask = (0xffffu << 16); sh = 16; break;
> + case RSEL_31_0: mask = 0xffffffffu; sh = 0; break;
> + default: sim_io_error (NULL, "invalid regsel");
> + }
> +
> + *reg = (*reg & ~mask) | ((val << sh) & mask);
> +}
> +
> +/* Convert the given IMEM word address to a regular byte address used by the
> + GNU ELF container. */
> +static uint32_t
> +imem_wordaddr_to_byteaddr (SIM_CPU *cpu, uint16_t wa)
> +{
> + return (((uint32_t) wa << 2) & IMEM_ADDR_MASK) | PC_ADDR_SPACE_MARKER;
> +}
> +
> +/* Convert the given ELF text byte address to IMEM word address. */
> +static uint16_t
> +imem_byteaddr_to_wordaddr (SIM_CPU *cpu, uint32_t ba)
> +{
> + return (ba >> 2) & 0xffff;
> +}
> +
> +
> +/* Store "nbytes" into DMEM "addr" from CPU register file, starting with
> + register "regn", and byte "regb" within it. */
> +static inline void
> +pru_reg2dmem (SIM_CPU *cpu, uint32_t addr, unsigned int nbytes,
> + int regn, int regb)
> +{
> + /* GDB assumes unconditional access to all memories, so enable additional
> + checks only in standalone mode. */
> + bool standalone = (STATE_OPEN_KIND (CPU_STATE (cpu)) == SIM_OPEN_STANDALONE);
> +
> + if (abort_on_dmem_zero_access && addr < 4)
> + {
> + sim_core_signal (CPU_STATE (cpu), cpu, PC_byteaddr, write_map,
> + nbytes, addr, write_transfer,
> + sim_core_unmapped_signal);
> + }
> + else if (standalone && ((addr >= PC_ADDR_SPACE_MARKER)
> + || (addr + nbytes > PC_ADDR_SPACE_MARKER)))
> + {
> + sim_core_signal (CPU_STATE (cpu), cpu, PC_byteaddr, write_map,
> + nbytes, addr, write_transfer,
> + sim_core_unmapped_signal);
> + }
> + else if ((regn * 4 + regb + nbytes) > (32 * 4))
> + {
> + sim_io_eprintf (CPU_STATE (cpu),
> + "SBBO/SBCO with invalid store data length\n");
> + RAISE_SIGILL (CPU_STATE (cpu));
> + }
> + else
> + {
> + TRACE_MEMORY (cpu, "write of %d bytes to %08x", nbytes, addr);
> + while (nbytes--)
> + {
> + sim_core_write_1 (cpu,
> + PC_byteaddr,
> + write_map,
> + addr++,
> + extract_regval (CPU.regs[regn], regb));
> +
> + if (++regb >= 4)
> + {
> + regb = 0;
> + regn++;
> + }
> + }
> + }
> +}
> +
> +/* Load "nbytes" from DMEM "addr" into CPU register file, starting with
> + register "regn", and byte "regb" within it. */
> +static inline void
> +pru_dmem2reg (SIM_CPU *cpu, uint32_t addr, unsigned int nbytes,
> + int regn, int regb)
> +{
> + /* GDB assumes unconditional access to all memories, so enable additional
> + checks only in standalone mode. */
> + bool standalone = (STATE_OPEN_KIND (CPU_STATE (cpu)) == SIM_OPEN_STANDALONE);
> +
> + if (abort_on_dmem_zero_access && addr < 4)
> + {
> + sim_core_signal (CPU_STATE (cpu), cpu, PC_byteaddr, read_map,
> + nbytes, addr, read_transfer,
> + sim_core_unmapped_signal);
> + }
> + else if (standalone && ((addr >= PC_ADDR_SPACE_MARKER)
> + || (addr + nbytes > PC_ADDR_SPACE_MARKER)))
> + {
> + /* This check is necessary because our IMEM "address space"
> + is not really accessible, yet we have mapped it as a generic
> + memory space. */
> + sim_core_signal (CPU_STATE (cpu), cpu, PC_byteaddr, read_map,
> + nbytes, addr, read_transfer,
> + sim_core_unmapped_signal);
> + }
> + else if ((regn * 4 + regb + nbytes) > (32 * 4))
> + {
> + sim_io_eprintf (CPU_STATE (cpu),
> + "LBBO/LBCO with invalid load data length\n");
> + RAISE_SIGILL (CPU_STATE (cpu));
> + }
> + else
> + {
> + unsigned int b;
> + TRACE_MEMORY (cpu, "read of %d bytes from %08x", nbytes, addr);
> + while (nbytes--)
> + {
> + b = sim_core_read_1 (cpu, PC_byteaddr, read_map, addr++);
> +
> + /* Reuse the fact the Register Byte Number maps directly to RSEL. */
> + ASSERT (RSEL_7_0 == 0);
> + write_regval (b, &CPU.regs[regn], regb);
> +
> + if (++regb >= 4)
> + {
> + regb = 0;
> + regn++;
> + }
> + }
> + }
> +}
> +
> +/* Set reset values of general-purpose registers. */
> +static void
> +set_initial_gprs (SIM_CPU *cpu)
> +{
> + int i;
> +
> + /* Set up machine just out of reset. */
> + CPU_PC_SET (cpu, 0);
> + PC_ADDR_SPACE_MARKER = IMEM_ADDR_DEFAULT; /* from default linker script? */
> +
> + /* Clean out the GPRs. */
> + for (i = 0; i < ARRAY_SIZE (CPU.regs); i++)
> + CPU.regs[i] = 0;
> + for (i = 0; i < ARRAY_SIZE (CPU.macregs); i++)
> + CPU.macregs[i] = 0;
> +
> + CPU.loop.looptop = CPU.loop.loopend = 0;
> + CPU.loop.loop_in_progress = 0;
> + CPU.loop.loop_counter = 0;
> +
> + CPU.carry = 0;
> + CPU.insts = 0;
> + CPU.cycles = 0;
> +
> + /* AM335x should provide sane defaults. */
> + CPU.ctable[0] = 0x00020000;
> + CPU.ctable[1] = 0x48040000;
> + CPU.ctable[2] = 0x4802a000;
> + CPU.ctable[3] = 0x00030000;
> + CPU.ctable[4] = 0x00026000;
> + CPU.ctable[5] = 0x48060000;
> + CPU.ctable[6] = 0x48030000;
> + CPU.ctable[7] = 0x00028000;
> + CPU.ctable[8] = 0x46000000;
> + CPU.ctable[9] = 0x4a100000;
> + CPU.ctable[10] = 0x48318000;
> + CPU.ctable[11] = 0x48022000;
> + CPU.ctable[12] = 0x48024000;
> + CPU.ctable[13] = 0x48310000;
> + CPU.ctable[14] = 0x481cc000;
> + CPU.ctable[15] = 0x481d0000;
> + CPU.ctable[16] = 0x481a0000;
> + CPU.ctable[17] = 0x4819c000;
> + CPU.ctable[18] = 0x48300000;
> + CPU.ctable[19] = 0x48302000;
> + CPU.ctable[20] = 0x48304000;
> + CPU.ctable[21] = 0x00032400;
> + CPU.ctable[22] = 0x480c8000;
> + CPU.ctable[23] = 0x480ca000;
> + CPU.ctable[24] = 0x00000000;
> + CPU.ctable[25] = 0x00002000;
> + CPU.ctable[26] = 0x0002e000;
> + CPU.ctable[27] = 0x00032000;
> + CPU.ctable[28] = 0x00000000;
> + CPU.ctable[29] = 0x49000000;
> + CPU.ctable[30] = 0x40000000;
> + CPU.ctable[31] = 0x80000000;
> +}
> +
> +/* Map regsel selector to subregister field width. */
> +static inline unsigned int
> +regsel_width (uint32_t regsel)
> +{
> + switch (regsel)
> + {
> + case RSEL_7_0: return 8;
> + case RSEL_15_8: return 8;
> + case RSEL_23_16: return 8;
> + case RSEL_31_24: return 8;
> + case RSEL_15_0: return 16;
> + case RSEL_23_8: return 16;
> + case RSEL_31_16: return 16;
> + case RSEL_31_0: return 32;
> + default: sim_io_error (NULL, "invalid regsel");
> + }
> +}
> +
> +/* Handle XIN instruction addressing the MAC peripheral. */
> +static void
> +pru_sim_xin_mac (SIM_DESC sd, SIM_CPU *cpu, unsigned int rd_regn,
> + unsigned int rdb, unsigned int length)
> +{
> + if (rd_regn < 25 || (rd_regn * 4 + rdb + length) > (27 + 1) * 4)
> + sim_io_error (sd, "XIN MAC: invalid transfer regn=%u.%u, length=%u\n",
> + rd_regn, rdb, length);
> +
> + /* Copy from MAC to PRU regs. Ranges have been validated above. */
> + while (length--)
> + {
> + write_regval (CPU.macregs[rd_regn - 25] >> (rdb * 8),
> + &CPU.regs[rd_regn],
> + rdb);
> + if (++rdb == 4)
> + {
> + rdb = 0;
> + rd_regn++;
> + }
> + }
> +}
> +
> +/* Handle XIN instruction. */
> +static void
> +pru_sim_xin (SIM_DESC sd, SIM_CPU *cpu, unsigned int wba,
> + unsigned int rd_regn, unsigned int rdb, unsigned int length)
> +{
> + if (wba == 0)
> + {
> + pru_sim_xin_mac (sd, cpu, rd_regn, rdb, length);
> + }
> + else if (wba == XFRID_SCRATCH_BANK_0 || wba == XFRID_SCRATCH_BANK_1
> + || wba == XFRID_SCRATCH_BANK_2 || wba == XFRID_SCRATCH_BANK_PEER)
> + {
> + while (length--)
> + {
> + unsigned int val;
> +
> + val = extract_regval (CPU.scratchpads[wba][rd_regn], rdb);
> + write_regval (val, &CPU.regs[rd_regn], rdb);
> + if (++rdb == 4)
> + {
> + rdb = 0;
> + rd_regn++;
> + }
> + }
> + }
> + else if (wba == 254 || wba == 255)
> + {
> + /* FILL/ZERO pseudos implemented via XIN. */
> + unsigned int fillbyte = (wba == 254) ? 0xff : 0x00;
> + while (length--)
> + {
> + write_regval (fillbyte, &CPU.regs[rd_regn], rdb);
> + if (++rdb == 4)
> + {
> + rdb = 0;
> + rd_regn++;
> + }
> + }
> + }
> + else
> + {
> + sim_io_error (sd, "XIN: XFR device %d not supported.\n", wba);
> + }
> +}
> +
> +/* Handle XOUT instruction addressing the MAC peripheral. */
> +static void
> +pru_sim_xout_mac (SIM_DESC sd, SIM_CPU *cpu, unsigned int rd_regn,
> + unsigned int rdb, unsigned int length)
> +{
> + const int modereg_accessed = (rd_regn == 25);
> +
> + /* Multiple Accumulate. */
> + if (rd_regn < 25 || (rd_regn * 4 + rdb + length) > (27 + 1) * 4)
> + sim_io_error (sd, "XOUT MAC: invalid transfer regn=%u.%u, length=%u\n",
> + rd_regn, rdb, length);
> +
> + /* Copy from PRU to MAC regs. Ranges have been validated above. */
> + while (length--)
> + {
> + write_regval (CPU.regs[rd_regn] >> (rdb * 8),
> + &CPU.macregs[rd_regn - 25],
> + rdb);
> + if (++rdb == 4)
> + {
> + rdb = 0;
> + rd_regn++;
> + }
> + }
> +
> + if (modereg_accessed
> + && (CPU.macregs[PRU_MACREG_MODE] & MAC_R25_MAC_MODE_MASK))
> + {
> + /* MUL/MAC operands are sampled every XOUT in multiply and
> + accumulate mode. */
> + uint64_t prod, oldsum, sum;
> + CPU.macregs[PRU_MACREG_OP_0] = CPU.regs[28];
> + CPU.macregs[PRU_MACREG_OP_1] = CPU.regs[29];
> +
> + prod = CPU.macregs[PRU_MACREG_OP_0];
> + prod *= (uint64_t)CPU.macregs[PRU_MACREG_OP_1];
> +
> + oldsum = CPU.macregs[PRU_MACREG_ACC_L];
> + oldsum += (uint64_t)CPU.macregs[PRU_MACREG_ACC_H] << 32;
> + sum = oldsum + prod;
> +
> + CPU.macregs[PRU_MACREG_PROD_L] = sum & 0xfffffffful;
> + CPU.macregs[PRU_MACREG_PROD_H] = sum >> 32;
> + CPU.macregs[PRU_MACREG_ACC_L] = CPU.macregs[PRU_MACREG_PROD_L];
> + CPU.macregs[PRU_MACREG_ACC_H] = CPU.macregs[PRU_MACREG_PROD_H];
> +
> + if (oldsum > sum)
> + CPU.macregs[PRU_MACREG_MODE] |= MAC_R25_ACC_CARRY_MASK;
> + }
> + if (modereg_accessed
> + && (CPU.macregs[PRU_MACREG_MODE] & MAC_R25_ACC_CARRY_MASK))
> + {
> + /* store 1 to clear. */
> + CPU.macregs[PRU_MACREG_MODE] &= ~MAC_R25_ACC_CARRY_MASK;
> + CPU.macregs[PRU_MACREG_ACC_L] = 0;
> + CPU.macregs[PRU_MACREG_ACC_H] = 0;
> + }
> +
> +}
> +
> +/* Handle XOUT instruction. */
> +static void
> +pru_sim_xout (SIM_DESC sd, SIM_CPU *cpu, unsigned int wba,
> + unsigned int rd_regn, unsigned int rdb, unsigned int length)
> +{
> + if (wba == 0)
> + {
> + pru_sim_xout_mac (sd, cpu, rd_regn, rdb, length);
> + }
> + else if (wba == XFRID_SCRATCH_BANK_0 || wba == XFRID_SCRATCH_BANK_1
> + || wba == XFRID_SCRATCH_BANK_2 || wba == XFRID_SCRATCH_BANK_PEER)
> + {
> + while (length--)
> + {
> + unsigned int val;
> +
> + val = extract_regval (CPU.regs[rd_regn], rdb);
> + write_regval (val, &CPU.scratchpads[wba][rd_regn], rdb);
> + if (++rdb == 4)
> + {
> + rdb = 0;
> + rd_regn++;
> + }
> + }
> + }
> + else
> + sim_io_error (sd, "XOUT: XFR device %d not supported.\n", wba);
> +}
> +
> +/* Handle XCHG instruction. */
> +static void
> +pru_sim_xchg (SIM_DESC sd, SIM_CPU *cpu, unsigned int wba,
> + unsigned int rd_regn, unsigned int rdb, unsigned int length)
> +{
> + if (wba == XFRID_SCRATCH_BANK_0 || wba == XFRID_SCRATCH_BANK_1
> + || wba == XFRID_SCRATCH_BANK_2 || wba == XFRID_SCRATCH_BANK_PEER)
> + {
> + while (length--)
> + {
> + unsigned int valr, vals;
> +
> + valr = extract_regval (CPU.regs[rd_regn], rdb);
> + vals = extract_regval (CPU.scratchpads[wba][rd_regn], rdb);
> + write_regval (valr, &CPU.scratchpads[wba][rd_regn], rdb);
> + write_regval (vals, &CPU.regs[rd_regn], rdb);
> + if (++rdb == 4)
> + {
> + rdb = 0;
> + rd_regn++;
> + }
> + }
> + }
> + else
> + sim_io_error (sd, "XOUT: XFR device %d not supported.\n", wba);
> +}
> +
> +/* Handle syscall simulation. Its ABI is specific to the GNU simulator. */
> +static void
> +pru_sim_syscall (SIM_DESC sd, SIM_CPU *cpu)
> +{
> + /* If someday TI confirms that the "reserved" HALT opcode fields
> + can be used for extra arguments, then maybe we can embed
> + the syscall number there. Until then, let's use R1. */
> + const uint32_t syscall_num = CPU.regs[1];
> + long ret;
> +
> + ret = sim_syscall (cpu, syscall_num,
> + CPU.regs[14], CPU.regs[15],
> + CPU.regs[16], CPU.regs[17]);
> + CPU.regs[14] = ret;
> +}
> +
> +/* Simulate one instruction. */
> +static void
> +sim_step_once (SIM_DESC sd)
> +{
> + SIM_CPU *cpu = STATE_CPU (sd, 0);
> + const struct pru_opcode *op;
> + uint32_t inst;
> + uint32_t _RDVAL, OP2; /* intermediate values. */
> + int rd_is_modified = 0; /* RD modified and must be stored back. */
> +
> + /* Fetch the initial instruction that we'll decode. */
> + inst = sim_core_read_4 (cpu, PC_byteaddr, exec_map, PC_byteaddr);
> + TRACE_MEMORY (cpu, "read of insn 0x%08x from %08x", inst, PC_byteaddr);
> +
> + op = pru_find_opcode (inst);
> +
> + if (!op)
> + {
> + sim_io_eprintf (sd, "Unknown instruction 0x%04x\n", inst);
> + RAISE_SIGILL (sd);
> + }
> + else
> + {
> + TRACE_DISASM (cpu, PC_byteaddr);
> +
> + /* In multiply-only mode, R28/R29 operands are sampled on every clock
> + cycle. */
> + if ((CPU.macregs[PRU_MACREG_MODE] & MAC_R25_MAC_MODE_MASK) == 0)
> + {
> + CPU.macregs[PRU_MACREG_OP_0] = CPU.regs[28];
> + CPU.macregs[PRU_MACREG_OP_1] = CPU.regs[29];
> + }
> +
> + switch (op->type)
> + {
> +/* Helper macro to improve clarity of pru.isa. The empty while is a
> + guard against using RD as a left-hand side value. */
> +#define RD do { } while (0); rd_is_modified = 1; _RDVAL
> +#define INSTRUCTION(NAME, ACTION) \
> + case prui_ ## NAME: \
> + ACTION; \
> + break;
> +#include "pru.isa"
> +#undef INSTRUCTION
> +#undef RD
> +
> + default:
> + RAISE_SIGILL (sd);
> + }
> +
> + if (rd_is_modified)
> + write_regval (_RDVAL, &CPU.regs[RD_REGN], RDSEL);
> +
> + /* Don't treat r30 and r31 as regular registers, they are I/O! */
> + CPU.regs[30] = 0;
> + CPU.regs[31] = 0;
> +
> + /* Handle PC match of loop end. */
> + if (LOOP_IN_PROGRESS && (PC == LOOPEND))
> + {
> + SIM_ASSERT (LOOPCNT > 0);
> + if (--LOOPCNT == 0)
> + LOOP_IN_PROGRESS = 0;
> + else
> + PC = LOOPTOP;
> + }
> +
> + /* In multiply-only mode, MAC does multiplication every cycle. */
> + if ((CPU.macregs[PRU_MACREG_MODE] & MAC_R25_MAC_MODE_MASK) == 0)
> + {
> + uint64_t prod;
> + prod = CPU.macregs[PRU_MACREG_OP_0];
> + prod *= (uint64_t)CPU.macregs[PRU_MACREG_OP_1];
> + CPU.macregs[PRU_MACREG_PROD_L] = prod & 0xfffffffful;
> + CPU.macregs[PRU_MACREG_PROD_H] = prod >> 32;
> +
> + /* Clear the MAC accumulator when in normal mode. */
> + CPU.macregs[PRU_MACREG_ACC_L] = 0;
> + CPU.macregs[PRU_MACREG_ACC_H] = 0;
> + }
> +
> + /* Update cycle counts. */
> + CPU.insts += 1; /* One instruction completed ... */
> + CPU.cycles += 1; /* ... and it takes a single cycle. */
> +
> + /* Account for memory access latency with a reasonable estimate.
> + No distinction is currently made between SRAM, DRAM and generic
> + L3 slaves. */
> + if (op->type == prui_lbbo || op->type == prui_sbbo
> + || op->type == prui_lbco || op->type == prui_sbco)
> + CPU.cycles += 2;
> +
> + }
> +}
> +
> +/* Implement standard sim_engine_run function. */
> +void
> +sim_engine_run (SIM_DESC sd,
> + int next_cpu_nr, /* ignore */
> + int nr_cpus, /* ignore */
> + int siggnal) /* ignore */
> +{
> + while (1)
> + {
> + sim_step_once (sd);
> + if (sim_events_tick (sd))
> + sim_events_process (sd);
> + }
> +}
> +
> +
> +/* Implement callback for standard CPU_PC_FETCH routine. */
> +static sim_cia
> +pru_pc_get (sim_cpu *cpu)
> +{
> + /* Present PC as byte address. */
> + return imem_wordaddr_to_byteaddr (cpu, cpu->pru_cpu.pc);
> +}
> +
> +/* Implement callback for standard CPU_PC_STORE routine. */
> +static void
> +pru_pc_set (sim_cpu *cpu, sim_cia pc)
> +{
> + /* PC given as byte address. */
> + cpu->pru_cpu.pc = imem_byteaddr_to_wordaddr (cpu, pc);
> +}
> +
> +
> +/* Implement callback for standard CPU_REG_STORE routine. */
> +static int
> +pru_store_register (SIM_CPU *cpu, int rn, unsigned char *memory, int length)
> +{
> + if (rn < NUM_REGS && rn >= 0)
> + {
> + if (length == 4)
> + {
> + /* Misalignment safe. */
> + long ival = pru_extract_unsigned_integer (memory, 4);
> + if (rn < 32)
> + CPU.regs[rn] = ival;
> + else
> + pru_pc_set (cpu, ival);
> + return 4;
> + }
> + else
> + return 0;
> + }
> + else
> + return 0;
> +}
> +
> +/* Implement callback for standard CPU_REG_FETCH routine. */
> +static int
> +pru_fetch_register (SIM_CPU *cpu, int rn, unsigned char *memory, int length)
> +{
> + long ival;
> +
> + if (rn < NUM_REGS && rn >= 0)
> + {
> + if (length == 4)
> + {
> + if (rn < 32)
> + ival = CPU.regs[rn];
> + else
> + ival = pru_pc_get (cpu);
> +
> + /* Misalignment-safe. */
> + pru_store_unsigned_integer (memory, 4, ival);
> + return 4;
> + }
> + else
> + return 0;
> + }
> + else
> + return 0;
> +}
> +
> +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);
> +}
> +
> +/* Declare the PRU option handler. */
> +static DECLARE_OPTION_HANDLER (pru_option_handler);
> +
> +/* Implement the PRU option handler. */
> +static SIM_RC
> +pru_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt, char *arg,
> + int is_command)
> +{
> + switch (opt)
> + {
> + case OPTION_ERROR_NULL_DEREF:
> + abort_on_dmem_zero_access = TRUE;
> + return SIM_RC_OK;
> +
> + default:
> + sim_io_eprintf (sd, "Unknown PRU option %d\n", opt);
> + return SIM_RC_FAIL;
> + }
> +}
> +
> +/* List of PRU-specific options. */
> +static const OPTION pru_options[] =
> +{
> + { {"error-null-deref", no_argument, NULL, OPTION_ERROR_NULL_DEREF},
> + '\0', NULL, "Trap any access to DMEM address zero",
> + pru_option_handler, NULL },
> +
> + { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL, NULL }
> +};
> +
> +/* Implement standard sim_open function. */
> +SIM_DESC
> +sim_open (SIM_OPEN_KIND kind, host_callback *cb,
> + struct bfd *abfd, char * const *argv)
> +{
> + int i;
> + char c;
> + SIM_DESC sd = sim_state_alloc (kind, cb);
> + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
> +
> + /* The cpu data is kept in a separately allocated chunk of memory. */
> + if (sim_cpu_alloc_all (sd, 1, /*cgen_cpu_max_extra_bytes ()*/0) != SIM_RC_OK)
> + {
> + free_state (sd);
> + return 0;
> + }
> +
> + if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
> + {
> + free_state (sd);
> + return 0;
> + }
> + sim_add_option_table (sd, NULL, pru_options);
> +
> + /* The parser will print an error message for us, so we silently return. */
> + if (sim_parse_args (sd, argv) != SIM_RC_OK)
> + {
> + free_state (sd);
> + return 0;
> + }
> +
> + /* Check for/establish a reference program image. */
> + if (sim_analyze_program (sd,
> + (STATE_PROG_ARGV (sd) != NULL
> + ? *STATE_PROG_ARGV (sd)
> + : NULL), abfd) != SIM_RC_OK)
> + {
> + free_state (sd);
> + return 0;
> + }
> +
> + /* Configure/verify the target byte order and other runtime
> + configuration options. */
> + if (sim_config (sd) != SIM_RC_OK)
> + {
> + sim_module_uninstall (sd);
> + return 0;
> + }
> +
> + if (sim_post_argv_init (sd) != SIM_RC_OK)
> + {
> + /* Uninstall the modules to avoid memory leaks,
> + file descriptor leaks, etc. */
> + sim_module_uninstall (sd);
> + return 0;
> + }
> +
> + /* CPU specific initialization. */
> + for (i = 0; i < MAX_NR_PROCESSORS; ++i)
> + {
> + SIM_CPU *cpu = STATE_CPU (sd, i);
> +
> + CPU_REG_STORE (cpu) = pru_store_register;
> + CPU_REG_FETCH (cpu) = pru_fetch_register;
> + CPU_PC_FETCH (cpu) = pru_pc_get;
> + CPU_PC_STORE (cpu) = pru_pc_set;
> +
> + set_initial_gprs (cpu);
> + }
> +
> + /* Allocate external memory if none specified by user.
> + Use address 4 here in case the user wanted address 0 unmapped. */
> + if (sim_core_read_buffer (sd, NULL, read_map, &c, 4, 1) == 0)
> + {
> + sim_do_commandf (sd, "memory-region 0x%x,0x%x",
> + 0,
> + DMEM_DEFAULT_SIZE);
> + }
> + if (sim_core_read_buffer (sd, NULL, read_map, &c, IMEM_ADDR_DEFAULT, 1) == 0)
> + {
> + sim_do_commandf (sd, "memory-region 0x%x,0x%x",
> + IMEM_ADDR_DEFAULT,
> + IMEM_DEFAULT_SIZE);
> + }
> +
> + return sd;
> +}
> +
> +/* Implement standard sim_create_inferior function. */
> +SIM_RC
> +sim_create_inferior (SIM_DESC sd, struct bfd *prog_bfd,
> + char * const *argv, char * const *env)
> +{
> + SIM_CPU *cpu = STATE_CPU (sd, 0);
> + SIM_ADDR addr;
> +
> + addr = bfd_get_start_address (prog_bfd);
> +
> + sim_pc_set (cpu, addr);
> + PC_ADDR_SPACE_MARKER = addr & ~IMEM_ADDR_MASK;
> +
> + /* Standalone mode (i.e. `run`) will take care of the argv for us in
> + sim_open () -> sim_parse_args (). But in debug mode (i.e. 'target sim'
> + with `gdb`), we need to handle it because the user can change the
> + argv on the fly via gdb's 'run'. */
> + if (STATE_PROG_ARGV (sd) != argv)
> + {
> + freeargv (STATE_PROG_ARGV (sd));
> + STATE_PROG_ARGV (sd) = dupargv (argv);
> + }
> +
> + return SIM_RC_OK;
> +}
> diff --git a/sim/pru/pru.h b/sim/pru/pru.h
> new file mode 100644
> index 0000000000..8b005ef0b5
> --- /dev/null
> +++ b/sim/pru/pru.h
> @@ -0,0 +1,110 @@
> +/* Copyright 2016-2019 Free Software Foundation, Inc.
> + Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
> +
> + This file is part of the PRU simulator.
> +
> + This library 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 PRU_H
> +#define PRU_H
> +
> +#include "config.h"
> +#include "opcode/pru.h"
> +
> +/* NOTE: Needed for handling the dual PRU address space. */
> +#define IMEM_ADDR_MASK ((1u << 23) - 1)
> +
> +#define IMEM_ADDR_DEFAULT 0x20000000
> +
> +/* Define memory sizes to allocate for simulated target. Sizes are
> + artificially large to accommodate execution of compiler test suite.
> + Please synchronize with the linker script for prusim target. */
> +#define DMEM_DEFAULT_SIZE (64 * 1024 * 1024)
> +
> +/* 16-bit word addressable space. */
> +#define IMEM_DEFAULT_SIZE (64 * 4 * 1024)
> +
> +/* For AM335x SoCs. */
> +#define XFRID_SCRATCH_BANK_0 10
> +#define XFRID_SCRATCH_BANK_1 11
> +#define XFRID_SCRATCH_BANK_2 12
> +#define XFRID_SCRATCH_BANK_PEER 14
> +#define XFRID_MAX 255
> +
> +#define CPU (cpu->pru_cpu)
> +
> +#define PC (CPU.pc)
> +#define PC_byteaddr ((PC << 2) | PC_ADDR_SPACE_MARKER)
> +
> +/* Various opcode fields. */
> +#define RS1 extract_regval (CPU.regs[GET_INSN_FIELD (RS1, inst)], \
> + GET_INSN_FIELD (RS1SEL, inst))
> +#define RS2 extract_regval (CPU.regs[GET_INSN_FIELD (RS2, inst)], \
> + GET_INSN_FIELD (RS2SEL, inst))
> +
> +#define RS2_w0 extract_regval (CPU.regs[GET_INSN_FIELD (RS2, inst)], \
> + RSEL_15_0)
> +
> +#define XBBO_BASEREG (CPU.regs[GET_INSN_FIELD (RS1, inst)])
> +
> +#define RDSEL GET_INSN_FIELD (RDSEL, inst)
> +#define RD_WIDTH regsel_width (RDSEL)
> +#define RD_REGN GET_INSN_FIELD (RD, inst)
> +#define IO GET_INSN_FIELD (IO, inst)
> +#define IMM8 GET_INSN_FIELD (IMM8, inst)
> +#define IMM16 GET_INSN_FIELD (IMM16, inst)
> +#define WAKEONSTATUS GET_INSN_FIELD (WAKEONSTATUS, inst)
> +#define CB GET_INSN_FIELD (CB, inst)
> +#define RDB GET_INSN_FIELD (RDB, inst)
> +#define XFR_WBA GET_INSN_FIELD (XFR_WBA, inst)
> +#define LOOP_JMPOFFS GET_INSN_FIELD (LOOP_JMPOFFS, inst)
> +#define BROFF ((uint32_t) GET_BROFF_SIGNED (inst))
> +
> +#define _BURSTLEN_CALCULATE(BITFIELD) \
> + ((BITFIELD) >= LSSBBO_BYTECOUNT_R0_BITS7_0 ? \
> + (CPU.regs[0] >> ((BITFIELD) - LSSBBO_BYTECOUNT_R0_BITS7_0) * 8) & 0xff \
> + : (BITFIELD) + 1)
> +
> +#define BURSTLEN _BURSTLEN_CALCULATE (GET_BURSTLEN (inst))
> +#define XFR_LENGTH _BURSTLEN_CALCULATE (GET_INSN_FIELD (XFR_LENGTH, inst))
> +
> +#define DO_XIN(wba,regn,rdb,l) \
> + pru_sim_xin (sd, cpu, (wba), (regn), (rdb), (l))
> +#define DO_XOUT(wba,regn,rdb,l) \
> + pru_sim_xout (sd, cpu, (wba), (regn), (rdb), (l))
> +#define DO_XCHG(wba,regn,rdb,l) \
> + pru_sim_xchg (sd, cpu, (wba), (regn), (rdb), (l))
> +
> +#define RAISE_SIGILL(sd) sim_engine_halt ((sd), NULL, NULL, PC_byteaddr, \
> + sim_stopped, SIM_SIGILL)
> +#define RAISE_SIGINT(sd) sim_engine_halt ((sd), NULL, NULL, PC_byteaddr, \
> + sim_stopped, SIM_SIGINT)
> +
> +#define MAC_R25_MAC_MODE_MASK (1u << 0)
> +#define MAC_R25_ACC_CARRY_MASK (1u << 1)
> +
> +#define CARRY CPU.carry
> +#define CTABLE CPU.ctable
> +
> +#define PC_ADDR_SPACE_MARKER CPU.pc_addr_space_marker
> +
> +#define LOOPTOP CPU.loop.looptop
> +#define LOOPEND CPU.loop.loopend
> +#define LOOP_IN_PROGRESS CPU.loop.loop_in_progress
> +#define LOOPCNT CPU.loop.loop_counter
> +
> +/* 32 GP registers plus PC. */
> +#define NUM_REGS 33
> +
> +#endif /* PRU_H */
> diff --git a/sim/pru/pru.isa b/sim/pru/pru.isa
> new file mode 100644
> index 0000000000..c906b2a169
> --- /dev/null
> +++ b/sim/pru/pru.isa
> @@ -0,0 +1,249 @@
> +/* Copyright 2016-2019 Free Software Foundation, Inc.
> + Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
> +
> + This file is part of the PRU simulator.
> +
> + This library 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/>. */
> +
> +/*
> + PRU Instruction Set Architecture
> +
> + INSTRUCTION (NAME,
> + SEMANTICS)
> + */
> +
> +INSTRUCTION (add,
> + OP2 = (IO ? IMM8 : RS2);
> + RD = RS1 + OP2;
> + CARRY = (((uint64_t) RS1 + (uint64_t) OP2) >> RD_WIDTH) & 1;
> + PC++)
> +
> +INSTRUCTION (adc,
> + OP2 = (IO ? IMM8 : RS2);
> + RD = RS1 + OP2 + CARRY;
> + CARRY = (((uint64_t) RS1 + (uint64_t) OP2 + (uint64_t) CARRY)
> + >> RD_WIDTH) & 1;
> + PC++)
> +
> +INSTRUCTION (sub,
> + OP2 = (IO ? IMM8 : RS2);
> + RD = RS1 - OP2;
> + CARRY = (((uint64_t) RS1 - (uint64_t) OP2) >> RD_WIDTH) & 1;
> + PC++)
> +
> +INSTRUCTION (suc,
> + OP2 = (IO ? IMM8 : RS2);
> + RD = RS1 - OP2 - CARRY;
> + CARRY = (((uint64_t) RS1 - (uint64_t) OP2 - (uint64_t) CARRY)
> + >> RD_WIDTH) & 1;
> + PC++)
> +
> +INSTRUCTION (rsb,
> + OP2 = (IO ? IMM8 : RS2);
> + RD = OP2 - RS1;
> + CARRY = (((uint64_t) OP2 - (uint64_t) RS1) >> RD_WIDTH) & 1;
> + PC++)
> +
> +INSTRUCTION (rsc,
> + OP2 = (IO ? IMM8 : RS2);
> + RD = OP2 - RS1 - CARRY;
> + CARRY = (((uint64_t) OP2 - (uint64_t) RS1 - (uint64_t) CARRY)
> + >> RD_WIDTH) & 1;
> + PC++)
> +
> +INSTRUCTION (lsl,
> + OP2 = (IO ? IMM8 : RS2);
> + RD = RS1 << (OP2 & 0x1f);
> + PC++)
> +
> +INSTRUCTION (lsr,
> + OP2 = (IO ? IMM8 : RS2);
> + RD = RS1 >> (OP2 & 0x1f);
> + PC++)
> +
> +INSTRUCTION (and,
> + OP2 = (IO ? IMM8 : RS2);
> + RD = RS1 & OP2;
> + PC++)
> +
> +INSTRUCTION (or,
> + OP2 = (IO ? IMM8 : RS2);
> + RD = RS1 | OP2;
> + PC++)
> +
> +INSTRUCTION (xor,
> + OP2 = (IO ? IMM8 : RS2);
> + RD = RS1 ^ OP2;
> + PC++)
> +
> +INSTRUCTION (not,
> + RD = ~RS1;
> + PC++)
> +
> +INSTRUCTION (min,
> + OP2 = (IO ? IMM8 : RS2);
> + RD = RS1 < OP2 ? RS1 : OP2;
> + PC++)
> +
> +INSTRUCTION (max,
> + OP2 = (IO ? IMM8 : RS2);
> + RD = RS1 > OP2 ? RS1 : OP2;
> + PC++)
> +
> +INSTRUCTION (clr,
> + OP2 = (IO ? IMM8 : RS2);
> + RD = RS1 & ~(1u << (OP2 & 0x1f));
> + PC++)
> +
> +INSTRUCTION (set,
> + OP2 = (IO ? IMM8 : RS2);
> + RD = RS1 | (1u << (OP2 & 0x1f));
> + PC++)
> +
> +INSTRUCTION (jmp,
> + OP2 = (IO ? IMM16 : RS2);
> + PC = OP2)
> +
> +INSTRUCTION (jal,
> + OP2 = (IO ? IMM16 : RS2);
> + RD = PC + 1;
> + PC = OP2)
> +
> +INSTRUCTION (ldi,
> + RD = IMM16;
> + PC++)
> +
> +INSTRUCTION (halt,
> + pru_sim_syscall (sd, cpu);
> + PC++)
> +
> +INSTRUCTION (slp,
> + if (!WAKEONSTATUS)
> + {
> + RAISE_SIGINT (sd);
> + }
> + else
> + {
> + PC++;
> + })
> +
> +INSTRUCTION (qbgt,
> + OP2 = (IO ? IMM8 : RS2);
> + PC = (OP2 > RS1) ? (PC + BROFF) : (PC + 1))
> +
> +INSTRUCTION (qbge,
> + OP2 = (IO ? IMM8 : RS2);
> + PC = (OP2 >= RS1) ? (PC + BROFF) : (PC + 1))
> +
> +INSTRUCTION (qblt,
> + OP2 = (IO ? IMM8 : RS2);
> + PC = (OP2 < RS1) ? (PC + BROFF) : (PC + 1))
> +
> +INSTRUCTION (qble,
> + OP2 = (IO ? IMM8 : RS2);
> + PC = (OP2 <= RS1) ? (PC + BROFF) : (PC + 1))
> +
> +INSTRUCTION (qbeq,
> + OP2 = (IO ? IMM8 : RS2);
> + PC = (OP2 == RS1) ? (PC + BROFF) : (PC + 1))
> +
> +INSTRUCTION (qbne,
> + OP2 = (IO ? IMM8 : RS2);
> + PC = (OP2 != RS1) ? (PC + BROFF) : (PC + 1))
> +
> +INSTRUCTION (qba,
> + OP2 = (IO ? IMM8 : RS2);
> + PC = PC + BROFF)
> +
> +INSTRUCTION (qbbs,
> + OP2 = (IO ? IMM8 : RS2);
> + PC = (RS1 & (1u << (OP2 & 0x1f))) ? (PC + BROFF) : (PC + 1))
> +
> +INSTRUCTION (qbbc,
> + OP2 = (IO ? IMM8 : RS2);
> + PC = !(RS1 & (1u << (OP2 & 0x1f))) ? (PC + BROFF) : (PC + 1))
> +
> +INSTRUCTION (lbbo,
> + pru_dmem2reg (cpu, XBBO_BASEREG + (IO ? IMM8 : RS2),
> + BURSTLEN, RD_REGN, RDB);
> + PC++)
> +
> +INSTRUCTION (sbbo,
> + pru_reg2dmem (cpu, XBBO_BASEREG + (IO ? IMM8 : RS2),
> + BURSTLEN, RD_REGN, RDB);
> + PC++)
> +
> +INSTRUCTION (lbco,
> + pru_dmem2reg (cpu, CTABLE[CB] + (IO ? IMM8 : RS2),
> + BURSTLEN, RD_REGN, RDB);
> + PC++)
> +
> +INSTRUCTION (sbco,
> + pru_reg2dmem (cpu, CTABLE[CB] + (IO ? IMM8 : RS2),
> + BURSTLEN, RD_REGN, RDB);
> + PC++)
> +
> +INSTRUCTION (xin,
> + DO_XIN (XFR_WBA, RD_REGN, RDB, XFR_LENGTH);
> + PC++)
> +
> +INSTRUCTION (xout,
> + DO_XOUT (XFR_WBA, RD_REGN, RDB, XFR_LENGTH);
> + PC++)
> +
> +INSTRUCTION (xchg,
> + DO_XCHG (XFR_WBA, RD_REGN, RDB, XFR_LENGTH);
> + PC++)
> +
> +INSTRUCTION (sxin,
> + sim_io_eprintf (sd, "SXIN instruction not supported by sim\n");
> + RAISE_SIGILL (sd))
> +
> +INSTRUCTION (sxout,
> + sim_io_eprintf (sd, "SXOUT instruction not supported by sim\n");
> + RAISE_SIGILL (sd))
> +
> +INSTRUCTION (sxchg,
> + sim_io_eprintf (sd, "SXCHG instruction not supported by sim\n");
> + RAISE_SIGILL (sd))
> +
> +INSTRUCTION (loop,
> + OP2 = (IO ? IMM8 + 1 : RS2_w0);
> + if (OP2 == 0)
> + {
> + PC = LOOPEND;
> + }
> + else
> + {
> + LOOPTOP = PC + 1;
> + LOOPEND = PC + LOOP_JMPOFFS;
> + LOOPCNT = OP2;
> + LOOP_IN_PROGRESS = 1;
> + PC++;
> + })
> +
> +INSTRUCTION (iloop,
> + OP2 = (IO ? IMM8 + 1 : RS2_w0);
> + if (OP2 == 0)
> + {
> + PC = LOOPEND;
> + }
> + else
> + {
> + LOOPTOP = PC + 1;
> + LOOPEND = PC + LOOP_JMPOFFS;
> + LOOPCNT = OP2;
> + LOOP_IN_PROGRESS = 1;
> + PC++;
> + })
> diff --git a/sim/pru/sim-main.h b/sim/pru/sim-main.h
> new file mode 100644
> index 0000000000..b8a2c20ea8
> --- /dev/null
> +++ b/sim/pru/sim-main.h
> @@ -0,0 +1,91 @@
> +/* Copyright 2016-2019 Free Software Foundation, Inc.
> + Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
> +
> + This file is part of the PRU simulator.
> +
> + This library 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 PRU_SIM_MAIN
> +#define PRU_SIM_MAIN
> +
> +#include <stdint.h>
> +#include <stddef.h>
> +#include "pru.h"
> +#include "sim-basics.h"
> +
> +#include "sim-base.h"
> +
> +/* The machine state.
> + This state is maintained in host byte order. The
> + fetch/store register functions must translate between host
> + byte order and the target processor byte order.
> + Keeping this data in target byte order simplifies the register
> + read/write functions. Keeping this data in host order improves
> + the performance of the simulator. Simulation speed is deemed more
> + important. */
> +
> +/* For clarity, please keep the same relative order in this enum as in the
> + corresponding group of GP registers.
> +
> + In PRU ISA, Multiplier-Accumulator-Unit's registers are like "shadows" of
> + the GP registers. MAC registers are implicitly addressed when executing
> + the XIN/XOUT instructions to access them. Transfer to/from a MAC register
> + can happen only from/to its corresponding GP peer register. */
> +
> +enum pru_macreg_id {
> + /* MAC register CPU GP register Description. */
> + PRU_MACREG_MODE, /* r25 */ /* Mode (MUL/MAC). */
> + PRU_MACREG_PROD_L, /* r26 */ /* Lower 32 bits of product. */
> + PRU_MACREG_PROD_H, /* r27 */ /* Higher 32 bits of product. */
> + PRU_MACREG_OP_0, /* r28 */ /* First operand. */
> + PRU_MACREG_OP_1, /* r29 */ /* Second operand. */
> + PRU_MACREG_ACC_L, /* N/A */ /* Accumulator (not exposed) */
> + PRU_MACREG_ACC_H, /* N/A */ /* Higher 32 bits of MAC
> + accumulator. */
> + PRU_MAC_NREGS
> +};
> +
> +struct pru_regset
> +{
> + uint32_t regs[32]; /* Primary registers. */
> + uint16_t pc; /* IMEM _word_ address. */
> + uint32_t pc_addr_space_marker; /* IMEM virtual linker offset. This
> + is the artificial offset that
> + we invent in order to "separate"
> + the DMEM and IMEM memory spaces. */
> + unsigned int carry : 1;
> + uint32_t ctable[32]; /* Constant offsets table for xBCO. */
> + uint32_t macregs[PRU_MAC_NREGS];
> + uint32_t scratchpads[XFRID_MAX + 1][32];
> + struct {
> + uint16_t looptop; /* LOOP top (PC of loop instr). */
> + uint16_t loopend; /* LOOP end (PC of loop end label). */
> + int loop_in_progress; /* Whether to check for PC==loopend. */
> + uint32_t loop_counter; /* LOOP counter. */
> + } loop;
> + int cycles;
> + int insts;
> +};
> +
> +struct _sim_cpu {
> + struct pru_regset pru_cpu;
> + sim_cpu_base base;
> +};
> +
> +struct sim_state {
> + sim_cpu *cpu[MAX_NR_PROCESSORS];
> +
> + sim_state_base base;
> +};
> +#endif /* PRU_SIM_MAIN */
> --
> 2.20.1
>
On вторник, 24 септември 2019 г. 0:12:58 EEST Andrew Burgess wrote:
> From: Andrew Burgess <andrew.burgess@embecosm.com>
> To: Dimitar Dimitrov <dimitar@dinux.eu>
> CC: gdb-patches@sourceware.org
> Sender: gdb-patches-owner@sourceware.org
> List-Id: <gdb-patches.sourceware.org>
> Date: 24.09.19 г. 0:12
> Spam Status: Spamassassin
>
> * Dimitar Dimitrov <dimitar@dinux.eu> [2019-09-04 22:40:29 +0300]:
> > I'd like to contribute a sim port for the TI PRU I/O processor. This
> > is the sixth version of the patch series.
> >
> > Changes since patch series v5:
> > - Added copyright headers to test cases.
> > - Regenerated using autoconf-2.69 and automake-1.5.1
> > - Added more comments to functions and MAC register enum.
> > - Updated copyright years.
>
> Thanks for all this effort over the years!
>
> I merged together patch #3 with #1 and pushed this to master.
>
> Thanks,
> Andrew
Thank you for reviewing it.
Regards,
Dimitar
@@ -318,6 +318,10 @@ maint show test-options-completion-result
GDB now bundles GNU readline 8.0, but if you choose to use
--with-system-readline, only readline >= 7.0 can be used.
+* New Simulators
+
+TI PRU pru-*-elf
+
*** Changes in GDB 8.3
* GDB and GDBserver now support access to additional registers on
@@ -29,6 +29,7 @@ mips I-IV Maciej W. Rozycki <macro@linux-mips.org>
moxie Anthony Green <green@moxielogic.com>
msp430 Nick Clifton <nickc@redhat.com>
or1k Stafford Horne <shorne@gmail.com>
+pru Dimitar Dimitrov <dimitar@dinux.eu>
sh (global maintainers)
sh64 Dave Brolley <brolley@redhat.com>
common Frank Ch. Eigler <fche@redhat.com>
@@ -95,3 +95,7 @@ $shell ${srccom}/gentvals.sh $target sys ${newlibroot}/$dir \
dir=libgloss target=lm32
$shell ${srccom}/gentvals.sh $target sys ${newlibroot}/$dir \
"syscall.h" 'SYS_[_[:alnum:]]*' "${cpp}"
+
+dir=libgloss target=pru
+$shell ${srccom}/gentvals.sh $target sys ${newlibroot}/$dir \
+ "syscall.h" 'SYS_[_[:alnum:]]*' "${cpp}"
@@ -574,3 +574,34 @@
/* end lm32 sys target macros */
#endif
#endif
+#ifdef NL_TARGET_pru
+#ifdef sys_defs
+/* from syscall.h */
+/* begin pru sys target macros */
+ { "SYS_argc", 22 },
+ { "SYS_argn", 24 },
+ { "SYS_argnlen", 23 },
+ { "SYS_argv", 13 },
+ { "SYS_argvlen", 12 },
+ { "SYS_chdir", 14 },
+ { "SYS_chmod", 16 },
+ { "SYS_close", 3 },
+ { "SYS_exit", 1 },
+ { "SYS_fstat", 10 },
+ { "SYS_getpid", 8 },
+ { "SYS_gettimeofday", 19 },
+ { "SYS_kill", 9 },
+ { "SYS_link", 21 },
+ { "SYS_lseek", 6 },
+ { "SYS_open", 2 },
+ { "SYS_read", 4 },
+ { "SYS_reconfig", 25 },
+ { "SYS_stat", 15 },
+ { "SYS_time", 18 },
+ { "SYS_times", 20 },
+ { "SYS_unlink", 7 },
+ { "SYS_utime", 17 },
+ { "SYS_write", 5 },
+/* end pru sys target macros */
+#endif
+#endif
@@ -686,6 +686,7 @@ mn10300
moxie
msp430
or1k
+pru
rl78
rx
sh64
@@ -3837,6 +3838,13 @@ subdirs="$subdirs aarch64"
subdirs="$subdirs or1k"
+ ;;
+ pru*-*-*)
+
+ sim_arch=pru
+ subdirs="$subdirs pru"
+
+
;;
rl78-*-*)
@@ -79,6 +79,9 @@ case "${target}" in
or1k-*-* | or1knd-*-*)
SIM_ARCH(or1k)
;;
+ pru*-*-*)
+ SIM_ARCH(pru)
+ ;;
rl78-*-*)
SIM_ARCH(rl78)
;;
new file mode 100644
@@ -0,0 +1,29 @@
+# Makefile template for Configure for the PRU sim library.
+# Copyright (C) 1990-2019 Free Software Foundation, Inc.
+# Written by Dimitar Dimitrov <dimitar@dinux.eu>
+#
+# Based on the MCore sim library
+#
+# 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_OBJS = \
+ $(SIM_NEW_COMMON_OBJS) \
+ interp.o \
+ sim-resume.o
+
+NL_TARGET = -DNL_TARGET_pru
+
+## COMMON_POST_CONFIG_FRAG
new file mode 100644
@@ -0,0 +1,119 @@
+# generated automatically by aclocal 1.15.1 -*- Autoconf -*-
+
+# Copyright (C) 1996-2017 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.
+
+m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
+# AM_CONDITIONAL -*- Autoconf -*-
+
+# Copyright (C) 1997-2017 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.
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ([2.52])dnl
+ m4_if([$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])])
+
+# Copyright (C) 2003-2017 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.
+
+# Check whether the underlying file-system supports filenames
+# with a leading dot. For instance MS-DOS doesn't.
+AC_DEFUN([AM_SET_LEADING_DOT],
+[rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+ am__leading_dot=.
+else
+ am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+AC_SUBST([am__leading_dot])])
+
+# Add --enable-maintainer-mode option to configure. -*- Autoconf -*-
+# From Jim Meyering
+
+# Copyright (C) 1996-2017 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.
+
+# 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],
+ [AS_HELP_STRING([--]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
+]
+)
+
+# Copyright (C) 2006-2017 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.
+
+# _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($@)])
+
new file mode 100644
@@ -0,0 +1,248 @@
+/* config.in. Generated from configure.ac by autoheader. */
+
+/* Define if building universal (internal helper macro) */
+#undef AC_APPLE_UNIVERSAL_BUILD
+
+/* Sim debug setting */
+#undef DEBUG
+
+/* 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 `ftruncate' function. */
+#undef HAVE_FTRUNCATE
+
+/* 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 `lstat' function. */
+#undef HAVE_LSTAT
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `mmap' function. */
+#undef HAVE_MMAP
+
+/* Define to 1 if you have the `munmap' function. */
+#undef HAVE_MUNMAP
+
+/* Define to 1 if you have the `posix_fallocate' function. */
+#undef HAVE_POSIX_FALLOCATE
+
+/* Define to 1 if you have the `sigaction' function. */
+#undef HAVE_SIGACTION
+
+/* Define to 1 if the system has the type `socklen_t'. */
+#undef HAVE_SOCKLEN_T
+
+/* 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 `st_atime' is a member of `struct stat'. */
+#undef HAVE_STRUCT_STAT_ST_ATIME
+
+/* Define to 1 if `st_blksize' is a member of `struct stat'. */
+#undef HAVE_STRUCT_STAT_ST_BLKSIZE
+
+/* Define to 1 if `st_blocks' is a member of `struct stat'. */
+#undef HAVE_STRUCT_STAT_ST_BLOCKS
+
+/* Define to 1 if `st_ctime' is a member of `struct stat'. */
+#undef HAVE_STRUCT_STAT_ST_CTIME
+
+/* Define to 1 if `st_dev' is a member of `struct stat'. */
+#undef HAVE_STRUCT_STAT_ST_DEV
+
+/* Define to 1 if `st_gid' is a member of `struct stat'. */
+#undef HAVE_STRUCT_STAT_ST_GID
+
+/* Define to 1 if `st_ino' is a member of `struct stat'. */
+#undef HAVE_STRUCT_STAT_ST_INO
+
+/* Define to 1 if `st_mode' is a member of `struct stat'. */
+#undef HAVE_STRUCT_STAT_ST_MODE
+
+/* Define to 1 if `st_mtime' is a member of `struct stat'. */
+#undef HAVE_STRUCT_STAT_ST_MTIME
+
+/* Define to 1 if `st_nlink' is a member of `struct stat'. */
+#undef HAVE_STRUCT_STAT_ST_NLINK
+
+/* Define to 1 if `st_rdev' is a member of `struct stat'. */
+#undef HAVE_STRUCT_STAT_ST_RDEV
+
+/* Define to 1 if `st_size' is a member of `struct stat'. */
+#undef HAVE_STRUCT_STAT_ST_SIZE
+
+/* Define to 1 if `st_uid' is a member of `struct stat'. */
+#undef HAVE_STRUCT_STAT_ST_UID
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#undef HAVE_SYS_MMAN_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/times.h> header file. */
+#undef HAVE_SYS_TIMES_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 `truncate' function. */
+#undef HAVE_TRUNCATE
+
+/* 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
+
+/* Sim profile settings */
+#undef PROFILE
+
+/* 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
+
+
+/* Sim assert settings */
+#undef WITH_ASSERT
+
+/* Sim debug setting */
+#undef WITH_DEBUG
+
+/* Sim default environment */
+#undef WITH_ENVIRONMENT
+
+/* Sim profile settings */
+#undef WITH_PROFILE
+
+/* How to route I/O */
+#undef WITH_STDIO
+
+/* Sim trace settings */
+#undef WITH_TRACE
+
+/* 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
new file mode 100644
@@ -0,0 +1,31 @@
+dnl Process this file with autoconf to produce a configure script.
+
+dnl Copyright (C) 2016-2019 Free Software Foundation, Inc.
+dnl Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
+dnl
+dnl This file is part of the GNU simulators.
+dnl
+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/>.
+dnl
+AC_PREREQ(2.64)dnl
+AC_INIT(Makefile.in)
+sinclude(../common/acinclude.m4)
+
+SIM_AC_COMMON
+
+SIM_AC_OPTION_ENDIAN(LITTLE)
+SIM_AC_OPTION_ALIGNMENT(STRICT_ALIGNMENT,STRICT_ALIGNMENT)
+SIM_AC_OPTION_WARNINGS
+
+SIM_AC_OUTPUT
new file mode 100644
@@ -0,0 +1,848 @@
+/* Simulator for the Texas Instruments PRU processor
+ Copyright 2009-2019 Free Software Foundation, Inc.
+ Inspired by the Microblaze simulator
+ Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
+
+ This file is part of the simulators.
+
+ 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 <stdbool.h>
+#include <stdint.h>
+#include <stddef.h>
+#include "bfd.h"
+#include "gdb/callback.h"
+#include "libiberty.h"
+#include "gdb/remote-sim.h"
+#include "sim-main.h"
+#include "sim-assert.h"
+#include "sim-options.h"
+#include "sim-syscall.h"
+#include "pru.h"
+
+/* DMEM zero address is perfectly valid. But if CRT leaves the first word
+ alone, we can use it as a trap to catch NULL pointer access. */
+static bfd_boolean abort_on_dmem_zero_access;
+
+enum {
+ OPTION_ERROR_NULL_DEREF = OPTION_START,
+};
+
+/* Extract (from PRU endianess) and return an integer in HOST's endianness. */
+static uint32_t
+pru_extract_unsigned_integer (uint8_t *addr, size_t len)
+{
+ uint32_t retval;
+ uint8_t *p;
+ uint8_t *startaddr = addr;
+ uint8_t *endaddr = startaddr + len;
+
+ /* Start at the most significant end of the integer, and work towards
+ the least significant. */
+ retval = 0;
+
+ for (p = endaddr; p > startaddr;)
+ retval = (retval << 8) | * -- p;
+ return retval;
+}
+
+/* Store "val" (which is in HOST's endianess) into "addr"
+ (using PRU's endianness). */
+static void
+pru_store_unsigned_integer (uint8_t *addr, size_t len, uint32_t val)
+{
+ uint8_t *p;
+ uint8_t *startaddr = (uint8_t *)addr;
+ uint8_t *endaddr = startaddr + len;
+
+ for (p = startaddr; p < endaddr;)
+ {
+ *p++ = val & 0xff;
+ val >>= 8;
+ }
+}
+
+/* Extract a field value from CPU register using the given REGSEL selector.
+
+ Byte number maps directly to first values of RSEL, so we can
+ safely use "regsel" as a register byte number (0..3). */
+static inline uint32_t
+extract_regval (uint32_t val, uint32_t regsel)
+{
+ ASSERT (RSEL_7_0 == 0);
+ ASSERT (RSEL_15_8 == 1);
+ ASSERT (RSEL_23_16 == 2);
+ ASSERT (RSEL_31_24 == 3);
+
+ switch (regsel)
+ {
+ case RSEL_7_0: return (val >> 0) & 0xff;
+ case RSEL_15_8: return (val >> 8) & 0xff;
+ case RSEL_23_16: return (val >> 16) & 0xff;
+ case RSEL_31_24: return (val >> 24) & 0xff;
+ case RSEL_15_0: return (val >> 0) & 0xffff;
+ case RSEL_23_8: return (val >> 8) & 0xffff;
+ case RSEL_31_16: return (val >> 16) & 0xffff;
+ case RSEL_31_0: return val;
+ default: sim_io_error (NULL, "invalid regsel");
+ }
+}
+
+/* Write a value into CPU subregister pointed by reg and regsel. */
+static inline void
+write_regval (uint32_t val, uint32_t *reg, uint32_t regsel)
+{
+ uint32_t mask, sh;
+
+ switch (regsel)
+ {
+ case RSEL_7_0: mask = (0xffu << 0); sh = 0; break;
+ case RSEL_15_8: mask = (0xffu << 8); sh = 8; break;
+ case RSEL_23_16: mask = (0xffu << 16); sh = 16; break;
+ case RSEL_31_24: mask = (0xffu << 24); sh = 24; break;
+ case RSEL_15_0: mask = (0xffffu << 0); sh = 0; break;
+ case RSEL_23_8: mask = (0xffffu << 8); sh = 8; break;
+ case RSEL_31_16: mask = (0xffffu << 16); sh = 16; break;
+ case RSEL_31_0: mask = 0xffffffffu; sh = 0; break;
+ default: sim_io_error (NULL, "invalid regsel");
+ }
+
+ *reg = (*reg & ~mask) | ((val << sh) & mask);
+}
+
+/* Convert the given IMEM word address to a regular byte address used by the
+ GNU ELF container. */
+static uint32_t
+imem_wordaddr_to_byteaddr (SIM_CPU *cpu, uint16_t wa)
+{
+ return (((uint32_t) wa << 2) & IMEM_ADDR_MASK) | PC_ADDR_SPACE_MARKER;
+}
+
+/* Convert the given ELF text byte address to IMEM word address. */
+static uint16_t
+imem_byteaddr_to_wordaddr (SIM_CPU *cpu, uint32_t ba)
+{
+ return (ba >> 2) & 0xffff;
+}
+
+
+/* Store "nbytes" into DMEM "addr" from CPU register file, starting with
+ register "regn", and byte "regb" within it. */
+static inline void
+pru_reg2dmem (SIM_CPU *cpu, uint32_t addr, unsigned int nbytes,
+ int regn, int regb)
+{
+ /* GDB assumes unconditional access to all memories, so enable additional
+ checks only in standalone mode. */
+ bool standalone = (STATE_OPEN_KIND (CPU_STATE (cpu)) == SIM_OPEN_STANDALONE);
+
+ if (abort_on_dmem_zero_access && addr < 4)
+ {
+ sim_core_signal (CPU_STATE (cpu), cpu, PC_byteaddr, write_map,
+ nbytes, addr, write_transfer,
+ sim_core_unmapped_signal);
+ }
+ else if (standalone && ((addr >= PC_ADDR_SPACE_MARKER)
+ || (addr + nbytes > PC_ADDR_SPACE_MARKER)))
+ {
+ sim_core_signal (CPU_STATE (cpu), cpu, PC_byteaddr, write_map,
+ nbytes, addr, write_transfer,
+ sim_core_unmapped_signal);
+ }
+ else if ((regn * 4 + regb + nbytes) > (32 * 4))
+ {
+ sim_io_eprintf (CPU_STATE (cpu),
+ "SBBO/SBCO with invalid store data length\n");
+ RAISE_SIGILL (CPU_STATE (cpu));
+ }
+ else
+ {
+ TRACE_MEMORY (cpu, "write of %d bytes to %08x", nbytes, addr);
+ while (nbytes--)
+ {
+ sim_core_write_1 (cpu,
+ PC_byteaddr,
+ write_map,
+ addr++,
+ extract_regval (CPU.regs[regn], regb));
+
+ if (++regb >= 4)
+ {
+ regb = 0;
+ regn++;
+ }
+ }
+ }
+}
+
+/* Load "nbytes" from DMEM "addr" into CPU register file, starting with
+ register "regn", and byte "regb" within it. */
+static inline void
+pru_dmem2reg (SIM_CPU *cpu, uint32_t addr, unsigned int nbytes,
+ int regn, int regb)
+{
+ /* GDB assumes unconditional access to all memories, so enable additional
+ checks only in standalone mode. */
+ bool standalone = (STATE_OPEN_KIND (CPU_STATE (cpu)) == SIM_OPEN_STANDALONE);
+
+ if (abort_on_dmem_zero_access && addr < 4)
+ {
+ sim_core_signal (CPU_STATE (cpu), cpu, PC_byteaddr, read_map,
+ nbytes, addr, read_transfer,
+ sim_core_unmapped_signal);
+ }
+ else if (standalone && ((addr >= PC_ADDR_SPACE_MARKER)
+ || (addr + nbytes > PC_ADDR_SPACE_MARKER)))
+ {
+ /* This check is necessary because our IMEM "address space"
+ is not really accessible, yet we have mapped it as a generic
+ memory space. */
+ sim_core_signal (CPU_STATE (cpu), cpu, PC_byteaddr, read_map,
+ nbytes, addr, read_transfer,
+ sim_core_unmapped_signal);
+ }
+ else if ((regn * 4 + regb + nbytes) > (32 * 4))
+ {
+ sim_io_eprintf (CPU_STATE (cpu),
+ "LBBO/LBCO with invalid load data length\n");
+ RAISE_SIGILL (CPU_STATE (cpu));
+ }
+ else
+ {
+ unsigned int b;
+ TRACE_MEMORY (cpu, "read of %d bytes from %08x", nbytes, addr);
+ while (nbytes--)
+ {
+ b = sim_core_read_1 (cpu, PC_byteaddr, read_map, addr++);
+
+ /* Reuse the fact the Register Byte Number maps directly to RSEL. */
+ ASSERT (RSEL_7_0 == 0);
+ write_regval (b, &CPU.regs[regn], regb);
+
+ if (++regb >= 4)
+ {
+ regb = 0;
+ regn++;
+ }
+ }
+ }
+}
+
+/* Set reset values of general-purpose registers. */
+static void
+set_initial_gprs (SIM_CPU *cpu)
+{
+ int i;
+
+ /* Set up machine just out of reset. */
+ CPU_PC_SET (cpu, 0);
+ PC_ADDR_SPACE_MARKER = IMEM_ADDR_DEFAULT; /* from default linker script? */
+
+ /* Clean out the GPRs. */
+ for (i = 0; i < ARRAY_SIZE (CPU.regs); i++)
+ CPU.regs[i] = 0;
+ for (i = 0; i < ARRAY_SIZE (CPU.macregs); i++)
+ CPU.macregs[i] = 0;
+
+ CPU.loop.looptop = CPU.loop.loopend = 0;
+ CPU.loop.loop_in_progress = 0;
+ CPU.loop.loop_counter = 0;
+
+ CPU.carry = 0;
+ CPU.insts = 0;
+ CPU.cycles = 0;
+
+ /* AM335x should provide sane defaults. */
+ CPU.ctable[0] = 0x00020000;
+ CPU.ctable[1] = 0x48040000;
+ CPU.ctable[2] = 0x4802a000;
+ CPU.ctable[3] = 0x00030000;
+ CPU.ctable[4] = 0x00026000;
+ CPU.ctable[5] = 0x48060000;
+ CPU.ctable[6] = 0x48030000;
+ CPU.ctable[7] = 0x00028000;
+ CPU.ctable[8] = 0x46000000;
+ CPU.ctable[9] = 0x4a100000;
+ CPU.ctable[10] = 0x48318000;
+ CPU.ctable[11] = 0x48022000;
+ CPU.ctable[12] = 0x48024000;
+ CPU.ctable[13] = 0x48310000;
+ CPU.ctable[14] = 0x481cc000;
+ CPU.ctable[15] = 0x481d0000;
+ CPU.ctable[16] = 0x481a0000;
+ CPU.ctable[17] = 0x4819c000;
+ CPU.ctable[18] = 0x48300000;
+ CPU.ctable[19] = 0x48302000;
+ CPU.ctable[20] = 0x48304000;
+ CPU.ctable[21] = 0x00032400;
+ CPU.ctable[22] = 0x480c8000;
+ CPU.ctable[23] = 0x480ca000;
+ CPU.ctable[24] = 0x00000000;
+ CPU.ctable[25] = 0x00002000;
+ CPU.ctable[26] = 0x0002e000;
+ CPU.ctable[27] = 0x00032000;
+ CPU.ctable[28] = 0x00000000;
+ CPU.ctable[29] = 0x49000000;
+ CPU.ctable[30] = 0x40000000;
+ CPU.ctable[31] = 0x80000000;
+}
+
+/* Map regsel selector to subregister field width. */
+static inline unsigned int
+regsel_width (uint32_t regsel)
+{
+ switch (regsel)
+ {
+ case RSEL_7_0: return 8;
+ case RSEL_15_8: return 8;
+ case RSEL_23_16: return 8;
+ case RSEL_31_24: return 8;
+ case RSEL_15_0: return 16;
+ case RSEL_23_8: return 16;
+ case RSEL_31_16: return 16;
+ case RSEL_31_0: return 32;
+ default: sim_io_error (NULL, "invalid regsel");
+ }
+}
+
+/* Handle XIN instruction addressing the MAC peripheral. */
+static void
+pru_sim_xin_mac (SIM_DESC sd, SIM_CPU *cpu, unsigned int rd_regn,
+ unsigned int rdb, unsigned int length)
+{
+ if (rd_regn < 25 || (rd_regn * 4 + rdb + length) > (27 + 1) * 4)
+ sim_io_error (sd, "XIN MAC: invalid transfer regn=%u.%u, length=%u\n",
+ rd_regn, rdb, length);
+
+ /* Copy from MAC to PRU regs. Ranges have been validated above. */
+ while (length--)
+ {
+ write_regval (CPU.macregs[rd_regn - 25] >> (rdb * 8),
+ &CPU.regs[rd_regn],
+ rdb);
+ if (++rdb == 4)
+ {
+ rdb = 0;
+ rd_regn++;
+ }
+ }
+}
+
+/* Handle XIN instruction. */
+static void
+pru_sim_xin (SIM_DESC sd, SIM_CPU *cpu, unsigned int wba,
+ unsigned int rd_regn, unsigned int rdb, unsigned int length)
+{
+ if (wba == 0)
+ {
+ pru_sim_xin_mac (sd, cpu, rd_regn, rdb, length);
+ }
+ else if (wba == XFRID_SCRATCH_BANK_0 || wba == XFRID_SCRATCH_BANK_1
+ || wba == XFRID_SCRATCH_BANK_2 || wba == XFRID_SCRATCH_BANK_PEER)
+ {
+ while (length--)
+ {
+ unsigned int val;
+
+ val = extract_regval (CPU.scratchpads[wba][rd_regn], rdb);
+ write_regval (val, &CPU.regs[rd_regn], rdb);
+ if (++rdb == 4)
+ {
+ rdb = 0;
+ rd_regn++;
+ }
+ }
+ }
+ else if (wba == 254 || wba == 255)
+ {
+ /* FILL/ZERO pseudos implemented via XIN. */
+ unsigned int fillbyte = (wba == 254) ? 0xff : 0x00;
+ while (length--)
+ {
+ write_regval (fillbyte, &CPU.regs[rd_regn], rdb);
+ if (++rdb == 4)
+ {
+ rdb = 0;
+ rd_regn++;
+ }
+ }
+ }
+ else
+ {
+ sim_io_error (sd, "XIN: XFR device %d not supported.\n", wba);
+ }
+}
+
+/* Handle XOUT instruction addressing the MAC peripheral. */
+static void
+pru_sim_xout_mac (SIM_DESC sd, SIM_CPU *cpu, unsigned int rd_regn,
+ unsigned int rdb, unsigned int length)
+{
+ const int modereg_accessed = (rd_regn == 25);
+
+ /* Multiple Accumulate. */
+ if (rd_regn < 25 || (rd_regn * 4 + rdb + length) > (27 + 1) * 4)
+ sim_io_error (sd, "XOUT MAC: invalid transfer regn=%u.%u, length=%u\n",
+ rd_regn, rdb, length);
+
+ /* Copy from PRU to MAC regs. Ranges have been validated above. */
+ while (length--)
+ {
+ write_regval (CPU.regs[rd_regn] >> (rdb * 8),
+ &CPU.macregs[rd_regn - 25],
+ rdb);
+ if (++rdb == 4)
+ {
+ rdb = 0;
+ rd_regn++;
+ }
+ }
+
+ if (modereg_accessed
+ && (CPU.macregs[PRU_MACREG_MODE] & MAC_R25_MAC_MODE_MASK))
+ {
+ /* MUL/MAC operands are sampled every XOUT in multiply and
+ accumulate mode. */
+ uint64_t prod, oldsum, sum;
+ CPU.macregs[PRU_MACREG_OP_0] = CPU.regs[28];
+ CPU.macregs[PRU_MACREG_OP_1] = CPU.regs[29];
+
+ prod = CPU.macregs[PRU_MACREG_OP_0];
+ prod *= (uint64_t)CPU.macregs[PRU_MACREG_OP_1];
+
+ oldsum = CPU.macregs[PRU_MACREG_ACC_L];
+ oldsum += (uint64_t)CPU.macregs[PRU_MACREG_ACC_H] << 32;
+ sum = oldsum + prod;
+
+ CPU.macregs[PRU_MACREG_PROD_L] = sum & 0xfffffffful;
+ CPU.macregs[PRU_MACREG_PROD_H] = sum >> 32;
+ CPU.macregs[PRU_MACREG_ACC_L] = CPU.macregs[PRU_MACREG_PROD_L];
+ CPU.macregs[PRU_MACREG_ACC_H] = CPU.macregs[PRU_MACREG_PROD_H];
+
+ if (oldsum > sum)
+ CPU.macregs[PRU_MACREG_MODE] |= MAC_R25_ACC_CARRY_MASK;
+ }
+ if (modereg_accessed
+ && (CPU.macregs[PRU_MACREG_MODE] & MAC_R25_ACC_CARRY_MASK))
+ {
+ /* store 1 to clear. */
+ CPU.macregs[PRU_MACREG_MODE] &= ~MAC_R25_ACC_CARRY_MASK;
+ CPU.macregs[PRU_MACREG_ACC_L] = 0;
+ CPU.macregs[PRU_MACREG_ACC_H] = 0;
+ }
+
+}
+
+/* Handle XOUT instruction. */
+static void
+pru_sim_xout (SIM_DESC sd, SIM_CPU *cpu, unsigned int wba,
+ unsigned int rd_regn, unsigned int rdb, unsigned int length)
+{
+ if (wba == 0)
+ {
+ pru_sim_xout_mac (sd, cpu, rd_regn, rdb, length);
+ }
+ else if (wba == XFRID_SCRATCH_BANK_0 || wba == XFRID_SCRATCH_BANK_1
+ || wba == XFRID_SCRATCH_BANK_2 || wba == XFRID_SCRATCH_BANK_PEER)
+ {
+ while (length--)
+ {
+ unsigned int val;
+
+ val = extract_regval (CPU.regs[rd_regn], rdb);
+ write_regval (val, &CPU.scratchpads[wba][rd_regn], rdb);
+ if (++rdb == 4)
+ {
+ rdb = 0;
+ rd_regn++;
+ }
+ }
+ }
+ else
+ sim_io_error (sd, "XOUT: XFR device %d not supported.\n", wba);
+}
+
+/* Handle XCHG instruction. */
+static void
+pru_sim_xchg (SIM_DESC sd, SIM_CPU *cpu, unsigned int wba,
+ unsigned int rd_regn, unsigned int rdb, unsigned int length)
+{
+ if (wba == XFRID_SCRATCH_BANK_0 || wba == XFRID_SCRATCH_BANK_1
+ || wba == XFRID_SCRATCH_BANK_2 || wba == XFRID_SCRATCH_BANK_PEER)
+ {
+ while (length--)
+ {
+ unsigned int valr, vals;
+
+ valr = extract_regval (CPU.regs[rd_regn], rdb);
+ vals = extract_regval (CPU.scratchpads[wba][rd_regn], rdb);
+ write_regval (valr, &CPU.scratchpads[wba][rd_regn], rdb);
+ write_regval (vals, &CPU.regs[rd_regn], rdb);
+ if (++rdb == 4)
+ {
+ rdb = 0;
+ rd_regn++;
+ }
+ }
+ }
+ else
+ sim_io_error (sd, "XOUT: XFR device %d not supported.\n", wba);
+}
+
+/* Handle syscall simulation. Its ABI is specific to the GNU simulator. */
+static void
+pru_sim_syscall (SIM_DESC sd, SIM_CPU *cpu)
+{
+ /* If someday TI confirms that the "reserved" HALT opcode fields
+ can be used for extra arguments, then maybe we can embed
+ the syscall number there. Until then, let's use R1. */
+ const uint32_t syscall_num = CPU.regs[1];
+ long ret;
+
+ ret = sim_syscall (cpu, syscall_num,
+ CPU.regs[14], CPU.regs[15],
+ CPU.regs[16], CPU.regs[17]);
+ CPU.regs[14] = ret;
+}
+
+/* Simulate one instruction. */
+static void
+sim_step_once (SIM_DESC sd)
+{
+ SIM_CPU *cpu = STATE_CPU (sd, 0);
+ const struct pru_opcode *op;
+ uint32_t inst;
+ uint32_t _RDVAL, OP2; /* intermediate values. */
+ int rd_is_modified = 0; /* RD modified and must be stored back. */
+
+ /* Fetch the initial instruction that we'll decode. */
+ inst = sim_core_read_4 (cpu, PC_byteaddr, exec_map, PC_byteaddr);
+ TRACE_MEMORY (cpu, "read of insn 0x%08x from %08x", inst, PC_byteaddr);
+
+ op = pru_find_opcode (inst);
+
+ if (!op)
+ {
+ sim_io_eprintf (sd, "Unknown instruction 0x%04x\n", inst);
+ RAISE_SIGILL (sd);
+ }
+ else
+ {
+ TRACE_DISASM (cpu, PC_byteaddr);
+
+ /* In multiply-only mode, R28/R29 operands are sampled on every clock
+ cycle. */
+ if ((CPU.macregs[PRU_MACREG_MODE] & MAC_R25_MAC_MODE_MASK) == 0)
+ {
+ CPU.macregs[PRU_MACREG_OP_0] = CPU.regs[28];
+ CPU.macregs[PRU_MACREG_OP_1] = CPU.regs[29];
+ }
+
+ switch (op->type)
+ {
+/* Helper macro to improve clarity of pru.isa. The empty while is a
+ guard against using RD as a left-hand side value. */
+#define RD do { } while (0); rd_is_modified = 1; _RDVAL
+#define INSTRUCTION(NAME, ACTION) \
+ case prui_ ## NAME: \
+ ACTION; \
+ break;
+#include "pru.isa"
+#undef INSTRUCTION
+#undef RD
+
+ default:
+ RAISE_SIGILL (sd);
+ }
+
+ if (rd_is_modified)
+ write_regval (_RDVAL, &CPU.regs[RD_REGN], RDSEL);
+
+ /* Don't treat r30 and r31 as regular registers, they are I/O! */
+ CPU.regs[30] = 0;
+ CPU.regs[31] = 0;
+
+ /* Handle PC match of loop end. */
+ if (LOOP_IN_PROGRESS && (PC == LOOPEND))
+ {
+ SIM_ASSERT (LOOPCNT > 0);
+ if (--LOOPCNT == 0)
+ LOOP_IN_PROGRESS = 0;
+ else
+ PC = LOOPTOP;
+ }
+
+ /* In multiply-only mode, MAC does multiplication every cycle. */
+ if ((CPU.macregs[PRU_MACREG_MODE] & MAC_R25_MAC_MODE_MASK) == 0)
+ {
+ uint64_t prod;
+ prod = CPU.macregs[PRU_MACREG_OP_0];
+ prod *= (uint64_t)CPU.macregs[PRU_MACREG_OP_1];
+ CPU.macregs[PRU_MACREG_PROD_L] = prod & 0xfffffffful;
+ CPU.macregs[PRU_MACREG_PROD_H] = prod >> 32;
+
+ /* Clear the MAC accumulator when in normal mode. */
+ CPU.macregs[PRU_MACREG_ACC_L] = 0;
+ CPU.macregs[PRU_MACREG_ACC_H] = 0;
+ }
+
+ /* Update cycle counts. */
+ CPU.insts += 1; /* One instruction completed ... */
+ CPU.cycles += 1; /* ... and it takes a single cycle. */
+
+ /* Account for memory access latency with a reasonable estimate.
+ No distinction is currently made between SRAM, DRAM and generic
+ L3 slaves. */
+ if (op->type == prui_lbbo || op->type == prui_sbbo
+ || op->type == prui_lbco || op->type == prui_sbco)
+ CPU.cycles += 2;
+
+ }
+}
+
+/* Implement standard sim_engine_run function. */
+void
+sim_engine_run (SIM_DESC sd,
+ int next_cpu_nr, /* ignore */
+ int nr_cpus, /* ignore */
+ int siggnal) /* ignore */
+{
+ while (1)
+ {
+ sim_step_once (sd);
+ if (sim_events_tick (sd))
+ sim_events_process (sd);
+ }
+}
+
+
+/* Implement callback for standard CPU_PC_FETCH routine. */
+static sim_cia
+pru_pc_get (sim_cpu *cpu)
+{
+ /* Present PC as byte address. */
+ return imem_wordaddr_to_byteaddr (cpu, cpu->pru_cpu.pc);
+}
+
+/* Implement callback for standard CPU_PC_STORE routine. */
+static void
+pru_pc_set (sim_cpu *cpu, sim_cia pc)
+{
+ /* PC given as byte address. */
+ cpu->pru_cpu.pc = imem_byteaddr_to_wordaddr (cpu, pc);
+}
+
+
+/* Implement callback for standard CPU_REG_STORE routine. */
+static int
+pru_store_register (SIM_CPU *cpu, int rn, unsigned char *memory, int length)
+{
+ if (rn < NUM_REGS && rn >= 0)
+ {
+ if (length == 4)
+ {
+ /* Misalignment safe. */
+ long ival = pru_extract_unsigned_integer (memory, 4);
+ if (rn < 32)
+ CPU.regs[rn] = ival;
+ else
+ pru_pc_set (cpu, ival);
+ return 4;
+ }
+ else
+ return 0;
+ }
+ else
+ return 0;
+}
+
+/* Implement callback for standard CPU_REG_FETCH routine. */
+static int
+pru_fetch_register (SIM_CPU *cpu, int rn, unsigned char *memory, int length)
+{
+ long ival;
+
+ if (rn < NUM_REGS && rn >= 0)
+ {
+ if (length == 4)
+ {
+ if (rn < 32)
+ ival = CPU.regs[rn];
+ else
+ ival = pru_pc_get (cpu);
+
+ /* Misalignment-safe. */
+ pru_store_unsigned_integer (memory, 4, ival);
+ return 4;
+ }
+ else
+ return 0;
+ }
+ else
+ return 0;
+}
+
+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);
+}
+
+/* Declare the PRU option handler. */
+static DECLARE_OPTION_HANDLER (pru_option_handler);
+
+/* Implement the PRU option handler. */
+static SIM_RC
+pru_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt, char *arg,
+ int is_command)
+{
+ switch (opt)
+ {
+ case OPTION_ERROR_NULL_DEREF:
+ abort_on_dmem_zero_access = TRUE;
+ return SIM_RC_OK;
+
+ default:
+ sim_io_eprintf (sd, "Unknown PRU option %d\n", opt);
+ return SIM_RC_FAIL;
+ }
+}
+
+/* List of PRU-specific options. */
+static const OPTION pru_options[] =
+{
+ { {"error-null-deref", no_argument, NULL, OPTION_ERROR_NULL_DEREF},
+ '\0', NULL, "Trap any access to DMEM address zero",
+ pru_option_handler, NULL },
+
+ { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL, NULL }
+};
+
+/* Implement standard sim_open function. */
+SIM_DESC
+sim_open (SIM_OPEN_KIND kind, host_callback *cb,
+ struct bfd *abfd, char * const *argv)
+{
+ int i;
+ char c;
+ SIM_DESC sd = sim_state_alloc (kind, cb);
+ SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
+
+ /* The cpu data is kept in a separately allocated chunk of memory. */
+ if (sim_cpu_alloc_all (sd, 1, /*cgen_cpu_max_extra_bytes ()*/0) != SIM_RC_OK)
+ {
+ free_state (sd);
+ return 0;
+ }
+
+ if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
+ {
+ free_state (sd);
+ return 0;
+ }
+ sim_add_option_table (sd, NULL, pru_options);
+
+ /* The parser will print an error message for us, so we silently return. */
+ if (sim_parse_args (sd, argv) != SIM_RC_OK)
+ {
+ free_state (sd);
+ return 0;
+ }
+
+ /* Check for/establish a reference program image. */
+ if (sim_analyze_program (sd,
+ (STATE_PROG_ARGV (sd) != NULL
+ ? *STATE_PROG_ARGV (sd)
+ : NULL), abfd) != SIM_RC_OK)
+ {
+ free_state (sd);
+ return 0;
+ }
+
+ /* Configure/verify the target byte order and other runtime
+ configuration options. */
+ if (sim_config (sd) != SIM_RC_OK)
+ {
+ sim_module_uninstall (sd);
+ return 0;
+ }
+
+ if (sim_post_argv_init (sd) != SIM_RC_OK)
+ {
+ /* Uninstall the modules to avoid memory leaks,
+ file descriptor leaks, etc. */
+ sim_module_uninstall (sd);
+ return 0;
+ }
+
+ /* CPU specific initialization. */
+ for (i = 0; i < MAX_NR_PROCESSORS; ++i)
+ {
+ SIM_CPU *cpu = STATE_CPU (sd, i);
+
+ CPU_REG_STORE (cpu) = pru_store_register;
+ CPU_REG_FETCH (cpu) = pru_fetch_register;
+ CPU_PC_FETCH (cpu) = pru_pc_get;
+ CPU_PC_STORE (cpu) = pru_pc_set;
+
+ set_initial_gprs (cpu);
+ }
+
+ /* Allocate external memory if none specified by user.
+ Use address 4 here in case the user wanted address 0 unmapped. */
+ if (sim_core_read_buffer (sd, NULL, read_map, &c, 4, 1) == 0)
+ {
+ sim_do_commandf (sd, "memory-region 0x%x,0x%x",
+ 0,
+ DMEM_DEFAULT_SIZE);
+ }
+ if (sim_core_read_buffer (sd, NULL, read_map, &c, IMEM_ADDR_DEFAULT, 1) == 0)
+ {
+ sim_do_commandf (sd, "memory-region 0x%x,0x%x",
+ IMEM_ADDR_DEFAULT,
+ IMEM_DEFAULT_SIZE);
+ }
+
+ return sd;
+}
+
+/* Implement standard sim_create_inferior function. */
+SIM_RC
+sim_create_inferior (SIM_DESC sd, struct bfd *prog_bfd,
+ char * const *argv, char * const *env)
+{
+ SIM_CPU *cpu = STATE_CPU (sd, 0);
+ SIM_ADDR addr;
+
+ addr = bfd_get_start_address (prog_bfd);
+
+ sim_pc_set (cpu, addr);
+ PC_ADDR_SPACE_MARKER = addr & ~IMEM_ADDR_MASK;
+
+ /* Standalone mode (i.e. `run`) will take care of the argv for us in
+ sim_open () -> sim_parse_args (). But in debug mode (i.e. 'target sim'
+ with `gdb`), we need to handle it because the user can change the
+ argv on the fly via gdb's 'run'. */
+ if (STATE_PROG_ARGV (sd) != argv)
+ {
+ freeargv (STATE_PROG_ARGV (sd));
+ STATE_PROG_ARGV (sd) = dupargv (argv);
+ }
+
+ return SIM_RC_OK;
+}
new file mode 100644
@@ -0,0 +1,110 @@
+/* Copyright 2016-2019 Free Software Foundation, Inc.
+ Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
+
+ This file is part of the PRU simulator.
+
+ This library 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 PRU_H
+#define PRU_H
+
+#include "config.h"
+#include "opcode/pru.h"
+
+/* NOTE: Needed for handling the dual PRU address space. */
+#define IMEM_ADDR_MASK ((1u << 23) - 1)
+
+#define IMEM_ADDR_DEFAULT 0x20000000
+
+/* Define memory sizes to allocate for simulated target. Sizes are
+ artificially large to accommodate execution of compiler test suite.
+ Please synchronize with the linker script for prusim target. */
+#define DMEM_DEFAULT_SIZE (64 * 1024 * 1024)
+
+/* 16-bit word addressable space. */
+#define IMEM_DEFAULT_SIZE (64 * 4 * 1024)
+
+/* For AM335x SoCs. */
+#define XFRID_SCRATCH_BANK_0 10
+#define XFRID_SCRATCH_BANK_1 11
+#define XFRID_SCRATCH_BANK_2 12
+#define XFRID_SCRATCH_BANK_PEER 14
+#define XFRID_MAX 255
+
+#define CPU (cpu->pru_cpu)
+
+#define PC (CPU.pc)
+#define PC_byteaddr ((PC << 2) | PC_ADDR_SPACE_MARKER)
+
+/* Various opcode fields. */
+#define RS1 extract_regval (CPU.regs[GET_INSN_FIELD (RS1, inst)], \
+ GET_INSN_FIELD (RS1SEL, inst))
+#define RS2 extract_regval (CPU.regs[GET_INSN_FIELD (RS2, inst)], \
+ GET_INSN_FIELD (RS2SEL, inst))
+
+#define RS2_w0 extract_regval (CPU.regs[GET_INSN_FIELD (RS2, inst)], \
+ RSEL_15_0)
+
+#define XBBO_BASEREG (CPU.regs[GET_INSN_FIELD (RS1, inst)])
+
+#define RDSEL GET_INSN_FIELD (RDSEL, inst)
+#define RD_WIDTH regsel_width (RDSEL)
+#define RD_REGN GET_INSN_FIELD (RD, inst)
+#define IO GET_INSN_FIELD (IO, inst)
+#define IMM8 GET_INSN_FIELD (IMM8, inst)
+#define IMM16 GET_INSN_FIELD (IMM16, inst)
+#define WAKEONSTATUS GET_INSN_FIELD (WAKEONSTATUS, inst)
+#define CB GET_INSN_FIELD (CB, inst)
+#define RDB GET_INSN_FIELD (RDB, inst)
+#define XFR_WBA GET_INSN_FIELD (XFR_WBA, inst)
+#define LOOP_JMPOFFS GET_INSN_FIELD (LOOP_JMPOFFS, inst)
+#define BROFF ((uint32_t) GET_BROFF_SIGNED (inst))
+
+#define _BURSTLEN_CALCULATE(BITFIELD) \
+ ((BITFIELD) >= LSSBBO_BYTECOUNT_R0_BITS7_0 ? \
+ (CPU.regs[0] >> ((BITFIELD) - LSSBBO_BYTECOUNT_R0_BITS7_0) * 8) & 0xff \
+ : (BITFIELD) + 1)
+
+#define BURSTLEN _BURSTLEN_CALCULATE (GET_BURSTLEN (inst))
+#define XFR_LENGTH _BURSTLEN_CALCULATE (GET_INSN_FIELD (XFR_LENGTH, inst))
+
+#define DO_XIN(wba,regn,rdb,l) \
+ pru_sim_xin (sd, cpu, (wba), (regn), (rdb), (l))
+#define DO_XOUT(wba,regn,rdb,l) \
+ pru_sim_xout (sd, cpu, (wba), (regn), (rdb), (l))
+#define DO_XCHG(wba,regn,rdb,l) \
+ pru_sim_xchg (sd, cpu, (wba), (regn), (rdb), (l))
+
+#define RAISE_SIGILL(sd) sim_engine_halt ((sd), NULL, NULL, PC_byteaddr, \
+ sim_stopped, SIM_SIGILL)
+#define RAISE_SIGINT(sd) sim_engine_halt ((sd), NULL, NULL, PC_byteaddr, \
+ sim_stopped, SIM_SIGINT)
+
+#define MAC_R25_MAC_MODE_MASK (1u << 0)
+#define MAC_R25_ACC_CARRY_MASK (1u << 1)
+
+#define CARRY CPU.carry
+#define CTABLE CPU.ctable
+
+#define PC_ADDR_SPACE_MARKER CPU.pc_addr_space_marker
+
+#define LOOPTOP CPU.loop.looptop
+#define LOOPEND CPU.loop.loopend
+#define LOOP_IN_PROGRESS CPU.loop.loop_in_progress
+#define LOOPCNT CPU.loop.loop_counter
+
+/* 32 GP registers plus PC. */
+#define NUM_REGS 33
+
+#endif /* PRU_H */
new file mode 100644
@@ -0,0 +1,249 @@
+/* Copyright 2016-2019 Free Software Foundation, Inc.
+ Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
+
+ This file is part of the PRU simulator.
+
+ This library 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/>. */
+
+/*
+ PRU Instruction Set Architecture
+
+ INSTRUCTION (NAME,
+ SEMANTICS)
+ */
+
+INSTRUCTION (add,
+ OP2 = (IO ? IMM8 : RS2);
+ RD = RS1 + OP2;
+ CARRY = (((uint64_t) RS1 + (uint64_t) OP2) >> RD_WIDTH) & 1;
+ PC++)
+
+INSTRUCTION (adc,
+ OP2 = (IO ? IMM8 : RS2);
+ RD = RS1 + OP2 + CARRY;
+ CARRY = (((uint64_t) RS1 + (uint64_t) OP2 + (uint64_t) CARRY)
+ >> RD_WIDTH) & 1;
+ PC++)
+
+INSTRUCTION (sub,
+ OP2 = (IO ? IMM8 : RS2);
+ RD = RS1 - OP2;
+ CARRY = (((uint64_t) RS1 - (uint64_t) OP2) >> RD_WIDTH) & 1;
+ PC++)
+
+INSTRUCTION (suc,
+ OP2 = (IO ? IMM8 : RS2);
+ RD = RS1 - OP2 - CARRY;
+ CARRY = (((uint64_t) RS1 - (uint64_t) OP2 - (uint64_t) CARRY)
+ >> RD_WIDTH) & 1;
+ PC++)
+
+INSTRUCTION (rsb,
+ OP2 = (IO ? IMM8 : RS2);
+ RD = OP2 - RS1;
+ CARRY = (((uint64_t) OP2 - (uint64_t) RS1) >> RD_WIDTH) & 1;
+ PC++)
+
+INSTRUCTION (rsc,
+ OP2 = (IO ? IMM8 : RS2);
+ RD = OP2 - RS1 - CARRY;
+ CARRY = (((uint64_t) OP2 - (uint64_t) RS1 - (uint64_t) CARRY)
+ >> RD_WIDTH) & 1;
+ PC++)
+
+INSTRUCTION (lsl,
+ OP2 = (IO ? IMM8 : RS2);
+ RD = RS1 << (OP2 & 0x1f);
+ PC++)
+
+INSTRUCTION (lsr,
+ OP2 = (IO ? IMM8 : RS2);
+ RD = RS1 >> (OP2 & 0x1f);
+ PC++)
+
+INSTRUCTION (and,
+ OP2 = (IO ? IMM8 : RS2);
+ RD = RS1 & OP2;
+ PC++)
+
+INSTRUCTION (or,
+ OP2 = (IO ? IMM8 : RS2);
+ RD = RS1 | OP2;
+ PC++)
+
+INSTRUCTION (xor,
+ OP2 = (IO ? IMM8 : RS2);
+ RD = RS1 ^ OP2;
+ PC++)
+
+INSTRUCTION (not,
+ RD = ~RS1;
+ PC++)
+
+INSTRUCTION (min,
+ OP2 = (IO ? IMM8 : RS2);
+ RD = RS1 < OP2 ? RS1 : OP2;
+ PC++)
+
+INSTRUCTION (max,
+ OP2 = (IO ? IMM8 : RS2);
+ RD = RS1 > OP2 ? RS1 : OP2;
+ PC++)
+
+INSTRUCTION (clr,
+ OP2 = (IO ? IMM8 : RS2);
+ RD = RS1 & ~(1u << (OP2 & 0x1f));
+ PC++)
+
+INSTRUCTION (set,
+ OP2 = (IO ? IMM8 : RS2);
+ RD = RS1 | (1u << (OP2 & 0x1f));
+ PC++)
+
+INSTRUCTION (jmp,
+ OP2 = (IO ? IMM16 : RS2);
+ PC = OP2)
+
+INSTRUCTION (jal,
+ OP2 = (IO ? IMM16 : RS2);
+ RD = PC + 1;
+ PC = OP2)
+
+INSTRUCTION (ldi,
+ RD = IMM16;
+ PC++)
+
+INSTRUCTION (halt,
+ pru_sim_syscall (sd, cpu);
+ PC++)
+
+INSTRUCTION (slp,
+ if (!WAKEONSTATUS)
+ {
+ RAISE_SIGINT (sd);
+ }
+ else
+ {
+ PC++;
+ })
+
+INSTRUCTION (qbgt,
+ OP2 = (IO ? IMM8 : RS2);
+ PC = (OP2 > RS1) ? (PC + BROFF) : (PC + 1))
+
+INSTRUCTION (qbge,
+ OP2 = (IO ? IMM8 : RS2);
+ PC = (OP2 >= RS1) ? (PC + BROFF) : (PC + 1))
+
+INSTRUCTION (qblt,
+ OP2 = (IO ? IMM8 : RS2);
+ PC = (OP2 < RS1) ? (PC + BROFF) : (PC + 1))
+
+INSTRUCTION (qble,
+ OP2 = (IO ? IMM8 : RS2);
+ PC = (OP2 <= RS1) ? (PC + BROFF) : (PC + 1))
+
+INSTRUCTION (qbeq,
+ OP2 = (IO ? IMM8 : RS2);
+ PC = (OP2 == RS1) ? (PC + BROFF) : (PC + 1))
+
+INSTRUCTION (qbne,
+ OP2 = (IO ? IMM8 : RS2);
+ PC = (OP2 != RS1) ? (PC + BROFF) : (PC + 1))
+
+INSTRUCTION (qba,
+ OP2 = (IO ? IMM8 : RS2);
+ PC = PC + BROFF)
+
+INSTRUCTION (qbbs,
+ OP2 = (IO ? IMM8 : RS2);
+ PC = (RS1 & (1u << (OP2 & 0x1f))) ? (PC + BROFF) : (PC + 1))
+
+INSTRUCTION (qbbc,
+ OP2 = (IO ? IMM8 : RS2);
+ PC = !(RS1 & (1u << (OP2 & 0x1f))) ? (PC + BROFF) : (PC + 1))
+
+INSTRUCTION (lbbo,
+ pru_dmem2reg (cpu, XBBO_BASEREG + (IO ? IMM8 : RS2),
+ BURSTLEN, RD_REGN, RDB);
+ PC++)
+
+INSTRUCTION (sbbo,
+ pru_reg2dmem (cpu, XBBO_BASEREG + (IO ? IMM8 : RS2),
+ BURSTLEN, RD_REGN, RDB);
+ PC++)
+
+INSTRUCTION (lbco,
+ pru_dmem2reg (cpu, CTABLE[CB] + (IO ? IMM8 : RS2),
+ BURSTLEN, RD_REGN, RDB);
+ PC++)
+
+INSTRUCTION (sbco,
+ pru_reg2dmem (cpu, CTABLE[CB] + (IO ? IMM8 : RS2),
+ BURSTLEN, RD_REGN, RDB);
+ PC++)
+
+INSTRUCTION (xin,
+ DO_XIN (XFR_WBA, RD_REGN, RDB, XFR_LENGTH);
+ PC++)
+
+INSTRUCTION (xout,
+ DO_XOUT (XFR_WBA, RD_REGN, RDB, XFR_LENGTH);
+ PC++)
+
+INSTRUCTION (xchg,
+ DO_XCHG (XFR_WBA, RD_REGN, RDB, XFR_LENGTH);
+ PC++)
+
+INSTRUCTION (sxin,
+ sim_io_eprintf (sd, "SXIN instruction not supported by sim\n");
+ RAISE_SIGILL (sd))
+
+INSTRUCTION (sxout,
+ sim_io_eprintf (sd, "SXOUT instruction not supported by sim\n");
+ RAISE_SIGILL (sd))
+
+INSTRUCTION (sxchg,
+ sim_io_eprintf (sd, "SXCHG instruction not supported by sim\n");
+ RAISE_SIGILL (sd))
+
+INSTRUCTION (loop,
+ OP2 = (IO ? IMM8 + 1 : RS2_w0);
+ if (OP2 == 0)
+ {
+ PC = LOOPEND;
+ }
+ else
+ {
+ LOOPTOP = PC + 1;
+ LOOPEND = PC + LOOP_JMPOFFS;
+ LOOPCNT = OP2;
+ LOOP_IN_PROGRESS = 1;
+ PC++;
+ })
+
+INSTRUCTION (iloop,
+ OP2 = (IO ? IMM8 + 1 : RS2_w0);
+ if (OP2 == 0)
+ {
+ PC = LOOPEND;
+ }
+ else
+ {
+ LOOPTOP = PC + 1;
+ LOOPEND = PC + LOOP_JMPOFFS;
+ LOOPCNT = OP2;
+ LOOP_IN_PROGRESS = 1;
+ PC++;
+ })
new file mode 100644
@@ -0,0 +1,91 @@
+/* Copyright 2016-2019 Free Software Foundation, Inc.
+ Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
+
+ This file is part of the PRU simulator.
+
+ This library 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 PRU_SIM_MAIN
+#define PRU_SIM_MAIN
+
+#include <stdint.h>
+#include <stddef.h>
+#include "pru.h"
+#include "sim-basics.h"
+
+#include "sim-base.h"
+
+/* The machine state.
+ This state is maintained in host byte order. The
+ fetch/store register functions must translate between host
+ byte order and the target processor byte order.
+ Keeping this data in target byte order simplifies the register
+ read/write functions. Keeping this data in host order improves
+ the performance of the simulator. Simulation speed is deemed more
+ important. */
+
+/* For clarity, please keep the same relative order in this enum as in the
+ corresponding group of GP registers.
+
+ In PRU ISA, Multiplier-Accumulator-Unit's registers are like "shadows" of
+ the GP registers. MAC registers are implicitly addressed when executing
+ the XIN/XOUT instructions to access them. Transfer to/from a MAC register
+ can happen only from/to its corresponding GP peer register. */
+
+enum pru_macreg_id {
+ /* MAC register CPU GP register Description. */
+ PRU_MACREG_MODE, /* r25 */ /* Mode (MUL/MAC). */
+ PRU_MACREG_PROD_L, /* r26 */ /* Lower 32 bits of product. */
+ PRU_MACREG_PROD_H, /* r27 */ /* Higher 32 bits of product. */
+ PRU_MACREG_OP_0, /* r28 */ /* First operand. */
+ PRU_MACREG_OP_1, /* r29 */ /* Second operand. */
+ PRU_MACREG_ACC_L, /* N/A */ /* Accumulator (not exposed) */
+ PRU_MACREG_ACC_H, /* N/A */ /* Higher 32 bits of MAC
+ accumulator. */
+ PRU_MAC_NREGS
+};
+
+struct pru_regset
+{
+ uint32_t regs[32]; /* Primary registers. */
+ uint16_t pc; /* IMEM _word_ address. */
+ uint32_t pc_addr_space_marker; /* IMEM virtual linker offset. This
+ is the artificial offset that
+ we invent in order to "separate"
+ the DMEM and IMEM memory spaces. */
+ unsigned int carry : 1;
+ uint32_t ctable[32]; /* Constant offsets table for xBCO. */
+ uint32_t macregs[PRU_MAC_NREGS];
+ uint32_t scratchpads[XFRID_MAX + 1][32];
+ struct {
+ uint16_t looptop; /* LOOP top (PC of loop instr). */
+ uint16_t loopend; /* LOOP end (PC of loop end label). */
+ int loop_in_progress; /* Whether to check for PC==loopend. */
+ uint32_t loop_counter; /* LOOP counter. */
+ } loop;
+ int cycles;
+ int insts;
+};
+
+struct _sim_cpu {
+ struct pru_regset pru_cpu;
+ sim_cpu_base base;
+};
+
+struct sim_state {
+ sim_cpu *cpu[MAX_NR_PROCESSORS];
+
+ sim_state_base base;
+};
+#endif /* PRU_SIM_MAIN */