From patchwork Wed Nov 16 19:15:36 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Palmer Dabbelt X-Patchwork-Id: 17528 Received: (qmail 17435 invoked by alias); 16 Nov 2016 19:17:11 -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 17133 invoked by uid 89); 16 Nov 2016 19:17:10 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=1.9 required=5.0 tests=AWL, BAYES_50, KAM_ASCII_DIVIDERS, RCVD_IN_SORBS_SPAM, SPF_PASS autolearn=no version=3.3.2 spammy=sister, op, am, HOME X-HELO: mail-pg0-f65.google.com Received: from mail-pg0-f65.google.com (HELO mail-pg0-f65.google.com) (74.125.83.65) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 16 Nov 2016 19:17:00 +0000 Received: by mail-pg0-f65.google.com with SMTP id e9so15046585pgc.1 for ; Wed, 16 Nov 2016 11:16:59 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:to:cc:cc:subject:date:message-id :in-reply-to:references; bh=Y3oUm9GvuAXQ0JrQ+wbF9K2JVnUlDrOeGlkVmoMrBjA=; b=gJT4qoSI/9fsUpxcska9E+klivZfxp5M/HO/woRhtnnXZ2V3ZE2TvxngL7zX79lDCv IVFzy3LEeS+mhfDeiXhERg0hwB7ALAS0yG4w1J5Y5wlccewJWan8wcsmGoTHrMpgGOWO Wiu4Ej1yNnwI4ENGSkR9YFSOoLVm6SLLl5jaTiCkzv8wRCAy1Cr2khg8mDDZg3VnzfQw KbTPXOimgVDVLN5Z4Wj/clA1Zk52ql3WPryua5B7W003PruqvFEWDji3qwh9kIZZ/dXv XKGrCuitGb04LAcGLWX3yuKqi9e/9EAqaCTNDD93OjZIO2MAavr06DsEt82+RILHwWNk ZMIQ== X-Gm-Message-State: ABUngvfoUTTcBjJVpinTeicPHzStQDFIy8GoxfwEiFG2MFspW1w9n6ZdueLLsWN+toIARA== X-Received: by 10.98.217.67 with SMTP id s64mr6709880pfg.66.1479323816723; Wed, 16 Nov 2016 11:16:56 -0800 (PST) Received: from localhost (c-73-222-189-110.hsd1.ca.comcast.net. [73.222.189.110]) by smtp.gmail.com with ESMTPSA id w24sm54143000pfa.9.2016.11.16.11.16.55 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 16 Nov 2016 11:16:56 -0800 (PST) From: Palmer Dabbelt To: gdb-patches@sourceware.org To: qiyaoltc@gmail.com Cc: Andrew Waterman Cc: Palmer Dabbelt Subject: [PATCH 1/3] RISC-V Sim Port Date: Wed, 16 Nov 2016 11:15:36 -0800 Message-Id: <1479323738-1960-2-git-send-email-palmer@dabbelt.com> In-Reply-To: <1479323738-1960-1-git-send-email-palmer@dabbelt.com> References: <1477179592-32501-1-git-send-email-palmer@dabbelt.com> <1479323738-1960-1-git-send-email-palmer@dabbelt.com> X-IsSubscribed: yes ChangeLog: * New RISC-V simulator. --- include/gdb/sim-riscv.h | 98 +++ sim/common/nltvals.def | 48 ++ sim/configure.tgt | 3 + sim/riscv/ChangeLog | 6 + sim/riscv/Makefile.in | 35 + sim/riscv/aclocal.m4 | 119 ++++ sim/riscv/config.in | 248 +++++++ sim/riscv/configure.ac | 31 + sim/riscv/interp.c | 177 +++++ sim/riscv/machs.c | 125 ++++ sim/riscv/machs.h | 45 ++ sim/riscv/model_list.def | 9 + sim/riscv/sim-main.c | 1189 +++++++++++++++++++++++++++++++++ sim/riscv/sim-main.h | 87 +++ sim/riscv/tconfig.h | 4 + sim/testsuite/sim/riscv/ChangeLog | 3 + sim/testsuite/sim/riscv/allinsn.exp | 15 + sim/testsuite/sim/riscv/pass.s | 7 + sim/testsuite/sim/riscv/testutils.inc | 50 ++ 19 files changed, 2299 insertions(+) create mode 100644 include/gdb/sim-riscv.h create mode 100644 sim/riscv/ChangeLog create mode 100644 sim/riscv/Makefile.in create mode 100644 sim/riscv/aclocal.m4 create mode 100644 sim/riscv/config.in create mode 100644 sim/riscv/configure.ac create mode 100644 sim/riscv/interp.c create mode 100644 sim/riscv/machs.c create mode 100644 sim/riscv/machs.h create mode 100644 sim/riscv/model_list.def create mode 100644 sim/riscv/sim-main.c create mode 100644 sim/riscv/sim-main.h create mode 100644 sim/riscv/tconfig.h create mode 100644 sim/testsuite/sim/riscv/ChangeLog create mode 100644 sim/testsuite/sim/riscv/allinsn.exp create mode 100644 sim/testsuite/sim/riscv/pass.s create mode 100644 sim/testsuite/sim/riscv/testutils.inc diff --git a/include/gdb/sim-riscv.h b/include/gdb/sim-riscv.h new file mode 100644 index 0000000..932cf49 --- /dev/null +++ b/include/gdb/sim-riscv.h @@ -0,0 +1,98 @@ +/* This file defines the interface between the RISC-V simulator and GDB. + + Copyright (C) 2005-2015 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Order has to match gdb riscv-tdep list. */ +enum sim_riscv_regnum { + SIM_RISCV_ZERO_REGNUM = 0, + SIM_RISCV_RA_REGNUM, + SIM_RISCV_SP_REGNUM, + SIM_RISCV_GP_REGNUM, + SIM_RISCV_TP_REGNUM, + SIM_RISCV_T0_REGNUM, + SIM_RISCV_T1_REGNUM, + SIM_RISCV_T2_REGNUM, + SIM_RISCV_S0_REGNUM, +#define SIM_RISCV_FP_REGNUM SIM_RISCV_S0_REGNUM + SIM_RISCV_S1_REGNUM, + SIM_RISCV_A0_REGNUM, + SIM_RISCV_A1_REGNUM, + SIM_RISCV_A2_REGNUM, + SIM_RISCV_A3_REGNUM, + SIM_RISCV_A4_REGNUM, + SIM_RISCV_A5_REGNUM, + SIM_RISCV_A6_REGNUM, + SIM_RISCV_A7_REGNUM, + SIM_RISCV_S2_REGNUM, + SIM_RISCV_S3_REGNUM, + SIM_RISCV_S4_REGNUM, + SIM_RISCV_S5_REGNUM, + SIM_RISCV_S6_REGNUM, + SIM_RISCV_S7_REGNUM, + SIM_RISCV_S8_REGNUM, + SIM_RISCV_S9_REGNUM, + SIM_RISCV_S10_REGNUM, + SIM_RISCV_S11_REGNUM, + SIM_RISCV_T3_REGNUM, + SIM_RISCV_T4_REGNUM, + SIM_RISCV_T5_REGNUM, + SIM_RISCV_T6_REGNUM, + SIM_RISCV_PC_REGNUM, + SIM_RISCV_FT0_REGNUM, +#define SIM_RISCV_FIRST_FP_REGNUM SIM_RISCV_FT0_REGNUM + SIM_RISCV_FT1_REGNUM, + SIM_RISCV_FT2_REGNUM, + SIM_RISCV_FT3_REGNUM, + SIM_RISCV_FT4_REGNUM, + SIM_RISCV_FT5_REGNUM, + SIM_RISCV_FT6_REGNUM, + SIM_RISCV_FT7_REGNUM, + SIM_RISCV_FS0_REGNUM, + SIM_RISCV_FS1_REGNUM, + SIM_RISCV_FA0_REGNUM, + SIM_RISCV_FA1_REGNUM, + SIM_RISCV_FA2_REGNUM, + SIM_RISCV_FA3_REGNUM, + SIM_RISCV_FA4_REGNUM, + SIM_RISCV_FA5_REGNUM, + SIM_RISCV_FA6_REGNUM, + SIM_RISCV_FA7_REGNUM, + SIM_RISCV_FS2_REGNUM, + SIM_RISCV_FS3_REGNUM, + SIM_RISCV_FS4_REGNUM, + SIM_RISCV_FS5_REGNUM, + SIM_RISCV_FS6_REGNUM, + SIM_RISCV_FS7_REGNUM, + SIM_RISCV_FS8_REGNUM, + SIM_RISCV_FS9_REGNUM, + SIM_RISCV_FS10_REGNUM, + SIM_RISCV_FS11_REGNUM, + SIM_RISCV_FT8_REGNUM, + SIM_RISCV_FT9_REGNUM, + SIM_RISCV_FT10_REGNUM, + SIM_RISCV_FT11_REGNUM, +#define SIM_RISCV_LAST_FP_REGNUM SIM_RISCV_FT11_REGNUM + +#define SIM_RISCV_FIRST_CSR_REGNUM SIM_RISCV_LAST_FP_REGNUM + 1 +#define DECLARE_CSR(name, num) SIM_RISCV_ ## num ## _REGNUM, +#include "opcode/riscv-opc.h" +#undef DECLARE_CSR +#define SIM_RISCV_LAST_CSR_REGNUM SIM_RISCV_LAST_REGNUM - 1 + + SIM_RISCV_LAST_REGNUM +}; diff --git a/sim/common/nltvals.def b/sim/common/nltvals.def index 3f82d47..ff0a647 100644 --- a/sim/common/nltvals.def +++ b/sim/common/nltvals.def @@ -574,3 +574,51 @@ /* end lm32 sys target macros */ #endif #endif +#ifdef NL_TARGET_riscv +#ifdef sys_defs +/* from syscall.h */ +/* begin riscv sys target macros */ + { "SYS_access", 1033 }, + { "SYS_brk", 214 }, + { "SYS_chdir", 49 }, + { "SYS_close", 57 }, + { "SYS_dup", 23 }, + { "SYS_exit", 93 }, + { "SYS_exit_group", 94 }, + { "SYS_faccessat", 48 }, + { "SYS_fcntl", 25 }, + { "SYS_fstat", 80 }, + { "SYS_fstatat", 79 }, + { "SYS_getcwd", 17 }, + { "SYS_getdents", 61 }, + { "SYS_getegid", 177 }, + { "SYS_geteuid", 175 }, + { "SYS_getgid", 176 }, + { "SYS_getmainvars", 2011 }, + { "SYS_getpid", 172 }, + { "SYS_gettimeofday", 169 }, + { "SYS_getuid", 174 }, + { "SYS_kill", 129 }, + { "SYS_link", 1025 }, + { "SYS_lseek", 62 }, + { "SYS_lstat", 1039 }, + { "SYS_mkdir", 1030 }, + { "SYS_mmap", 222 }, + { "SYS_mremap", 216 }, + { "SYS_munmap", 215 }, + { "SYS_open", 1024 }, + { "SYS_openat", 56 }, + { "SYS_pread", 67 }, + { "SYS_pwrite", 68 }, + { "SYS_read", 63 }, + { "SYS_rt_sigaction", 134 }, + { "SYS_stat", 1038 }, + { "SYS_time", 1062 }, + { "SYS_times", 153 }, + { "SYS_uname", 160 }, + { "SYS_unlink", 1026 }, + { "SYS_write", 64 }, + { "SYS_writev", 66 }, +/* end riscv sys target macros */ +#endif +#endif diff --git a/sim/configure.tgt b/sim/configure.tgt index c958fb3..c05ad98 100644 --- a/sim/configure.tgt +++ b/sim/configure.tgt @@ -76,6 +76,9 @@ case "${target}" in msp430*-*-*) SIM_ARCH(msp430) ;; + riscv*-*-*) + SIM_ARCH(riscv) + ;; rl78-*-*) SIM_ARCH(rl78) ;; diff --git a/sim/riscv/ChangeLog b/sim/riscv/ChangeLog new file mode 100644 index 0000000..a960da8 --- /dev/null +++ b/sim/riscv/ChangeLog @@ -0,0 +1,6 @@ +2015-04-27 Mike Frysinger + + * configure.ac, interp.c, Makefile.in, README, README-ISA, + sim-main.c, sim-main.h: New files for example simulator. + * aclocal.m4, config.in, configure: Regenerated. + diff --git a/sim/riscv/Makefile.in b/sim/riscv/Makefile.in new file mode 100644 index 0000000..2902cf6 --- /dev/null +++ b/sim/riscv/Makefile.in @@ -0,0 +1,35 @@ +# Makefile template for Configure for the example basic simulator. +# Copyright (C) 2005-2015 Free Software Foundation, Inc. +# Written by Mike Frysinger. +# +# 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 . + +# This selects the newlib/libgloss syscall definitions. +NL_TARGET = -DNL_TARGET_riscv + +## COMMON_PRE_CONFIG_FRAG + +SIM_OBJS = \ + $(SIM_NEW_COMMON_OBJS) \ + sim-hload.o \ + sim-model.o \ + sim-reason.o \ + sim-reg.o \ + sim-resume.o \ + sim-stop.o \ + interp.o \ + machs.o \ + sim-main.o + +## COMMON_POST_CONFIG_FRAG diff --git a/sim/riscv/aclocal.m4 b/sim/riscv/aclocal.m4 new file mode 100644 index 0000000..c81c155 --- /dev/null +++ b/sim/riscv/aclocal.m4 @@ -0,0 +1,119 @@ +# generated automatically by aclocal 1.14.1 -*- Autoconf -*- + +# Copyright (C) 1996-2013 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-2013 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-2013 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-2013 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-2013 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/riscv/config.in b/sim/riscv/config.in new file mode 100644 index 0000000..aa3e45c --- /dev/null +++ b/sim/riscv/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 `struct stat' is a member of `st_atime'. */ +#undef HAVE_STRUCT_STAT_ST_ATIME + +/* Define to 1 if `struct stat' is a member of `st_blksize'. */ +#undef HAVE_STRUCT_STAT_ST_BLKSIZE + +/* Define to 1 if `struct stat' is a member of `st_blocks'. */ +#undef HAVE_STRUCT_STAT_ST_BLOCKS + +/* Define to 1 if `struct stat' is a member of `st_ctime'. */ +#undef HAVE_STRUCT_STAT_ST_CTIME + +/* Define to 1 if `struct stat' is a member of `st_dev'. */ +#undef HAVE_STRUCT_STAT_ST_DEV + +/* Define to 1 if `struct stat' is a member of `st_gid'. */ +#undef HAVE_STRUCT_STAT_ST_GID + +/* Define to 1 if `struct stat' is a member of `st_ino'. */ +#undef HAVE_STRUCT_STAT_ST_INO + +/* Define to 1 if `struct stat' is a member of `st_mode'. */ +#undef HAVE_STRUCT_STAT_ST_MODE + +/* Define to 1 if `struct stat' is a member of `st_mtime'. */ +#undef HAVE_STRUCT_STAT_ST_MTIME + +/* Define to 1 if `struct stat' is a member of `st_nlink'. */ +#undef HAVE_STRUCT_STAT_ST_NLINK + +/* Define to 1 if `struct stat' is a member of `st_rdev'. */ +#undef HAVE_STRUCT_STAT_ST_RDEV + +/* Define to 1 if `struct stat' is a member of `st_size'. */ +#undef HAVE_STRUCT_STAT_ST_SIZE + +/* Define to 1 if `struct stat' is a member of `st_uid'. */ +#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/riscv/configure.ac b/sim/riscv/configure.ac new file mode 100644 index 0000000..0209a2b --- /dev/null +++ b/sim/riscv/configure.ac @@ -0,0 +1,31 @@ +dnl Process this file with autoconf to produce a configure script. +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(NONSTRICT_ALIGNMENT) +SIM_AC_OPTION_HOSTENDIAN +SIM_AC_OPTION_ENVIRONMENT +SIM_AC_OPTION_INLINE +SIM_AC_OPTION_WARNINGS + +# Select the default model for the target. +riscv_model= +case "${target}" in +riscv32*) riscv_model="RV32G" ;; +riscv*) riscv_model="RV64G" ;; +esac +SIM_AC_OPTION_DEFAULT_MODEL(${riscv_model}) + +# Select the bitsize of the target. +riscv_addr_bitsize= +case "${target}" in +riscv32*) riscv_addr_bitsize=32 ;; +riscv*) riscv_addr_bitsize=64 ;; +esac +SIM_AC_OPTION_BITSIZE($riscv_addr_bitsize) + +SIM_AC_OUTPUT diff --git a/sim/riscv/interp.c b/sim/riscv/interp.c new file mode 100644 index 0000000..8e6d454 --- /dev/null +++ b/sim/riscv/interp.c @@ -0,0 +1,177 @@ +/* RISC-V simulator. + + Copyright (C) 2005-2015 Free Software Foundation, Inc. + Contributed by Mike Frysinger. + + This file is part of 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 . */ + +/* This file contains the main glue logic between the sim core and the target + specific simulator. Normally this file will be kept small and the target + details will live in other files. + + For more specific details on these functions, see the gdb/remote-sim.h + header file. */ + +#include "config.h" + +#include "sim-main.h" +#include "sim-options.h" + +/* This function is the main loop. It should process ticks and decode+execute + a single instruction. + + Usually you do not need to change things here. */ + +void +sim_engine_run (SIM_DESC sd, + int next_cpu_nr, /* ignore */ + int nr_cpus, /* ignore */ + int siggnal) /* ignore */ +{ + SIM_CPU *cpu; + + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + + cpu = STATE_CPU (sd, 0); + + while (1) + { + step_once (cpu); + if (sim_events_tick (sd)) + sim_events_process (sd); + } +} + +/* Initialize the simulator from scratch. This is called once per lifetime of + the simulation. Think of it as a processor reset. + + Usually all cpu-specific setup is handled in the initialize_cpu callback. + If you want to do cpu-independent stuff, then it should go at the end (see + where memory is initialized). */ + +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); +} + +SIM_DESC +sim_open (SIM_OPEN_KIND kind, host_callback *callback, + struct bfd *abfd, char * const *argv) +{ + char c; + int i; + SIM_DESC sd = sim_state_alloc (kind, callback); + + /* 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; + } + + /* XXX: Default to the Virtual environment. */ + if (STATE_ENVIRONMENT (sd) == ALL_ENVIRONMENT) + STATE_ENVIRONMENT (sd) = VIRTUAL_ENVIRONMENT; + + /* getopt will print the error message so we just have to exit if this fails. + FIXME: Hmmm... in the case of gdb we need getopt to call + print_filtered. */ + if (sim_parse_args (sd, argv) != SIM_RC_OK) + { + free_state (sd); + return 0; + } + + /* Check for/establish the 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; + } + + /* Establish any remaining configuration options. */ + if (sim_config (sd) != SIM_RC_OK) + { + free_state (sd); + return 0; + } + + if (sim_post_argv_init (sd) != SIM_RC_OK) + { + free_state (sd); + return 0; + } + + /* CPU specific initialization. */ + for (i = 0; i < MAX_NR_PROCESSORS; ++i) + { + SIM_CPU *cpu = STATE_CPU (sd, i); + + initialize_cpu (sd, cpu, i); + } + + /* 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-size %#x", DEFAULT_MEM_SIZE); + + return sd; +} + +/* Prepare to run a program that has already been loaded into memory. + + Usually you do not need to change things here. */ + +SIM_RC +sim_create_inferior (SIM_DESC sd, struct bfd *abfd, + char * const *argv, char * const *env) +{ + SIM_CPU *cpu = STATE_CPU (sd, 0); + sim_cia addr; + + /* Set the PC. */ + if (abfd != NULL) + addr = bfd_get_start_address (abfd); + else + addr = 0; + sim_pc_set (cpu, addr); + + /* 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. */ + if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG) + { + freeargv (STATE_PROG_ARGV (sd)); + STATE_PROG_ARGV (sd) = dupargv (argv); + } + + initialize_env (sd, (void *)argv, (void *)env); + + return SIM_RC_OK; +} diff --git a/sim/riscv/machs.c b/sim/riscv/machs.c new file mode 100644 index 0000000..16056f6 --- /dev/null +++ b/sim/riscv/machs.c @@ -0,0 +1,125 @@ +/* RISC-V simulator. + + Copyright (C) 2005-2015 Free Software Foundation, Inc. + Contributed by Mike Frysinger. + + This file is part of 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 "sim-main.h" + +static void +riscv_model_init (SIM_CPU *cpu) +{ +} + +static void +riscv_init_cpu (SIM_CPU *cpu) +{ +} + +static void +riscv_prepare_run (SIM_CPU *cpu) +{ +} + +static const SIM_MACH_IMP_PROPERTIES riscv_imp_properties = +{ + sizeof (SIM_CPU), + 0, +}; + +#if WITH_TARGET_WORD_BITSIZE >= 32 + +static const SIM_MACH rv32i_mach; + +static const SIM_MODEL rv32_models[] = +{ +#define M(ext) { "RV32"#ext, &rv32i_mach, MODEL_RV32##ext, NULL, riscv_model_init }, +#include "model_list.def" +#undef M + { 0, NULL, 0, NULL, NULL, } +}; + +static const SIM_MACH rv32i_mach = +{ + "rv32i", "riscv", MACH_RV32I, + 32, 32, &rv32_models[0], &riscv_imp_properties, + riscv_init_cpu, + riscv_prepare_run +}; + +#endif + +#if WITH_TARGET_WORD_BITSIZE >= 64 + +static const SIM_MACH rv64i_mach; + +static const SIM_MODEL rv64_models[] = +{ +#define M(ext) { "RV64"#ext, &rv64i_mach, MODEL_RV64##ext, NULL, riscv_model_init }, +#include "model_list.def" +#undef M + { 0, NULL, 0, NULL, NULL, } +}; + +static const SIM_MACH rv64i_mach = +{ + "rv64i", "riscv", MACH_RV64I, + 64, 64, &rv64_models[0], &riscv_imp_properties, + riscv_init_cpu, + riscv_prepare_run +}; + +#endif + +#if WITH_TARGET_WORD_BITSIZE >= 128 + +static const SIM_MACH rv128i_mach; + +static const SIM_MODEL rv128_models[] = +{ +#define M(ext) { "RV128"#ext, &rv128i_mach, MODEL_RV128##ext, NULL, riscv_model_init }, +#include "model_list.def" +#undef M + { 0, NULL, 0, NULL, NULL, } +}; + +static const SIM_MACH rv128i_mach = +{ + "rv128i", "riscv", MACH_RV128I, + 128, 128, &rv128_models[0], &riscv_imp_properties, + riscv_init_cpu, + riscv_prepare_run +}; + +#endif + +/* Order matters here. */ +const SIM_MACH *sim_machs[] = +{ +#if WITH_TARGET_WORD_BITSIZE >= 128 + &rv128i_mach, +#endif +#if WITH_TARGET_WORD_BITSIZE >= 64 + &rv64i_mach, +#endif +#if WITH_TARGET_WORD_BITSIZE >= 32 + &rv32i_mach, +#endif + NULL +}; diff --git a/sim/riscv/machs.h b/sim/riscv/machs.h new file mode 100644 index 0000000..6c8cd43 --- /dev/null +++ b/sim/riscv/machs.h @@ -0,0 +1,45 @@ +/* RISC-V simulator. + + Copyright (C) 2005-2014 Free Software Foundation, Inc. + Contributed by Mike Frysinger. + + This file is part of 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 . */ + +#ifndef RISCV_SIM_MACHS_H +#define RISCV_SIM_MACHS_H + +typedef enum model_type { +#define M(ext) MODEL_RV32##ext, +#include "model_list.def" +#undef M +#define M(ext) MODEL_RV64##ext, +#include "model_list.def" +#undef M +#define M(ext) MODEL_RV128##ext, +#include "model_list.def" +#undef M + MODEL_MAX +} MODEL_TYPE; + +typedef enum mach_attr { + MACH_BASE, + MACH_RV32I, + MACH_RV64I, + MACH_RV128I, + MACH_MAX +} MACH_ATTR; + +#endif diff --git a/sim/riscv/model_list.def b/sim/riscv/model_list.def new file mode 100644 index 0000000..5efd85a --- /dev/null +++ b/sim/riscv/model_list.def @@ -0,0 +1,9 @@ +M(G) +M(I) +M(IM) +M(IMA) +M(IA) +M(E) +M(EM) +M(EMA) +M(EA) diff --git a/sim/riscv/sim-main.c b/sim/riscv/sim-main.c new file mode 100644 index 0000000..97e37d2 --- /dev/null +++ b/sim/riscv/sim-main.c @@ -0,0 +1,1189 @@ +/* RISC-V simulator. + + Copyright (C) 2005-2014 Free Software Foundation, Inc. + Contributed by Mike Frysinger. + + This file is part of 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 . */ + +/* This file contains the main simulator decoding logic. i.e. everything that + is architecture specific. */ + +#include "config.h" + +#include +#include + +#include "sim-main.h" +#include "sim-syscall.h" + +#include "opcode/riscv.h" + +#include "gdb/sim-riscv.h" + +#include "targ-vals.h" + + +#define TRACE_REG(cpu, reg) TRACE_REGISTER (cpu, "wrote %s = %#"PRIxTW, riscv_gpr_names_abi[reg], cpu->regs[reg]) + +static const struct riscv_opcode *riscv_hash[OP_MASK_OP + 1]; +#define OP_HASH_IDX(i) ((i) & (riscv_insn_length (i) == 2 ? 0x3 : 0x7f)) + +#define RISCV_ASSERT_RV32(cpu, fmt, args...) \ + do { \ + if (RISCV_XLEN (cpu) != 32) \ + { \ + SIM_DESC sd = CPU_STATE (cpu); \ + TRACE_INSN (cpu, "RV32I-only " fmt, ## args); \ + sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL); \ + } \ + } while (0) + +#define RISCV_ASSERT_RV64(cpu, fmt, args...) \ + do { \ + if (RISCV_XLEN (cpu) != 64) \ + { \ + SIM_DESC sd = CPU_STATE (cpu); \ + TRACE_INSN (cpu, "RV64I-only " fmt, ## args); \ + sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL); \ + } \ + } while (0) + +static INLINE void +store_rd (SIM_CPU *cpu, int rd, unsigned_word val) +{ + if (rd) + { + cpu->regs[rd] = val; + TRACE_REG (cpu, rd); + } +} + +static INLINE unsigned_word +fetch_csr (SIM_CPU *cpu, const char *name, int csr, unsigned_word *reg) +{ + /* Handle pseudo registers. */ + switch (csr) + { + /* Allow certain registers only in respective modes. */ + case CSR_CYCLEH: + case CSR_INSTRETH: + case CSR_TIMEH: + RISCV_ASSERT_RV32 (cpu, "CSR: %s", name); + break; + } + + return *reg; +} + +static INLINE void +store_csr (SIM_CPU *cpu, const char *name, int csr, unsigned_word *reg, + unsigned_word val) +{ + switch (csr) + { + /* These are pseudo registers that modify sub-fields of fcsr. */ + case CSR_FRM: + val &= 0x7; + *reg = val; + cpu->csr.fcsr = (cpu->csr.fcsr & ~0xe0) | (val << 5); + break; + case CSR_FFLAGS: + val &= 0x1f; + *reg = val; + cpu->csr.fcsr = (cpu->csr.fcsr & ~0x1f) | val; + break; + /* Keep the sub-fields in sync. */ + case CSR_FCSR: + *reg = val; + cpu->csr.frm = (val >> 5) & 0x7; + cpu->csr.fflags = val & 0x1f; + break; + + /* Allow certain registers only in respective modes. */ + case CSR_CYCLEH: + case CSR_INSTRETH: + case CSR_TIMEH: + RISCV_ASSERT_RV32 (cpu, "CSR: %s", name); + + /* All the rest are immutable. */ + default: + val = *reg; + break; + } + + TRACE_REGISTER (cpu, "wrote CSR %s = %#"PRIxTW, name, val); +} + +static inline unsigned_word +ashiftrt (unsigned_word val, unsigned_word shift) +{ + unsigned32 sign = (val & 0x80000000) ? ~(0xfffffffful >> shift) : 0; + return (val >> shift) | sign; +} + +static inline unsigned_word +ashiftrt64 (unsigned_word val, unsigned_word shift) +{ + unsigned64 sign = (val & 0x8000000000000000ull) ? ~(0xffffffffffffffffull >> shift) : 0; + return (val >> shift) | sign; +} + +static sim_cia +execute_i (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op) +{ + SIM_DESC sd = CPU_STATE (cpu); + int rd = (iw >> OP_SH_RD) & OP_MASK_RD; + int rs1 = (iw >> OP_SH_RS1) & OP_MASK_RS1; + int rs2 = (iw >> OP_SH_RS2) & OP_MASK_RS2; + const char *rd_name = riscv_gpr_names_abi[rd]; + const char *rs1_name = riscv_gpr_names_abi[rs1]; + const char *rs2_name = riscv_gpr_names_abi[rs2]; + unsigned int csr = (iw >> OP_SH_CSR) & OP_MASK_CSR; + unsigned_word i_imm = EXTRACT_ITYPE_IMM (iw); + unsigned_word u_imm = EXTRACT_UTYPE_IMM ((unsigned64) iw); + unsigned_word s_imm = EXTRACT_STYPE_IMM (iw); + unsigned_word sb_imm = EXTRACT_SBTYPE_IMM (iw); + unsigned_word shamt_imm = ((iw >> OP_SH_SHAMT) & OP_MASK_SHAMT); + unsigned_word tmp; + sim_cia pc = cpu->pc + 4; + + TRACE_EXTRACT (cpu, "rd:%-2i:%-4s rs1:%-2i:%-4s %0*"PRIxTW" rs2:%-2i:%-4s %0*"PRIxTW" match:%#x mask:%#x", + rd, rd_name, + rs1, rs1_name, (int)sizeof (unsigned_word) * 2, cpu->regs[rs1], + rs2, rs2_name, (int)sizeof (unsigned_word) * 2, cpu->regs[rs2], + (unsigned) op->match, (unsigned) op->mask); + + switch (op->match) + { + case MATCH_ADD: + TRACE_INSN (cpu, "add %s, %s, %s; // %s = %s + %s", + rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name); + store_rd (cpu, rd, cpu->regs[rs1] + cpu->regs[rs2]); + break; + case MATCH_ADDW: + TRACE_INSN (cpu, "addw %s, %s, %s; // %s = %s + %s", + rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name); + RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name); + store_rd (cpu, rd, EXTEND32 (cpu->regs[rs1] + cpu->regs[rs2])); + break; + case MATCH_ADDI: + TRACE_INSN (cpu, "addi %s, %s, %#"PRIxTW"; // %s = %s + %#"PRIxTW, + rd_name, rs1_name, i_imm, rd_name, rs1_name, i_imm); + store_rd (cpu, rd, cpu->regs[rs1] + i_imm); + break; + case MATCH_ADDIW: + TRACE_INSN (cpu, "addiw %s, %s, %#"PRIxTW"; // %s = %s + %#"PRIxTW, + rd_name, rs1_name, i_imm, rd_name, rs1_name, i_imm); + RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name); + store_rd (cpu, rd, EXTEND32 (cpu->regs[rs1] + i_imm)); + break; + case MATCH_AND: + TRACE_INSN (cpu, "and %s, %s, %s; // %s = %s & %s", + rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name); + store_rd (cpu, rd, cpu->regs[rs1] & cpu->regs[rs2]); + break; + case MATCH_ANDI: + TRACE_INSN (cpu, "andi %s, %s, %"PRIiTW"; // %s = %s & %#"PRIxTW, + rd_name, rs1_name, i_imm, rd_name, rs1_name, i_imm); + store_rd (cpu, rd, cpu->regs[rs1] & i_imm); + break; + case MATCH_OR: + TRACE_INSN (cpu, "or %s, %s, %s; // %s = %s | %s", + rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name); + store_rd (cpu, rd, cpu->regs[rs1] | cpu->regs[rs2]); + break; + case MATCH_ORI: + TRACE_INSN (cpu, "ori %s, %s, %"PRIiTW"; // %s = %s | %#"PRIxTW, + rd_name, rs1_name, i_imm, rd_name, rs1_name, i_imm); + store_rd (cpu, rd, cpu->regs[rs1] | i_imm); + break; + case MATCH_XOR: + TRACE_INSN (cpu, "xor %s, %s, %s; // %s = %s ^ %s", + rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name); + store_rd (cpu, rd, cpu->regs[rs1] ^ cpu->regs[rs2]); + break; + case MATCH_XORI: + TRACE_INSN (cpu, "xori %s, %s, %"PRIiTW"; // %s = %s ^ %#"PRIxTW, + rd_name, rs1_name, i_imm, rd_name, rs1_name, i_imm); + store_rd (cpu, rd, cpu->regs[rs1] ^ i_imm); + break; + case MATCH_SUB: + TRACE_INSN (cpu, "sub %s, %s, %s; // %s = %s - %s", + rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name); + store_rd (cpu, rd, cpu->regs[rs1] - cpu->regs[rs2]); + break; + case MATCH_SUBW: + TRACE_INSN (cpu, "subw %s, %s, %s; // %s = %s - %s", + rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name); + RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name); + store_rd (cpu, rd, EXTEND32 (cpu->regs[rs1] - cpu->regs[rs2])); + break; + case MATCH_LUI: + TRACE_INSN (cpu, "lui %s, %#"PRIxTW";", rd_name, u_imm); + store_rd (cpu, rd, u_imm); + break; + case MATCH_SLL: + TRACE_INSN (cpu, "sll %s, %s, %s; // %s = %s << %s", + rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name); + u_imm = RISCV_XLEN (cpu) == 32 ? 0x1f : 0x3f; + store_rd (cpu, rd, cpu->regs[rs1] << (cpu->regs[rs2] & u_imm)); + break; + case MATCH_SLLW: + TRACE_INSN (cpu, "sllw %s, %s, %s; // %s = %s << %s", + rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name); + RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name); + store_rd (cpu, rd, EXTEND32 ((unsigned32)cpu->regs[rs1] << (cpu->regs[rs2] & 0x1f))); + break; + case MATCH_SLLI: + TRACE_INSN (cpu, "slli %s, %s, %"PRIiTW"; // %s = %s << %#"PRIxTW, + rd_name, rs1_name, shamt_imm, rd_name, rs1_name, shamt_imm); + if (RISCV_XLEN (cpu) == 32 && shamt_imm > 0x1f) + sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL); + store_rd (cpu, rd, cpu->regs[rs1] << shamt_imm); + break; + case MATCH_SLLIW: + TRACE_INSN (cpu, "slliw %s, %s, %"PRIiTW"; // %s = %s << %#"PRIxTW, + rd_name, rs1_name, shamt_imm, rd_name, rs1_name, shamt_imm); + RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name); + store_rd (cpu, rd, EXTEND32 ((unsigned32)cpu->regs[rs1] << shamt_imm)); + break; + case MATCH_SRL: + TRACE_INSN (cpu, "srl %s, %s, %s; // %s = %s >> %s", + rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name); + u_imm = RISCV_XLEN (cpu) == 32 ? 0x1f : 0x3f; + store_rd (cpu, rd, cpu->regs[rs1] >> (cpu->regs[rs2] & u_imm)); + break; + case MATCH_SRLW: + TRACE_INSN (cpu, "srlw %s, %s, %s; // %s = %s >> %s", + rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name); + RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name); + store_rd (cpu, rd, EXTEND32 ((unsigned32)cpu->regs[rs1] >> (cpu->regs[rs2] & 0x1f))); + break; + case MATCH_SRLI: + TRACE_INSN (cpu, "srli %s, %s, %"PRIiTW"; // %s = %s >> %#"PRIxTW, + rd_name, rs1_name, shamt_imm, rd_name, rs1_name, shamt_imm); + if (RISCV_XLEN (cpu) == 32 && shamt_imm > 0x1f) + sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL); + store_rd (cpu, rd, cpu->regs[rs1] >> shamt_imm); + break; + case MATCH_SRLIW: + TRACE_INSN (cpu, "srliw %s, %s, %"PRIiTW"; // %s = %s >> %#"PRIxTW, + rd_name, rs1_name, shamt_imm, rd_name, rs1_name, shamt_imm); + RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name); + store_rd (cpu, rd, EXTEND32 ((unsigned32)cpu->regs[rs1] >> shamt_imm)); + break; + case MATCH_SRA: + TRACE_INSN (cpu, "sra %s, %s, %s; // %s = %s >>> %s", + rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name); + if (RISCV_XLEN (cpu) == 32) + tmp = ashiftrt (cpu->regs[rs1], cpu->regs[rs2] & 0x1f); + else + tmp = ashiftrt64 (cpu->regs[rs1], cpu->regs[rs2] & 0x3f); + store_rd (cpu, rd, tmp); + break; + case MATCH_SRAW: + TRACE_INSN (cpu, "sraw %s, %s, %s; // %s = %s >>> %s", + rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name); + RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name); + store_rd (cpu, rd, EXTEND32 (ashiftrt ((signed32)cpu->regs[rs1], cpu->regs[rs2] & 0x1f))); + break; + case MATCH_SRAI: + TRACE_INSN (cpu, "srai %s, %s, %"PRIiTW"; // %s = %s >>> %#"PRIxTW, + rd_name, rs1_name, shamt_imm, rd_name, rs1_name, shamt_imm); + if (RISCV_XLEN (cpu) == 32) + { + if (shamt_imm > 0x1f) + sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL); + tmp = ashiftrt (cpu->regs[rs1], shamt_imm); + } + else + tmp = ashiftrt64 (cpu->regs[rs1], shamt_imm); + store_rd (cpu, rd, tmp); + break; + case MATCH_SRAIW: + TRACE_INSN (cpu, "sraiw %s, %s, %"PRIiTW"; // %s = %s >>> %#"PRIxTW, + rd_name, rs1_name, shamt_imm, rd_name, rs1_name, shamt_imm); + RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name); + store_rd (cpu, rd, EXTEND32 (ashiftrt ((signed32)cpu->regs[rs1], shamt_imm))); + break; + case MATCH_SLT: + TRACE_INSN (cpu, "slt"); + store_rd (cpu, rd, !!((signed_word)cpu->regs[rs1] < (signed_word)cpu->regs[rs2])); + break; + case MATCH_SLTU: + TRACE_INSN (cpu, "sltu"); + store_rd (cpu, rd, !!((unsigned_word)cpu->regs[rs1] < (unsigned_word)cpu->regs[rs2])); + break; + case MATCH_SLTI: + TRACE_INSN (cpu, "slti"); + store_rd (cpu, rd, !!((signed_word)cpu->regs[rs1] < (signed_word)i_imm)); + break; + case MATCH_SLTIU: + TRACE_INSN (cpu, "sltiu"); + store_rd (cpu, rd, !!((unsigned_word)cpu->regs[rs1] < (unsigned_word)i_imm)); + break; + case MATCH_AUIPC: + TRACE_INSN (cpu, "auipc %s, %"PRIiTW"; // %s = pc + %"PRIiTW, + rd_name, u_imm, rd_name, u_imm); + store_rd (cpu, rd, cpu->pc + u_imm); + break; + case MATCH_BEQ: + TRACE_INSN (cpu, "beq %s, %s, %#"PRIxTW"; // if (%s == %s) goto %#"PRIxTW, + rs1_name, rs2_name, sb_imm, rs1_name, rs2_name, sb_imm); + if (cpu->regs[rs1] == cpu->regs[rs2]) + { + pc = cpu->pc + sb_imm; + TRACE_BRANCH (cpu, "to %#"PRIxTW, pc); + } + break; + case MATCH_BLT: + TRACE_INSN (cpu, "blt %s, %s, %#"PRIxTW"; // if (%s < %s) goto %#"PRIxTW, + rs1_name, rs2_name, sb_imm, rs1_name, rs2_name, sb_imm); + if ((signed_word)cpu->regs[rs1] < (signed_word)cpu->regs[rs2]) + { + pc = cpu->pc + sb_imm; + TRACE_BRANCH (cpu, "to %#"PRIxTW, pc); + } + break; + case MATCH_BLTU: + TRACE_INSN (cpu, "bltu %s, %s, %#"PRIxTW"; // if (%s < %s) goto %#"PRIxTW, + rs1_name, rs2_name, sb_imm, rs1_name, rs2_name, sb_imm); + if ((unsigned_word)cpu->regs[rs1] < (unsigned_word)cpu->regs[rs2]) + { + pc = cpu->pc + sb_imm; + TRACE_BRANCH (cpu, "to %#"PRIxTW, pc); + } + break; + case MATCH_BGE: + TRACE_INSN (cpu, "bge %s, %s, %#"PRIxTW"; // if (%s >= %s) goto %#"PRIxTW, + rs1_name, rs2_name, sb_imm, rs1_name, rs2_name, sb_imm); + if ((signed_word)cpu->regs[rs1] >= (signed_word)cpu->regs[rs2]) + { + pc = cpu->pc + sb_imm; + TRACE_BRANCH (cpu, "to %#"PRIxTW, pc); + } + break; + case MATCH_BGEU: + TRACE_INSN (cpu, "bgeu %s, %s, %#"PRIxTW"; // if (%s >= %s) goto %#"PRIxTW, + rs1_name, rs2_name, sb_imm, rs1_name, rs2_name, sb_imm); + if ((unsigned_word)cpu->regs[rs1] >= (unsigned_word)cpu->regs[rs2]) + { + pc = cpu->pc + sb_imm; + TRACE_BRANCH (cpu, "to %#"PRIxTW, pc); + } + break; + case MATCH_BNE: + TRACE_INSN (cpu, "bne %s, %s, %#"PRIxTW"; // if (%s != %s) goto %#"PRIxTW, + rs1_name, rs2_name, sb_imm, rs1_name, rs2_name, sb_imm); + if (cpu->regs[rs1] != cpu->regs[rs2]) + { + pc = cpu->pc + sb_imm; + TRACE_BRANCH (cpu, "to %#"PRIxTW, pc); + } + break; + case MATCH_JAL: + TRACE_INSN (cpu, "jal %s, %"PRIiTW";", rd_name, EXTRACT_UJTYPE_IMM (iw)); + store_rd (cpu, rd, cpu->pc + 4); + pc = cpu->pc + EXTRACT_UJTYPE_IMM (iw); + TRACE_BRANCH (cpu, "to %#"PRIxTW, pc); + break; + case MATCH_JALR: + TRACE_INSN (cpu, "jalr %s, %s, %"PRIiTW";", rd_name, rs1_name, i_imm); + store_rd (cpu, rd, cpu->pc + 4); + pc = cpu->regs[rs1] + i_imm; + TRACE_BRANCH (cpu, "to %#"PRIxTW, pc); + break; + + case MATCH_LD: + TRACE_INSN (cpu, "ld %s, %"PRIiTW"(%s); // ", + rd_name, i_imm, rs1_name); + RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name); + store_rd (cpu, rd, + sim_core_read_unaligned_8 (cpu, cpu->pc, read_map, + cpu->regs[rs1] + i_imm)); + break; + case MATCH_LW: + TRACE_INSN (cpu, "lw %s, %"PRIiTW"(%s); // ", + rd_name, i_imm, rs1_name); + store_rd (cpu, rd, EXTEND32 ( + sim_core_read_unaligned_4 (cpu, cpu->pc, read_map, + cpu->regs[rs1] + i_imm))); + break; + case MATCH_LWU: + TRACE_INSN (cpu, "lwu %s, %"PRIiTW"(%s); // ", + rd_name, i_imm, rs1_name); + store_rd (cpu, rd, + sim_core_read_unaligned_4 (cpu, cpu->pc, read_map, + cpu->regs[rs1] + i_imm)); + break; + case MATCH_LH: + TRACE_INSN (cpu, "lh %s, %"PRIiTW"(%s); // ", + rd_name, i_imm, rs1_name); + store_rd (cpu, rd, EXTEND16 ( + sim_core_read_unaligned_2 (cpu, cpu->pc, read_map, + cpu->regs[rs1] + i_imm))); + break; + case MATCH_LHU: + TRACE_INSN (cpu, "lbu %s, %"PRIiTW"(%s); // ", + rd_name, i_imm, rs1_name); + store_rd (cpu, rd, + sim_core_read_unaligned_2 (cpu, cpu->pc, read_map, + cpu->regs[rs1] + i_imm)); + break; + case MATCH_LB: + TRACE_INSN (cpu, "lb %s, %"PRIiTW"(%s); // ", + rd_name, i_imm, rs1_name); + store_rd (cpu, rd, EXTEND8 ( + sim_core_read_unaligned_1 (cpu, cpu->pc, read_map, + cpu->regs[rs1] + i_imm))); + break; + case MATCH_LBU: + TRACE_INSN (cpu, "lbu %s, %"PRIiTW"(%s); // ", + rd_name, i_imm, rs1_name); + store_rd (cpu, rd, + sim_core_read_unaligned_1 (cpu, cpu->pc, read_map, + cpu->regs[rs1] + i_imm)); + break; + case MATCH_SD: + TRACE_INSN (cpu, "sd %s, %"PRIiTW"(%s); // ", + rs2_name, s_imm, rs1_name); + RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name); + sim_core_write_unaligned_8 (cpu, cpu->pc, write_map, + cpu->regs[rs1] + s_imm, cpu->regs[rs2]); + break; + case MATCH_SW: + TRACE_INSN (cpu, "sw %s, %"PRIiTW"(%s); // ", + rs2_name, s_imm, rs1_name); + sim_core_write_unaligned_4 (cpu, cpu->pc, write_map, + cpu->regs[rs1] + s_imm, cpu->regs[rs2]); + break; + case MATCH_SH: + TRACE_INSN (cpu, "sh %s, %"PRIiTW"(%s); // ", + rs2_name, s_imm, rs1_name); + sim_core_write_unaligned_2 (cpu, cpu->pc, write_map, + cpu->regs[rs1] + s_imm, cpu->regs[rs2]); + break; + case MATCH_SB: + TRACE_INSN (cpu, "sb %s, %"PRIiTW"(%s); // ", + rs2_name, s_imm, rs1_name); + sim_core_write_unaligned_1 (cpu, cpu->pc, write_map, + cpu->regs[rs1] + s_imm, cpu->regs[rs2]); + break; + + case MATCH_CSRRC: + TRACE_INSN (cpu, "csrrc"); + switch (csr) + { +#define DECLARE_CSR(name, num) \ + case num: \ + store_rd (cpu, rd, fetch_csr (cpu, #name, num, &cpu->csr.name)); \ + store_csr (cpu, #name, num, &cpu->csr.name, \ + cpu->csr.name & !cpu->regs[rs1]); \ + break; +#include "opcode/riscv-opc.h" +#undef DECLARE_CSR + } + break; + case MATCH_CSRRS: + TRACE_INSN (cpu, "csrrs"); + switch (csr) + { +#define DECLARE_CSR(name, num) \ + case num: \ + store_rd (cpu, rd, fetch_csr (cpu, #name, num, &cpu->csr.name)); \ + store_csr (cpu, #name, num, &cpu->csr.name, \ + cpu->csr.name | cpu->regs[rs1]); \ + break; +#include "opcode/riscv-opc.h" +#undef DECLARE_CSR + } + break; + case MATCH_CSRRW: + TRACE_INSN (cpu, "csrrw"); + switch (csr) + { +#define DECLARE_CSR(name, num) \ + case num: \ + store_rd (cpu, rd, fetch_csr (cpu, #name, num, &cpu->csr.name)); \ + store_csr (cpu, #name, num, &cpu->csr.name, cpu->regs[rs1]); \ + break; +#include "opcode/riscv-opc.h" +#undef DECLARE_CSR + } + break; + + case MATCH_RDCYCLE: + TRACE_INSN (cpu, "rdcycle %s;", rd_name); + store_rd (cpu, rd, fetch_csr (cpu, "cycle", CSR_CYCLE, &cpu->csr.cycle)); + break; + case MATCH_RDCYCLEH: + TRACE_INSN (cpu, "rdcycleh %s;", rd_name); + RISCV_ASSERT_RV32 (cpu, "insn: %s", op->name); + store_rd (cpu, rd, fetch_csr (cpu, "cycleh", CSR_CYCLEH, &cpu->csr.cycleh)); + break; + case MATCH_RDINSTRET: + TRACE_INSN (cpu, "rdinstret %s;", rd_name); + store_rd (cpu, rd, fetch_csr (cpu, "instret", CSR_INSTRET, &cpu->csr.instret)); + break; + case MATCH_RDINSTRETH: + TRACE_INSN (cpu, "rdinstreth %s;", rd_name); + RISCV_ASSERT_RV32 (cpu, "insn: %s", op->name); + store_rd (cpu, rd, fetch_csr (cpu, "instreth", CSR_INSTRETH, &cpu->csr.instreth)); + break; + case MATCH_RDTIME: + TRACE_INSN (cpu, "rdtime %s;", rd_name); + store_rd (cpu, rd, fetch_csr (cpu, "time", CSR_TIME, &cpu->csr.cycle)); + break; + case MATCH_RDTIMEH: + TRACE_INSN (cpu, "rdtimeh %s;", rd_name); + RISCV_ASSERT_RV32 (cpu, "insn: %s", op->name); + store_rd (cpu, rd, fetch_csr (cpu, "timeh", CSR_TIMEH, &cpu->csr.cycleh)); + break; + + case MATCH_FENCE: + TRACE_INSN (cpu, "fence;"); + break; + case MATCH_FENCE_I: + TRACE_INSN (cpu, "fence.i;"); + break; + case MATCH_SBREAK: + TRACE_INSN (cpu, "sbreak;"); + /* GDB expects us to step over SBREAK. */ + sim_engine_halt (sd, cpu, NULL, cpu->pc + 4, sim_stopped, SIM_SIGTRAP); + break; + case MATCH_ECALL: + TRACE_INSN (cpu, "ecall;"); + cpu->a0 = sim_syscall (cpu, cpu->a7, cpu->a0, cpu->a1, cpu->a2, cpu->a3); + break; + default: + TRACE_INSN (cpu, "UNHANDLED INSN: %s", op->name); + sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL); + } + + return pc; +} + +static unsigned64 +mulhu (unsigned64 a, unsigned64 b) +{ + uint64_t t; + uint32_t y1, y2, y3; + uint64_t a0 = (uint32_t)a, a1 = a >> 32; + uint64_t b0 = (uint32_t)b, b1 = b >> 32; + + t = a1*b0 + ((a0*b0) >> 32); + y1 = t; + y2 = t >> 32; + + t = a0*b1 + y1; + y1 = t; + + t = a1*b1 + y2 + (t >> 32); + y2 = t; + y3 = t >> 32; + + return ((uint64_t)y3 << 32) | y2; +} + +static unsigned64 +mulh (signed64 a, signed64 b) +{ + int negate = (a < 0) != (b < 0); + uint64_t res = mulhu (a < 0 ? -a : a, b < 0 ? -b : b); + return negate ? ~res + (a * b == 0) : res; +} + +static unsigned64 +mulhsu (signed64 a, unsigned64 b) +{ + int negate = a < 0; + uint64_t res = mulhu (a < 0 ? -a : a, b); + return negate ? ~res + (a * b == 0) : res; +} + +static sim_cia +execute_m (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op) +{ + SIM_DESC sd = CPU_STATE (cpu); + int rd = (iw >> OP_SH_RD) & OP_MASK_RD; + int rs1 = (iw >> OP_SH_RS1) & OP_MASK_RS1; + int rs2 = (iw >> OP_SH_RS2) & OP_MASK_RS2; + const char *rd_name = riscv_gpr_names_abi[rd]; + const char *rs1_name = riscv_gpr_names_abi[rs1]; + const char *rs2_name = riscv_gpr_names_abi[rs2]; + unsigned_word tmp, dividend_max; + signed_word dividend32_max; + sim_cia pc = cpu->pc + 4; + + dividend_max = -((unsigned_word)1 << (WITH_TARGET_WORD_BITSIZE - 1)); + dividend32_max = INT32_MIN; + + switch (op->match) + { + case MATCH_DIV: + TRACE_INSN (cpu, "div %s, %s, %s; // %s = %s / %s", + rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name); + if (cpu->regs[rs1] == dividend_max && cpu->regs[rs2] == -1) + tmp = dividend_max; + else if (cpu->regs[rs2]) + tmp = (signed_word)cpu->regs[rs1] / (signed_word)cpu->regs[rs2]; + else + tmp = -1; + store_rd (cpu, rd, tmp); + break; + case MATCH_DIVW: + TRACE_INSN (cpu, "divw %s, %s, %s; // %s = %s / %s", + rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name); + RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name); + if (EXTEND32 (cpu->regs[rs1]) == dividend32_max + && EXTEND32 (cpu->regs[rs2]) == -1) + tmp = 1 << 31; + else if (EXTEND32 (cpu->regs[rs2])) + tmp = EXTEND32 (cpu->regs[rs1]) / EXTEND32 (cpu->regs[rs2]); + else + tmp = -1; + store_rd (cpu, rd, EXTEND32 (tmp)); + break; + case MATCH_DIVU: + TRACE_INSN (cpu, "divu %s, %s, %s; // %s = %s / %s", + rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name); + if (cpu->regs[rs2]) + store_rd (cpu, rd, (unsigned_word)cpu->regs[rs1] + / (unsigned_word)cpu->regs[rs2]); + else + store_rd (cpu, rd, -1); + break; + case MATCH_DIVUW: + TRACE_INSN (cpu, "divuw %s, %s, %s; // %s = %s / %s", + rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name); + RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name); + if ((unsigned32)cpu->regs[rs2]) + tmp = (unsigned32)cpu->regs[rs1] / (unsigned32)cpu->regs[rs2]; + else + tmp = -1; + store_rd (cpu, rd, EXTEND32 (tmp)); + break; + case MATCH_MUL: + TRACE_INSN (cpu, "mul %s, %s, %s; // %s = %s * %s", + rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name); + store_rd (cpu, rd, cpu->regs[rs1] * cpu->regs[rs2]); + break; + case MATCH_MULW: + TRACE_INSN (cpu, "mulw %s, %s, %s; // %s = %s * %s", + rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name); + RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name); + store_rd (cpu, rd, EXTEND32 ((signed32)cpu->regs[rs1] + * (signed32)cpu->regs[rs2])); + break; + case MATCH_MULH: + TRACE_INSN (cpu, "mulh %s, %s, %s; // %s = %s * %s", + rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name); + if (RISCV_XLEN (cpu) == 32) + store_rd (cpu, rd, ((signed64)(signed_word)cpu->regs[rs1] + * (signed64)(signed_word)cpu->regs[rs2]) >> 32); + else + store_rd (cpu, rd, mulh (cpu->regs[rs1], cpu->regs[rs2])); + break; + case MATCH_MULHU: + TRACE_INSN (cpu, "mulhu %s, %s, %s; // %s = %s * %s", + rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name); + if (RISCV_XLEN (cpu) == 32) + store_rd (cpu, rd, ((unsigned64)cpu->regs[rs1] + * (unsigned64)cpu->regs[rs2]) >> 32); + else + store_rd (cpu, rd, mulhu (cpu->regs[rs1], cpu->regs[rs2])); + break; + case MATCH_MULHSU: + TRACE_INSN (cpu, "mulhsu %s, %s, %s; // %s = %s * %s", + rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name); + if (RISCV_XLEN (cpu) == 32) + store_rd (cpu, rd, ((signed64)(signed_word)cpu->regs[rs1] + * (unsigned64)cpu->regs[rs2]) >> 32); + else + store_rd (cpu, rd, mulhsu (cpu->regs[rs1], cpu->regs[rs2])); + break; + case MATCH_REM: + TRACE_INSN (cpu, "rem %s, %s, %s; // %s = %s %% %s", + rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name); + if (cpu->regs[rs1] == dividend_max && cpu->regs[rs2] == -1) + tmp = 0; + else if (cpu->regs[rs2]) + tmp = (signed_word)cpu->regs[rs1] % (signed_word)cpu->regs[rs2]; + else + tmp = cpu->regs[rs1]; + store_rd (cpu, rd, tmp); + break; + case MATCH_REMW: + TRACE_INSN (cpu, "remw %s, %s, %s; // %s = %s %% %s", + rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name); + RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name); + if (EXTEND32 (cpu->regs[rs1]) == dividend32_max + && EXTEND32 (cpu->regs[rs2]) == -1) + tmp = 0; + else if (EXTEND32 (cpu->regs[rs2])) + tmp = EXTEND32 (cpu->regs[rs1]) % EXTEND32 (cpu->regs[rs2]); + else + tmp = cpu->regs[rs1]; + store_rd (cpu, rd, EXTEND32 (tmp)); + break; + case MATCH_REMU: + TRACE_INSN (cpu, "remu %s, %s, %s; // %s = %s %% %s", + rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name); + if (cpu->regs[rs2]) + store_rd (cpu, rd, cpu->regs[rs1] % cpu->regs[rs2]); + else + store_rd (cpu, rd, cpu->regs[rs1]); + break; + case MATCH_REMUW: + TRACE_INSN (cpu, "remuw %s, %s, %s; // %s = %s %% %s", + rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name); + RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name); + if ((unsigned32)cpu->regs[rs2]) + tmp = (unsigned32)cpu->regs[rs1] % (unsigned32)cpu->regs[rs2]; + else + tmp = cpu->regs[rs1]; + store_rd (cpu, rd, EXTEND32 (tmp)); + break; + default: + TRACE_INSN (cpu, "UNHANDLED INSN: %s", op->name); + sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL); + } + + return pc; +} + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +static sim_cia +execute_a (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op) +{ + SIM_DESC sd = CPU_STATE (cpu); + int rd = (iw >> OP_SH_RD) & OP_MASK_RD; + int rs1 = (iw >> OP_SH_RS1) & OP_MASK_RS1; + int rs2 = (iw >> OP_SH_RS2) & OP_MASK_RS2; + const char *rd_name = riscv_gpr_names_abi[rd]; + const char *rs1_name = riscv_gpr_names_abi[rs1]; + const char *rs2_name = riscv_gpr_names_abi[rs2]; + struct atomic_mem_reserved_list *amo_prev, *amo_curr; + unsigned_word tmp; + sim_cia pc = cpu->pc + 4; + + /* Handle these two load/store operations specifically. */ + switch (op->match) + { + case MATCH_LR_W: + TRACE_INSN (cpu, "%s %s, (%s);", op->name, rd_name, rs1_name); + store_rd (cpu, rd, + sim_core_read_unaligned_4 (cpu, cpu->pc, read_map, cpu->regs[rs1])); + + /* Walk the reservation list to find an existing match. */ + amo_curr = sd->amo_reserved_list; + while (amo_curr) + { + if (amo_curr->addr == cpu->regs[rs1]) + goto done; + amo_curr = amo_curr->next; + } + + /* No reservation exists, so add one. */ + amo_curr = xmalloc (sizeof (*amo_curr)); + amo_curr->addr = cpu->regs[rs1]; + amo_curr->next = sd->amo_reserved_list; + sd->amo_reserved_list = amo_curr; + goto done; + case MATCH_SC_W: + TRACE_INSN (cpu, "%s %s, %s, (%s);", op->name, rd_name, rs2_name, rs1_name); + + /* Walk the reservation list to find a match. */ + amo_curr = amo_prev = sd->amo_reserved_list; + while (amo_curr) + { + if (amo_curr->addr == cpu->regs[rs1]) + { + /* We found a reservation, so operate it. */ + sim_core_write_unaligned_4 (cpu, cpu->pc, write_map, + cpu->regs[rs1], cpu->regs[rs2]); + store_rd (cpu, rd, 0); + if (amo_curr == sd->amo_reserved_list) + sd->amo_reserved_list = amo_curr->next; + else + amo_prev->next = amo_curr->next; + free (amo_curr); + goto done; + } + amo_prev = amo_curr; + amo_curr = amo_curr->next; + } + + /* If we're still here, then no reservation exists, so mark as failed. */ + store_rd (cpu, rd, 1); + goto done; + } + + /* Handle the rest of the atomic insns with common code paths. */ + TRACE_INSN (cpu, "%s %s, %s, (%s);", + op->name, rd_name, rs2_name, rs1_name); + if (op->subset[0] == '6') + store_rd (cpu, rd, + sim_core_read_unaligned_8 (cpu, cpu->pc, read_map, cpu->regs[rs1])); + else + store_rd (cpu, rd, EXTEND32 ( + sim_core_read_unaligned_4 (cpu, cpu->pc, read_map, cpu->regs[rs1]))); + + switch (op->match) + { + case MATCH_AMOADD_D: + case MATCH_AMOADD_W: + tmp = cpu->regs[rd] + cpu->regs[rs2]; + break; + case MATCH_AMOAND_D: + case MATCH_AMOAND_W: + tmp = cpu->regs[rd] & cpu->regs[rs2]; + break; + case MATCH_AMOMAX_D: + case MATCH_AMOMAX_W: + tmp = MAX ((signed_word)cpu->regs[rd], (signed_word)cpu->regs[rs2]); + break; + case MATCH_AMOMAXU_D: + case MATCH_AMOMAXU_W: + tmp = MAX ((unsigned_word)cpu->regs[rd], (unsigned_word)cpu->regs[rs2]); + break; + case MATCH_AMOMIN_D: + case MATCH_AMOMIN_W: + tmp = MIN ((signed_word)cpu->regs[rd], (signed_word)cpu->regs[rs2]); + break; + case MATCH_AMOMINU_D: + case MATCH_AMOMINU_W: + tmp = MIN ((unsigned_word)cpu->regs[rd], (unsigned_word)cpu->regs[rs2]); + break; + case MATCH_AMOOR_D: + case MATCH_AMOOR_W: + tmp = cpu->regs[rd] | cpu->regs[rs2]; + break; + case MATCH_AMOSWAP_D: + case MATCH_AMOSWAP_W: + tmp = cpu->regs[rs2]; + break; + case MATCH_AMOXOR_D: + case MATCH_AMOXOR_W: + tmp = cpu->regs[rd] ^ cpu->regs[rs2]; + break; + default: + TRACE_INSN (cpu, "UNHANDLED INSN: %s", op->name); + sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL); + } + + if (op->subset[0] == '6') + sim_core_write_unaligned_8 (cpu, cpu->pc, write_map, cpu->regs[rs1], tmp); + else + sim_core_write_unaligned_4 (cpu, cpu->pc, write_map, cpu->regs[rs1], tmp); + + done: + return pc; +} + +static sim_cia +execute_one (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op) +{ + SIM_DESC sd = CPU_STATE (cpu); + const char *subset = op->subset; + + rescan: + switch (subset[0]) + { + case 'A': + return execute_a (cpu, iw, op); + case 'I': + return execute_i (cpu, iw, op); + case 'M': + return execute_m (cpu, iw, op); + case '3': + if (subset[1] == '2') + { + RISCV_ASSERT_RV32 (cpu, "insn: %s", op->name); + subset += 2; + goto rescan; + } + goto case_default; + case '6': + if (subset[1] == '4') + { + RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name); + subset += 2; + goto rescan; + } + goto case_default; + case_default: + default: + TRACE_INSN (cpu, "UNHANDLED EXTENSION: %s", op->subset); + sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL); + } + + return cpu->pc + riscv_insn_length (iw); +} + +/* Decode & execute a single instruction. */ +void step_once (SIM_CPU *cpu) +{ + SIM_DESC sd = CPU_STATE (cpu); + unsigned_word iw; + unsigned int len; + sim_cia pc = cpu->pc; + const struct riscv_opcode *op; + + if (TRACE_ANY_P (cpu)) + trace_prefix (sd, cpu, NULL_CIA, pc, TRACE_LINENUM_P (cpu), + NULL, 0, " "); /* Use a space for gcc warnings. */ + + iw = sim_core_read_aligned_2 (cpu, pc, exec_map, pc); + + /* Reject non-32-bit opcodes first. */ + len = riscv_insn_length (iw); + if (len != 4) + { + sim_io_printf (sd, "sim: bad insn len %#x @ %#"PRIxTA": %#"PRIxTW"\n", + len, pc, iw); + sim_engine_halt (sd, cpu, NULL, pc, sim_signalled, SIM_SIGILL); + } + + iw |= ((unsigned_word)sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2) << 16); + + TRACE_CORE (cpu, "0x%08"PRIxTW, iw); + + op = riscv_hash[OP_HASH_IDX (iw)]; + if (!op) + sim_engine_halt (sd, cpu, NULL, pc, sim_signalled, SIM_SIGILL); + + for (; op->name; op++) + if ((op->match_func) (op, iw) && !(op->pinfo & INSN_ALIAS)) + { + pc = execute_one (cpu, iw, op); + break; + } + + /* TODO: Handle overflow into high 32 bits. */ + /* TODO: Try to use a common counter and only update on demand (reads). */ + ++cpu->csr.cycle; + ++cpu->csr.instret; + + cpu->pc = pc; +} + +/* Return the program counter for this cpu. */ +static sim_cia +pc_get (sim_cpu *cpu) +{ + return cpu->pc; +} + +/* Set the program counter for this cpu to the new pc value. */ +static void +pc_set (sim_cpu *cpu, sim_cia pc) +{ + cpu->pc = pc; +} + +static int +reg_fetch (sim_cpu *cpu, int rn, unsigned char *buf, int len) +{ + if (len <= 0 || len > sizeof (unsigned_word)) + return -1; + + switch (rn) + { + case SIM_RISCV_RA_REGNUM ... SIM_RISCV_T6_REGNUM: + memcpy (buf, &cpu->regs[rn], len); + return len; + case SIM_RISCV_FIRST_FP_REGNUM ... SIM_RISCV_LAST_FP_REGNUM: + memcpy (buf, &cpu->fpregs[rn], len); + return len; + case SIM_RISCV_PC_REGNUM: + memcpy (buf, &cpu->pc, len); + return len; + +#define DECLARE_CSR(name, num) \ + case SIM_RISCV_ ## num ## _REGNUM: \ + memcpy (buf, &cpu->csr.name, len); \ + return len; +#include "opcode/riscv-opc.h" +#undef DECLARE_CSR + + default: + return -1; + } +} + +static int +reg_store (sim_cpu *cpu, int rn, unsigned char *buf, int len) +{ + if (len <= 0 || len > sizeof (unsigned_word)) + return -1; + + switch (rn) + { + case SIM_RISCV_RA_REGNUM ... SIM_RISCV_T6_REGNUM: + memcpy (&cpu->regs[rn], buf, len); + return len; + case SIM_RISCV_FIRST_FP_REGNUM ... SIM_RISCV_LAST_FP_REGNUM: + memcpy (&cpu->fpregs[rn], buf, len); + return len; + case SIM_RISCV_PC_REGNUM: + memcpy (&cpu->pc, buf, len); + return len; + +#define DECLARE_CSR(name, num) \ + case SIM_RISCV_ ## num ## _REGNUM: \ + memcpy (&cpu->csr.name, buf, len); \ + return len; +#include "opcode/riscv-opc.h" +#undef DECLARE_CSR + + default: + return -1; + } +} + +/* Initialize the state for a single cpu. Usuaully this involves clearing all + registers back to their reset state. Should also hook up the fetch/store + helper functions too. */ +void initialize_cpu (SIM_DESC sd, SIM_CPU *cpu, int mhartid) +{ + const char *extensions; + int i; + + memset (cpu->regs, 0, sizeof (cpu->regs)); + + CPU_PC_FETCH (cpu) = pc_get; + CPU_PC_STORE (cpu) = pc_set; + CPU_REG_FETCH (cpu) = reg_fetch; + CPU_REG_STORE (cpu) = reg_store; + + if (!riscv_hash[0]) + { + const struct riscv_opcode *op; + + for (op = riscv_opcodes; op->name; op++) + if (!riscv_hash[OP_HASH_IDX (op->match)]) + riscv_hash[OP_HASH_IDX (op->match)] = op; + } + + cpu->csr.misa = 0; + /* RV32 sets this field to 0, and we don't really support RV128 yet. */ + if (RISCV_XLEN (cpu) == 64) + cpu->csr.misa |= (unsigned64)2 << 62; + + /* Skip the leading "rv" prefix and the two numbers. */ + extensions = MODEL_NAME (CPU_MODEL (cpu)) + 4; + for (i = 0; i < 26; ++i) + { + char ext = 'A' + i; + + if (ext == 'X') + continue; + else if (strchr (extensions, ext) != NULL) + { + if (ext == 'G') + cpu->csr.misa |= 0x1129; /* G = IMAFD. */ + else + cpu->csr.misa |= (1 << i); + } + } + + cpu->csr.mimpid = 0x8000; + cpu->csr.mhartid = mhartid; +} + +/* Some utils don't like having a NULL environ. */ +static const char * const simple_env[] = { "HOME=/", "PATH=/bin", NULL }; + +/* Count the number of arguments in an argv. */ +static int +count_argv (const char * const *argv) +{ + int i; + + if (!argv) + return -1; + + for (i = 0; argv[i] != NULL; ++i) + continue; + return i; +} + +void initialize_env (SIM_DESC sd, const char * const *argv, + const char * const *env) +{ + SIM_CPU *cpu = STATE_CPU (sd, 0); + int i; + int argc, argv_flat; + int envc, env_flat; + address_word sp, sp_flat; + unsigned char null[8] = { 0, 0, 0, 0, 0, 0, 0, 0, }; + + /* Figure out how many bytes the argv strings take up. */ + argc = count_argv (argv); + if (argc == -1) + argc = 0; + argv_flat = argc; /* NUL bytes. */ + for (i = 0; i < argc; ++i) + argv_flat += strlen (argv[i]); + + /* Figure out how many bytes the environ strings take up. */ + if (!env) + env = simple_env; + envc = count_argv (env); + env_flat = envc; /* NUL bytes. */ + for (i = 0; i < envc; ++i) + env_flat += strlen (env[i]); + + /* Make space for the strings themselves. */ + sp_flat = (DEFAULT_MEM_SIZE - argv_flat - env_flat) & -sizeof (address_word); + /* Then the pointers to the strings. */ + sp = sp_flat - ((argc + 1 + envc + 1) * sizeof (address_word)); + /* Then the argc. */ + sp -= sizeof (unsigned_word); + + /* Set up the regs the libgloss crt0 expects. */ + cpu->a0 = argc; + cpu->sp = sp; + + /* First push the argc value. */ + sim_write (sd, sp, (void *)&argc, sizeof (unsigned_word)); + sp += sizeof (unsigned_word); + + /* Then the actual argv strings so we know where to point argv[]. */ + for (i = 0; i < argc; ++i) + { + unsigned len = strlen (argv[i]) + 1; + sim_write (sd, sp_flat, (void *)argv[i], len); + sim_write (sd, sp, (void *)&sp_flat, sizeof (address_word)); + sp_flat += len; + sp += sizeof (address_word); + } + sim_write (sd, sp, null, sizeof (address_word)); + sp += sizeof (address_word); + + /* Then the actual env strings so we know where to point env[]. */ + for (i = 0; i < envc; ++i) + { + unsigned len = strlen (env[i]) + 1; + sim_write (sd, sp_flat, (void *)env[i], len); + sim_write (sd, sp, (void *)&sp_flat, sizeof (address_word)); + sp_flat += len; + sp += sizeof (address_word); + } +} diff --git a/sim/riscv/sim-main.h b/sim/riscv/sim-main.h new file mode 100644 index 0000000..6e53587 --- /dev/null +++ b/sim/riscv/sim-main.h @@ -0,0 +1,87 @@ +/* RISC-V simulator. + + Copyright (C) 2005-2014 Free Software Foundation, Inc. + Contributed by Mike Frysinger. + + This file is part of 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 . */ + +#ifndef SIM_MAIN_H +#define SIM_MAIN_H + +#include "tconfig.h" +#include "sim-basics.h" +#include "machs.h" +#include "sim-base.h" + +struct _sim_cpu { + union { + unsigned_word regs[32]; + struct { + /* These are the ABI names. */ + unsigned_word zero, ra, sp, gp, tp; + unsigned_word t0, t1, t2; + unsigned_word s0, s1; + unsigned_word a0, a1, a2, a3, a4, a5, a6, a7; + unsigned_word s2, s3, s4, s5, s6, s7, s8, s9, s10, s11; + unsigned_word t3, t4, t5, t6; + }; + }; + union { + unsigned_word fpregs[32]; + struct { + /* These are the ABI names. */ + unsigned_word ft0, ft1, ft2, ft3, ft4, ft5, ft6, ft7; + unsigned_word fs0, fs1; + unsigned_word fa0, fa1, fa2, fa3, fa4, fa5, fa6, fa7; + unsigned_word fs2, fs3, fs4, fs5, fs6, fs7, fs8, fs9, fs10, fs11; + unsigned_word ft8, ft9, ft10, ft11; + }; + }; + sim_cia pc; + + struct { +#define DECLARE_CSR(name, num) unsigned_word name; +#include "opcode/riscv-opc.h" +#undef DECLARE_CSR + } csr; + + sim_cpu_base base; +}; + +struct atomic_mem_reserved_list; +struct atomic_mem_reserved_list { + struct atomic_mem_reserved_list *next; + address_word addr; +}; + +struct sim_state { + sim_cpu *cpu[MAX_NR_PROCESSORS]; + struct atomic_mem_reserved_list *amo_reserved_list; + + /* ... simulator specific members ... */ + sim_state_base base; +}; + +extern void step_once (SIM_CPU *); +extern void initialize_cpu (SIM_DESC, SIM_CPU *, int); +extern void initialize_env (SIM_DESC, const char * const *argv, + const char * const *env); + +#define DEFAULT_MEM_SIZE (16 * 1024 * 1024) + +#define RISCV_XLEN(cpu) MACH_WORD_BITSIZE (CPU_MACH (cpu)) + +#endif diff --git a/sim/riscv/tconfig.h b/sim/riscv/tconfig.h new file mode 100644 index 0000000..25e6a79 --- /dev/null +++ b/sim/riscv/tconfig.h @@ -0,0 +1,4 @@ +/* RISC-V target configuration file. -*- C -*- */ + +/* ??? Temporary hack until model support unified. */ +#define SIM_HAVE_MODEL diff --git a/sim/testsuite/sim/riscv/ChangeLog b/sim/testsuite/sim/riscv/ChangeLog new file mode 100644 index 0000000..72dd0c3 --- /dev/null +++ b/sim/testsuite/sim/riscv/ChangeLog @@ -0,0 +1,3 @@ +2015-03-29 Mike Frysinger + + * allinsn.exp, exit-0.s, exit-7.s, isa.inc, testutils.inc: New files. diff --git a/sim/testsuite/sim/riscv/allinsn.exp b/sim/testsuite/sim/riscv/allinsn.exp new file mode 100644 index 0000000..4ed7cff --- /dev/null +++ b/sim/testsuite/sim/riscv/allinsn.exp @@ -0,0 +1,15 @@ +# mcore simulator testsuite + +if [istarget riscv-*] { + # all machines + set all_machs "riscv" + + foreach src [lsort [glob -nocomplain $srcdir/$subdir/*.s]] { + # If we're only testing specific files and this isn't one of them, + # skip it. + if ![runtest_file_p $runtests $src] { + continue + } + run_sim_test $src $all_machs + } +} diff --git a/sim/testsuite/sim/riscv/pass.s b/sim/testsuite/sim/riscv/pass.s new file mode 100644 index 0000000..bd428ca --- /dev/null +++ b/sim/testsuite/sim/riscv/pass.s @@ -0,0 +1,7 @@ +# check that the sim doesn't die immediately. +# mach: riscv + +.include "testutils.inc" + + start + pass diff --git a/sim/testsuite/sim/riscv/testutils.inc b/sim/testsuite/sim/riscv/testutils.inc new file mode 100644 index 0000000..bb92ac0 --- /dev/null +++ b/sim/testsuite/sim/riscv/testutils.inc @@ -0,0 +1,50 @@ +# MACRO: exit + .macro exit nr + li a0, \nr + # The exit utility function. + li a7, 93; + .endm + +# MACRO: pass +# Write 'pass' to stdout and quit + .macro pass + # syscall write(). + li a7, 64; + # Use stdout. + li a0, 1; + # Point to the string. + lla a1, 1f; + # Number of bytes to write. + li a2, 5; + # Trigger OS trap. + ecall; + exit 0; + .data + 1: .asciz "pass\n" + .endm + +# MACRO: fail +# Write 'fail' to stdout and quit + .macro fail + # syscall write(); + li a7, 64; + # Use stdout. + li a0, 1; + # Point to the string. + lla a1, 1f; + # Number of bytes to write. + li a2, 5; + # Trigger OS trap. + ecall; + exit 0; + .data + 1: .asciz "fail\n" + .endm + +# MACRO: start +# All assembler tests should start with a call to "start" + .macro start + .text +.global _start +_start: + .endm