[v6,1/3] PRU Simulator port

Message ID 20190904194031.30525-1-dimitar@dinux.eu
State New
Headers show
Series
  • [v6,1/3] PRU Simulator port
Related show

Commit Message

Dimitar Dimitrov Sept. 4, 2019, 7:40 p.m.
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

-- 
2.20.1

Comments

Dimitar Dimitrov Sept. 4, 2019, 8:09 p.m. | #1
Since the new file is rather big, I'm sending it as a separate bzipped patch.

Regards,
Dimitar
Dimitar Dimitrov Sept. 22, 2019, 8:08 a.m. | #2
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 */
Andrew Burgess Sept. 23, 2019, 8:59 a.m. | #3
* 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 */

> 

> 

> 

>
Andrew Burgess Sept. 23, 2019, 9:12 p.m. | #4
* 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

>
Dimitar Dimitrov Sept. 24, 2019, 4:45 a.m. | #5
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

Patch

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 */