public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v2 0/3] sim: riscv: Compressed instruction simulation and semi-hosting support
@ 2023-10-30 13:00 jaydeep.patil
  2023-10-30 13:00 ` [PATCH v2 1/3] [sim/riscv] Add basic " jaydeep.patil
                   ` (3 more replies)
  0 siblings, 4 replies; 17+ messages in thread
From: jaydeep.patil @ 2023-10-30 13:00 UTC (permalink / raw)
  To: gdb-patches
  Cc: aburgess, vapier, joseph.faulls, bhushan.attarde, jaydeep.patil

From: Jaydeep Patil <jaydeep.patil@imgtec.com>

Hi Andrew,

Addressed review comments. Simulator specific tests are added in sim/testsuite/riscv/c-ext.s file.

This is a collection of patches that add simulation of compressed integer
instruction set ("c") and semi-hosting support to the RISC-V simulator. Two tests are
added in gdb.arch to test basic semi-hosting and then the simulation of
compressed integer instructions.

Patch #1 adds basic semi-hosting support (OPEN, EXIT and GET_CMDLINE)
and gdb.arch/riscv-exit-getcmd.c test

Patch #2 adds support for compressed integer instruction set ("c")
and gdb.arch/riscv-insn-simulation.c and sim/testsuite/riscv/c-ext.s tests

Patch #3 adds support for remaining semi-hosting calls

Contributions from:
  Joseph Faulls (Joseph.Faulls@imgtec.com)
  Jaydeep Patil (Jaydeep.Patil@imgtec.com)
  Bhushan Attarde (Bhushan.Attarde@imgtec.com)

Jaydeep Patil (3):
  [sim/riscv] Add basic semi-hosting support
  [sim/riscv] Add support for compressed integer instruction set
  [sim/riscv] Add semi-hosting support

 gdb/testsuite/gdb.arch/riscv-exit-getcmd.c    |   26 +
 gdb/testsuite/gdb.arch/riscv-exit-getcmd.exp  |   27 +
 .../gdb.arch/riscv-insn-simulation.c          | 1542 +++++++++++++++++
 .../gdb.arch/riscv-insn-simulation.exp        |   32 +
 sim/riscv/riscv-sim.h                         |   57 +
 sim/riscv/sim-main.c                          | 1050 ++++++++++-
 sim/testsuite/riscv/c-ext.s                   |  110 ++
 7 files changed, 2829 insertions(+), 15 deletions(-)
 create mode 100644 gdb/testsuite/gdb.arch/riscv-exit-getcmd.c
 create mode 100644 gdb/testsuite/gdb.arch/riscv-exit-getcmd.exp
 create mode 100755 gdb/testsuite/gdb.arch/riscv-insn-simulation.c
 create mode 100755 gdb/testsuite/gdb.arch/riscv-insn-simulation.exp
 create mode 100644 sim/testsuite/riscv/c-ext.s

-- 
2.25.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v2 1/3] [sim/riscv] Add basic semi-hosting support
  2023-10-30 13:00 [PATCH v2 0/3] sim: riscv: Compressed instruction simulation and semi-hosting support jaydeep.patil
@ 2023-10-30 13:00 ` jaydeep.patil
  2023-11-29  7:57   ` Mike Frysinger
  2023-12-12 17:57   ` Andrew Burgess
  2023-10-30 13:00 ` [PATCH v2 2/3] [sim/riscv] Add support for compressed integer instruction set jaydeep.patil
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 17+ messages in thread
From: jaydeep.patil @ 2023-10-30 13:00 UTC (permalink / raw)
  To: gdb-patches
  Cc: aburgess, vapier, joseph.faulls, bhushan.attarde, jaydeep.patil

From: Jaydeep Patil <jaydeep.patil@imgtec.com>

Added support for basic semi-hosting calls OPEN, EXIT and GET_CMDLINE.
Added gdb.arch/riscv-exit-getcmd.c to test it.
---
 gdb/testsuite/gdb.arch/riscv-exit-getcmd.c   |  26 +++
 gdb/testsuite/gdb.arch/riscv-exit-getcmd.exp |  27 +++
 sim/riscv/riscv-sim.h                        |  32 +++
 sim/riscv/sim-main.c                         | 230 ++++++++++++++++++-
 4 files changed, 310 insertions(+), 5 deletions(-)
 create mode 100644 gdb/testsuite/gdb.arch/riscv-exit-getcmd.c
 create mode 100644 gdb/testsuite/gdb.arch/riscv-exit-getcmd.exp

diff --git a/gdb/testsuite/gdb.arch/riscv-exit-getcmd.c b/gdb/testsuite/gdb.arch/riscv-exit-getcmd.c
new file mode 100644
index 00000000000..02a97da8643
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/riscv-exit-getcmd.c
@@ -0,0 +1,26 @@
+/* This file is part of GDB, the GNU debugger.
+
+   Copyright 2023 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Test basic semi-hosting calls SYS_GET_CMDLINE and SYS_EXIT.  */
+
+int
+main (int argc, char **argv)
+{
+  if (argc != 4)
+    return 1;
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/riscv-exit-getcmd.exp b/gdb/testsuite/gdb.arch/riscv-exit-getcmd.exp
new file mode 100644
index 00000000000..7f5670200c2
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/riscv-exit-getcmd.exp
@@ -0,0 +1,27 @@
+# Copyright 2023 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test basic semi-hosting calls SYS_GET_CMDLINE and SYS_EXIT.
+
+require {istarget "riscv*-*-*"}
+
+standard_testfile
+
+if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \
+	  {debug quiet}] } {
+    return -1
+}
+
+gdb_test "run 1 2 3" ".*Inferior.*process.*exited normally.*"
diff --git a/sim/riscv/riscv-sim.h b/sim/riscv/riscv-sim.h
index 1bc9aa12156..bb296fa6e62 100644
--- a/sim/riscv/riscv-sim.h
+++ b/sim/riscv/riscv-sim.h
@@ -75,4 +75,36 @@ extern void initialize_env (SIM_DESC, const char * const *argv,
 
 #define RISCV_XLEN(cpu) MACH_WORD_BITSIZE (CPU_MACH (cpu))
 
+#define APPLICATION_EXIT 0x20026
+
+#define SYS_OPEN 0x01
+#define SYS_GET_CMDLINE 0x15
+#define SYS_EXIT 0x18
+
+#define GDB_O_RDONLY 0x000
+#define GDB_O_WRONLY 0x001
+#define GDB_O_RDWR 0x002
+#define GDB_O_APPEND 0x008
+#define GDB_O_CREAT 0x200
+#define GDB_O_TRUNC 0x400
+#define GDB_O_BINARY 0
+
+#define SEMI_HOSTING_SLLI 0x01f01013
+#define SEMI_HOSTING_SRAI 0x40705013
+
+static int gdb_open_modeflags[12] = {
+  GDB_O_RDONLY,
+  GDB_O_RDONLY | GDB_O_BINARY,
+  GDB_O_RDWR,
+  GDB_O_RDWR | GDB_O_BINARY,
+  GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC,
+  GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY,
+  GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC,
+  GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY,
+  GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND,
+  GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY,
+  GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND,
+  GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY
+};
+
 #endif
diff --git a/sim/riscv/sim-main.c b/sim/riscv/sim-main.c
index afdfcf50656..8e08eb9fc4e 100644
--- a/sim/riscv/sim-main.c
+++ b/sim/riscv/sim-main.c
@@ -136,6 +136,176 @@ store_csr (SIM_CPU *cpu, const char *name, int csr, unsigned_word *reg,
   TRACE_REGISTER (cpu, "wrote CSR %s = %#" PRIxTW, name, val);
 }
 
+/* Read 4 or 8 bytes of data from the core memory.  ADDR and (INDEX * XLEN)
+   form the base address.  */
+static uintptr_t
+get_core_data (SIM_CPU *cpu, unsigned_word addr, unsigned_word index)
+{
+  uintptr_t param;
+  int xlen = RISCV_XLEN (cpu);
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+
+  if (xlen == 64)
+    param = sim_core_read_unaligned_8 (cpu, riscv_cpu->pc, read_map,
+		addr + (index * 8));
+  else
+    param = sim_core_read_unaligned_4 (cpu, riscv_cpu->pc, read_map,
+		addr + (index * 4));
+
+  return param;
+}
+
+/* Write string in HOST_BUF at CORE_ADDR.  The length of string is LEN.  */
+static void
+set_core_string (SIM_CPU *cpu, unsigned_word core_addr, char *host_buf,
+		 int len)
+{
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+  for (int i = 0; i < len; i++)
+    {
+      sim_core_write_unaligned_1 (cpu, riscv_cpu->pc, write_map,
+				  core_addr + i, host_buf[i]);
+    }
+}
+
+/* Read string of length LEN at address ADDR.  */
+static char *
+get_core_string_with_len (SIM_CPU *cpu, unsigned_word addr,
+			  unsigned_word len)
+{
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+  char * str;
+  str = (char *) malloc (len + 1);
+
+  for (int i = 0; i < len; i++)
+    {
+      str[i] = sim_core_read_unaligned_1 (cpu, riscv_cpu->pc, read_map,
+					  addr + i);
+    }
+  str[len] = 0;
+
+  return str;
+}
+
+/* SYS_OPEN
+   Register a1 points to a buffer containing:
+   Index 0: Pointer: Address of the file name string.
+   Index 1: Integer: File open flags.
+   Index 2: Integer: Length of the file name string.
+   File handle is returned through register a0.  */
+static void
+semihosting_open (SIM_CPU *cpu)
+{
+  uintptr_t fname_addr;
+  uintptr_t flags;
+  uintptr_t fname_len;
+  char *name;
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+
+  fname_addr = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 0);
+  flags = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 1);
+  fname_len = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 2);
+
+  if (fname_len <= 0)
+    {
+      riscv_cpu->a0 = -1;
+      return;
+    }
+
+  name = get_core_string_with_len (cpu, fname_addr, fname_len);
+  riscv_cpu->a0 = sim_io_open (CPU_STATE (cpu), name,
+			       gdb_open_modeflags[flags]);
+  free (name);
+}
+
+/* SYS_EXIT.  In case of RV32, register a1 holds the application stop reason
+   and the exit code is decided based on it.  Otherwise, register a1 points to
+   a buffer containing:
+   Index 0: Integer: Application stop reason (ignored)
+   Index 1: Integer: Exit code.  */
+static void
+semihosting_exit (SIM_CPU *cpu)
+{
+  uintptr_t app_code, exit_code;
+  SIM_DESC sd = CPU_STATE (cpu);
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+  if (RISCV_XLEN (cpu) == 32)
+    {
+      app_code = riscv_cpu->a1;
+      if (app_code == APPLICATION_EXIT)
+	exit_code = 0;
+      else
+	exit_code = 1;
+    }
+  else
+    exit_code = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 1);
+  riscv_cpu->a0 = exit_code;
+  sim_engine_halt (sd, cpu, NULL, riscv_cpu->pc, sim_exited, exit_code);
+}
+
+/* SYS_GET_CMDLINE.  Write command line arguments to a buffer.  Arguments
+   passed to "run" command are stored in STATE_PROG_ARGV member of SIM_DESC.
+   Register a1 points to a buffer containing:
+   Index 0: Pointer: Buffer to store command line arguments
+   Index 1: Integer: Maximum length of the buffer.  */
+static void
+semihosting_get_cmdline (SIM_CPU *cpu)
+{
+  int i = 0, len = 0, total_len = 0;
+  uintptr_t buf_addr, max_buf_len;
+  SIM_DESC sd = CPU_STATE (cpu);
+  char *space = " ";
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+
+  char **prog_argv = STATE_PROG_ARGV (sd);
+  if (prog_argv == NULL)
+    {
+      riscv_cpu->a0 = 1; /* Return non-zero to indicate error.  */
+      return;
+    }
+
+  buf_addr = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 0);
+  max_buf_len = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 1);
+
+  while (prog_argv[i])
+    {
+      len = strlen (prog_argv[i]);
+      if ((total_len + len) > max_buf_len)
+	break;
+      set_core_string (cpu, buf_addr, prog_argv[i], len);
+      set_core_string (cpu, buf_addr + len, space, 1);
+      len++;	/* Terminate it with space.  */
+      buf_addr += len;
+      total_len += len;
+      i++;
+    }
+  riscv_cpu->a0 = 0;	/* No error.  */
+}
+
+/* Handle semi-hosting calls.  Register a0 contains semi-hosting call number
+   and a1 contains pointer to a buffer containing additional arguments.  */
+static int
+do_semihosting (SIM_CPU *cpu)
+{
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+  switch (riscv_cpu->a0)
+    {
+    case SYS_OPEN:
+      semihosting_open (cpu);
+      break;
+    case SYS_GET_CMDLINE:
+      semihosting_get_cmdline (cpu);
+      break;
+    case SYS_EXIT:
+      semihosting_exit (cpu);
+      break;
+    default:
+      return -1;	/* Semi-hosting call not supported.  */
+    }
+
+  return 0;
+}
+
 static inline unsigned_word
 ashiftrt (unsigned_word val, unsigned_word shift)
 {
@@ -623,11 +793,60 @@ execute_i (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op)
       TRACE_INSN (cpu, "fence.i;");
       break;
     case MATCH_EBREAK:
-      TRACE_INSN (cpu, "ebreak;");
-      /* GDB expects us to step over EBREAK.  */
-      sim_engine_halt (sd, cpu, NULL, riscv_cpu->pc + 4, sim_stopped,
-		       SIM_SIGTRAP);
-      break;
+	{
+	  /* If ebreak is at PC 0 then do not check for semi-hosting.  */
+	  if (riscv_cpu->pc != 0)
+	    {
+	      /* RISC-V semi-hosting call is flagged using these three
+		 instructions
+		 slli zero, zero, 0x1f	0x01f01013
+		 ebreak			0x00100073
+		 srai zero, zero, 0x7	0x40705013
+		 Register a0 holds the system call number and a1 holds the
+		 pointer to parameter buffer.  Do not read 4 bytes in one go
+		 as we might read malformed 4 byte instruction.  */
+	      int iw_len;
+	      sim_cia pre_pc = riscv_cpu->pc - 4;
+	      unsigned_word pre_iw;
+	      pre_iw = sim_core_read_aligned_2 (cpu, pre_pc, exec_map, pre_pc);
+	      iw_len = riscv_insn_length (pre_iw);
+	      if (iw_len == 4)
+		pre_iw |= ((unsigned_word) sim_core_read_aligned_2
+			   (cpu, pre_pc, exec_map, pre_pc + 2) << 16);
+
+	      if (pre_iw == SEMI_HOSTING_SLLI)
+		{
+		  sim_cia post_pc = riscv_cpu->pc + 4;
+		  unsigned_word post_iw;
+		  post_iw = sim_core_read_aligned_2 (cpu, post_pc, exec_map,
+						     post_pc);
+		  iw_len = riscv_insn_length (post_iw);
+		  if (iw_len == 4)
+		    post_iw |= ((unsigned_word) sim_core_read_aligned_2
+				(cpu, post_pc, exec_map, post_pc + 2) << 16);
+
+		  if (post_iw == SEMI_HOSTING_SRAI)
+		    {
+		      TRACE_INSN (cpu, "semi-hosting a0=%lx,a1=%lx;",
+				  riscv_cpu->a0, riscv_cpu->a1);
+		      if (do_semihosting (cpu))
+			{
+			  /* Invalid semi-hosting call.  */
+			  TRACE_INSN (cpu, "ebreak;");
+			  sim_engine_halt (sd, cpu, NULL, riscv_cpu->pc,
+					   sim_stopped, SIM_SIGTRAP);
+			}
+		      else
+			pc = pc + 4;	/* post srai.  */
+		      break;
+		    }
+		}
+	    }
+	  TRACE_INSN (cpu, "ebreak;");
+	  sim_engine_halt (sd, cpu, NULL, riscv_cpu->pc, sim_stopped,
+			   SIM_SIGTRAP);
+	  break;
+	}
     case MATCH_ECALL:
       TRACE_INSN (cpu, "ecall;");
       riscv_cpu->a0 = sim_syscall (cpu, riscv_cpu->a7, riscv_cpu->a0,
@@ -990,6 +1209,7 @@ execute_one (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op)
     case INSN_CLASS_A:
       return execute_a (cpu, iw, op);
     case INSN_CLASS_I:
+    case INSN_CLASS_ZICSR:
       return execute_i (cpu, iw, op);
     case INSN_CLASS_M:
     case INSN_CLASS_ZMMUL:
-- 
2.25.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v2 2/3] [sim/riscv] Add support for compressed integer instruction set
  2023-10-30 13:00 [PATCH v2 0/3] sim: riscv: Compressed instruction simulation and semi-hosting support jaydeep.patil
  2023-10-30 13:00 ` [PATCH v2 1/3] [sim/riscv] Add basic " jaydeep.patil
@ 2023-10-30 13:00 ` jaydeep.patil
  2023-11-29  7:58   ` Mike Frysinger
  2023-10-30 13:00 ` [PATCH v2 3/3] [sim/riscv] Add semi-hosting support jaydeep.patil
  2023-11-13 12:07 ` [PATCH v2 0/3] sim: riscv: Compressed instruction simulation and " Jaydeep Patil
  3 siblings, 1 reply; 17+ messages in thread
From: jaydeep.patil @ 2023-10-30 13:00 UTC (permalink / raw)
  To: gdb-patches
  Cc: aburgess, vapier, joseph.faulls, bhushan.attarde, jaydeep.patil

From: Jaydeep Patil <jaydeep.patil@imgtec.com>

Added support for compressed integer instruction set ("c").
Added gdb.arch/riscv-insn-simulation.c to test it.
Added simulator tests in sim/testsuite/riscv/c-ext.s
---
 .../gdb.arch/riscv-insn-simulation.c          | 1544 +++++++++++++++++
 .../gdb.arch/riscv-insn-simulation.exp        |   31 +
 sim/riscv/riscv-sim.h                         |    4 +
 sim/riscv/sim-main.c                          |  326 +++-
 sim/testsuite/riscv/c-ext.s                   |  110 ++
 5 files changed, 2005 insertions(+), 10 deletions(-)
 create mode 100755 gdb/testsuite/gdb.arch/riscv-insn-simulation.c
 create mode 100755 gdb/testsuite/gdb.arch/riscv-insn-simulation.exp
 create mode 100644 sim/testsuite/riscv/c-ext.s

diff --git a/gdb/testsuite/gdb.arch/riscv-insn-simulation.c b/gdb/testsuite/gdb.arch/riscv-insn-simulation.c
new file mode 100755
index 00000000000..db2b8b4f3d8
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/riscv-insn-simulation.c
@@ -0,0 +1,1544 @@
+/* This file is part of GDB, the GNU debugger.
+
+   Copyright 2023 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+
+#if (__riscv_xlen >= 64)
+#define SKIP_c_flw
+#define SKIP_c_flwsp
+#define SKIP_c_fsw
+#define SKIP_c_fswsp
+#define SKIP_c_jal
+#endif
+
+#if (__riscv_xlen == 32)
+#define SKIP_c_ld
+#define SKIP_c_ldsp
+#define SKIP_c_sd
+#define SKIP_c_sdsp
+#define SKIP_c_addiw
+#define SKIP_c_addw
+#define SKIP_c_subw
+#endif
+
+/* Disable tests that are not implemented in GDB simulator yet.  */
+#define DISABLE_GDB_SIM_TESTS
+
+#if defined (DISABLE_GDB_SIM_TESTS)
+#define SKIP_c_flw
+#define SKIP_c_flwsp
+#define SKIP_c_fsw
+#define SKIP_c_fswsp
+#define SKIP_c_fld
+#define SKIP_c_fldsp
+#define SKIP_c_fsd
+#define SKIP_c_fsdsp
+#endif
+
+#define DISABLE_PRINTS
+
+#if defined (DISABLE_PRINTS)
+#define print(...) ;
+#else
+#define print(format, ...) printf (format, __VA_ARGS__)
+#endif
+
+#if (__riscv_xlen >= 64)
+typedef uint64_t riscv_reg_t;
+#elif (__riscv_xlen == 32)
+typedef uint32_t riscv_reg_t;
+#endif
+
+int total_tests = 0;
+int num_fail = 0;
+int num_pass = 0;
+int debug = 0;
+
+void
+i_check (int line, const char *func, uint32_t value1, uint32_t value2)
+{
+  total_tests++;
+  if (value1 != value2)
+    {
+      print ("  *** FAIL: %s:%d: (%d) != (%d)\n", func, line, value1, value2);
+      num_fail++;
+    }
+  else
+    {
+      num_pass ++;
+      if (debug)
+	print ("  PASS: %s:%d\n", func, line);
+    }
+}
+
+void
+l_check (int line, const char *func, uint64_t value1, uint64_t value2)
+{
+  total_tests++;
+  if (value1 != value2)
+    {
+      print ("  *** FAIL: %s:%d: (0x%lx) != (0x%lx)\n", func, line, value1,
+	     value2);
+      num_fail++;
+    }
+  else
+    {
+      num_pass++;
+      if (debug)
+	print ("  PASS: %s:%d\n", func, line);
+    }
+}
+
+void
+f_check (int line, const char *func, float value1, float value2)
+{
+  total_tests++;
+  if (value1 != value2)
+    {
+      print ("  *** FAIL: %s:%d: (%ff) != (%ff)\n", func, line, value1,
+	     value2);
+      num_fail++;
+    }
+  else
+    {
+      num_pass++;
+      if (debug)
+	print ("  PASS: %s:%d\n", func, line);
+    }
+}
+
+void
+d_check (int line, const char *func, double value1, double value2)
+{
+  total_tests++;
+  if (value1 != value2)
+    {
+      print ("  *** FAIL: %s:%d: (%lf) != (%lf)\n", func, line, value1,
+	     value2);
+      num_fail++;
+    }
+  else
+    {
+      num_pass++;
+      if (debug)
+	print ("  PASS: %s:%d\n", func, line);
+    }
+}
+
+void
+fail (int line, const char *func, const char *msg)
+{
+  total_tests++;
+  print ("  *** FAIL: %s:%d: (%s)\n", func, line, msg);
+  num_fail++;
+}
+
+void
+info (const char *str)
+{
+  print ("%s\n", str);
+}
+
+#define I_CHECK(VAL1, VAL2) i_check (__LINE__, __FUNCTION__, (VAL1), (VAL2));
+#define L_CHECK(VAL1, VAL2) l_check (__LINE__, __FUNCTION__, (VAL1), (VAL2));
+#define F_CHECK(VAL1, VAL2) f_check (__LINE__, __FUNCTION__, (VAL1), (VAL2));
+#define D_CHECK(VAL1, VAL2) d_check (__LINE__, __FUNCTION__, (VAL1), (VAL2));
+#define FAIL(STR) fail (__LINE__, __FUNCTION__, (STR));
+
+void
+test_c_lwsp ()
+{
+  volatile uint32_t on_stack[] = { 0x1111, 0x2222, 0x3333, 0x4444 };
+  uint32_t a = 0, offset = 0;
+  riscv_reg_t stack_ptr, var_ptr;
+
+  info ("Testing c.lwsp");
+
+  /* Find offset of on_stack.  */
+  asm volatile ("c.mv %0,sp" : "=r" (stack_ptr));
+  var_ptr = (riscv_reg_t) &on_stack[0];
+  offset = var_ptr - stack_ptr;
+  (void) offset;
+
+  if (offset == 0)
+    {
+      asm volatile ("c.lwsp %0,0(sp)" : "=r" (a));
+      I_CHECK (a, 0x1111);
+
+      asm volatile ("c.lwsp %0,4(sp)" : "=r" (a));
+      I_CHECK (a, 0x2222);
+
+      asm volatile ("c.lwsp %0,8(sp)" : "=r" (a));
+      I_CHECK (a, 0x3333);
+
+      asm volatile ("c.lwsp %0,12(sp)" : "=r" (a));
+      I_CHECK (a, 0x4444);
+    }
+  else if (offset == 8)
+    {
+      asm volatile ("c.lwsp %0,8(sp)" : "=r" (a));
+      I_CHECK (a, 0x1111);
+
+      asm volatile ("c.lwsp %0,12(sp)" : "=r" (a));
+      I_CHECK (a, 0x2222);
+
+      asm volatile ("c.lwsp %0,16(sp)" : "=r" (a));
+      I_CHECK (a, 0x3333);
+
+      asm volatile ("c.lwsp %0,20(sp)" : "=r" (a));
+      I_CHECK (a, 0x4444);
+    }
+}
+
+void
+test_c_ldsp ()
+{
+#if defined (SKIP_c_ldsp)
+  info ("--- Disable c.ldsp");
+#else
+  volatile uint64_t on_stack[] = { 0x11112222, 0x33334444 };
+  uint64_t a = 0, offset = 0;
+  riscv_reg_t stack_ptr, var_ptr;
+
+  info ("Testing c.ldsp");
+
+  /* Find offset of on_stack.  */
+  asm volatile ("c.mv %0,sp" : "=r" (stack_ptr));
+  var_ptr = (riscv_reg_t) &on_stack[0];
+  offset = var_ptr - stack_ptr;
+  (void) offset;
+
+  asm volatile ("c.ldsp %0,0(sp)" : "=r" (a));
+  L_CHECK (a, 0x11112222ul);
+
+  asm volatile ("c.ldsp %0,8(sp)" : "=r" (a));
+  L_CHECK (a, 0x33334444ul);
+#endif
+}
+
+void
+test_c_flwsp ()
+{
+#if defined (SKIP_c_flwsp)
+  info ("--- Disable c.flwsp");
+#else
+  volatile float on_stack[] = { 1.23f, 3.14f, -5.6f, 10.9f };
+  float a;
+  uint32_t offset = 0;
+  riscv_reg_t stack_ptr, var_ptr;
+
+  info ("Testing c.flwsp");
+
+  /* Find offset of on_stack.  */
+  asm volatile ("c.mv %0,sp" : "=r" (stack_ptr));
+  var_ptr = (riscv_reg_t) &on_stack[0];
+  offset = var_ptr - stack_ptr;
+  (void) offset;
+
+  if (offset == 0)
+    {
+      asm volatile ("c.flwsp %0,0(sp)" : "=f" (a));
+      F_CHECK (a, 1.23f);
+
+      asm volatile ("c.flwsp %0,4(sp)" : "=f" (a));
+      F_CHECK (a, 3.14f);
+
+      asm volatile ("c.flwsp %0,8(sp)" : "=f" (a));
+      F_CHECK (a, -5.6f);
+
+      asm volatile ("c.flwsp %0,12(sp)" : "=f" (a));
+      F_CHECK (a, 10.9f);
+    }
+  else if (offset == 8)
+    {
+      asm volatile ("c.flwsp %0,8(sp)" : "=f" (a));
+      F_CHECK (a, 1.23f);
+
+      asm volatile ("c.flwsp %0,12(sp)" : "=f" (a));
+      F_CHECK (a, 3.14f);
+
+      asm volatile ("c.flwsp %0,16(sp)" : "=f" (a));
+      F_CHECK (a, -5.6f);
+
+      asm volatile ("c.flwsp %0,20(sp)" : "=f" (a));
+      F_CHECK (a, 10.9f);
+    }
+#endif
+}
+
+void
+test_c_fldsp ()
+{
+#if defined (SKIP_c_fldsp)
+  info ("--- Disable c.fldsp");
+#else
+  volatile double on_stack[] = { 1.23, -5.89 };
+  double a = 0;
+  uint32_t offset = 0;
+  riscv_reg_t stack_ptr, var_ptr;
+
+  info ("Testing c.fldsp");
+
+  /* Find offset of on_stack.  */
+  asm volatile ("c.mv %0,sp" : "=r" (stack_ptr));
+  var_ptr = (riscv_reg_t) &on_stack[0];
+  offset = var_ptr - stack_ptr;
+  (void) offset;
+
+  asm volatile ("c.fldsp %0,0(sp)" : "=f" (a));
+  D_CHECK (a, 1.23);
+
+  asm volatile ("c.fldsp %0,8(sp)" : "=f" (a));
+  D_CHECK (a, -5.89);
+#endif
+}
+
+void
+test_c_swsp ()
+{
+  volatile uint32_t on_stack[] = { 0x1111, 0x2222, 0x3333, 0x4444 };
+  uint32_t a, offset = 0;
+  riscv_reg_t stack_ptr, var_ptr;
+
+  info ("Testing c.swsp");
+
+  /* Find offset of on_stack.  */
+  asm volatile ("c.mv %0,sp" : "=r" (stack_ptr));
+  var_ptr = (riscv_reg_t) &on_stack[0];
+  offset = var_ptr - stack_ptr;
+
+  if (offset == 0)
+    {
+      a = 0xbeef;
+      asm volatile ("c.swsp %0,0(sp)" : : "r" (a));
+
+      a = 0xdead;
+      asm volatile ("c.swsp %0,4(sp)" : : "r" (a));
+
+      a = 0xabcd;
+      asm volatile ("c.swsp %0,8(sp)" : : "r" (a));
+
+      a = 0x1298;
+      asm volatile ("c.swsp %0,12(sp)" : : "r" (a));
+    }
+  else if (offset == 8)
+    {
+      a = 0xbeef;
+      asm volatile ("c.swsp %0,8(sp)" : : "r" (a));
+
+      a = 0xdead;
+      asm volatile ("c.swsp %0,12(sp)" : : "r" (a));
+
+      a = 0xabcd;
+      asm volatile ("c.swsp %0,16(sp)" : : "r" (a));
+
+      a = 0x1298;
+      asm volatile ("c.swsp %0,20(sp)" : : "r" (a));
+    }
+  else
+    {
+      FAIL ("Invalid stack offset (expected 0 or 8)");
+      return;
+    }
+
+  I_CHECK (on_stack[0], 0xbeef);
+  I_CHECK (on_stack[1], 0xdead);
+  I_CHECK (on_stack[2], 0xabcd);
+  I_CHECK (on_stack[3], 0x1298);
+}
+
+void
+test_c_sdsp ()
+{
+#if defined (SKIP_c_sdsp)
+  info ("--- Disable c.sdsp");
+#else
+  volatile uint64_t on_stack[] = { 0x11112222, 0x33334444 };
+  uint64_t a = 0, offset = 0;
+  riscv_reg_t stack_ptr, var_ptr;
+
+  info ("Testing c.sdsp");
+
+  /* Find offset of on_stack.  */
+  asm volatile ("c.mv %0,sp" : "=r" (stack_ptr));
+  var_ptr = (riscv_reg_t) &on_stack[0];
+  offset = var_ptr - stack_ptr;
+  (void) offset;
+
+  a = 0xdeadbeef;
+  asm volatile ("c.sdsp %0,0(sp)" : : "r" (a));
+
+  a = 0xabcd1234;
+  asm volatile ("c.sdsp %0,8(sp)" : : "r" (a));
+
+  L_CHECK (on_stack[0], 0xdeadbeef);
+  L_CHECK (on_stack[1], 0xabcd1234);
+#endif
+}
+
+void
+test_c_fswsp ()
+{
+#if defined (SKIP_c_fswsp)
+  info ("--- Disable c.fswsp");
+#else
+  volatile float on_stack[] = { 1.23f, 3.14f, -5.6f, 10.9f };
+  float a;
+  uint32_t offset = 0;
+  riscv_reg_t stack_ptr, var_ptr;
+
+  info ("Testing c.fswsp");
+
+  /* Find offset of on_stack.  */
+  asm volatile ("c.mv %0,sp" : "=r" (stack_ptr));
+  var_ptr = (riscv_reg_t) &on_stack[0];
+  offset = var_ptr - stack_ptr;
+  (void) offset;
+
+  if (offset == 0)
+    {
+      a = -12.5f;
+      asm volatile ("c.fswsp %0,0(sp)" : : "f" (a));
+
+      a = 72.8f;
+      asm volatile ("c.fswsp %0,4(sp)" : "=f" (a));
+
+      a = 0.5f;
+      asm volatile ("c.fswsp %0,8(sp)" : "=f" (a));
+
+      a = 4.7f;
+      asm volatile ("c.fswsp %0,12(sp)" : "=f" (a));
+
+    }
+  else if (offset == 8)
+    {
+      a = -12.5f;
+      asm volatile ("c.fswsp %0,8(sp)" : "=f" (a));
+
+      a = 72.8f;
+      asm volatile ("c.fswsp %0,12(sp)" : "=f" (a));
+
+      a = 0.5f;
+      asm volatile ("c.fswsp %0,16(sp)" : "=f" (a));
+
+      a = 4.7f;
+      asm volatile ("c.fswsp %0,20(sp)" : "=f" (a));
+    }
+  else
+    {
+      FAIL ("Invalid stack offset (expected 0 or 8)");
+      return;
+    }
+
+  F_CHECK (on_stack[0], -12.5f);
+  F_CHECK (on_stack[1], 72.8f);
+  F_CHECK (on_stack[2], 0.5f);
+  F_CHECK (on_stack[3], 4.7f);
+
+#endif
+}
+
+void
+test_c_fsdsp ()
+{
+#if defined (SKIP_c_fsdsp)
+  info ("--- Disable c.fsdsp");
+#else
+  volatile double on_stack[] = { -1.23, 5.89 };
+  double a = 0;
+  uint32_t offset = 0;
+  riscv_reg_t stack_ptr, var_ptr;
+
+  info ("Testing c.fsdsp");
+
+  /* Find offset of on_stack.  */
+  asm volatile ("c.mv %0,sp" : "=r" (stack_ptr));
+  var_ptr = (riscv_reg_t) &on_stack[0];
+  offset = var_ptr - stack_ptr;
+  (void) offset;
+
+  a = 1234.55;
+  asm volatile ("c.fsdsp %0,0(sp)" : : "f" (a));
+
+  a = -7890.15;
+  asm volatile ("c.fsdsp %0,8(sp)" : : "f" (a));
+
+  D_CHECK (on_stack[0], 1234.55);
+  D_CHECK (on_stack[1], -7890.15);
+#endif
+}
+
+void
+test_c_lw ()
+{
+  static uint32_t g_data[] = { 0x1111, 0x2222, 0x3333, 0x4444 };
+  uint32_t a = 0;
+  riscv_reg_t var_ptr;
+
+  info ("Testing c.lw");
+
+  var_ptr = (riscv_reg_t) &g_data[0];
+
+  asm volatile ("c.lw %0,0(%1)" : "=r" (a) : "r" (var_ptr));
+  I_CHECK (a, 0x1111);
+
+  asm volatile ("c.lw %0,4(%1)" : "=r" (a) : "r" (var_ptr));
+  I_CHECK (a, 0x2222);
+
+  asm volatile ("c.lw %0,8(%1)" : "=r" (a) : "r" (var_ptr));
+  I_CHECK (a, 0x3333);
+
+  asm volatile ("c.lw %0,12(%1)" : "=r" (a) : "r" (var_ptr));
+  I_CHECK (a, 0x4444);
+}
+
+void
+test_c_ld ()
+{
+#if defined (SKIP_c_ld)
+  info ("--- Disable c.ld");
+#else
+  static uint64_t g_data[] = { 0x11112222, 0x33334444 };
+  uint32_t a = 0;
+  riscv_reg_t var_ptr;
+
+  info ("Testing c.ld");
+
+  var_ptr = (riscv_reg_t) &g_data[0];
+
+  asm volatile ("c.ld %0,0(%1)" : "=r" (a) : "r" (var_ptr));
+  L_CHECK (a, 0x11112222);
+
+  asm volatile ("c.ld %0,8(%1)" : "=r" (a) : "r" (var_ptr));
+  L_CHECK (a, 0x33334444);
+#endif
+}
+
+void
+test_c_flw ()
+{
+#if defined (SKIP_c_flw)
+  info ("--- Disable c.flw");
+#else
+  static float g_data[] = { 1.23f, 3.14f, -5.6f, 10.9f };
+  float a = 0;
+  riscv_reg_t var_ptr;
+
+  info ("Testing c.flw");
+
+  var_ptr = (riscv_reg_t) &g_data[0];
+
+  asm volatile ("c.flw %0,0(%1)" : "=f" (a) : "r" (var_ptr));
+  F_CHECK (a, 1.23f);
+
+  asm volatile ("c.flw %0,4(%1)" : "=f" (a) : "r" (var_ptr));
+  F_CHECK (a, 3.14f);
+
+  asm volatile ("c.flw %0,8(%1)" : "=f" (a) : "r" (var_ptr));
+  F_CHECK (a, -5.6f);
+
+  asm volatile ("c.flw %0,12(%1)" : "=f" (a) : "r" (var_ptr));
+  F_CHECK (a, 10.9f);
+#endif
+}
+
+void
+test_c_fld ()
+{
+#if defined (SKIP_c_fld)
+  info ("--- Disable c.fld");
+#else
+  static double g_data[] = { 1234.5, -7890.4 };
+  double a = 0;
+  riscv_reg_t var_ptr;
+
+  info ("Testing c.fld");
+
+  var_ptr = (riscv_reg_t) &g_data[0];
+
+  asm volatile ("c.fld %0,0(%1)" : "=f" (a) : "r" (var_ptr));
+  D_CHECK (a, 1234.5);
+
+  asm volatile ("c.fld %0,8(%1)" : "=f" (a) : "r" (var_ptr));
+  D_CHECK (a, -7890.4);
+#endif
+}
+
+void
+test_c_sw ()
+{
+  volatile uint32_t g_data[] = { 0x1111, 0x2222, 0x3333, 0x4444 };
+  uint32_t a;
+  riscv_reg_t stack_ptr, var_ptr;
+
+  info ("Testing c.sw");
+
+  var_ptr = (riscv_reg_t) &g_data[0];
+
+  a = 0xbeef;
+  asm volatile ("c.sw %0,0(%1)" : : "r" (a), "r" (var_ptr));
+
+  a = 0xdead;
+  asm volatile ("c.sw %0,4(%1)" : : "r" (a), "r" (var_ptr));
+
+  a = 0xabcd;
+  asm volatile ("c.sw %0,8(%1)" : : "r" (a), "r" (var_ptr));
+
+  a = 0x1298;
+  asm volatile ("c.sw %0,12(%1)" : : "r" (a), "r" (var_ptr));
+
+  I_CHECK (g_data[0], 0xbeef);
+  I_CHECK (g_data[1], 0xdead);
+  I_CHECK (g_data[2], 0xabcd);
+  I_CHECK (g_data[3], 0x1298);
+}
+
+void
+test_c_sd ()
+{
+#if defined (SKIP_c_sd)
+  info ("--- Disable c.sd");
+#else
+  volatile uint64_t g_data[] = { 0x1111, 0x2222, 0x3333, 0x4444 };
+  uint64_t a;
+  riscv_reg_t var_ptr;
+
+  info ("Testing c.sd");
+
+  var_ptr = (riscv_reg_t) &g_data[0];
+
+  a = 0xbeefdead;
+  asm volatile ("c.sd %0,0(%1)" : : "r" (a), "r" (var_ptr));
+
+  a = 0xabcd1298;
+  asm volatile ("c.sd %0,8(%1)" : : "r" (a), "r" (var_ptr));
+
+  L_CHECK (g_data[0], 0xbeefdead);
+  L_CHECK (g_data[1], 0xabcd1298);
+#endif
+}
+
+void
+test_c_fsw ()
+{
+#if defined (SKIP_c_fsw)
+  info ("--- Disable c.fsw");
+#else
+  volatile float g_data[] = { 1.0f, 2.0f, 3.0f, -4.0f };
+  float a;
+  riscv_reg_t stack_ptr, var_ptr;
+
+  info ("Testing c.fsw");
+
+  var_ptr = (riscv_reg_t) &g_data[0];
+
+  a = 12.5f;
+  asm volatile ("c.fsw %0,0(%1)" : : "f" (a), "r" (var_ptr));
+
+  a = -7.9f;
+  asm volatile ("c.fsw %0,4(%1)" : : "f" (a), "r" (var_ptr));
+
+  a = 123.4f;
+  asm volatile ("c.fsw %0,8(%1)" : : "f" (a), "r" (var_ptr));
+
+  a = 0.5f;
+  asm volatile ("c.fsw %0,12(%1)" : : "f" (a), "r" (var_ptr));
+
+  F_CHECK (g_data[0], 12.5f);
+  F_CHECK (g_data[1], -7.9f);
+  F_CHECK (g_data[2], 123.4f);
+  F_CHECK (g_data[3], 0.5f);
+#endif
+}
+
+void
+test_c_fsd ()
+{
+#if defined (SKIP_c_fsd)
+  info ("--- Disable c.fsd");
+#else
+  volatile double g_data[] = { 1.0, 2.0 };
+  double a;
+  riscv_reg_t stack_ptr, var_ptr;
+
+  info ("Testing c.fsd");
+
+  var_ptr = (riscv_reg_t) &g_data[0];
+
+  a = 1234.5;
+  asm volatile ("c.fsd %0,0(%1)" : : "f" (a), "r" (var_ptr));
+
+  a = -7892.9;
+  asm volatile ("c.fsd %0,8(%1)" : : "f" (a), "r" (var_ptr));
+
+  F_CHECK (g_data[0], 1234.5);
+  F_CHECK (g_data[1], -7892.9);
+
+#endif
+}
+
+void
+test_c_j ()
+{
+  volatile int a = 0, b = 5;
+
+  info ("Testing c.j");
+
+label_b:
+  /* If we have jumped back.  */
+  if (a == 7 && b == 5)
+    return;
+
+  asm goto ("c.j %l[label_f]" : : : : label_f);
+  asm volatile ("c.mv %0, %1" : "=r" (a) : "r" (b));
+
+  FAIL ("Jumped at wrong location");
+  return;
+
+label_f:
+
+  I_CHECK (a, 0);
+  I_CHECK (b, 5);
+
+  a = 7;
+  asm goto ("c.j %l[label_b]" : : : : label_b);
+  asm volatile ("c.mv %0, %1" : "=r" (a) : "r" (b));
+}
+
+void
+test_c_jal ()
+{
+#if defined (SKIP_c_jal)
+  info ("--- Disable c.jal");
+#else
+  volatile int a = 0, b = 5;
+  riscv_reg_t ra;
+
+  info ("Testing c.jal");
+
+label_b:
+  /* If we have jumped back.  */
+  if (a == 7 && b == 5)
+    {
+      asm volatile ("c.mv %0, ra" : "=r" (ra));
+      L_CHECK (ra, (riscv_reg_t) &&ret_label_2);
+      return;
+    }
+
+  asm goto ("c.jal %l[label_f]" : : : : label_f);
+ret_label_1:
+  asm volatile ("c.mv %0, %1" : "=r" (a) : "r" (b));
+
+  FAIL ("Jumped at wrong location");
+  return;
+
+label_f:
+  asm volatile ("c.mv %0, ra" : "=r" (ra));
+
+  L_CHECK (ra, (riscv_reg_t) &&ret_label_1);
+  I_CHECK (a, 0);
+  I_CHECK (b, 5);
+
+  /* Jump back.  */
+  a = 7;
+  asm goto ("c.jal %l[label_b]" : : : : label_b);
+ret_label_2:
+  asm volatile ("c.nop");
+#endif
+}
+
+void
+test_c_jr ()
+{
+  volatile int a = 0, b = 5;
+  riscv_reg_t addr;
+
+  info ("Testing c.jr");
+
+  addr = (riscv_reg_t) &&label_f;
+
+label_b:
+  /* If we have jumped back.  */
+  if (a == 7 && b == 5)
+    return;
+
+  asm volatile ("c.jr %0" : : "r" (addr));
+  asm volatile ("c.mv %0, %1" : "=r" (a) : "r" (b));
+
+  FAIL ("Jumped at wrong location");
+
+label_f:
+  I_CHECK(a, 0);
+  I_CHECK(b, 5);
+
+  a = 7;
+  addr = (riscv_reg_t) &&label_b;
+  asm volatile ("c.jr %0" : : "r" (addr));
+
+  FAIL ("Jumped at wrong location");
+}
+
+void
+test_c_jalr ()
+{
+  volatile int a = 0, b = 5;
+  riscv_reg_t addr, ra;
+
+  info ("Testing c.jalr");
+
+  addr = (riscv_reg_t) &&label_f;
+
+label_b:
+  /* If we have jumped back.  */
+  if (a == 7)
+    {
+      asm volatile ("c.mv %0, ra" : "=r" (ra));
+      L_CHECK (ra, (riscv_reg_t) &&label_ra_2);
+      return;
+    }
+
+  asm volatile ("c.jalr %0" : : "r" (addr));
+label_ra_1:
+  asm volatile ("c.nop");
+  asm volatile ("c.mv %0, %1" : "=r" (a) : "r" (b));
+
+  FAIL ("Jumped at wrong location");
+
+label_f:
+  asm volatile ("c.mv %0, ra" : "=r" (ra));
+
+  L_CHECK (ra, (riscv_reg_t) &&label_ra_1);
+  I_CHECK (a, 0);
+  I_CHECK (b, 5);
+
+  a = 7;
+  addr = (riscv_reg_t) &&label_b;
+  asm volatile ("c.jalr %0" : : "r" (addr));
+label_ra_2:
+  asm volatile ("c.nop");
+
+  FAIL ("Jumped at wrong location");
+}
+
+void
+test_c_beqz ()
+{
+  volatile int zero = 0, non_zero = 1;
+  int a = 0, b = 5;
+
+  info ("Testing c.beqz");
+
+label_b_1:
+  /* If we have branched back.  */
+  if (a == 17)
+    {
+      I_CHECK (b, 8);
+      if (b != 8)
+	FAIL ("Backward-taken branch failed");
+      return;
+    }
+
+  asm goto ("c.beqz %0, %l[label_f_1]"
+	    : : "r" (zero) : : label_f_1);	/* Forward taken.  */
+  asm volatile ("c.li %0, 7" : "=r" (a));
+  asm volatile ("c.li %0, 8" : "=r" (b));
+
+label_f_1:
+  I_CHECK (a, 0);
+  I_CHECK (b, 5);
+  if (a != 0 || b != 5)
+    {
+      FAIL ("Forward-taken branch failed");
+      return;
+    }
+
+  asm goto ("c.beqz %0, %l[label_f_2]"
+	    :
+	    : "r" (non_zero)
+	    :
+	    : label_f_2);	/* Not taken.  */
+
+  a = 7;
+  b = 8;
+
+label_f_2:
+  I_CHECK (a, 7);
+  I_CHECK (b, 8);
+  if (a != 7 || b != 8)
+    {
+      FAIL ("Not-taken branch failed");
+      return;
+    }
+
+  /* Branch back.  */
+  a = 17;
+  asm goto ("c.beqz %0, %l[label_b_1]"
+	    :
+	    : "r" (zero)
+	    :
+	    : label_b_1);	/* Backward taken.  */
+
+  FAIL ("Backward-taken branch failed");
+}
+
+void
+test_c_bnez ()
+{
+  volatile int zero = 0, non_zero = 1;
+  int a = 0, b = 5;
+
+  info ("Testing c.bnez");
+
+label_b_1:
+  /* If we have branched back.  */
+  if (a == 17)
+    {
+      if (b != 8)
+	FAIL ("Backward-taken branch failed");
+      return;
+    }
+
+  asm goto ("c.bnez %0, %l[label_f_1]"
+	    :
+	    : "r" (non_zero)
+	    :
+	    : label_f_1);	/* Forward taken.  */
+  asm volatile ("c.li %0, 7" : "=r" (a));
+  asm volatile ("c.li %0, 8" : "=r" (b));
+
+label_f_1:
+  if (a != 0 || b != 5)
+    {
+      FAIL ("Forward-taken branch failed");
+      num_fail++;
+      return;
+    }
+
+  asm goto ("c.bnez %0, %l[label_f_2]"
+	    :
+	    : "r" (zero)
+	    :
+	    : label_f_2);	/* Not taken.  */
+  a = 7;
+  b = 8;
+
+label_f_2:
+  if (a != 7 || b != 8)
+    {
+      FAIL ("Not-taken branch failed");
+      num_fail++;
+      return;
+    }
+
+  /* Branch back.  */
+  a = 17;
+  asm goto ("c.bnez %0, %l[label_b_1]"
+	    :
+	    : "r" (non_zero)
+	    :
+	    : label_b_1);	/* Backward taken.  */
+
+  FAIL ("backward-taken branch failed");
+  num_fail++;
+}
+
+void
+test_c_li ()
+{
+  riscv_reg_t a, b, c;
+
+  info ("Testing c.li");
+
+  asm volatile ("c.li %0,0" : "=r" (a));
+  asm volatile ("c.li %0,-1" : "=r" (b));
+  asm volatile ("c.li %0,31" : "=r" (c));
+
+#if (__riscv_xlen >= 64)
+  L_CHECK (a, 0);
+  L_CHECK (b, -1);
+  L_CHECK (c, 31);
+#else
+  I_CHECK (a, 0);
+  I_CHECK (b, -1);
+  I_CHECK (c, 31);
+#endif
+}
+
+void
+test_c_lui ()
+{
+  int a = 0;
+
+  info ("Testing c.lui");
+
+  asm volatile ("c.lui %0,1" : "=r" (a));
+  I_CHECK (a, 0x1000);
+
+  asm volatile ("c.lui %0,31" : "=r" (a));
+  I_CHECK (a, 0x1F000);
+}
+
+void
+test_c_addi ()
+{
+  int a = 0;
+
+  info ("Testing c.addi");
+
+  asm volatile ("c.addi %0,1" : "+r" (a));
+  I_CHECK (a, 1);
+
+  asm volatile ("c.addi %0,-1" : "+r" (a));
+  I_CHECK (a, 0);
+
+  asm volatile ("c.addi %0,31" : "+r" (a));
+  I_CHECK (a, 31);
+}
+
+void
+test_c_addiw ()
+{
+#if defined (SKIP_c_addiw)
+  info ("--- Disable c.addiw");
+#else
+  int a = 1;
+
+  info ("Testing c.addiw");
+
+  asm volatile ("c.addiw %0,0" : "+r" (a));
+  I_CHECK (a, 1);
+
+  asm volatile ("c.addiw %0,-1" : "+r" (a));
+  I_CHECK (a, 0);
+
+  asm volatile ("c.addiw %0,31" : "+r" (a));
+  I_CHECK (a, 31);
+#endif
+}
+
+void
+test_c_addi16sp ()
+{
+  volatile riscv_reg_t orig_sp, sp_1, sp_2;
+
+  info ("Testing c.addi16sp");
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated"
+  asm volatile ("\
+		c.mv %0, sp		\n\
+		c.addi16sp sp,32	\n\
+		c.mv %1, sp		\n\
+		c.addi16sp sp,-32	\n\
+		c.mv %2, sp		\n\
+		c.mv sp, %0"	/* Restore sp.  */
+		: "=r" (orig_sp), "=r" (sp_1), "=r" (sp_2)
+		: "r" (orig_sp)
+		: "sp");
+#pragma GCC diagnostic pop
+
+#if (__riscv_xlen >= 64)
+  L_CHECK (orig_sp, sp_2);
+  L_CHECK ((sp_1 - sp_2), 32);
+#else
+  I_CHECK (orig_sp, sp_2);
+  I_CHECK ((sp_1 - sp_2), 32);
+#endif
+}
+
+void
+test_c_addi4spn ()
+{
+  volatile riscv_reg_t orig_sp, sp_1, sp_2;
+
+  info ("Testing c.addi4spn");
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated"
+  asm volatile ("\
+		c.mv %0, sp		\n\
+		c.addi4spn %1,sp,16	\n\
+		c.addi4spn %2,sp,32"
+		: "=r" (orig_sp), "=r" (sp_1), "=r" (sp_2)
+		: "r" (orig_sp)
+		: "sp");
+#pragma GCC diagnostic pop
+
+#if (__riscv_xlen >= 64)
+  L_CHECK ((orig_sp + 16), sp_1);
+  L_CHECK ((orig_sp + 32), sp_2);
+#else
+  I_CHECK ((orig_sp + 16), sp_1);
+  I_CHECK ((orig_sp + 32), sp_2);
+#endif
+}
+
+void
+test_c_slli ()
+{
+  volatile riscv_reg_t val = -5, r1, r2, r3;
+
+  info ("Testing c.slli");
+
+  asm volatile ("c.slli %0,1" : "+r" (val));
+  asm volatile ("c.mv %0,%1" : "=r" (r1) : "r" (val));
+  asm volatile ("c.slli %0,2" : "+r" (val));
+  asm volatile ("c.mv %0,%1" : "=r" (r2) : "r" (val));
+  asm volatile ("c.slli %0,3" : "+r" (val));
+  asm volatile ("c.mv %0,%1" : "=r" (r3) : "r" (val));
+  asm volatile ("c.slli %0,4" : "+r" (val));
+
+#if (__riscv_xlen >= 64)
+  L_CHECK (r1, -10);
+  L_CHECK (r2, -40);
+  L_CHECK (r3, -320);
+  L_CHECK (val, -5120);
+#else
+  I_CHECK (r1, -10);
+  I_CHECK (r2, -40);
+  I_CHECK (r3, -320);
+  I_CHECK (val, -5120);
+#endif
+
+  val = 5;
+  asm volatile ("c.slli %0,1" : "+r" (val));
+  asm volatile ("c.mv %0,%1" : "=r" (r1) : "r" (val));
+  asm volatile ("c.slli %0,2" : "+r" (val));
+  asm volatile ("c.mv %0,%1" : "=r" (r2) : "r" (val));
+  asm volatile ("c.slli %0,3" : "+r" (val));
+  asm volatile ("c.mv %0,%1" : "=r" (r3) : "r" (val));
+  asm volatile ("c.slli %0,4" : "+r" (val));
+
+#if (__riscv_xlen >= 64)
+  L_CHECK (r1, 10);
+  L_CHECK (r2, 40);
+  L_CHECK (r3, 320);
+  L_CHECK (val, 5120);
+#else
+  I_CHECK (r1, 10);
+  I_CHECK (r2, 40);
+  I_CHECK (r3, 320);
+  I_CHECK (val, 5120);
+#endif
+}
+
+void
+test_c_srli ()
+{
+  volatile riscv_reg_t val = -105, r1, r2, r3;
+
+  info ("Testing c.srli");
+
+  asm volatile ("c.srli %0,1" : "+r" (val));
+  asm volatile ("c.mv %0,%1" : "=r" (r1) : "r" (val));
+  asm volatile ("c.srli %0,2" : "+r" (val));
+  asm volatile ("c.mv %0,%1" : "=r" (r2) : "r" (val));
+  asm volatile ("c.srli %0,3" : "+r" (val));
+  asm volatile ("c.mv %0,%1" : "=r" (r3) : "r" (val));
+  asm volatile ("c.srli %0,4" : "+r" (val));
+
+#if (__riscv_xlen >= 64)
+  L_CHECK (r1, 0x7fffffffffffffcbul);
+  L_CHECK (r2, 0x1ffffffffffffff2ul);
+  L_CHECK (r3, 0x3fffffffffffffeul);
+  L_CHECK (val, 0x3ffffffffffffful);
+#else
+  I_CHECK (r1, 0x7fffffcb);
+  I_CHECK (r2, 0x1ffffff2);
+  I_CHECK (r3, 0x3fffffe);
+  I_CHECK (val, 0x3fffff);
+#endif
+
+  val = 105;
+  asm volatile ("c.srli %0,1" : "+r" (val));
+  asm volatile ("c.mv %0,%1" : "=r" (r1) : "r" (val));
+  asm volatile ("c.srli %0,2" : "+r" (val));
+  asm volatile ("c.mv %0,%1" : "=r" (r2) : "r" (val));
+  asm volatile ("c.srli %0,3" : "+r" (val));
+  asm volatile ("c.mv %0,%1" : "=r" (r3) : "r" (val));
+  asm volatile ("c.srli %0,4" : "+r" (val));
+
+#if (__riscv_xlen >= 64)
+  L_CHECK (r1, 52);
+  L_CHECK (r2, 13);
+  L_CHECK (r3, 1);
+  L_CHECK (val, 0);
+#else
+  I_CHECK (r1, 52);
+  I_CHECK (r2, 13);
+  I_CHECK (r3, 1);
+  I_CHECK (val, 0);
+#endif
+}
+
+void
+test_c_srai ()
+{
+  volatile riscv_reg_t val = -105, r1, r2, r3;
+
+  info ("Testing c.srai");
+
+  asm volatile ("c.srai %0,1" : "+r" (val));
+  asm volatile ("c.mv %0,%1" : "=r" (r1) : "r" (val));
+  asm volatile ("c.srai %0,2" : "+r" (val));
+  asm volatile ("c.mv %0,%1" : "=r" (r2) : "r" (val));
+  asm volatile ("c.srai %0,3" : "+r" (val));
+  asm volatile ("c.mv %0,%1" : "=r" (r3) : "r" (val));
+  asm volatile ("c.srai %0,4" : "+r" (val));
+
+#if (__riscv_xlen >= 64)
+  L_CHECK (r1, -53);
+  L_CHECK (r2, -14);
+  L_CHECK (r3, -2);
+  L_CHECK (val, -1);
+#else
+  I_CHECK (r1, -53);
+  I_CHECK (r2, -14);
+  I_CHECK (r3, -2);
+  I_CHECK (val, -1);
+#endif
+
+  val = 105;
+  asm volatile ("c.srai %0,1" : "+r" (val));
+  asm volatile ("c.mv %0,%1" : "=r" (r1) : "r" (val));
+  asm volatile ("c.srai %0,2" : "+r" (val));
+  asm volatile ("c.mv %0,%1" : "=r" (r2) : "r" (val));
+  asm volatile ("c.srai %0,3" : "+r" (val));
+  asm volatile ("c.mv %0,%1" : "=r" (r3) : "r" (val));
+  asm volatile ("c.srai %0,4" : "+r" (val));
+
+#if (__riscv_xlen >= 64)
+  L_CHECK (r1, 52);
+  L_CHECK (r2, 13);
+  L_CHECK (r3, 1);
+  L_CHECK (val, 0);
+#else
+  I_CHECK (r1, 52);
+  I_CHECK (r2, 13);
+  I_CHECK (r3, 1);
+  I_CHECK (val, 0);
+#endif
+}
+
+void
+test_c_andi ()
+{
+  riscv_reg_t val1 = -1, val2 = 0x101;
+
+  info ("Testing c.andi");
+
+  asm volatile ("c.andi %0,5" : "+r" (val1));
+  asm volatile ("c.andi %0,7" : "+r" (val2));
+
+#if (__riscv_xlen >= 64)
+  L_CHECK (val1, 5);
+  L_CHECK (val2, 1);
+#else
+  I_CHECK (val1, 5);
+  I_CHECK (val2, 1);
+#endif
+}
+
+void
+test_c_add ()
+{
+  riscv_reg_t dst, rs2;
+
+  info ("Testing c.add");
+
+  dst = -1;
+  rs2 = 1;
+  asm volatile ("c.add %0,%1" : "+r" (dst) : "r" (rs2));
+
+#if (__riscv_xlen >= 64)
+  L_CHECK (dst, 0);
+  L_CHECK (rs2, 1);
+#else
+  I_CHECK (dst, 0);
+  I_CHECK (rs2, 1);
+#endif
+
+  dst = -1;
+  rs2 = 0;
+  asm volatile ("c.add %0,%1" : "+r" (dst) : "r" (rs2));
+
+#if (__riscv_xlen >= 64)
+  L_CHECK (dst, -1);
+  L_CHECK (rs2, 0);
+#else
+  I_CHECK (dst, -1);
+  I_CHECK (rs2, 0);
+#endif
+}
+
+void
+test_c_and ()
+{
+  riscv_reg_t dst, rs2;
+
+  info ("Testing c.and");
+
+  dst = -1;
+  rs2 = 1;
+  asm volatile ("c.and %0,%1" : "+r" (dst) : "r" (rs2));
+
+#if (__riscv_xlen >= 64)
+  L_CHECK (dst, 1);
+  L_CHECK (rs2, 1);
+#else
+  I_CHECK (dst, 1);
+  I_CHECK (rs2, 1);
+#endif
+
+  dst = -1;
+  rs2 = 0;
+  asm volatile ("c.and %0,%1" : "+r" (dst) : "r" (rs2));
+
+#if (__riscv_xlen >= 64)
+  L_CHECK (dst, 0);
+  L_CHECK (rs2, 0);
+#else
+  I_CHECK (dst, 0);
+  I_CHECK (rs2, 0);
+#endif
+}
+
+void
+test_c_or ()
+{
+  riscv_reg_t dst, rs2;
+
+  info ("Testing c.or");
+
+  dst = -3;
+  rs2 = 2;
+  asm volatile ("c.or %0,%1" : "+r" (dst) : "r" (rs2));
+
+#if (__riscv_xlen >= 64)
+  L_CHECK (dst, -1);
+  L_CHECK (rs2, 2);
+#else
+  I_CHECK (dst, -1);
+  I_CHECK (rs2, 2);
+#endif
+
+  dst = 0x7ffffffd;
+  rs2 = 0x80000002;
+  asm volatile ("c.or %0,%1" : "+r" (dst) : "r" (rs2));
+
+#if (__riscv_xlen >= 64)
+  L_CHECK (dst, 0xffffffff);
+  L_CHECK (rs2, 0x80000002);
+#else
+  I_CHECK (dst, 0xffffffff);
+  I_CHECK (rs2, 0x80000002);
+#endif
+}
+
+void
+test_c_xor ()
+{
+  riscv_reg_t dst, rs2;
+
+  info ("Testing c.xor");
+
+  dst = -3;
+  rs2 = -3;
+  asm volatile ("c.xor %0,%1" : "+r" (dst) : "r" (rs2));
+
+#if (__riscv_xlen >= 64)
+  L_CHECK (dst, 0);
+  L_CHECK (rs2, -3);
+#else
+  I_CHECK (dst, 0);
+  I_CHECK (rs2, -3);
+#endif
+
+  dst = 0x7ffffffd;
+  rs2 = 0x80000002;
+  asm volatile ("c.xor %0,%1" : "+r" (dst) : "r" (rs2));
+
+#if (__riscv_xlen >= 64)
+  L_CHECK (dst, 0xffffffff);
+  L_CHECK (rs2, 0x80000002);
+#else
+  I_CHECK (dst, 0xffffffff);
+  I_CHECK (rs2, 0x80000002);
+#endif
+}
+
+void
+test_c_sub ()
+{
+  riscv_reg_t dst, rs2;
+
+  info ("Testing c.sub");
+
+  dst = -1;
+  rs2 = 1;
+  asm volatile ("c.sub %0,%1" : "+r" (dst) : "r" (rs2));
+
+#if (__riscv_xlen >= 64)
+  L_CHECK (dst, -2);
+  L_CHECK (rs2, 1);
+#else
+  I_CHECK (dst, -2);
+  I_CHECK (rs2, 1);
+#endif
+
+  dst = 0;
+  rs2 = -1;
+  asm volatile ("c.sub %0,%1" : "+r" (dst) : "r" (rs2));
+
+#if (__riscv_xlen >= 64)
+  L_CHECK (dst, 1);
+  L_CHECK (rs2, -1);
+#else
+  I_CHECK (dst, 1);
+  I_CHECK (rs2, -1);
+#endif
+}
+
+void
+test_c_addw ()
+{
+#if defined (SKIP_c_addw)
+  info ("--- Disable c.addw");
+#else
+
+  riscv_reg_t dst, rs2;
+
+  info ("Testing c.addw");
+
+  dst = -1;
+  rs2 = 1;
+  asm volatile ("c.addw %0,%1" : "+r" (dst) : "r" (rs2));
+
+#if (__riscv_xlen >= 64)
+  L_CHECK (dst, 0);
+  L_CHECK (rs2, 1);
+#else
+  I_CHECK (dst, 0);
+  I_CHECK (rs2, 1);
+#endif
+
+  dst = -1;
+  rs2 = 0;
+  asm volatile ("c.addw %0,%1" : "+r" (dst) : "r" (rs2));
+
+#if (__riscv_xlen >= 64)
+  L_CHECK (dst, -1);
+  L_CHECK (rs2, 0);
+#else
+  I_CHECK (dst, -1);
+  I_CHECK (rs2, 0);
+#endif
+#endif
+}
+
+void
+test_c_subw ()
+{
+#if defined (SKIP_c_subw)
+  info ("--- Disable c.subw");
+#else
+  riscv_reg_t dst, rs2;
+
+  info ("Testing c.subw");
+
+  dst = -1;
+  rs2 = 1;
+  asm volatile ("c.subw %0,%1" : "+r" (dst) : "r" (rs2));
+
+#if (__riscv_xlen >= 64)
+  L_CHECK (dst, -2);
+  L_CHECK (rs2, 1);
+#else
+  I_CHECK (dst, -2);
+  I_CHECK (rs2, 1);
+#endif
+
+  dst = 0;
+  rs2 = -1;
+  asm volatile ("c.subw %0,%1" : "+r" (dst) : "r" (rs2));
+
+#if (__riscv_xlen >= 64)
+  L_CHECK (dst, 1);
+  L_CHECK (rs2, -1);
+#else
+  I_CHECK (dst, 1);
+  I_CHECK (rs2, -1);
+#endif
+#endif
+}
+
+int
+main ()
+{
+  test_c_lwsp ();
+  test_c_ldsp ();
+  test_c_flwsp ();
+  test_c_fldsp ();
+  test_c_swsp ();
+  test_c_sdsp ();
+  test_c_fswsp ();
+  test_c_fsdsp ();
+  test_c_lw ();
+  test_c_ld ();
+  test_c_flw ();
+  test_c_fld ();
+  test_c_sw ();
+  test_c_sd ();
+  test_c_fsw ();
+  test_c_fsd ();
+  test_c_j ();
+  test_c_jal ();
+  test_c_jr ();
+  test_c_jalr ();
+  test_c_beqz ();
+  test_c_bnez ();
+  test_c_li ();
+  test_c_lui ();
+  test_c_addi ();
+  test_c_addiw ();
+  test_c_addi16sp ();
+  test_c_addi4spn ();
+  test_c_slli ();
+  test_c_srli ();
+  test_c_srai ();
+  test_c_andi ();
+  test_c_add ();
+  test_c_and ();
+  test_c_or ();
+  test_c_xor ();
+  test_c_sub ();
+  test_c_addw ();
+  test_c_subw ();
+
+  if (num_fail == 0)
+    {
+      print ("*** All %d tests pass\n", total_tests);
+    }
+  else
+    {
+      print ("*** Total %d tests out of %d fail\n", num_fail, total_tests);
+    }
+
+  return num_fail;
+}
diff --git a/gdb/testsuite/gdb.arch/riscv-insn-simulation.exp b/gdb/testsuite/gdb.arch/riscv-insn-simulation.exp
new file mode 100755
index 00000000000..f94a31cc236
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/riscv-insn-simulation.exp
@@ -0,0 +1,31 @@
+# Copyright 2023 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Tests to check instruction simulation of RISC-V instructions.
+
+require {istarget "riscv*-*-*"}
+
+standard_testfile
+
+if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \
+	  {debug quiet}] } {
+    return -1
+}
+
+if { ![runto_main] } {
+    return -1
+}
+
+gdb_continue_to_end ".*All.*tests pass.*Inferior.*process.*exited normally.*"
diff --git a/sim/riscv/riscv-sim.h b/sim/riscv/riscv-sim.h
index bb296fa6e62..6d9a719eadf 100644
--- a/sim/riscv/riscv-sim.h
+++ b/sim/riscv/riscv-sim.h
@@ -107,4 +107,8 @@ static int gdb_open_modeflags[12] = {
   GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY
 };
 
+#define C_REG(X) ((X) + 8) /* Register in a compressed instruction.  */
+#define REG_RA 1 /* Return address register.  */
+#define REG_SP 2 /* Stack piner register.  */
+
 #endif
diff --git a/sim/riscv/sim-main.c b/sim/riscv/sim-main.c
index 8e08eb9fc4e..da9a1aa4cdf 100644
--- a/sim/riscv/sim-main.c
+++ b/sim/riscv/sim-main.c
@@ -1193,6 +1193,317 @@ execute_a (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op)
   return pc;
 }
 
+static sim_cia
+execute_c (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op)
+{
+  SIM_DESC sd = CPU_STATE (cpu);
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+  int rd = (iw >> OP_SH_RD) & OP_MASK_RD;
+  int rs1_c = ((iw >> OP_SH_CRS1S) & OP_MASK_CRS1S) + 8;
+  int rs2 = (iw >> OP_SH_CRS2) & OP_MASK_CRS2;
+  int rs2_c = ((iw >> OP_SH_CRS2S) & OP_MASK_CRS2S) + 8;
+  const char *rd_name = riscv_gpr_names_abi[rd];
+  const char *rs1_c_name = riscv_gpr_names_abi[rs1_c];
+  const char *rs2_name = riscv_gpr_names_abi[rs2];
+  const char *rs2_c_name = riscv_gpr_names_abi[rs2_c];
+  signed_word imm;
+  unsigned_word tmp;
+  sim_cia pc = riscv_cpu->pc + 2;
+
+  switch (op->match)
+    {
+    case MATCH_C_JR | MATCH_C_MV:
+      switch (op->mask)
+	{
+	case MASK_C_MV:
+	  TRACE_INSN (cpu, "c.mv %s, %s; // %s = %s",
+		      rd_name, rs2_name, rd_name, rs2_name);
+	  store_rd (cpu, rd, riscv_cpu->regs[rs2]);
+	  break;
+	case MASK_C_JR:
+	  TRACE_INSN (cpu, "c.jr %s;",
+		      rd_name);
+	  pc = riscv_cpu->regs[rd];
+	  TRACE_BRANCH (cpu, "to %#" PRIxTW, pc);
+	  break;
+	}
+      break;
+    case MATCH_C_J:
+      imm = EXTRACT_CJTYPE_IMM (iw);
+      TRACE_INSN (cpu, "c.j %" PRIxTW,
+		  imm);
+      pc = riscv_cpu->pc + imm;
+      TRACE_BRANCH (cpu, "to %#" PRIxTW, pc);
+      break;
+    case MATCH_C_JAL | MATCH_C_ADDIW:
+      /* JAL and ADDIW have the same mask, so switch based on op name.  */
+      switch (op->name[2])
+	{
+	case 'j':
+	  imm = EXTRACT_CJTYPE_IMM (iw);
+	  TRACE_INSN (cpu, "c.jal %" PRIxTW,
+		      imm);
+	  store_rd (cpu, REG_RA, riscv_cpu->pc + 2);
+	  pc = riscv_cpu->pc + imm;
+	  TRACE_BRANCH (cpu, "to %#" PRIxTW, pc);
+	  break;
+	case 'a':
+	  imm = EXTRACT_CITYPE_IMM (iw);
+	  TRACE_INSN (cpu, "c.addiw %s, %s, %#" PRIxTW ";  // %s += %#" PRIxTW,
+		      rd_name, rd_name, imm, rd_name, imm);
+	  RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
+	  store_rd (cpu, rd, EXTEND32 (riscv_cpu->regs[rd] + imm));
+	  break;
+	default:
+	  TRACE_INSN (cpu, "UNHANDLED INSN: %s", op->name);
+	  sim_engine_halt (sd, cpu, NULL, riscv_cpu->pc, sim_signalled,
+			   SIM_SIGILL);
+	}
+      break;
+    case MATCH_C_JALR | MATCH_C_ADD | MATCH_C_EBREAK:
+      switch (op->mask)
+	{
+	case MASK_C_ADD:
+	  TRACE_INSN (cpu, "c.add %s, %s; // %s += %s",
+		      rd_name, rs2_name, rd_name, rs2_name);
+	  store_rd (cpu, rd, riscv_cpu->regs[rd] + riscv_cpu->regs[rs2]);
+	  break;
+	case MASK_C_JALR:
+	  TRACE_INSN (cpu, "c.jalr %s, %s;",
+		      riscv_gpr_names_abi[REG_RA], rd_name);
+	  store_rd (cpu, REG_RA, riscv_cpu->pc + 2);
+	  pc = riscv_cpu->regs[rd];
+	  TRACE_BRANCH (cpu, "to %#" PRIxTW, pc);
+	  break;
+	case MASK_C_EBREAK:
+	  TRACE_INSN (cpu, "ebreak");
+	  sim_engine_halt (sd, cpu, NULL, riscv_cpu->pc, sim_stopped,
+			   SIM_SIGTRAP);
+	}
+      break;
+    case MATCH_C_BEQZ:
+      imm = EXTRACT_CBTYPE_IMM (iw);
+      TRACE_INSN (cpu, "c.beqz %s, %#" PRIxTW ";  "
+		       "// if (%s == 0) goto %#" PRIxTW,
+		  rs1_c_name, imm, rs1_c_name, riscv_cpu->pc + imm);
+      if (riscv_cpu->regs[rs1_c] == riscv_cpu->regs[0])
+	{
+	  pc = riscv_cpu->pc + imm;
+	  TRACE_BRANCH (cpu, "to %#" PRIxTW, pc);
+	}
+      break;
+    case MATCH_C_BNEZ:
+      imm = EXTRACT_CBTYPE_IMM (iw);
+      TRACE_INSN (cpu, "c.bnez %s, %#" PRIxTW ";  "
+		       "// if (%s != 0) goto %#" PRIxTW,
+		  rs1_c_name, imm, rs1_c_name, riscv_cpu->pc + imm);
+      if (riscv_cpu->regs[rs1_c] != riscv_cpu->regs[0])
+	{
+	  pc = riscv_cpu->pc + imm;
+	  TRACE_BRANCH (cpu, "to %#" PRIxTW, pc);
+	}
+      break;
+    case MATCH_C_LWSP:
+      imm = EXTRACT_CITYPE_LWSP_IMM (iw);
+      TRACE_INSN (cpu, "c.lwsp %s, %" PRIiTW "(sp);",
+		  rd_name, imm);
+      store_rd (cpu, rd, EXTEND32 (
+	    sim_core_read_unaligned_4 (cpu, riscv_cpu->pc, read_map,
+				       riscv_cpu->regs[REG_SP] + imm)));
+      break;
+    case MATCH_C_LW:
+      imm = EXTRACT_CLTYPE_LW_IMM (iw);
+      TRACE_INSN (cpu, "c.lw %s, %" PRIiTW "(%s);",
+		  rs2_c_name, imm, rs1_c_name);
+      store_rd (cpu, rs2_c, EXTEND32 (
+	    sim_core_read_unaligned_4 (cpu, riscv_cpu->pc, read_map,
+				       riscv_cpu->regs[rs1_c] + imm)));
+      break;
+    case MATCH_C_SWSP:
+      imm = EXTRACT_CSSTYPE_SWSP_IMM (iw);
+      TRACE_INSN (cpu, "c.swsp %s, %" PRIiTW "(sp);",
+		  rs2_name, imm);
+      sim_core_write_unaligned_4 (cpu, riscv_cpu->pc, write_map,
+				  riscv_cpu->regs[REG_SP] + imm,
+				  riscv_cpu->regs[rs2]);
+      break;
+    case MATCH_C_SW:
+      imm = EXTRACT_CLTYPE_LW_IMM (iw);
+      TRACE_INSN (cpu, "c.sw %s, %" PRIiTW "(%s);",
+		  rs2_c_name, imm, rs1_c_name);
+      sim_core_write_unaligned_4 (cpu, riscv_cpu->pc, write_map,
+				  riscv_cpu->regs[rs1_c] + (imm),
+				  riscv_cpu->regs[rs2_c]);
+      break;
+    case MATCH_C_ADDI:
+      imm = EXTRACT_CITYPE_IMM (iw);
+      TRACE_INSN (cpu, "c.addi %s, %s, %#" PRIxTW ";  // %s += %#" PRIxTW,
+		  rd_name, rd_name, imm, rd_name, imm);
+      store_rd (cpu, rd, riscv_cpu->regs[rd] + imm);
+      break;
+    case MATCH_C_LUI:
+      imm = EXTRACT_CITYPE_LUI_IMM (iw);
+      TRACE_INSN (cpu, "c.lui %s, %#" PRIxTW ";",
+		  rd_name, imm);
+      store_rd (cpu, rd, imm);
+      break;
+    case MATCH_C_LI:
+      imm = EXTRACT_CITYPE_IMM (iw);
+      TRACE_INSN (cpu, "c.li %s, %#" PRIxTW ";  // %s = %#" PRIxTW,
+		  rd_name, imm, rd_name, imm);
+      store_rd (cpu, rd, imm);
+      break;
+    case MATCH_C_ADDI4SPN:
+      imm = EXTRACT_CIWTYPE_ADDI4SPN_IMM (iw);
+      TRACE_INSN (cpu, "c.addi4spn %s, %" PRIiTW "; // %s = sp + %" PRIiTW,
+		  rs2_c_name, imm, rs2_c_name, imm);
+      store_rd (cpu, rs2_c, riscv_cpu->regs[REG_SP] + (imm));
+      break;
+    case MATCH_C_ADDI16SP:
+      imm = EXTRACT_CITYPE_ADDI16SP_IMM (iw);
+      TRACE_INSN (cpu, "c.addi16sp %s, %" PRIiTW "; // %s = sp + %" PRIiTW,
+		  rd_name, imm, rd_name, imm);
+      store_rd (cpu, rd, riscv_cpu->regs[REG_SP] + imm);
+      break;
+    case MATCH_C_SUB:
+      TRACE_INSN (cpu, "c.sub %s, %s;  // %s = %s - %s",
+		  rs1_c_name, rs2_c_name, rs1_c_name, rs1_c_name, rs2_c_name);
+      store_rd (cpu, rs1_c, riscv_cpu->regs[rs1_c] - riscv_cpu->regs[rs2_c]);
+      break;
+    case MATCH_C_AND:
+      TRACE_INSN (cpu, "c.and %s, %s;  // %s = %s & %s",
+		  rs1_c_name, rs2_c_name, rs1_c_name, rs1_c_name, rs2_c_name);
+      store_rd (cpu, rs1_c, riscv_cpu->regs[rs1_c] & riscv_cpu->regs[rs2_c]);
+      break;
+    case MATCH_C_OR:
+      TRACE_INSN (cpu, "c.or %s, %s;  // %s = %s | %s",
+		  rs1_c_name, rs2_c_name, rs1_c_name, rs1_c_name, rs2_c_name);
+      store_rd (cpu, rs1_c, riscv_cpu->regs[rs1_c] | riscv_cpu->regs[rs2_c]);
+      break;
+    case MATCH_C_XOR:
+      TRACE_INSN (cpu, "c.xor %s, %s;  // %s = %s ^ %s",
+		  rs1_c_name, rs2_c_name, rs1_c_name, rs1_c_name, rs2_c_name);
+      store_rd (cpu, rs1_c, riscv_cpu->regs[rs1_c] ^ riscv_cpu->regs[rs2_c]);
+      break;
+    case MATCH_C_SLLI | MATCH_C_SLLI64:
+      if (op->mask == MASK_C_SLLI64)
+	{
+	  /* Reserved for custom use.  */
+	  TRACE_INSN (cpu, "UNHANDLED INSN: %s", op->name);
+	  sim_engine_halt (sd, cpu, NULL, riscv_cpu->pc, sim_signalled,
+			   SIM_SIGILL);
+	  break;
+	}
+      imm = EXTRACT_CITYPE_IMM (iw);
+      TRACE_INSN (cpu, "c.slli %s, %" PRIiTW ";  // %s = %s << %#" PRIxTW,
+		  rd_name, imm, rd_name, rd_name, imm);
+      store_rd (cpu, rd, riscv_cpu->regs[rd] << imm);
+      break;
+    case MATCH_C_SRLI | MATCH_C_SRLI64:
+      if (op->mask == MASK_C_SRLI64)
+	{
+	  /* Reserved for custom use.  */
+	  TRACE_INSN (cpu, "UNHANDLED INSN: %s", op->name);
+	  sim_engine_halt (sd, cpu, NULL, riscv_cpu->pc, sim_signalled,
+			   SIM_SIGILL);
+	  break;
+	}
+      imm = EXTRACT_CITYPE_IMM (iw);
+      TRACE_INSN (cpu, "c.srli %s, %" PRIiTW ";  // %s = %s >> %#" PRIxTW,
+		  rs1_c_name, imm, rs1_c_name, rs1_c_name, imm);
+      if (RISCV_XLEN (cpu) == 32)
+	store_rd (cpu, rs1_c, ((uint32_t) riscv_cpu->regs[rs1_c]) >> imm);
+      else
+	store_rd (cpu, rs1_c, ((uint64_t) riscv_cpu->regs[rs1_c]) >> imm);
+      break;
+    case MATCH_C_SRAI | MATCH_C_SRAI64:
+      if (op->mask == MASK_C_SRAI64)
+	{
+	  /* Reserved for custom use.  */
+	  TRACE_INSN (cpu, "UNHANDLED INSN: %s", op->name);
+	  sim_engine_halt (sd, cpu, NULL, riscv_cpu->pc, sim_signalled,
+			   SIM_SIGILL);
+	  break;
+	}
+      imm = EXTRACT_CITYPE_IMM (iw);
+      TRACE_INSN (cpu, "c.srai %s, %" PRIiTW ";  // %s = %s >> %#" PRIxTW,
+		  rs1_c_name, imm, rs1_c_name, rs1_c_name, imm);
+      if (RISCV_XLEN (cpu) == 32)
+	{
+	  if (imm > 0x1f)
+	    sim_engine_halt (sd, cpu, NULL, riscv_cpu->pc, sim_signalled,
+			     SIM_SIGILL);
+	  tmp = ashiftrt (riscv_cpu->regs[rs1_c], imm);
+	}
+      else
+	tmp = ashiftrt64 (riscv_cpu->regs[rs1_c], imm);
+      store_rd (cpu, rd, tmp);
+      break;
+    case MATCH_C_ANDI:
+      imm = EXTRACT_CITYPE_IMM (iw);
+      TRACE_INSN (cpu, "c.andi %s, %" PRIiTW ";  // %s = %s & %#" PRIxTW,
+		  rs1_c_name, imm, rs1_c_name, rs1_c_name, imm);
+      store_rd (cpu, rs1_c, riscv_cpu->regs[rs1_c] & imm);
+      break;
+    case MATCH_C_ADDW:
+      TRACE_INSN (cpu, "c.addw %s, %s;  // %s = %s + %s",
+		  rs1_c_name, rs2_c_name, rs1_c_name, rs1_c_name, rs2_c_name);
+      RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
+      store_rd (cpu, rs1_c,
+		EXTEND32 (riscv_cpu->regs[rs1_c] + riscv_cpu->regs[rs2_c]));
+      break;
+    case MATCH_C_SUBW:
+      TRACE_INSN (cpu, "c.subw %s, %s;  // %s = %s - %s",
+		  rs1_c_name, rs2_c_name, rs1_c_name, rs1_c_name, rs2_c_name);
+      RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
+      store_rd (cpu, rs1_c,
+		EXTEND32 (riscv_cpu->regs[rs1_c] - riscv_cpu->regs[rs2_c]));
+      break;
+    case MATCH_C_LDSP:
+      imm = EXTRACT_CITYPE_LDSP_IMM (iw);
+      TRACE_INSN (cpu, "c.ldsp %s, %" PRIiTW "(sp);",
+		  rd_name, imm);
+      RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
+      store_rd (cpu, rd,
+	  sim_core_read_unaligned_8 (cpu, riscv_cpu->pc, read_map,
+				     riscv_cpu->regs[REG_SP] + imm));
+      break;
+    case MATCH_C_LD:
+      imm = EXTRACT_CLTYPE_LD_IMM (iw);
+      TRACE_INSN (cpu, "c.ld %s, %" PRIiTW "(%s);",
+		  rs1_c_name, imm, rs2_c_name);
+      RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
+      store_rd (cpu, rs2_c,
+	  sim_core_read_unaligned_8 (cpu, riscv_cpu->pc, read_map,
+				     riscv_cpu->regs[rs1_c] + imm));
+      break;
+    case MATCH_C_SDSP:
+      imm = EXTRACT_CSSTYPE_SDSP_IMM (iw);
+      TRACE_INSN (cpu, "c.sdsp %s, %" PRIiTW "(sp);",
+		  rs2_name, imm);
+      RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
+      sim_core_write_unaligned_8 (cpu, riscv_cpu->pc, write_map,
+				  riscv_cpu->regs[REG_SP] + imm,
+				  riscv_cpu->regs[rs2]);
+      break;
+    case MATCH_C_SD:
+      imm = EXTRACT_CLTYPE_LD_IMM (iw);
+      TRACE_INSN (cpu, "c.sd %s, %" PRIiTW "(%s);",
+		  rs2_c_name, imm, rs1_c_name);
+      RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
+      sim_core_write_unaligned_8 (cpu, riscv_cpu->pc, write_map,
+				  riscv_cpu->regs[rs1_c] + imm,
+				  riscv_cpu->regs[rs2_c]);
+      break;
+    default:
+      TRACE_INSN (cpu, "UNHANDLED INSN: %s", op->name);
+      sim_engine_halt (sd, cpu, NULL, riscv_cpu->pc, sim_signalled,
+		       SIM_SIGILL);
+  }
+
+  return pc;
+}
+
 static sim_cia
 execute_one (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op)
 {
@@ -1214,6 +1525,8 @@ execute_one (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op)
     case INSN_CLASS_M:
     case INSN_CLASS_ZMMUL:
       return execute_m (cpu, iw, op);
+    case INSN_CLASS_C:
+      return execute_c (cpu, iw, op);
     default:
       TRACE_INSN (cpu, "UNHANDLED EXTENSION: %d", op->insn_class);
       sim_engine_halt (sd, cpu, NULL, riscv_cpu->pc, sim_signalled, SIM_SIGILL);
@@ -1239,17 +1552,10 @@ void step_once (SIM_CPU *cpu)
 
   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);
+  if (len == 4)
+    iw |= ((unsigned_word) sim_core_read_aligned_2
+	   (cpu, pc, exec_map, pc + 2) << 16);
 
   TRACE_CORE (cpu, "0x%08" PRIxTW, iw);
 
diff --git a/sim/testsuite/riscv/c-ext.s b/sim/testsuite/riscv/c-ext.s
new file mode 100644
index 00000000000..049d2b4323e
--- /dev/null
+++ b/sim/testsuite/riscv/c-ext.s
@@ -0,0 +1,110 @@
+# Basic load store tests.
+# mach: riscv
+
+.include "testutils.inc"
+
+	.data
+	.align 4
+_data:
+	.word	1234
+	.word	0
+
+	start
+	la	a0, _data
+
+	# Test load-store instructions.
+	.option push
+	.option	arch, +c
+	c.lw	a1,0(a0)
+	c.sw	a1,4(a0)
+	c.lw	a2,4(a0)
+	.option pop
+
+	li	a5,1234
+	bne	a1,a5,test_fail
+	bne	a2,a5,test_fail
+
+	# Test basic arithmetic.
+	.option push
+	.option	arch, +c
+	c.li	a0,0
+	c.li	a1,1
+	c.addi	a0,1
+	c.addi	a0,-1
+	c.addw	a0,a1
+	c.subw	a0,a1
+	.option pop
+
+	li	a5,1
+	bne	a0,x0,test_fail
+	bne	a1,a5,test_fail
+
+	# Test logical operations.
+	.option push
+	.option	arch, +c
+	c.li	a0,7
+	c.li	a1,7
+	c.li	a2,4
+	c.li	a3,3
+	c.li	a4,3
+	c.andi	a0,3
+	c.and	a1,a0
+	c.or	a2,a3
+	c.xor	a4,a4
+	.option pop
+
+	li	a5,3
+	bne	a0,a5,test_fail
+	bne	a1,a5,test_fail
+	bne	a4,x0,test_fail
+	li	a5,7
+	bne	a2,a5,test_fail
+
+	# Test shift operations.
+	.option push
+	.option	arch, +c
+	c.li	a0,4
+	c.li	a1,4
+	c.slli	a0,1
+	c.srli	a1,1
+	.option pop
+
+	li	a5,8
+	bne	a0,a5,test_fail
+	li	a5,2
+	bne	a1,a5,test_fail
+
+	# Test jump instruction.
+	.option push
+	.option	arch, +c
+	c.j	1f
+	.option pop
+
+	j	test_fail
+1:
+	la	a0,2f
+
+	# Test jump register instruction.
+	.option push
+	.option	arch, +c
+	c.jr	a0
+	.option pop
+
+	j	test_fail
+
+2:
+	# Test branch instruction.
+	.option push
+	.option	arch, +c
+	c.li	a0,1
+	c.beqz	a0,test_fail
+	c.li	a0,0
+	c.bnez	a0,test_fail
+	.option pop
+
+test_pass:
+	pass
+	fail
+
+test_fail:
+	fail
-- 
2.25.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v2 3/3] [sim/riscv] Add semi-hosting support
  2023-10-30 13:00 [PATCH v2 0/3] sim: riscv: Compressed instruction simulation and semi-hosting support jaydeep.patil
  2023-10-30 13:00 ` [PATCH v2 1/3] [sim/riscv] Add basic " jaydeep.patil
  2023-10-30 13:00 ` [PATCH v2 2/3] [sim/riscv] Add support for compressed integer instruction set jaydeep.patil
@ 2023-10-30 13:00 ` jaydeep.patil
  2023-11-13 12:07 ` [PATCH v2 0/3] sim: riscv: Compressed instruction simulation and " Jaydeep Patil
  3 siblings, 0 replies; 17+ messages in thread
From: jaydeep.patil @ 2023-10-30 13:00 UTC (permalink / raw)
  To: gdb-patches
  Cc: aburgess, vapier, joseph.faulls, bhushan.attarde, jaydeep.patil

From: Jaydeep Patil <jaydeep.patil@imgtec.com>

Added support for all semi-hosting calls.
Enable prints in gdb.arch/riscv-insn-simulation.c.
---
 .../gdb.arch/riscv-insn-simulation.c          |   2 -
 .../gdb.arch/riscv-insn-simulation.exp        |   3 +-
 sim/riscv/riscv-sim.h                         |  21 +
 sim/riscv/sim-main.c                          | 494 ++++++++++++++++++
 4 files changed, 517 insertions(+), 3 deletions(-)

diff --git a/gdb/testsuite/gdb.arch/riscv-insn-simulation.c b/gdb/testsuite/gdb.arch/riscv-insn-simulation.c
index db2b8b4f3d8..12334bdd89e 100755
--- a/gdb/testsuite/gdb.arch/riscv-insn-simulation.c
+++ b/gdb/testsuite/gdb.arch/riscv-insn-simulation.c
@@ -51,8 +51,6 @@
 #define SKIP_c_fsdsp
 #endif
 
-#define DISABLE_PRINTS
-
 #if defined (DISABLE_PRINTS)
 #define print(...) ;
 #else
diff --git a/gdb/testsuite/gdb.arch/riscv-insn-simulation.exp b/gdb/testsuite/gdb.arch/riscv-insn-simulation.exp
index f94a31cc236..9ffa526b318 100755
--- a/gdb/testsuite/gdb.arch/riscv-insn-simulation.exp
+++ b/gdb/testsuite/gdb.arch/riscv-insn-simulation.exp
@@ -28,4 +28,5 @@ if { ![runto_main] } {
     return -1
 }
 
-gdb_continue_to_end ".*All.*tests pass.*Inferior.*process.*exited normally.*"
+gdb_continue_to_end "continue parent to end" "continue" 1
+
diff --git a/sim/riscv/riscv-sim.h b/sim/riscv/riscv-sim.h
index 6d9a719eadf..8e80a4f7374 100644
--- a/sim/riscv/riscv-sim.h
+++ b/sim/riscv/riscv-sim.h
@@ -78,8 +78,29 @@ extern void initialize_env (SIM_DESC, const char * const *argv,
 #define APPLICATION_EXIT 0x20026
 
 #define SYS_OPEN 0x01
+#define SYS_CLOSE 0x02
+#define SYS_WRITEC 0x03
+#define SYS_WRITE0 0x04
+#define SYS_WRITE 0x05
+#define SYS_READ 0x06
+#define SYS_READC 0x07
+#define SYS_ISERROR 0x08
+#define SYS_ISTTY 0x09
+#define SYS_SEEK 0x0A
+#define SYS_FLEN 0x0C
+#define SYS_TMPNAM 0x0D
+#define SYS_REMOVE 0x0E
+#define SYS_RENAME 0x0F
+#define SYS_CLOCK 0x10
+#define SYS_TIME 0x11
+#define SYS_SYSTEM 0x12
+#define SYS_ERRNO 0x13
 #define SYS_GET_CMDLINE 0x15
+#define SYS_HEAPINFO 0x16
 #define SYS_EXIT 0x18
+#define SYS_EXIT_EXTENDED 0x20
+#define SYS_ELAPSED 0x30
+#define SYS_TICKFREQ 0x31
 
 #define GDB_O_RDONLY 0x000
 #define GDB_O_WRONLY 0x001
diff --git a/sim/riscv/sim-main.c b/sim/riscv/sim-main.c
index da9a1aa4cdf..8362d85522a 100644
--- a/sim/riscv/sim-main.c
+++ b/sim/riscv/sim-main.c
@@ -26,7 +26,11 @@
 
 #include <inttypes.h>
 #include <time.h>
+#include <sys/stat.h>
+#include <sys/unistd.h>
+#include <sys/fcntl.h>
 
+#include "bfd.h"
 #include "sim-main.h"
 #include "sim-signal.h"
 #include "sim-syscall.h"
@@ -66,6 +70,8 @@ static const struct riscv_opcode *riscv_hash[OP_MASK_OP + 1];
       } \
   } while (0)
 
+static clock_t clock_start = 0;
+
 static INLINE void
 store_rd (SIM_CPU *cpu, int rd, unsigned_word val)
 {
@@ -187,6 +193,430 @@ get_core_string_with_len (SIM_CPU *cpu, unsigned_word addr,
   return str;
 }
 
+/* Write VALUE at specified address.  ADDR and (INDEX * XLEN)
+   form the base address.  */
+static void
+set_core_data (SIM_CPU *cpu, unsigned_word addr, unsigned_word index,
+	       uintptr_t value)
+{
+  int xlen = RISCV_XLEN (cpu);
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+
+  if (xlen == 64)
+    sim_core_write_unaligned_8 (cpu, riscv_cpu->pc, read_map,
+				addr + (index * 8), value);
+  else
+    sim_core_write_unaligned_4 (cpu, riscv_cpu->pc, read_map,
+				addr + (index * 4), (uint32_t) value);
+}
+
+/* Read data of length SLEN and address ADDR.  */
+static char *
+get_core_string (SIM_CPU *cpu, unsigned_word addr, int *slen)
+{
+  int len = 0;
+  char * str;
+  const int chunk_size = 128;	/* allocate buffer in chunks.  */
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+
+  str = (char *) malloc (chunk_size);
+
+  while (1)
+    {
+      uint8_t ch = sim_core_read_unaligned_1 (cpu, riscv_cpu->pc, read_map,
+					      addr + len);
+      str[len] = ch;
+      if (ch == 0)
+	break;
+      len++;
+      if ((len % chunk_size) == 0)
+	str = (char *) realloc (str, len + chunk_size);
+    }
+
+  *slen = len;
+  return str;
+}
+
+/* Find address of the symbol in SYMNAME.  */
+static uintptr_t
+get_symbol_value (SIM_CPU *cpu, const char *symname)
+{
+  struct bfd *abfd = STATE_PROG_BFD (CPU_STATE (cpu));
+  static asymbol **symbol_table = NULL;
+  static long number_of_symbols = 0;
+
+  if (symbol_table == NULL)
+    {
+      long storage_needed;
+      storage_needed = bfd_get_symtab_upper_bound (abfd);
+      if (storage_needed <= 0)
+	return 0;
+      symbol_table = (asymbol **) malloc (storage_needed);
+      if (symbol_table == NULL)
+	return 0;
+      number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);
+      if (number_of_symbols <= 0)
+	return 0;
+    }
+
+  for (long i = 0; i < number_of_symbols; i++)
+    {
+      asymbol *sym = symbol_table[i];
+      if (!strcmp (sym->name, symname))
+	return bfd_asymbol_value (sym);
+    }
+
+  return 0;
+}
+
+/* SYS_FLEN
+   Register a1 points to a buffer containing:
+   Index 0: Integer: File handle.
+   The file size in bytes is returned through register a0.  */
+static void
+semihosting_flen (SIM_CPU *cpu)
+{
+  int fd;
+  struct stat sb;
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+
+  fd = (int) get_core_data (cpu, riscv_cpu->a1, 0);
+
+  if (fd > STDERR_FILENO)
+    {
+      fstat (fd, &sb);
+      riscv_cpu->a0 = sb.st_size;
+    }
+  else
+    riscv_cpu->a0 = 0;
+}
+
+/* SYS_WRITE
+   Write data to a file.  Register a1 points to a buffer containing:
+   Index 0: Integer: File handle.
+   Index 1: Pointer: Pointer to buffer.
+   Index 2: Integer: Number of bytes to write.
+   Number of bytes written is returned through register a0.  */
+static void
+semihosting_write (SIM_CPU *cpu)
+{
+  int i, fd;
+  uintptr_t buf;
+  uintptr_t count;
+  char *str;
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+
+  fd = (int) get_core_data (cpu, riscv_cpu->a1, 0);
+  buf = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 1);
+  count = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 2);
+
+  if (count <= 0)
+    {
+      riscv_cpu->a0 = -1;
+      return;
+    }
+
+  str = get_core_string_with_len (cpu, buf, count);
+  riscv_cpu->a0 = sim_io_write (CPU_STATE (cpu), fd, str, count);
+  free (str);
+}
+
+/* SYS_WRITEC
+   Register a1 points to a buffer containing:
+   Index 0: Integer: Character to write to console.
+   Number of bytes written is returned through register a0.  */
+static void
+semihosting_writec (SIM_CPU *cpu)
+{
+  char ch;
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+  ch = (char) get_core_data (cpu, riscv_cpu->a1, 0);
+  riscv_cpu->a0 = sim_io_write_stdout (CPU_STATE (cpu), &ch, 1);
+}
+
+/* SYS_WRITE0
+   Register a1 points to a buffer containing:
+   Index 0: Integer: Null terminated string.
+   Number of bytes written is returned through register a0.  */
+static void
+semihosting_write0 (SIM_CPU *cpu)
+{
+  int len;
+  char *str;
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+  str = get_core_string (cpu, riscv_cpu->a1, &len);
+  riscv_cpu->a0 = sim_io_write_stdout (CPU_STATE (cpu), str, len);
+}
+
+/* SYS_READ
+   Read data from a file.  Register a1 points to a buffer containing:
+   Index 0: Integer: File handle.
+   Index 1: Pointer: Pointer to destination buffer.
+   Index 2: Integer: Number of bytes to read.
+   Number of bytes read is returned through register a0.  */
+static void
+semihosting_read (SIM_CPU *cpu)
+{
+  int i, fd, read_len;
+  uintptr_t dst_buf;
+  uintptr_t count;
+  char *host_buf;
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+
+  fd = (int) get_core_data (cpu, riscv_cpu->a1, 0);
+  dst_buf = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 1);
+  count = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 2);
+
+  if (count <= 0)
+    {
+      riscv_cpu->a0 = 0;
+      return;
+    }
+
+  host_buf = (char *) malloc (count);
+  read_len = sim_io_read (CPU_STATE (cpu), fd, host_buf, count);
+  if (read_len > 0)
+    set_core_string (cpu, dst_buf, host_buf, read_len);
+  riscv_cpu->a0 = read_len;
+  free (host_buf);
+}
+
+/* SYS_READC
+   Read a char from console and return it through register a0.  */
+static void
+semihosting_readc (SIM_CPU *cpu)
+{
+  char ch;
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+  sim_io_read_stdin (CPU_STATE (cpu), &ch, 1);
+  riscv_cpu->a0 = ch;
+}
+
+/* SYS_CLOSE
+   Close a file.  Register a1 points to a buffer containing:
+   Index 0: Integer: File handle.
+   Return status in register a0.  */
+static void
+semihosting_close (SIM_CPU *cpu)
+{
+  int fd;
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+  fd = (int) get_core_data (cpu, riscv_cpu->a1, 0);
+  riscv_cpu->a0 = sim_io_close (CPU_STATE (cpu), fd);
+}
+
+/* SYS_SEEK
+   Seek in a file.  Register a1 points to a buffer containing:
+   Index 0: Integer: File handle.
+   Index 1: Integer: Number of bytes to seek in the file.
+   Return status in register a0.  */
+static void
+semihosting_seek (SIM_CPU *cpu)
+{
+  int fd;
+  uintptr_t pos;
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+  fd = (int) get_core_data (cpu, riscv_cpu->a1, 0);
+  pos = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 1);
+  riscv_cpu->a0 = sim_io_lseek (CPU_STATE (cpu), fd, pos, 0);
+}
+
+/* SYS_EXIT_EXTENDED
+   Register a1 points to a buffer containing:
+   Index 0: Integer: Application code.
+   Index 1: Integer: Exit code.  */
+static void
+semihosting_exit_extended (SIM_CPU *cpu)
+{
+  int ret;
+  uintptr_t app_code, exit_status;
+  SIM_DESC sd = CPU_STATE (cpu);
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+  app_code = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 0);
+  exit_status = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 1);
+  if (app_code == APPLICATION_EXIT)
+    ret = exit_status;
+  else
+    ret = 1;
+  riscv_cpu->a0 = ret;
+  sim_engine_halt (sd, cpu, NULL, riscv_cpu->pc, sim_exited, ret);
+}
+
+/* SYS_ISERROR
+   Register a1 points to a buffer containing:
+   Index 0: Integer: Status code.  */
+static void
+semihosting_iserror (SIM_CPU *cpu)
+{
+  intptr_t status;
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+  status = (intptr_t) get_core_data (cpu, riscv_cpu->a1, 0);
+  riscv_cpu->a0 = (status < 0);
+}
+
+/* SYS_ISTTY
+   Register a1 points to a buffer containing:
+   Index 0: Integer: File handle.  */
+static void
+semihosting_istty (SIM_CPU *cpu)
+{
+  int fd;
+  SIM_DESC sd = CPU_STATE (cpu);
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+  fd = (int) get_core_data (cpu, riscv_cpu->a1, 0);
+  riscv_cpu->a0 = sim_io_isatty (sd, fd);
+}
+
+/* SYS_TMPNAM
+   Register a1 points to a buffer containing:
+   Index 0: Pointer: Destination buffer address.
+   Index 1: Integer: ID (ignored).
+   Index 2: Integer: Maximum length of the buffer.
+   Pointer to temporary name is returned through a0.  */
+static void
+semihosting_tmpnam (SIM_CPU *cpu)
+{
+  uintptr_t t_pname;
+  int len, id, maxpath;
+  char *pname;
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+
+  t_pname = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 0);
+  id = (int) get_core_data (cpu, riscv_cpu->a1, 1);
+  maxpath = (int) get_core_data (cpu, riscv_cpu->a1, 2);
+
+  pname = tmpnam (NULL);
+
+  if (pname == NULL)
+    {
+      riscv_cpu->a0 = 0;
+      return;
+    }
+
+  len = strlen (pname);
+  if (maxpath > len)
+    {
+      riscv_cpu->a0 = 0;
+      return;
+    }
+
+  set_core_string (cpu, t_pname, pname, len + 1);
+  riscv_cpu->a0 = t_pname;
+}
+
+/* SYS_REMOVE
+   Register a1 points to a buffer containing:
+   Index 0: Pointer: Name of the file to remove.
+   Index 1: Integer: Length of the file name.  */
+static void
+semihosting_remove (SIM_CPU *cpu)
+{
+  uintptr_t t_pname;
+  int len;
+  char *pname;
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+  t_pname = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 0);
+  len = (int) get_core_data (cpu, riscv_cpu->a1, 1);
+  pname = get_core_string_with_len (cpu, t_pname, len);
+  riscv_cpu->a0 = sim_io_unlink (CPU_STATE (cpu), pname);
+  free (pname);
+}
+
+/* SYS_RENAME
+   Register a1 points to a buffer containing:
+   Index 0: Pointer: Old file path.
+   Index 1: Integer: Length of the old file name.
+   Index 2: Pointer: New file name.
+   Index 3: Integer: Length of the new file name.  */
+static void
+semihosting_rename (SIM_CPU *cpu)
+{
+  uintptr_t old_name_addr, new_name_addr;
+  uintptr_t old_len, new_len;
+  char *old_host_name, *new_host_name;
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+  old_name_addr = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 0);
+  old_len = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 1);
+  new_name_addr = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 2);
+  new_len = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 3);
+  old_host_name = get_core_string_with_len (cpu, old_name_addr, old_len);
+  new_host_name = get_core_string_with_len (cpu, new_name_addr, new_len);
+  riscv_cpu->a0 = sim_io_rename (CPU_STATE (cpu), old_host_name,
+				 new_host_name);
+  free (old_host_name);
+  free (new_host_name);
+}
+
+/* SYS_SYSTEM
+   Register a1 points to a buffer containing:
+   Index 0: Pointer: Command string.
+   Index 1: Integer: Length of the command string.
+   Status of the command is returned through a0.  */
+static void
+semihosting_system (SIM_CPU *cpu)
+{
+  uintptr_t cmd_addr;
+  uintptr_t cmd_len;
+  char *cmd_host;
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+  cmd_addr = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 0);
+  cmd_len = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 1);
+  cmd_host = get_core_string_with_len (cpu, cmd_addr, cmd_len);
+  riscv_cpu->a0 = sim_io_system (CPU_STATE (cpu), cmd_host);
+  free (cmd_host);
+}
+
+/* SYS_ELAPSED
+   Return the elapsed seconds in a buffer pointed by register a1.  */
+static void
+semihosting_elapsed (SIM_CPU *cpu)
+{
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+  clock_t elapsed = clock () - clock_start;
+  if (RISCV_XLEN (cpu) == 32)
+    {
+      sim_core_write_unaligned_4 (cpu, riscv_cpu->pc, write_map,
+	riscv_cpu->a1, (uint32_t) elapsed);
+      sim_core_write_unaligned_4 (cpu, riscv_cpu->pc, write_map,
+	riscv_cpu->a1 + 4, (uint32_t) (elapsed >> 32));
+    }
+  else
+    sim_core_write_unaligned_8 (cpu, riscv_cpu->pc, write_map, riscv_cpu->a1,
+				elapsed);
+}
+
+/* SYS_HEAPINFO
+   Return the heap start, heap end, stack start and stack end
+   in a buffer pointed by register a1.  */
+static void
+semihosting_heapinfo (SIM_CPU *cpu)
+{
+  static uintptr_t heap_base = 0, heap_limit = 0,
+	stack_base = 0, stack_limit = 0, stack_size = 0;
+  static bool have_heap = false, have_stack = false;
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+
+  if (have_heap == false)
+    {
+      heap_base = get_symbol_value (cpu, "__heap_start");
+      heap_limit = get_symbol_value (cpu, "__heap_end");
+      have_heap = true;
+    }
+
+  if (have_stack == false)
+    {
+      stack_base = get_symbol_value (cpu, "__stack");
+      stack_size = get_symbol_value (cpu, "__stack_size");
+      stack_limit = stack_base + stack_size;
+      have_stack = true;
+    }
+
+  set_core_data (cpu, riscv_cpu->a1, 0, heap_base);
+  set_core_data (cpu, riscv_cpu->a1, 1, heap_limit);
+  set_core_data (cpu, riscv_cpu->a1, 2, stack_base);
+  set_core_data (cpu, riscv_cpu->a1, 3, stack_limit);
+}
+
 /* SYS_OPEN
    Register a1 points to a buffer containing:
    Index 0: Pointer: Address of the file name string.
@@ -299,6 +729,69 @@ do_semihosting (SIM_CPU *cpu)
     case SYS_EXIT:
       semihosting_exit (cpu);
       break;
+    case SYS_CLOSE:
+      semihosting_close (cpu);
+      break;
+    case SYS_WRITEC:
+      semihosting_writec (cpu);
+      break;
+    case SYS_WRITE0:
+      semihosting_write0 (cpu);
+      break;
+    case SYS_WRITE:
+      semihosting_write (cpu);
+      break;
+    case SYS_READ:
+      semihosting_read (cpu);
+      break;
+    case SYS_READC:
+      semihosting_readc (cpu);
+      break;
+    case SYS_ISERROR:
+      semihosting_iserror (cpu);
+      break;
+    case SYS_ISTTY:
+      semihosting_istty (cpu);
+      break;
+    case SYS_SEEK:
+      semihosting_seek (cpu);
+      break;
+    case SYS_FLEN:
+      semihosting_flen (cpu);
+      break;
+    case SYS_TMPNAM:
+      semihosting_tmpnam (cpu);
+      break;
+    case SYS_REMOVE:
+      semihosting_remove (cpu);
+      break;
+    case SYS_RENAME:
+      semihosting_rename (cpu);
+      break;
+    case SYS_CLOCK:
+      riscv_cpu->a0 = (clock () / (CLOCKS_PER_SEC / 100));
+      break;
+    case SYS_TIME:
+      riscv_cpu->a0 = sim_io_time (CPU_STATE (cpu));
+      break;
+    case SYS_SYSTEM:
+      semihosting_system (cpu);
+      break;
+    case SYS_ERRNO:
+      riscv_cpu->a0 = sim_io_get_errno (CPU_STATE (cpu));
+      break;
+    case SYS_HEAPINFO:
+      semihosting_heapinfo (cpu);
+      break;
+    case SYS_EXIT_EXTENDED:
+      semihosting_exit_extended (cpu);
+      break;
+    case SYS_ELAPSED:
+      semihosting_elapsed (cpu);
+      break;
+    case SYS_TICKFREQ:
+      riscv_cpu->a0 = 1000000000;
+      break;
     default:
       return -1;	/* Semi-hosting call not supported.  */
     }
@@ -1727,6 +2220,7 @@ initialize_cpu (SIM_DESC sd, SIM_CPU *cpu, int mhartid)
 
   riscv_cpu->csr.mimpid = 0x8000;
   riscv_cpu->csr.mhartid = mhartid;
+  clock_start = clock ();
 }
 \f
 /* Some utils don't like having a NULL environ.  */
-- 
2.25.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* RE: [PATCH v2 0/3] sim: riscv: Compressed instruction simulation and semi-hosting support
  2023-10-30 13:00 [PATCH v2 0/3] sim: riscv: Compressed instruction simulation and semi-hosting support jaydeep.patil
                   ` (2 preceding siblings ...)
  2023-10-30 13:00 ` [PATCH v2 3/3] [sim/riscv] Add semi-hosting support jaydeep.patil
@ 2023-11-13 12:07 ` Jaydeep Patil
  3 siblings, 0 replies; 17+ messages in thread
From: Jaydeep Patil @ 2023-11-13 12:07 UTC (permalink / raw)
  To: gdb-patches; +Cc: aburgess, vapier, Joseph Faulls, Bhushan Attarde

Hi Andrew,

Could you please find some time to review this?

Thank you,
Jaydeep

-----Original Message-----
From: Jaydeep Patil <Jaydeep.Patil@imgtec.com> 
Sent: Monday, October 30, 2023 6:31 PM
To: gdb-patches@sourceware.org
Cc: aburgess@redhat.com; vapier@gentoo.org; Joseph Faulls <Joseph.Faulls@imgtec.com>; Bhushan Attarde <Bhushan.Attarde@imgtec.com>; Jaydeep Patil <Jaydeep.Patil@imgtec.com>
Subject: [PATCH v2 0/3] sim: riscv: Compressed instruction simulation and semi-hosting support

*** NOTE: This is an internal email from Imagination Technologies ***




From: Jaydeep Patil <jaydeep.patil@imgtec.com>

Hi Andrew,

Addressed review comments. Simulator specific tests are added in sim/testsuite/riscv/c-ext.s file.

This is a collection of patches that add simulation of compressed integer instruction set ("c") and semi-hosting support to the RISC-V simulator. Two tests are added in gdb.arch to test basic semi-hosting and then the simulation of compressed integer instructions.

Patch #1 adds basic semi-hosting support (OPEN, EXIT and GET_CMDLINE) and gdb.arch/riscv-exit-getcmd.c test

Patch #2 adds support for compressed integer instruction set ("c") and gdb.arch/riscv-insn-simulation.c and sim/testsuite/riscv/c-ext.s tests

Patch #3 adds support for remaining semi-hosting calls

Contributions from:
  Joseph Faulls (Joseph.Faulls@imgtec.com)
  Jaydeep Patil (Jaydeep.Patil@imgtec.com)
  Bhushan Attarde (Bhushan.Attarde@imgtec.com)

Jaydeep Patil (3):
  [sim/riscv] Add basic semi-hosting support
  [sim/riscv] Add support for compressed integer instruction set
  [sim/riscv] Add semi-hosting support

 gdb/testsuite/gdb.arch/riscv-exit-getcmd.c    |   26 +
 gdb/testsuite/gdb.arch/riscv-exit-getcmd.exp  |   27 +
 .../gdb.arch/riscv-insn-simulation.c          | 1542 +++++++++++++++++
 .../gdb.arch/riscv-insn-simulation.exp        |   32 +
 sim/riscv/riscv-sim.h                         |   57 +
 sim/riscv/sim-main.c                          | 1050 ++++++++++-
 sim/testsuite/riscv/c-ext.s                   |  110 ++
 7 files changed, 2829 insertions(+), 15 deletions(-)  create mode 100644 gdb/testsuite/gdb.arch/riscv-exit-getcmd.c
 create mode 100644 gdb/testsuite/gdb.arch/riscv-exit-getcmd.exp
 create mode 100755 gdb/testsuite/gdb.arch/riscv-insn-simulation.c
 create mode 100755 gdb/testsuite/gdb.arch/riscv-insn-simulation.exp
 create mode 100644 sim/testsuite/riscv/c-ext.s

--
2.25.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v2 1/3] [sim/riscv] Add basic semi-hosting support
  2023-10-30 13:00 ` [PATCH v2 1/3] [sim/riscv] Add basic " jaydeep.patil
@ 2023-11-29  7:57   ` Mike Frysinger
  2023-12-12 17:24     ` Andrew Burgess
  2023-12-19  6:13     ` [EXTERNAL] " Jaydeep Patil
  2023-12-12 17:57   ` Andrew Burgess
  1 sibling, 2 replies; 17+ messages in thread
From: Mike Frysinger @ 2023-11-29  7:57 UTC (permalink / raw)
  To: jaydeep.patil; +Cc: gdb-patches, aburgess, joseph.faulls, bhushan.attarde

[-- Attachment #1: Type: text/plain, Size: 1012 bytes --]

On 30 Oct 2023 13:00, jaydeep.patil@imgtec.com wrote:
> Added support for basic semi-hosting calls OPEN, EXIT and GET_CMDLINE.

what host environment are you implementing ?  none of the syscalls you've
defined match what have long been in the riscv libgloss port.  those are
the only ones i'd really expect at this point to be wired up.

> Added gdb.arch/riscv-exit-getcmd.c to test it.
> ---
>  gdb/testsuite/gdb.arch/riscv-exit-getcmd.c   |  26 +++
>  gdb/testsuite/gdb.arch/riscv-exit-getcmd.exp |  27 +++
>  sim/riscv/riscv-sim.h                        |  32 +++
>  sim/riscv/sim-main.c                         | 230 ++++++++++++++++++-

you're missing sim/ tests.  gdb tests are great, but not sufficient.

> @@ -990,6 +1209,7 @@ execute_one (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op)
>      case INSN_CLASS_A:
>        return execute_a (cpu, iw, op);
>      case INSN_CLASS_I:
> +    case INSN_CLASS_ZICSR:
>        return execute_i (cpu, iw, op);

seems unrelated to this patch
-mike

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v2 2/3] [sim/riscv] Add support for compressed integer instruction set
  2023-10-30 13:00 ` [PATCH v2 2/3] [sim/riscv] Add support for compressed integer instruction set jaydeep.patil
@ 2023-11-29  7:58   ` Mike Frysinger
  2023-12-19  6:11     ` [EXTERNAL] " Jaydeep Patil
  0 siblings, 1 reply; 17+ messages in thread
From: Mike Frysinger @ 2023-11-29  7:58 UTC (permalink / raw)
  To: jaydeep.patil; +Cc: gdb-patches, aburgess, joseph.faulls, bhushan.attarde

[-- Attachment #1: Type: text/plain, Size: 874 bytes --]

On 30 Oct 2023 13:00, jaydeep.patil@imgtec.com wrote:
> Added support for compressed integer instruction set ("c").

i haven't been keeping up with riscv specs.  is the compressed extension
finalized ?  so you're only implementing official insns in the spec ?  i
don't think it's appropriate for the sim to implement vendor-specific
stuff at this point in time.

> Added gdb.arch/riscv-insn-simulation.c to test it.
> Added simulator tests in sim/testsuite/riscv/c-ext.s

afaict, there is no relationship between the compression & semi-hosting work.
these are just two things you're working on ?  so they don't really need to
be in the same patch series.

>  .../gdb.arch/riscv-insn-simulation.c          | 1544 +++++++++++++++++
>  .../gdb.arch/riscv-insn-simulation.exp        |   31 +

i'm missing something ... why does there need to be tests in gdb at all here ?
-mike

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v2 1/3] [sim/riscv] Add basic semi-hosting support
  2023-11-29  7:57   ` Mike Frysinger
@ 2023-12-12 17:24     ` Andrew Burgess
  2023-12-13  3:43       ` Mike Frysinger
  2023-12-19  6:13     ` [EXTERNAL] " Jaydeep Patil
  1 sibling, 1 reply; 17+ messages in thread
From: Andrew Burgess @ 2023-12-12 17:24 UTC (permalink / raw)
  To: Mike Frysinger, jaydeep.patil; +Cc: gdb-patches, joseph.faulls, bhushan.attarde

Mike Frysinger <vapier@gentoo.org> writes:

> On 30 Oct 2023 13:00, jaydeep.patil@imgtec.com wrote:
>> Added support for basic semi-hosting calls OPEN, EXIT and GET_CMDLINE.
>
> what host environment are you implementing ?  none of the syscalls you've
> defined match what have long been in the riscv libgloss port.  those are
> the only ones i'd really expect at this point to be wired up.

This would be the RISC-V semihosting target, which is included in
newlib (since 2020), but is separate to libgloss.

Where libgloss syscalls use ecall, the semihosting uses ebreak with two
specific nop instructions (one before, one after the ebreak).

Do you see any reason why we can't support both of these syscall
libraries?  Potentially we could have a switch to select between them,
but I'm inclined to say we should just support both until someone comes
with a use-case where supporting both is a bad idea...  But maybe you
have some deeper insights here.

>
>> Added gdb.arch/riscv-exit-getcmd.c to test it.
>> ---
>>  gdb/testsuite/gdb.arch/riscv-exit-getcmd.c   |  26 +++
>>  gdb/testsuite/gdb.arch/riscv-exit-getcmd.exp |  27 +++
>>  sim/riscv/riscv-sim.h                        |  32 +++
>>  sim/riscv/sim-main.c                         | 230 ++++++++++++++++++-
>
> you're missing sim/ tests.  gdb tests are great, but not sufficient.

100% agree with this.

Thanks,
Andrew

>
>> @@ -990,6 +1209,7 @@ execute_one (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op)
>>      case INSN_CLASS_A:
>>        return execute_a (cpu, iw, op);
>>      case INSN_CLASS_I:
>> +    case INSN_CLASS_ZICSR:
>>        return execute_i (cpu, iw, op);
>
> seems unrelated to this patch
> -mike


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v2 1/3] [sim/riscv] Add basic semi-hosting support
  2023-10-30 13:00 ` [PATCH v2 1/3] [sim/riscv] Add basic " jaydeep.patil
  2023-11-29  7:57   ` Mike Frysinger
@ 2023-12-12 17:57   ` Andrew Burgess
  1 sibling, 0 replies; 17+ messages in thread
From: Andrew Burgess @ 2023-12-12 17:57 UTC (permalink / raw)
  To: jaydeep.patil, gdb-patches
  Cc: vapier, joseph.faulls, bhushan.attarde, jaydeep.patil

<jaydeep.patil@imgtec.com> writes:

> From: Jaydeep Patil <jaydeep.patil@imgtec.com>
>
> Added support for basic semi-hosting calls OPEN, EXIT and GET_CMDLINE.
> Added gdb.arch/riscv-exit-getcmd.c to test it.
> ---
>  gdb/testsuite/gdb.arch/riscv-exit-getcmd.c   |  26 +++
>  gdb/testsuite/gdb.arch/riscv-exit-getcmd.exp |  27 +++
>  sim/riscv/riscv-sim.h                        |  32 +++
>  sim/riscv/sim-main.c                         | 230 ++++++++++++++++++-
>  4 files changed, 310 insertions(+), 5 deletions(-)
>  create mode 100644 gdb/testsuite/gdb.arch/riscv-exit-getcmd.c
>  create mode 100644 gdb/testsuite/gdb.arch/riscv-exit-getcmd.exp
>
> diff --git a/gdb/testsuite/gdb.arch/riscv-exit-getcmd.c b/gdb/testsuite/gdb.arch/riscv-exit-getcmd.c
> new file mode 100644
> index 00000000000..02a97da8643
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/riscv-exit-getcmd.c
> @@ -0,0 +1,26 @@
> +/* This file is part of GDB, the GNU debugger.
> +
> +   Copyright 2023 Free Software Foundation, Inc.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +/* Test basic semi-hosting calls SYS_GET_CMDLINE and SYS_EXIT.  */
> +
> +int
> +main (int argc, char **argv)
> +{
> +  if (argc != 4)
> +    return 1;
> +  return 0;
> +}
> diff --git a/gdb/testsuite/gdb.arch/riscv-exit-getcmd.exp b/gdb/testsuite/gdb.arch/riscv-exit-getcmd.exp
> new file mode 100644
> index 00000000000..7f5670200c2
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/riscv-exit-getcmd.exp
> @@ -0,0 +1,27 @@
> +# Copyright 2023 Free Software Foundation, Inc.
> +#
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +
> +# Test basic semi-hosting calls SYS_GET_CMDLINE and SYS_EXIT.
> +
> +require {istarget "riscv*-*-*"}
> +
> +standard_testfile
> +
> +if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \
> +	  {debug quiet}] } {
> +    return -1
> +}
> +
> +gdb_test "run 1 2 3" ".*Inferior.*process.*exited normally.*"
> diff --git a/sim/riscv/riscv-sim.h b/sim/riscv/riscv-sim.h
> index 1bc9aa12156..bb296fa6e62 100644
> --- a/sim/riscv/riscv-sim.h
> +++ b/sim/riscv/riscv-sim.h
> @@ -75,4 +75,36 @@ extern void initialize_env (SIM_DESC, const char * const *argv,
>  
>  #define RISCV_XLEN(cpu) MACH_WORD_BITSIZE (CPU_MACH (cpu))
>  
> +#define APPLICATION_EXIT 0x20026
> +
> +#define SYS_OPEN 0x01
> +#define SYS_GET_CMDLINE 0x15
> +#define SYS_EXIT 0x18

I wonder if we should avoid the SYS_ prefix here?  And instead go with
something that binds these more tightly to semi-hosting?  SEMIHOST_
maybe? e.g. SEMIHOST_OPEN

> +
> +#define GDB_O_RDONLY 0x000
> +#define GDB_O_WRONLY 0x001
> +#define GDB_O_RDWR 0x002
> +#define GDB_O_APPEND 0x008
> +#define GDB_O_CREAT 0x200
> +#define GDB_O_TRUNC 0x400
> +#define GDB_O_BINARY 0

The GDB_ prefix seems weird.  I haven't tried to figure this out.  Is
this in some way GDB specific?

> +
> +#define SEMI_HOSTING_SLLI 0x01f01013
> +#define SEMI_HOSTING_SRAI 0x40705013
> +
> +static int gdb_open_modeflags[12] = {
> +  GDB_O_RDONLY,
> +  GDB_O_RDONLY | GDB_O_BINARY,
> +  GDB_O_RDWR,
> +  GDB_O_RDWR | GDB_O_BINARY,
> +  GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC,
> +  GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY,
> +  GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC,
> +  GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY,
> +  GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND,
> +  GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY,
> +  GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND,
> +  GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY
> +};

So, my instinct would be that all of these should be moved into
sim-main.c.  That's the only place they are used, and is likely the only
place they are going to be used ... so I see no reason why they need to
live in the header file.

Additionally, I think we need to comment some/all of these defines; e.g.
APPLICATION_EXIT needs a comment, SEMI_HOSTING_{SLLI,SRAI} need
comments, and gdb_open_modeflags would need comments.  You should
describe where these values come from, what they mean, where should I go
to read/understand more (e.g. name the spec or reference implementation).

> +
>  #endif
> diff --git a/sim/riscv/sim-main.c b/sim/riscv/sim-main.c
> index afdfcf50656..8e08eb9fc4e 100644
> --- a/sim/riscv/sim-main.c
> +++ b/sim/riscv/sim-main.c
> @@ -136,6 +136,176 @@ store_csr (SIM_CPU *cpu, const char *name, int csr, unsigned_word *reg,
>    TRACE_REGISTER (cpu, "wrote CSR %s = %#" PRIxTW, name, val);
>  }
>  
> +/* Read 4 or 8 bytes of data from the core memory.  ADDR and (INDEX * XLEN)
> +   form the base address.  */
> +static uintptr_t

I would have thought unsigned_8 would be a better return type.  The
requirement for this function is that it return something unsigned, and
at least 8-bytes in length.

Also the comment should say that 4-byte values are zero extended.

> +get_core_data (SIM_CPU *cpu, unsigned_word addr, unsigned_word index)
> +{
> +  uintptr_t param;
> +  int xlen = RISCV_XLEN (cpu);
> +  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
> +
> +  if (xlen == 64)
> +    param = sim_core_read_unaligned_8 (cpu, riscv_cpu->pc, read_map,
> +		addr + (index * 8));
> +  else
> +    param = sim_core_read_unaligned_4 (cpu, riscv_cpu->pc, read_map,
> +		addr + (index * 4));
> +
> +  return param;
> +}
> +
> +/* Write string in HOST_BUF at CORE_ADDR.  The length of string is LEN.  */
> +static void
> +set_core_string (SIM_CPU *cpu, unsigned_word core_addr, char *host_buf,
> +		 int len)
> +{
> +  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
> +  for (int i = 0; i < len; i++)
> +    {
> +      sim_core_write_unaligned_1 (cpu, riscv_cpu->pc, write_map,
> +				  core_addr + i, host_buf[i]);
> +    }

GNU style it to drop the { ... } around single statement blocks.

> +}
> +
> +/* Read string of length LEN at address ADDR.  */
> +static char *
> +get_core_string_with_len (SIM_CPU *cpu, unsigned_word addr,
> +			  unsigned_word len)
> +{
> +  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
> +  char * str;
> +  str = (char *) malloc (len + 1);

Use xmalloc.  It will handle (abort) for failure to allocate memory.

> +
> +  for (int i = 0; i < len; i++)
> +    {
> +      str[i] = sim_core_read_unaligned_1 (cpu, riscv_cpu->pc, read_map,
> +					  addr + i);
> +    }

Same with the single statement block.

> +  str[len] = 0;

Better I think to write:

  str[len] = '\0';

> +
> +  return str;
> +}
> +
> +/* SYS_OPEN
> +   Register a1 points to a buffer containing:
> +   Index 0: Pointer: Address of the file name string.
> +   Index 1: Integer: File open flags.
> +   Index 2: Integer: Length of the file name string.
> +   File handle is returned through register a0.  */
> +static void
> +semihosting_open (SIM_CPU *cpu)
> +{
> +  uintptr_t fname_addr;
> +  uintptr_t flags;
> +  uintptr_t fname_len;
> +  char *name;
> +  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
> +
> +  fname_addr = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 0);
> +  flags = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 1);
> +  fname_len = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 2);

These casts all seem redundant given the return type of get_core_data.

> +
> +  if (fname_len <= 0)
> +    {
> +      riscv_cpu->a0 = -1;
> +      return;
> +    }

I wonder if we should place some (arbitrary) cap on fname_len.  A badly
behaved application could cause the simulator to (try and) allocate 2^64
bytes of memory.

> +
> +  name = get_core_string_with_len (cpu, fname_addr, fname_len);
> +  riscv_cpu->a0 = sim_io_open (CPU_STATE (cpu), name,
> +			       gdb_open_modeflags[flags]);
> +  free (name);
> +}
> +
> +/* SYS_EXIT.  In case of RV32, register a1 holds the application stop reason
> +   and the exit code is decided based on it.  Otherwise, register a1 points to
> +   a buffer containing:
> +   Index 0: Integer: Application stop reason (ignored)
> +   Index 1: Integer: Exit code.  */
> +static void
> +semihosting_exit (SIM_CPU *cpu)
> +{
> +  uintptr_t app_code, exit_code;
> +  SIM_DESC sd = CPU_STATE (cpu);
> +  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
> +  if (RISCV_XLEN (cpu) == 32)
> +    {
> +      app_code = riscv_cpu->a1;
> +      if (app_code == APPLICATION_EXIT)
> +	exit_code = 0;
> +      else
> +	exit_code = 1;
> +    }
> +  else
> +    exit_code = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 1);
> +  riscv_cpu->a0 = exit_code;
> +  sim_engine_halt (sd, cpu, NULL, riscv_cpu->pc, sim_exited, exit_code);

I wonder if we should try to marshal these calls through sim_syscall
where possible?  I know we're going to need some syscall specific stubs
for each syscall as fetching the arguments is not as simple as just
reading the registers as for the ecall syscall case.  But it feels like,
once we've got the arguments we should try to get back onto the "normal"
syscall handling path if possible.  Thoughts?

> +}
> +
> +/* SYS_GET_CMDLINE.  Write command line arguments to a buffer.  Arguments
> +   passed to "run" command are stored in STATE_PROG_ARGV member of SIM_DESC.
> +   Register a1 points to a buffer containing:
> +   Index 0: Pointer: Buffer to store command line arguments
> +   Index 1: Integer: Maximum length of the buffer.  */
> +static void
> +semihosting_get_cmdline (SIM_CPU *cpu)
> +{

So this one, I think, doesn't have a "normal" syscall equivalent (or
maybe I missed it?), so this is going to have to be handled separately,
but that's OK I think.

> +  int i = 0, len = 0, total_len = 0;
> +  uintptr_t buf_addr, max_buf_len;
> +  SIM_DESC sd = CPU_STATE (cpu);
> +  char *space = " ";
> +  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
> +
> +  char **prog_argv = STATE_PROG_ARGV (sd);
> +  if (prog_argv == NULL)
> +    {
> +      riscv_cpu->a0 = 1; /* Return non-zero to indicate error.  */

Comments before the line of code please, not at the end of the line.

> +      return;
> +    }
> +
> +  buf_addr = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 0);
> +  max_buf_len = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 1);

Unnecessary casts again.

> +
> +  while (prog_argv[i])
> +    {
> +      len = strlen (prog_argv[i]);
> +      if ((total_len + len) > max_buf_len)
> +	break;
> +      set_core_string (cpu, buf_addr, prog_argv[i], len);
> +      set_core_string (cpu, buf_addr + len, space, 1);
> +      len++;	/* Terminate it with space.  */

Comment before the line of code.  And I don't see how that line is
adding a space, so the comment doesn't help me understand ... it's just
a clue that I need to go and investigate this code.

> +      buf_addr += len;
> +      total_len += len;
> +      i++;
> +    }
> +  riscv_cpu->a0 = 0;	/* No error.  */
> +}
> +
> +/* Handle semi-hosting calls.  Register a0 contains semi-hosting call number
> +   and a1 contains pointer to a buffer containing additional arguments.  */
> +static int
> +do_semihosting (SIM_CPU *cpu)
> +{
> +  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
> +  switch (riscv_cpu->a0)
> +    {
> +    case SYS_OPEN:
> +      semihosting_open (cpu);
> +      break;
> +    case SYS_GET_CMDLINE:
> +      semihosting_get_cmdline (cpu);
> +      break;
> +    case SYS_EXIT:
> +      semihosting_exit (cpu);
> +      break;
> +    default:
> +      return -1;	/* Semi-hosting call not supported.  */
> +    }
> +
> +  return 0;
> +}
> +
>  static inline unsigned_word
>  ashiftrt (unsigned_word val, unsigned_word shift)
>  {
> @@ -623,11 +793,60 @@ execute_i (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op)
>        TRACE_INSN (cpu, "fence.i;");
>        break;
>      case MATCH_EBREAK:
> -      TRACE_INSN (cpu, "ebreak;");
> -      /* GDB expects us to step over EBREAK.  */
> -      sim_engine_halt (sd, cpu, NULL, riscv_cpu->pc + 4, sim_stopped,
> -		       SIM_SIGTRAP);
> -      break;
> +	{

I think this whole semi-hosting logic should be moved out of this switch
statement into a separate function.  While reviewing I played around
with this, and ended up with this code in the switch statement:

    case MATCH_EBREAK:
      if (check_and_handle_riscv_semihosting (cpu, &pc))
	break;

      /* Not a RISC-V semihosting syscall.  */
      TRACE_INSN (cpu, "ebreak;");
      sim_engine_halt (sd, cpu, NULL, riscv_cpu->pc, sim_stopped,
		       SIM_SIGTRAP);
      break;

And then check_and_handle_riscv_semihosting was declared as:

  /* The instruction at *PC_PTR is assumed to be an ebreak instruction.
     Check if this ebreak is surrounded by the required slli/srai
     instructions that indicate this is a semihosting call.
  
     If this is a semihosting call then extract the argument data and
     perform the syscall, return 1 (true) to indicate a call was handled.  In
     this case, *PC_PTR is updated to point at the next instruction to
     execute, this will be the instruction after the srai.
  
     If no semihosting call was handled then return 0 (false).  */
  
  static int
  check_and_handle_riscv_semihosting (SIM_CPU *cpu, sim_cia *pc_ptr)
  { ... }

The implementation was what you wrote, just moved to the function.  I
think this makes it much easier, when scanning the original switch
statement, to understand what happens for an EBREAK.


> +	  /* If ebreak is at PC 0 then do not check for semi-hosting.  */
> +	  if (riscv_cpu->pc != 0)
> +	    {
> +	      /* RISC-V semi-hosting call is flagged using these three
> +		 instructions

I think this comment should explain that the random 32-bit hex numbers
in the following are the instruction encodings.  Also, I'd be very
tempted to move the SEMI_HOSTING_{SLLI,SRAI} definitions to somewhere
just after this comment.  They are only needed in this function, this
comment explains exactly what's going on ... feels like the perfect
location.

> +		 slli zero, zero, 0x1f	0x01f01013
> +		 ebreak			0x00100073
> +		 srai zero, zero, 0x7	0x40705013
> +		 Register a0 holds the system call number and a1 holds the
> +		 pointer to parameter buffer.  Do not read 4 bytes in one go
> +		 as we might read malformed 4 byte instruction.  */

This whole "Do not read 4 bytes in one go ..." business, is this just
an optimisation.  I don't see the problem with reading 4 bytes in one
go, and then checking the instruction length, and discarding if it is
wrong.  It feels like the double read is more complicated than the naive
approach....

> +	      int iw_len;
> +	      sim_cia pre_pc = riscv_cpu->pc - 4;
> +	      unsigned_word pre_iw;
> +	      pre_iw = sim_core_read_aligned_2 (cpu, pre_pc, exec_map, pre_pc);
> +	      iw_len = riscv_insn_length (pre_iw);
> +	      if (iw_len == 4)
> +		pre_iw |= ((unsigned_word) sim_core_read_aligned_2
> +			   (cpu, pre_pc, exec_map, pre_pc + 2) << 16);
> +
> +	      if (pre_iw == SEMI_HOSTING_SLLI)
> +		{
> +		  sim_cia post_pc = riscv_cpu->pc + 4;
> +		  unsigned_word post_iw;
> +		  post_iw = sim_core_read_aligned_2 (cpu, post_pc, exec_map,
> +						     post_pc);
> +		  iw_len = riscv_insn_length (post_iw);
> +		  if (iw_len == 4)
> +		    post_iw |= ((unsigned_word) sim_core_read_aligned_2
> +				(cpu, post_pc, exec_map, post_pc + 2) << 16);

Same double read that I don't understand the need for.

> +
> +		  if (post_iw == SEMI_HOSTING_SRAI)
> +		    {
> +		      TRACE_INSN (cpu, "semi-hosting a0=%lx,a1=%lx;",
> +				  riscv_cpu->a0, riscv_cpu->a1);
> +		      if (do_semihosting (cpu))
> +			{
> +			  /* Invalid semi-hosting call.  */
> +			  TRACE_INSN (cpu, "ebreak;");
> +			  sim_engine_halt (sd, cpu, NULL, riscv_cpu->pc,
> +					   sim_stopped, SIM_SIGTRAP);
> +			}
> +		      else
> +			pc = pc + 4;	/* post srai.  */
> +		      break;
> +		    }
> +		}
> +	    }
> +	  TRACE_INSN (cpu, "ebreak;");
> +	  sim_engine_halt (sd, cpu, NULL, riscv_cpu->pc, sim_stopped,
> +			   SIM_SIGTRAP);
> +	  break;
> +	}
>      case MATCH_ECALL:
>        TRACE_INSN (cpu, "ecall;");
>        riscv_cpu->a0 = sim_syscall (cpu, riscv_cpu->a7, riscv_cpu->a0,
> @@ -990,6 +1209,7 @@ execute_one (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op)
>      case INSN_CLASS_A:
>        return execute_a (cpu, iw, op);
>      case INSN_CLASS_I:
> +    case INSN_CLASS_ZICSR:

Revert this change?

Thanks,
Andrew

>        return execute_i (cpu, iw, op);
>      case INSN_CLASS_M:
>      case INSN_CLASS_ZMMUL:
> -- 
> 2.25.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v2 1/3] [sim/riscv] Add basic semi-hosting support
  2023-12-12 17:24     ` Andrew Burgess
@ 2023-12-13  3:43       ` Mike Frysinger
  2023-12-18 12:44         ` Andrew Burgess
  0 siblings, 1 reply; 17+ messages in thread
From: Mike Frysinger @ 2023-12-13  3:43 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: jaydeep.patil, gdb-patches, joseph.faulls, bhushan.attarde

[-- Attachment #1: Type: text/plain, Size: 2448 bytes --]

On 12 Dec 2023 17:24, Andrew Burgess wrote:
> Mike Frysinger <vapier@gentoo.org> writes:
> > On 30 Oct 2023 13:00, jaydeep.patil@imgtec.com wrote:
> >> Added support for basic semi-hosting calls OPEN, EXIT and GET_CMDLINE.
> >
> > what host environment are you implementing ?  none of the syscalls you've
> > defined match what have long been in the riscv libgloss port.  those are
> > the only ones i'd really expect at this point to be wired up.
> 
> This would be the RISC-V semihosting target, which is included in
> newlib (since 2020), but is separate to libgloss.

included where exactly ?  newlib/libc/machine/riscv/ has no syscalls afaict.
the word "semi" doesn't really appear anywhere in the codebase.

if you're referring to this commit, it's in libgloss, not newlib.
https://sourceware.org/git/?p=newlib-cygwin.git;a=commit;h=865cd30dcc2f00c81c8b3624a9f3464138cd24a5

looking at libgloss/riscv/machine/syscall.h, i see it defines the two sets
in parallel -- SYS_xxx and SEMIHOST_xxx.

the question is why does libgloss have both ?  if the riscv libgloss SYS_xxx
are only used by libgloss, and no one is implementing that (the sim hasn't),
and SEMIHOST_xxx are used by everyone, why not only use the semihost interface
and drop the SYS_xxx (and rename SEMIHOST_xxx to SYS_xxx).

where exactly is the riscv semihost standard defined such that people are
implementing the same API (source files) & ABI (the stub that processes the
ebreak calls) ?

> Where libgloss syscalls use ecall, the semihosting uses ebreak with two
> specific nop instructions (one before, one after the ebreak).

the calling convention doesn't really matter to the sim.  it can do either.

the question is whether we want to support them simultaneously, or only one
at a time.  what are other stubs doing ?

> Do you see any reason why we can't support both of these syscall
> libraries?  Potentially we could have a switch to select between them,
> but I'm inclined to say we should just support both until someone comes
> with a use-case where supporting both is a bad idea...  But maybe you
> have some deeper insights here.

supporting them both isn't a problem.  the port, as written, isn't following
our existing conventions for integrating with syscalls, but before i went down
that hole, i wanted to understand at a higher level the diff between the two.
the patch def needs a lot of work either way.
-mike

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v2 1/3] [sim/riscv] Add basic semi-hosting support
  2023-12-13  3:43       ` Mike Frysinger
@ 2023-12-18 12:44         ` Andrew Burgess
  2023-12-18 23:06           ` Mike Frysinger
  0 siblings, 1 reply; 17+ messages in thread
From: Andrew Burgess @ 2023-12-18 12:44 UTC (permalink / raw)
  To: Mike Frysinger; +Cc: jaydeep.patil, gdb-patches, joseph.faulls, bhushan.attarde

Mike Frysinger <vapier@gentoo.org> writes:

> On 12 Dec 2023 17:24, Andrew Burgess wrote:
>> Mike Frysinger <vapier@gentoo.org> writes:
>> > On 30 Oct 2023 13:00, jaydeep.patil@imgtec.com wrote:
>> >> Added support for basic semi-hosting calls OPEN, EXIT and GET_CMDLINE.
>> >
>> > what host environment are you implementing ?  none of the syscalls you've
>> > defined match what have long been in the riscv libgloss port.  those are
>> > the only ones i'd really expect at this point to be wired up.
>> 
>> This would be the RISC-V semihosting target, which is included in
>> newlib (since 2020), but is separate to libgloss.
>
> included where exactly ?  newlib/libc/machine/riscv/ has no syscalls afaict.
> the word "semi" doesn't really appear anywhere in the codebase.

I was referring to newlib the project rather than newlib the libc
library.  Which you figured out once you did a grep ...

> if you're referring to this commit, it's in libgloss, not newlib.
> https://sourceware.org/git/?p=newlib-cygwin.git;a=commit;h=865cd30dcc2f00c81c8b3624a9f3464138cd24a5

Yeah, it's a bit "yuck".  The commit lives in the libgloss directory,
but actually adds a parallel set of build rules that create a
libsemihost.a as a separate thing from libgloss.a, hence my "separate to
libgloss" comment.  Which I'll argue is both correct and incorrect at
the same time (correct: it's a separate library, incorrect: it's within
the libgloss part of the newlib project tree).

>
> looking at libgloss/riscv/machine/syscall.h, i see it defines the two sets
> in parallel -- SYS_xxx and SEMIHOST_xxx.
>
> the question is why does libgloss have both ?  if the riscv libgloss SYS_xxx
> are only used by libgloss, and no one is implementing that (the sim hasn't),
> and SEMIHOST_xxx are used by everyone, why not only use the semihost interface
> and drop the SYS_xxx (and rename SEMIHOST_xxx to SYS_xxx).

I don't know why they are both defined at the same time.  I guess that
could be changed.

I also don't know who implements either the semihosting syscalls, or the
libgloss sys_* syscalls.

>
> where exactly is the riscv semihost standard defined such that people are
> implementing the same API (source files) & ABI (the stub that processes the
> ebreak calls) ?

This is where things get even more iffy.  As best I can tell the RISC-V
semihosting spec is here:

  https://github.com/riscv-software-src/riscv-semihosting/blob/main/riscv-semihosting-spec.adoc

But this looks far from complete to me.  The commit that added
semihosting to newlib (the project) can be found here:

  https://inbox.sourceware.org/newlib/694d497b-bc07-a3ba-2643-a7336927e9a7@embecosm.com/

Comments in that thread seem to indicate that the situation is more of a
ad hoc standard, with (maybe) openocd being a first reference
implementation?  However, it is supported by QEMU with commit
a10b9d93ecea0a8 (though I think there are additional follow up commits
relating to this topic) so there are definitely other simulators
supporting this out there.

>
>> Where libgloss syscalls use ecall, the semihosting uses ebreak with two
>> specific nop instructions (one before, one after the ebreak).
>
> the calling convention doesn't really matter to the sim.  it can do either.
>
> the question is whether we want to support them simultaneously, or only one
> at a time.  what are other stubs doing ?

I haven't looked.  I'll leave that as an exercise for Jaydeep.  I'd be
open to supporting both simultaneously as a first cut ... but I guess if
you feel strongly then I'm not against making it a requirement for this
to be switchable... it feels like that should be simple enough.

>
>> Do you see any reason why we can't support both of these syscall
>> libraries?  Potentially we could have a switch to select between them,
>> but I'm inclined to say we should just support both until someone comes
>> with a use-case where supporting both is a bad idea...  But maybe you
>> have some deeper insights here.
>
> supporting them both isn't a problem.  the port, as written, isn't following
> our existing conventions for integrating with syscalls, but before i went down
> that hole, i wanted to understand at a higher level the diff between the two.
> the patch def needs a lot of work either way.

For my own education; the ECALL handling does make use of sim_syscall.
When you say: "the port, as written, isn't following our existing
conventions for integrating with syscalls", do you mean the new
semihosting port?  Or are you saying the (pre-patch) existing code is
also not using the standard sim syscall mechanism?

The problem I see (at a quick glance) with the semihosting API is that
the syscall arguments are read from memory, while the existing syscall
mechanism seems to assume syscall arguments are in registers.  My
initial thoughts were that getting the semihosting support to use the
existing mechanism might not be straight forward.

Thanks,
Andrew


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v2 1/3] [sim/riscv] Add basic semi-hosting support
  2023-12-18 12:44         ` Andrew Burgess
@ 2023-12-18 23:06           ` Mike Frysinger
  0 siblings, 0 replies; 17+ messages in thread
From: Mike Frysinger @ 2023-12-18 23:06 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: jaydeep.patil, gdb-patches, joseph.faulls, bhushan.attarde

[-- Attachment #1: Type: text/plain, Size: 8304 bytes --]

On 18 Dec 2023 12:44, Andrew Burgess wrote:
> Mike Frysinger <vapier@gentoo.org> writes:
> > On 12 Dec 2023 17:24, Andrew Burgess wrote:
> >> Mike Frysinger <vapier@gentoo.org> writes:
> >> > On 30 Oct 2023 13:00, jaydeep.patil@imgtec.com wrote:
> >> >> Added support for basic semi-hosting calls OPEN, EXIT and GET_CMDLINE.
> >> >
> >> > what host environment are you implementing ?  none of the syscalls you've
> >> > defined match what have long been in the riscv libgloss port.  those are
> >> > the only ones i'd really expect at this point to be wired up.
> >> 
> >> This would be the RISC-V semihosting target, which is included in
> >> newlib (since 2020), but is separate to libgloss.
> >
> > included where exactly ?  newlib/libc/machine/riscv/ has no syscalls afaict.
> > the word "semi" doesn't really appear anywhere in the codebase.
> 
> I was referring to newlib the project rather than newlib the libc
> library.  Which you figured out once you did a grep ...

some ports put their syscalls under newlib/.  it was more common in the past,
but the point of libgloss was to pull such things out.  it's why i was precise
when i said "libgloss" and not generically "newlib".  new ports should not be
putting things like syscalls into newlib, they should be in libgloss.

the exact path is important because we automate importing of syscalls from
libgloss & newlib (see sim/common/gennltvals.py), and handcoding the table in
the sim is not what we want at all.

> > if you're referring to this commit, it's in libgloss, not newlib.
> > https://sourceware.org/git/?p=newlib-cygwin.git;a=commit;h=865cd30dcc2f00c81c8b3624a9f3464138cd24a5
> 
> Yeah, it's a bit "yuck".  The commit lives in the libgloss directory,
> but actually adds a parallel set of build rules that create a
> libsemihost.a as a separate thing from libgloss.a, hence my "separate to
> libgloss" comment.  Which I'll argue is both correct and incorrect at
> the same time (correct: it's a separate library, incorrect: it's within
> the libgloss part of the newlib project tree).

the output of the libgloss/ tree is not standard by any means.  while riscv
creates a literal "libgloss.a" file, that is not the most common behavior.
considering the mess and complete lack of agreement between gcc specs and
the libgloss project outputs, better to be precise here.

> > where exactly is the riscv semihost standard defined such that people are
> > implementing the same API (source files) & ABI (the stub that processes the
> > ebreak calls) ?
> 
> This is where things get even more iffy.  As best I can tell the RISC-V
> semihosting spec is here:
> 
>   https://github.com/riscv-software-src/riscv-semihosting/blob/main/riscv-semihosting-spec.adoc
> 
> But this looks far from complete to me.  The commit that added
> semihosting to newlib (the project) can be found here:
> 
>   https://inbox.sourceware.org/newlib/694d497b-bc07-a3ba-2643-a7336927e9a7@embecosm.com/
> 
> Comments in that thread seem to indicate that the situation is more of a
> ad hoc standard, with (maybe) openocd being a first reference
> implementation?  However, it is supported by QEMU with commit
> a10b9d93ecea0a8 (though I think there are additional follow up commits
> relating to this topic) so there are definitely other simulators
> supporting this out there.

the rsicv-semihosting spec is real rough.  ignoring the opening paragraph:
> This is a Discussion Document: Assume everything can change. This document is not complete yet and was created only for the purpose of conversation outside of the document. See http://riscv.org/spec-state for more details.

it merely defines part of the calling standard.  basically how to trigger the
semihost.  it doesn't cover the actual calling convention (where do extra args
go), the syscall ABI (numbers/arguments/etc...), or how errors are passed back
(in the return register ?  sep location ?  what are the error numbers ?).  or
how are non-basic types defined & passed (e.g. is off_t always 32-bit ?  how
are 64-bit values passed on a 32-bit system ?).  padding ?  alignment ?

if there's disagreements/bugs in implementations, how do we decide which is the
"correct" behavior ?  if someone wants to add another syscall, who decides ?

the libgloss port seems like "written to work against whatever reference
implementation they had available" rather than to/with a spec.

the qemu commit also lacks details beyond the bare min spec you linked.  it
makes it sound like riscv is just reusing the semihost syscall numbers that
arm already has ?  is it just copying & pasting the entire arm ABI then ?
if that's the case, it screams even more "don't put it in riscv/".  we have
arm & aarch64 ports which could also benefit.

to compare, QEMU links to this page for ARM:
https://github.com/ARM-software/abi-aa/blob/main/semihosting/semihosting.rst
that's an actual spec -- 1500 lines of detailed content.

> >> Where libgloss syscalls use ecall, the semihosting uses ebreak with two
> >> specific nop instructions (one before, one after the ebreak).
> >
> > the calling convention doesn't really matter to the sim.  it can do either.
> >
> > the question is whether we want to support them simultaneously, or only one
> > at a time.  what are other stubs doing ?
> 
> I haven't looked.  I'll leave that as an exercise for Jaydeep.  I'd be
> open to supporting both simultaneously as a first cut ... but I guess if
> you feel strongly then I'm not against making it a requirement for this
> to be switchable... it feels like that should be simple enough.

if they're both actually developed/used, i'm fine with both.  i'm not keen on
supporting the treadmill of "new group wants new feature, designs new thing in
isolation, adds another syscall ABI".  we're left holding the bag of dead ABIs
no one cares about.  so when someone shows up with an under-specified new thing,
i'm automatically suspicious.

> >> Do you see any reason why we can't support both of these syscall
> >> libraries?  Potentially we could have a switch to select between them,
> >> but I'm inclined to say we should just support both until someone comes
> >> with a use-case where supporting both is a bad idea...  But maybe you
> >> have some deeper insights here.
> >
> > supporting them both isn't a problem.  the port, as written, isn't following
> > our existing conventions for integrating with syscalls, but before i went down
> > that hole, i wanted to understand at a higher level the diff between the two.
> > the patch def needs a lot of work either way.
> 
> For my own education; the ECALL handling does make use of sim_syscall.
> When you say: "the port, as written, isn't following our existing
> conventions for integrating with syscalls", do you mean the new
> semihosting port?  Or are you saying the (pre-patch) existing code is
> also not using the standard sim syscall mechanism?
> 
> The problem I see (at a quick glance) with the semihosting API is that
> the syscall arguments are read from memory, while the existing syscall
> mechanism seems to assume syscall arguments are in registers.  My
> initial thoughts were that getting the semihosting support to use the
> existing mechanism might not be straight forward.

i'm referring to the new semihost code in this thread.

the sim_syscall is not perfect by any means, but i'd like to focus on improving
the existing core rather than each port & syscall ABI doing it themselves.  we
end up with each port working diff depending on the host OS, and having to copy
and paste fixes/improvements between them.  i'm a bit guilty of this myself with
the Blackfin port, but in my defense, i wasn't as familiar with the codebase.

sim_syscall itself is a convenience if you have arguments in registers.  if they
are in memory, then you can unpack before calling sim_syscall_multi yourself.

other problems at a glance (as i haven't gone too deep yet):
* isn't respecting --environment framework (existing code needs fixing too)
* hardcoding syscall numbers instead of using our framework to extract
* no error handling afaict
* casting from target addresses/ints to host uintptr_t looks fundamentally wrong
-mike

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* RE: [EXTERNAL] Re: [PATCH v2 2/3] [sim/riscv] Add support for compressed integer instruction set
  2023-11-29  7:58   ` Mike Frysinger
@ 2023-12-19  6:11     ` Jaydeep Patil
  2023-12-20  1:32       ` Mike Frysinger
  0 siblings, 1 reply; 17+ messages in thread
From: Jaydeep Patil @ 2023-12-19  6:11 UTC (permalink / raw)
  To: Mike Frysinger; +Cc: gdb-patches, aburgess, Joseph Faulls, Bhushan Attarde

Mike Frysinger <vapier@gentoo.org> writes:

> i haven't been keeping up with riscv specs.  is the compressed extension finalized ?  so you're only implementing official insns in the spec ?  i don't think it's appropriate for the sim to implement vendor-specific stuff at this point in time.

The compressed instruction set ("c") is not vendor specific. It has been ratified.

> afaict, there is no relationship between the compression & semi-hosting work.
> these are just two things you're working on ?  so they don't really need to be in the same patch series.

Yes, there is no relation between compression & semi-hosting work. The patches are independent and I can re-submit them if needed.

> i'm missing something ... why does there need to be tests in gdb at all here ?

Purpose of riscv-insn-simulation.exp is to test both C extension and semi-hosting. However, I have also added sim specific tests in patch v3.

Regards,
Jaydeep


^ permalink raw reply	[flat|nested] 17+ messages in thread

* RE: [EXTERNAL] Re: [PATCH v2 1/3] [sim/riscv] Add basic semi-hosting support
  2023-11-29  7:57   ` Mike Frysinger
  2023-12-12 17:24     ` Andrew Burgess
@ 2023-12-19  6:13     ` Jaydeep Patil
  2023-12-20  1:45       ` Mike Frysinger
  1 sibling, 1 reply; 17+ messages in thread
From: Jaydeep Patil @ 2023-12-19  6:13 UTC (permalink / raw)
  To: Mike Frysinger; +Cc: gdb-patches, aburgess, Joseph Faulls, Bhushan Attarde

Mike Frysinger <vapier@gentoo.org> writes:

> what host environment are you implementing ?  none of the syscalls you've defined match what have long been in the riscv libgloss port.  those are the only ones i'd really expect at this point to be wired up.

The semi-hosting calls generated by newlib (--specs=semihost.specs option) and picolibc libraries.

> you're missing sim/ tests.  gdb tests are great, but not sufficient.

I have added c-ext.s in the sim tests.

> seems unrelated to this patch

Removed it in patch v3

Regards,
Jaydeep

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [EXTERNAL] Re: [PATCH v2 2/3] [sim/riscv] Add support for compressed integer instruction set
  2023-12-19  6:11     ` [EXTERNAL] " Jaydeep Patil
@ 2023-12-20  1:32       ` Mike Frysinger
  0 siblings, 0 replies; 17+ messages in thread
From: Mike Frysinger @ 2023-12-20  1:32 UTC (permalink / raw)
  To: Jaydeep Patil; +Cc: gdb-patches, aburgess, Joseph Faulls, Bhushan Attarde

[-- Attachment #1: Type: text/plain, Size: 1582 bytes --]

On 19 Dec 2023 06:11, Jaydeep Patil wrote:
> Mike Frysinger <vapier@gentoo.org> writes:
> > i haven't been keeping up with riscv specs.  is the compressed extension finalized ?  so you're only implementing official insns in the spec ?  i don't think it's appropriate for the sim to implement vendor-specific stuff at this point in time.
> 
> The compressed instruction set ("c") is not vendor specific. It has been ratified.

that's good.  it's still an extension though and not in the base ISA.  it
shouldn't be available all the time, only when a compatible model is selected
via the --model option.  otherwise it should throw an SIM_SIGILL error.

look at riscv/model_list.def and machs.c files.

> > afaict, there is no relationship between the compression & semi-hosting work.
> > these are just two things you're working on ?  so they don't really need to be in the same patch series.
> 
> Yes, there is no relation between compression & semi-hosting work. The patches are independent and I can re-submit them if needed.

not strictly necessary, but makes it confusing when you label the patch
"semihost", and there's debate on that particular topic.

> > i'm missing something ... why does there need to be tests in gdb at all here ?
> 
> Purpose of riscv-insn-simulation.exp is to test both C extension and semi-hosting. However, I have also added sim specific tests in patch v3.

none of the semihost logic lives in gdb.  it's entirely in the sim code.
there's no need to have any test logic added to gdb -- it can all be in
the sim tree.
-mike

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [EXTERNAL] Re: [PATCH v2 1/3] [sim/riscv] Add basic semi-hosting support
  2023-12-19  6:13     ` [EXTERNAL] " Jaydeep Patil
@ 2023-12-20  1:45       ` Mike Frysinger
  2023-12-20  8:52         ` Jaydeep Patil
  0 siblings, 1 reply; 17+ messages in thread
From: Mike Frysinger @ 2023-12-20  1:45 UTC (permalink / raw)
  To: Jaydeep Patil; +Cc: gdb-patches, aburgess, Joseph Faulls, Bhushan Attarde

[-- Attachment #1: Type: text/plain, Size: 513 bytes --]

On 19 Dec 2023 06:13, Jaydeep Patil wrote:
> Mike Frysinger <vapier@gentoo.org> writes:
> > what host environment are you implementing ?  none of the syscalls you've defined match what have long been in the riscv libgloss port.  those are the only ones i'd really expect at this point to be wired up.
> 
> The semi-hosting calls generated by newlib (--specs=semihost.specs option) and picolibc libraries.

what specification are you implementing ?  newlib is an implementation, not a specification.
-mike

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* RE: [EXTERNAL] Re: [PATCH v2 1/3] [sim/riscv] Add basic semi-hosting support
  2023-12-20  1:45       ` Mike Frysinger
@ 2023-12-20  8:52         ` Jaydeep Patil
  0 siblings, 0 replies; 17+ messages in thread
From: Jaydeep Patil @ 2023-12-20  8:52 UTC (permalink / raw)
  To: Mike Frysinger; +Cc: gdb-patches, aburgess, Joseph Faulls, Bhushan Attarde

Mike Frysinger <vapier@gentoo.org> writes:

> what specification are you implementing ?  newlib is an implementation, not a specification.

I am referring to https://github.com/riscv-software-src/riscv-semihosting/blob/main/riscv-semihosting-spec.adoc. This is still a discussion document and not ratified. The document says "RISC-V semihosting borrows from the design of other publicly available and open source semihosting mechanisms to minimize the development effort required. At some stage, the document referred to "Semihosting for AArch32 and AArch64" (https://github.com/riscv-software-src/riscv-semihosting/blob/de2a56ff73439b1d955e361eb4d35c0e8e453a42/riscv-semihosting-spec.adoc). Looking at the implementation of newlib and picolib, they are following the same specification.

Regards,
Jaydeep


^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2023-12-20  8:52 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-10-30 13:00 [PATCH v2 0/3] sim: riscv: Compressed instruction simulation and semi-hosting support jaydeep.patil
2023-10-30 13:00 ` [PATCH v2 1/3] [sim/riscv] Add basic " jaydeep.patil
2023-11-29  7:57   ` Mike Frysinger
2023-12-12 17:24     ` Andrew Burgess
2023-12-13  3:43       ` Mike Frysinger
2023-12-18 12:44         ` Andrew Burgess
2023-12-18 23:06           ` Mike Frysinger
2023-12-19  6:13     ` [EXTERNAL] " Jaydeep Patil
2023-12-20  1:45       ` Mike Frysinger
2023-12-20  8:52         ` Jaydeep Patil
2023-12-12 17:57   ` Andrew Burgess
2023-10-30 13:00 ` [PATCH v2 2/3] [sim/riscv] Add support for compressed integer instruction set jaydeep.patil
2023-11-29  7:58   ` Mike Frysinger
2023-12-19  6:11     ` [EXTERNAL] " Jaydeep Patil
2023-12-20  1:32       ` Mike Frysinger
2023-10-30 13:00 ` [PATCH v2 3/3] [sim/riscv] Add semi-hosting support jaydeep.patil
2023-11-13 12:07 ` [PATCH v2 0/3] sim: riscv: Compressed instruction simulation and " Jaydeep Patil

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).