From patchwork Wed Sep 4 19:40:29 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dimitar Dimitrov X-Patchwork-Id: 34387 Received: (qmail 44244 invoked by alias); 4 Sep 2019 19:41:03 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 44185 invoked by uid 89); 4 Sep 2019 19:41:03 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-22.1 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_ASCII_DIVIDERS, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.1 spammy=fly, sister, H*F:D*eu, H*r:sk:server2 X-HELO: server28.superhosting.bg Received: from server28.superhosting.bg (HELO server28.superhosting.bg) (217.174.156.11) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 04 Sep 2019 19:40:50 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=dinux.eu; s=default; h=Content-Transfer-Encoding:MIME-Version:Message-Id:Date:Subject: Cc:To:From:Sender:Reply-To:Content-Type:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=2x4yr8k3LR+ORsWj/oaqMIA3i9l+pSQQoFP266OrPAY=; b=vqlMUvbmueXAK5k4noumf3HygG 1q6lfBttEnMSuAy6eWvkUCF5vlCCt0ep9XuT03WzD6kqxqGFxgie5E2E3aeFdG63fbnja7kmMmLAi CQPAelv7I9u0xzitl6KCclhEo7FJ0q4yqWl8rQWnVs4otA2hV9rn5cyoCMQsQEi8mBXzXPczFw9sE TEt2U+pcsucI2Q8JvVy0Cz8GfLIdTrVdrEIgn93vw4f2i7nFHiXNF7MN+HVEzQ0UBmonJLMurNsoM 7ZfUSjrD8K0/UR7y8EgsxYEqBzI3TjO21AKmyX82N8wOaItsrSmTvtw5dhJJJ7N0puBbio05XOoK+ IXBXO6Hw==; Received: from [95.87.234.74] (port=43818 helo=localhost.localdomain) by server28.superhosting.bg with esmtpsa (TLSv1.2:ECDHE-RSA-AES128-GCM-SHA256:128) (Exim 4.92) (envelope-from ) id 1i5b90-000BNe-4e; Wed, 04 Sep 2019 22:40:46 +0300 From: Dimitar Dimitrov To: gdb-patches@sourceware.org Cc: Dimitar Dimitrov Subject: [PATCH v6 1/3] PRU Simulator port Date: Wed, 4 Sep 2019 22:40:29 +0300 Message-Id: <20190904194031.30525-1-dimitar@dinux.eu> MIME-Version: 1.0 X-OutGoing-Spam-Status: No, score=-0.2 X-IsSubscribed: yes 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 * NEWS: Mention new simulator port for PRU. sim/ 2019-09-04 Dimitar Dimitrov * MAINTAINERS: Add myself as PRU maintainer. * configure: Regenerated. * configure.tgt: Add PRU. sim/common/ 2019-09-04 Dimitar Dimitrov * gennltvals.sh: Add PRU libgloss target. * nltvals.def: Regenerate from the latest libgloss sources. sim/pru/ 2019-09-04 Dimitar Dimitrov * 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 --- 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 moxie Anthony Green msp430 Nick Clifton or1k Stafford Horne +pru Dimitar Dimitrov sh (global maintainers) sh64 Dave Brolley common Frank Ch. Eigler 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 +# +# 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 . + +## 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 header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ERRNO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the 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 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 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 header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the 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 header file. */ +#undef HAVE_SYS_MMAN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_RESOURCE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIMES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the 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 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 header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the 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 +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 . +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 + + 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 . */ + +#include "config.h" +#include +#include +#include +#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 + + 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 . */ + +#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 + + 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 . */ + +/* + 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 + + 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 . */ + +#ifndef PRU_SIM_MAIN +#define PRU_SIM_MAIN + +#include +#include +#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 */