From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id kOeLAaaF/V/lPAAAWB0awg (envelope-from ) for ; Tue, 12 Jan 2021 06:19:02 -0500 Received: by simark.ca (Postfix, from userid 112) id 036331EF7E; Tue, 12 Jan 2021 06:19:02 -0500 (EST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-1.1 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,MAILING_LIST_MULTI,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 8405A1EE1B for ; Tue, 12 Jan 2021 06:18:53 -0500 (EST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 2219638930E8; Tue, 12 Jan 2021 11:18:53 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 2219638930E8 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1610450333; bh=q3Zi1OjLeZECi5ucJ5h2UqEYnDcP2xF5qvHYQVgkgxE=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=GAHl/YQrDNhvX9bc2JNq7tmRdkf+y0Uz+QX6bTfnGK6t/UKtazRmjZu2SeZrj0zC+ pSMFcTT46nmnhJT6huX3ZAnFgEW3TNqtCOgclRJ2BoRmgEoqvL3FxqvPliNgWHHuSf pG7oeeyWnL0ghmLf1gjmqnB6ChJT9O8Mm5OhSdgs= Received: from smtp.gentoo.org (smtp.gentoo.org [140.211.166.183]) by sourceware.org (Postfix) with ESMTP id 31128386EC66 for ; Tue, 12 Jan 2021 11:18:46 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 31128386EC66 Received: from vapier.lan (localhost [127.0.0.1]) by smtp.gentoo.org (Postfix) with ESMTP id 54966340A85 for ; Tue, 12 Jan 2021 11:18:45 +0000 (UTC) To: gdb-patches@sourceware.org Subject: [PATCH 1/2] sim: riscv: new port Date: Tue, 12 Jan 2021 06:18:41 -0500 Message-Id: <20210112111842.17223-1-vapier@gentoo.org> X-Mailer: git-send-email 2.28.0 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Mike Frysinger via Gdb-patches Reply-To: Mike Frysinger Errors-To: gdb-patches-bounces@sourceware.org Sender: "Gdb-patches" --- sim/common/ChangeLog | 4 + sim/common/nltvals.def | 48 + sim/configure | 8 + sim/configure.tgt | 3 + sim/riscv/ChangeLog | 5 + sim/riscv/Makefile.in | 30 + sim/riscv/aclocal.m4 | 119 + sim/riscv/config.in | 242 + sim/riscv/configure | 16145 ++++++++++++++++++++++++ sim/riscv/configure.ac | 28 + sim/riscv/interp.c | 153 + sim/riscv/machs.c | 125 + sim/riscv/machs.h | 45 + sim/riscv/model_list.def | 9 + sim/riscv/sim-main.c | 1149 ++ sim/riscv/sim-main.h | 86 + sim/testsuite/ChangeLog | 5 + sim/testsuite/configure | 3 + 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 | 52 + 22 files changed, 18284 insertions(+) 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 100755 sim/riscv/configure 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/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/sim/common/ChangeLog b/sim/common/ChangeLog index 608a0859ce89..3b5439a6afe9 100644 --- a/sim/common/ChangeLog +++ b/sim/common/ChangeLog @@ -1,3 +1,7 @@ +2021-01-12 Mike Frysinger + + * nltvals.def: Regenerate from the latest libgloss sources. + 2021-01-12 Mike Frysinger * sim-profile.h [!WITH_PROFILE]: Rewrite to use #error. diff --git a/sim/common/nltvals.def b/sim/common/nltvals.def index 92ccc9aded8b..60467f343d27 100644 --- a/sim/common/nltvals.def +++ b/sim/common/nltvals.def @@ -605,3 +605,51 @@ /* end pru 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 a48c6966e8ae..5f201060f1c1 100644 --- a/sim/configure.tgt +++ b/sim/configure.tgt @@ -85,6 +85,9 @@ case "${target}" in pru*-*-*) SIM_ARCH(pru) ;; + riscv*-*-*) + SIM_ARCH(riscv) + ;; rl78-*-*) SIM_ARCH(rl78) ;; diff --git a/sim/riscv/ChangeLog b/sim/riscv/ChangeLog new file mode 100644 index 000000000000..f152de1e4646 --- /dev/null +++ b/sim/riscv/ChangeLog @@ -0,0 +1,5 @@ +2021-01-12 Mike Frysinger + + * Makefile.in, configure.ac, interp.c, machs.c, machs.h, + model_list.def, sim-main.c, sim-main.h: New files. + * aclocal.m4, config.in, configure: Regenerated. diff --git a/sim/riscv/Makefile.in b/sim/riscv/Makefile.in new file mode 100644 index 000000000000..17cb288eba3d --- /dev/null +++ b/sim/riscv/Makefile.in @@ -0,0 +1,30 @@ +# Makefile template for Configure for the example basic simulator. +# Copyright (C) 2005-2021 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-resume.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 000000000000..e9f11c775c31 diff --git a/sim/riscv/config.in b/sim/riscv/config.in new file mode 100644 index 000000000000..cb5ea1b01c95 diff --git a/sim/riscv/configure b/sim/riscv/configure new file mode 100755 index 000000000000..8236dc35c12a diff --git a/sim/riscv/configure.ac b/sim/riscv/configure.ac new file mode 100644 index 000000000000..6d5dce917504 --- /dev/null +++ b/sim/riscv/configure.ac @@ -0,0 +1,28 @@ +dnl Process this file with autoconf to produce a configure script. +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_ENVIRONMENT +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 000000000000..1bf60a43aec4 --- /dev/null +++ b/sim/riscv/interp.c @@ -0,0 +1,153 @@ +/* RISC-V simulator. + + Copyright (C) 2005-2021 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" +#include "sim-options.h" + +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); + } +} + +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; + + /* 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 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; +} + +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_ADDR 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 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); + } + + 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 000000000000..853a3afb42f6 --- /dev/null +++ b/sim/riscv/machs.c @@ -0,0 +1,125 @@ +/* RISC-V simulator. + + Copyright (C) 2005-2021 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:rv32", 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:rv64", 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:rv128", 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 000000000000..903488bc7650 --- /dev/null +++ b/sim/riscv/machs.h @@ -0,0 +1,45 @@ +/* RISC-V simulator. + + Copyright (C) 2005-2021 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 000000000000..5efd85ab280f --- /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 000000000000..15a0eb02ae26 --- /dev/null +++ b/sim/riscv/sim-main.c @@ -0,0 +1,1149 @@ +/* RISC-V simulator. + + Copyright (C) 2005-2021 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 "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.time)); + 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.timeh)); + 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) +{ +#ifdef __GNUC__ + return ((__int128)a * b) >> 64; +#else + 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; +#endif +} + +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; + sim_cia pc = cpu->pc + 4; + + dividend_max = -((unsigned_word) 1 << (WITH_TARGET_WORD_BITSIZE - 1)); + + 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[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[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->xlen_requirement == 64) + tmp = sim_core_read_unaligned_8 (cpu, cpu->pc, read_map, cpu->regs[rs1]); + else + tmp = EXTEND32 (sim_core_read_unaligned_4 (cpu, cpu->pc, read_map, + cpu->regs[rs1])); + store_rd (cpu, rd, tmp); + + 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->xlen_requirement == 64) + 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); + + if (op->xlen_requirement == 32) + RISCV_ASSERT_RV32 (cpu, "insn: %s", op->name); + else if (op->xlen_requirement == 64) + RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name); + + switch (op->insn_class) + { + case INSN_CLASS_A: + return execute_a (cpu, iw, op); + case INSN_CLASS_I: + return execute_i (cpu, iw, op); + case INSN_CLASS_M: + return execute_m (cpu, iw, op); + default: + TRACE_INSN (cpu, "UNHANDLED EXTENSION: %d", op->insn_class); + 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; + int xlen = RISCV_XLEN (cpu); + + 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); + + /* NB: Same loop logic as riscv_disassemble_insn. */ + for (; op->name; op++) + { + /* Does the opcode match? */ + if (! op->match_func (op, iw)) + continue; + /* Is this a pseudo-instruction and may we print it as such? */ + if (op->pinfo & INSN_ALIAS) + continue; + /* Is this instruction restricted to a certain value of XLEN? */ + if (op->xlen_requirement != 0 && op->xlen_requirement != xlen) + continue; + + /* It's a match. */ + 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; +} + +/* 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; + + 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 000000000000..4a1b31ee2fec --- /dev/null +++ b/sim/riscv/sim-main.h @@ -0,0 +1,86 @@ +/* RISC-V simulator. + + Copyright (C) 2005-2021 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 "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, ...) 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 (64 * 1024 * 1024) + +#define RISCV_XLEN(cpu) MACH_WORD_BITSIZE (CPU_MACH (cpu)) + +#endif diff --git a/sim/testsuite/ChangeLog b/sim/testsuite/ChangeLog index a32672a46bea..72cfa195542d 100644 --- a/sim/testsuite/ChangeLog +++ b/sim/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2021-01-12 Mike Frysinger + + * configure: Regenerate. + * sim/riscv: New directory. + 2021-01-11 Mike Frysinger * common/alu-tst.c: Include stdlib.h. diff --git a/sim/testsuite/sim/riscv/ChangeLog b/sim/testsuite/sim/riscv/ChangeLog new file mode 100644 index 000000000000..05c42fc7d6e5 --- /dev/null +++ b/sim/testsuite/sim/riscv/ChangeLog @@ -0,0 +1,3 @@ +2021-01-12 Mike Frysinger + + * allinsn.exp, pass.s, 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 000000000000..03bec1b541e7 --- /dev/null +++ b/sim/testsuite/sim/riscv/allinsn.exp @@ -0,0 +1,15 @@ +# RISC-V 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 000000000000..bd428ca16772 --- /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 000000000000..138417009122 --- /dev/null +++ b/sim/testsuite/sim/riscv/testutils.inc @@ -0,0 +1,52 @@ +# MACRO: exit + .macro exit nr + li a0, \nr + # The exit utility function. + li a7, 93; + # Trigger OS trap. + ecall; + .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 -- 2.28.0