sim: Add PRU simulator port
A simulator port for the TI PRU I/O processor. 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 v6: https://sourceware.org/ml/gdb-patches/2019-09/msg00036.html gdb/ChangeLog: * NEWS: Mention new simulator port for PRU. sim/ChangeLog: * MAINTAINERS: Add myself as PRU maintainer. * configure: Regenerated. * configure.tgt: Add PRU. sim/common/ChangeLog: * gennltvals.sh: Add PRU libgloss target. * nltvals.def: Regenerate from the latest libgloss sources. sim/pru/ChangeLog: * 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.
This commit is contained in:
parent
f945dedfd3
commit
ddd44b7053
|
@ -1,3 +1,7 @@
|
|||
2019-09-23 Dimitar Dimitrov <dimitar@dinux.eu>
|
||||
|
||||
* NEWS: Mention new simulator port for PRU.
|
||||
|
||||
2019-09-23 Christian Biesinger <cbiesinger@google.com>
|
||||
|
||||
* ada-exp.y (write_object_remaining): Update.
|
||||
|
|
4
gdb/NEWS
4
gdb/NEWS
|
@ -350,6 +350,10 @@ focus, winheight, +, -, >, <
|
|||
both debugging standalone Cell/B.E. SPU applications and integrated debugging
|
||||
of Cell/B.E. applications that use both the PPU and SPU architectures.
|
||||
|
||||
* New Simulators
|
||||
|
||||
TI PRU pru-*-elf
|
||||
|
||||
*** Changes in GDB 8.3
|
||||
|
||||
* GDB and GDBserver now support access to additional registers on
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
2019-09-23 Dimitar Dimitrov <dimitar@dinux.eu>
|
||||
|
||||
* MAINTAINERS: Add myself as PRU maintainer.
|
||||
* configure: Regenerated.
|
||||
* configure.tgt: Add PRU.
|
||||
|
||||
2019-09-20 Alan Modra <amodra@gmail.com>
|
||||
|
||||
* ppc/emul_generic.c (emul_add_tree_options): Delete old bfd code.
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
2019-09-23 Dimitar Dimitrov <dimitar@dinux.eu>
|
||||
|
||||
* gennltvals.sh: Add PRU libgloss target.
|
||||
* nltvals.def: Regenerate from the latest libgloss sources.
|
||||
|
||||
2019-06-13 Stafford Horne <shorne@gmail.com>
|
||||
|
||||
* cgen-accfp.c (unorderedsf, unordereddf): New functions.
|
||||
|
|
|
@ -95,3 +95,7 @@ $shell ${srccom}/gentvals.sh $target sys ${newlibroot}/$dir \
|
|||
dir=libgloss target=lm32
|
||||
$shell ${srccom}/gentvals.sh $target sys ${newlibroot}/$dir \
|
||||
"syscall.h" 'SYS_[_[:alnum:]]*' "${cpp}"
|
||||
|
||||
dir=libgloss target=pru
|
||||
$shell ${srccom}/gentvals.sh $target sys ${newlibroot}/$dir \
|
||||
"syscall.h" 'SYS_[_[:alnum:]]*' "${cpp}"
|
||||
|
|
|
@ -574,3 +574,34 @@
|
|||
/* end lm32 sys target macros */
|
||||
#endif
|
||||
#endif
|
||||
#ifdef NL_TARGET_pru
|
||||
#ifdef sys_defs
|
||||
/* from syscall.h */
|
||||
/* begin pru sys target macros */
|
||||
{ "SYS_argc", 22 },
|
||||
{ "SYS_argn", 24 },
|
||||
{ "SYS_argnlen", 23 },
|
||||
{ "SYS_argv", 13 },
|
||||
{ "SYS_argvlen", 12 },
|
||||
{ "SYS_chdir", 14 },
|
||||
{ "SYS_chmod", 16 },
|
||||
{ "SYS_close", 3 },
|
||||
{ "SYS_exit", 1 },
|
||||
{ "SYS_fstat", 10 },
|
||||
{ "SYS_getpid", 8 },
|
||||
{ "SYS_gettimeofday", 19 },
|
||||
{ "SYS_kill", 9 },
|
||||
{ "SYS_link", 21 },
|
||||
{ "SYS_lseek", 6 },
|
||||
{ "SYS_open", 2 },
|
||||
{ "SYS_read", 4 },
|
||||
{ "SYS_reconfig", 25 },
|
||||
{ "SYS_stat", 15 },
|
||||
{ "SYS_time", 18 },
|
||||
{ "SYS_times", 20 },
|
||||
{ "SYS_unlink", 7 },
|
||||
{ "SYS_utime", 17 },
|
||||
{ "SYS_write", 5 },
|
||||
/* end pru sys target macros */
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -686,6 +686,7 @@ mn10300
|
|||
moxie
|
||||
msp430
|
||||
or1k
|
||||
pru
|
||||
rl78
|
||||
rx
|
||||
sh64
|
||||
|
@ -3837,6 +3838,13 @@ subdirs="$subdirs aarch64"
|
|||
subdirs="$subdirs or1k"
|
||||
|
||||
|
||||
;;
|
||||
pru*-*-*)
|
||||
|
||||
sim_arch=pru
|
||||
subdirs="$subdirs pru"
|
||||
|
||||
|
||||
;;
|
||||
rl78-*-*)
|
||||
|
||||
|
|
|
@ -79,6 +79,9 @@ case "${target}" in
|
|||
or1k-*-* | or1knd-*-*)
|
||||
SIM_ARCH(or1k)
|
||||
;;
|
||||
pru*-*-*)
|
||||
SIM_ARCH(pru)
|
||||
;;
|
||||
rl78-*-*)
|
||||
SIM_ARCH(rl78)
|
||||
;;
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
2019-09-23 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.
|
|
@ -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
|
|
@ -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($@)])
|
||||
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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"
|
||||
|
||||
/* 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 */
|
|
@ -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++;
|
||||
})
|
|
@ -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 */
|
Loading…
Reference in New Issue