From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id TdJZKe/RG2AkeQAAWB0awg (envelope-from ) for ; Thu, 04 Feb 2021 05:52:31 -0500 Received: by simark.ca (Postfix, from userid 112) id 9AEF41EFCB; Thu, 4 Feb 2021 05:52:31 -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 6531D1EF7A for ; Thu, 4 Feb 2021 05:52:26 -0500 (EST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id E7DA138708C8; Thu, 4 Feb 2021 10:52:25 +0000 (GMT) Received: from mail-wm1-x32d.google.com (mail-wm1-x32d.google.com [IPv6:2a00:1450:4864:20::32d]) by sourceware.org (Postfix) with ESMTPS id 9F80B38708C1 for ; Thu, 4 Feb 2021 10:52:18 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 9F80B38708C1 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=embecosm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=andrew.burgess@embecosm.com Received: by mail-wm1-x32d.google.com with SMTP id w4so2696504wmi.4 for ; Thu, 04 Feb 2021 02:52:18 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embecosm.com; s=google; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to; bh=We0Xyzw6f9TiT19rjGENLozpxSErf/21rQfa0RHC0Pw=; b=C3nWRTpoU2c76oxxDg8KeRh7Voeg7NqexSLZ7NUqe38m5UD3MGuo6YzrPNel3pD3/B eQMKQbYSwgSbc03fCy+vQ1pHbsxNTWIRrhRjlGrsXpJwScyySvXN59VBuGTERx2iAQ53 x8jr2jLeHfECI0kZSNvh22KytAOb9wZxRlKoaG9qI1UViZcsDE+LziGqbFvzgk+jtRrX Jz/luLzHO7FugZfXw06BwXWpfFnZgpzyR5gvq5A55n5q5GfYc6oF+wOMLJ56q27Uflek z7Y7Fs+OJWU7z8PDzKc/jVA/2EUThET4g67nEHyrUszo0k3ff4rn+/lIatN7mee9J6/W 5Dbw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to; bh=We0Xyzw6f9TiT19rjGENLozpxSErf/21rQfa0RHC0Pw=; b=XC/uvixZMYvRz/V6jkNDm6UWpPV0LgEwRVZcsyj/t2pHUYIWoqYo/f/FVOdQ30YH6l EAdG69yrpGq+blUqw8+qHNpiazBqBZfn+8RID/ScrSDaYpMFZG9PVrxA43xk5kSdjYsO 5BwBQT4zVvxDRy+B/X/+RGyq9nZunSlj7PkaWMQsG7Cxa/+sfEd7jIbQB6iSU2kf5Z0p W8Twoyr0wIji2mB51p6rjC3ATMx2opiaKwInONfLeySDZ84AlafJgTjaHvd+zdxG/oLv 2lSqJZayu0pp1BaR70k7kh8RfUzx8JKYXoe4UhO+KObuPVQ75x4kfgHWsuhVTUq/r/Ai LlmQ== X-Gm-Message-State: AOAM533Wb5RhjhZNt4/OD0VQrOb7scC6UhLHXw9CLlsGOQ9d8CAk2tBY 56kA/4DC+OdCgfH5UxmaPucmEw== X-Google-Smtp-Source: ABdhPJwjEX9l3hEtcmF/hQP/uYB+m5ov3rw2ekz1dV6sPlJz4iV+i5gLNAcAi2EQXso3mnWHaAOBug== X-Received: by 2002:a1c:730f:: with SMTP id d15mr6820548wmb.135.1612435936988; Thu, 04 Feb 2021 02:52:16 -0800 (PST) Received: from localhost (host109-151-46-64.range109-151.btcentralplus.com. [109.151.46.64]) by smtp.gmail.com with ESMTPSA id e4sm7320274wrw.96.2021.02.04.02.52.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Feb 2021 02:52:16 -0800 (PST) Date: Thu, 4 Feb 2021 10:52:15 +0000 From: Andrew Burgess To: Mike Frysinger Subject: Re: [PATCH 1/2] sim: riscv: new port Message-ID: <20210204105215.GY265215@embecosm.com> References: <20210112111842.17223-1-vapier@gentoo.org> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20210112111842.17223-1-vapier@gentoo.org> X-Operating-System: Linux/5.8.13-100.fc31.x86_64 (x86_64) X-Uptime: 10:45:33 up 57 days, 15:30, X-Editor: GNU Emacs [ http://www.gnu.org/software/emacs ] 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: , Cc: gdb-patches@sourceware.org Errors-To: gdb-patches-bounces@sourceware.org Sender: "Gdb-patches" Mike, Sorry I didn't spot this patch earlier, I just saw it thanks to the recent activity. Thanks for doing this. I've been using this simulator for a while now out of tree. Obviously I could never upstream this as I didn't own the copyright. As Jim mentioned some of my colleagues do have a CGEN simulator, though I don't know what the current state is on that. I've reached out to them to make them aware of your patch. Maybe you could wait a couple more days before committing, just to give them a chance to respond? I haven't tested this patch, but I'm happy to just get this committed for now and bugs can be ironed out afterwards. Thanks, Andrew * Mike Frysinger via Gdb-patches [2021-01-12 06:18:41 -0500]: > --- > 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 >