Skip to contentSkip to conversation

target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G)

PATCH In review Sagar Karandikar 6 participants 45 messages Sep 26, 2016 – Sep 27, 2016

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G)

This patch set adds support for the RISC-V ISA [1] as a system-mode target. It has been tested booting Linux and FreeBSD, passes the RISC-V assembly test suite, and has had the riscv-torture [2] tester running on it for a while now without any issues arising. This patch set supports RV64G and RV32G.

Potentially useful references:
-RISC-V User Spec: See [3]. This spec is frozen.
-RISC-V Privileged Spec: See [4]. This spec is a draft, we implement v1.9. -Spike, the reference simulator for the ISA: See [5].

The comments from an earlier RFC were addressed:
-We use QEMU's built-in softfloat
-cpu-qom.h merged into cpu.h
-remove active_tc/riscv-defs.h that were mirrored from MIPS
-Use DEF_HELPER_FLAGS_* where necessary
-DIV/REM now use movcond instead of branches
-handlers for arithmetic instructions and their "W" counterparts were merged to reduce code duplication
-Updated to use tcg_gen_qemu_ld_tl(..., MO_SB) etc.

[1] https://riscv.org
[2] https://github.com/ucb-bar/riscv-torture
[3] https://content.riscv.org/wp-content/uploads/2016/06/riscv-spec-v2.1.pdf
[4] https://content.riscv.org/wp-content/uploads/2016/07/riscv-privileged-v1.9-1.pdf
[5] https://github.com/riscv/riscv-isa-sim

Sagar Karandikar (18):
target-riscv: Add RISC-V target stubs and Maintainer
target-riscv: Add RISC-V Target stubs inside target-riscv/
target-riscv: Add initialization for translation
target-riscv: Add framework for instruction decode
target-riscv: Add Arithmetic instructions
target-riscv: Add JALR, Branch Instructions
target-riscv: Add Loads/Stores, FP Loads/Stores
target-riscv: Add Atomic Instructions
target-riscv: Add FMADD, FMSUB, FNMADD, FNMSUB Instructions,
target-riscv: Add Single Precision Floating-Point Instructions
target-riscv: Add Double Precision Floating-Point Instructions
target-riscv: Add system instructions
target-riscv: Add CSR read/write helpers
target-riscv: softmmu/address translation support
target-riscv: Interrupt Handling
target-riscv: Timer Support
target-riscv: Add support for Host-Target Interface (HTIF) Devices
target-riscv: Add generic test board, activate target

 MAINTAINERS                           |    7 +
 arch_init.c                           |    2 +
 configure                             |    6 +
 cpus.c                                |    6 +
 default-configs/riscv32-softmmu.mak   |   38 +
 default-configs/riscv64-softmmu.mak   |   38 +
 fpu/softfloat-specialize.h            |    7 +-
 hw/riscv/Makefile.objs                |    5 +
 hw/riscv/cpudevs.h                    |   17 +
 hw/riscv/htif/elf_symb.c              |  286 ++++++
 hw/riscv/htif/elf_symb.h              |   80 ++
 hw/riscv/htif/htif.c                  |  423 +++++++++
 hw/riscv/riscv_board.c                |  264 ++++++
 hw/riscv/riscv_int.c                  |   67 ++
 hw/riscv/riscv_rtc.c                  |  230 +++++
 include/elf.h                         |    2 +
 include/hw/riscv/htif/htif.h          |   61 ++
 include/hw/riscv/riscv_rtc.h          |   25 +
 include/hw/riscv/riscv_rtc_internal.h |    3 +
 include/sysemu/arch_init.h            |    1 +
 qapi-schema.json                      |   14 +-
 target-riscv/Makefile.objs            |    1 +
 target-riscv/cpu.c                    |  154 +++
 target-riscv/cpu.h                    |  497 ++++++++++
 target-riscv/fpu_helper.c             |  582 ++++++++++++
 target-riscv/helper.c                 |  420 +++++++++
 target-riscv/helper.h                 |   87 ++
 target-riscv/instmap.h                |  328 +++++++
 target-riscv/op_helper.c              |  577 ++++++++++++
 target-riscv/translate.c              | 1658 +++++++++++++++++++++++++++++++++
 30 files changed, 5882 insertions(+), 4 deletions(-)
 create mode 100644 default-configs/riscv32-softmmu.mak
 create mode 100644 default-configs/riscv64-softmmu.mak
 create mode 100644 hw/riscv/Makefile.objs
 create mode 100644 hw/riscv/cpudevs.h
 create mode 100644 hw/riscv/htif/elf_symb.c
 create mode 100644 hw/riscv/htif/elf_symb.h
 create mode 100644 hw/riscv/htif/htif.c
 create mode 100644 hw/riscv/riscv_board.c
 create mode 100644 hw/riscv/riscv_int.c
 create mode 100644 hw/riscv/riscv_rtc.c
 create mode 100644 include/hw/riscv/htif/htif.h
 create mode 100644 include/hw/riscv/riscv_rtc.h
 create mode 100644 include/hw/riscv/riscv_rtc_internal.h
 create mode 100644 target-riscv/Makefile.objs
 create mode 100644 target-riscv/cpu.c
 create mode 100644 target-riscv/cpu.h
 create mode 100644 target-riscv/fpu_helper.c
 create mode 100644 target-riscv/helper.c
 create mode 100644 target-riscv/helper.h
 create mode 100644 target-riscv/instmap.h
 create mode 100644 target-riscv/op_helper.c
 create mode 100644 target-riscv/translate.c
Signature · 1 line
2.9.3
#1 lore raw

PATCH 1/18 target-riscv: Add RISC-V target stubs and Maintainer

Only files that live outside of target-riscv and hw/riscv, excluding configure and default-configs changes.

---
 MAINTAINERS                |  7 +++++++
 arch_init.c                |  2 ++
 cpus.c                     |  6 ++++++
 include/elf.h              |  2 ++
 include/sysemu/arch_init.h |  1 +
 qapi-schema.json           | 14 +++++++++++++-
 6 files changed, 31 insertions(+), 1 deletion(-)
MAINTAINERS +7 -0
index a3a2ad7..dbbbe0f 100644
@@ -175,6 +175,13 @@ F: hw/ppc/
 F: include/hw/ppc/
 F: disas/ppc.c
 
+RISC-V
+M: Sagar Karandikar <[email protected]>
+M: Bastian Koppelmann <[email protected]>
+S: Maintained
+F: target-riscv/
+F: hw/riscv/
+
 S390
 M: Richard Henderson <[email protected]>
 M: Alexander Graf <[email protected]>
arch_init.c +2 -0
index 5cc58b2..c89c45d 100644
@@ -62,6 +62,8 @@ int graphic_depth = 32;
 #define QEMU_ARCH QEMU_ARCH_MICROBLAZE
 #elif defined(TARGET_MIPS)
 #define QEMU_ARCH QEMU_ARCH_MIPS
+#elif defined(TARGET_RISCV)
+#define QEMU_ARCH QEMU_ARCH_RISCV
 #elif defined(TARGET_MOXIE)
 #define QEMU_ARCH QEMU_ARCH_MOXIE
 #elif defined(TARGET_OPENRISC)
cpus.c +6 -0
index e39ccb7..41ccc29 100644
@@ -1618,6 +1618,9 @@ CpuInfoList *qmp_query_cpus(Error **errp)
 #elif defined(TARGET_SPARC)
         SPARCCPU *sparc_cpu = SPARC_CPU(cpu);
         CPUSPARCState *env = &sparc_cpu->env;
+#elif defined(TARGET_RISCV)
+        RISCVCPU *riscv_cpu = RISCV_CPU(cpu);
+        CPURISCVState *env = &riscv_cpu->env;
 #elif defined(TARGET_MIPS)
         MIPSCPU *mips_cpu = MIPS_CPU(cpu);
         CPUMIPSState *env = &mips_cpu->env;
@@ -1651,6 +1654,9 @@ CpuInfoList *qmp_query_cpus(Error **errp)
 #elif defined(TARGET_TRICORE)
         info->value->arch = CPU_INFO_ARCH_TRICORE;
         info->value->u.tricore.PC = env->PC;
+#elif defined(TARGET_RISCV)
+        info->value->arch = CPU_INFO_ARCH_RISCV;
+        info->value->u.riscv.pc = env->PC;
 #else
         info->value->arch = CPU_INFO_ARCH_OTHER;
 #endif
include/elf.h +2 -0
index 1c2975d..1221359 100644
@@ -112,6 +112,8 @@ typedef int64_t  Elf64_Sxword;
 
 #define EM_UNICORE32    110     /* UniCore32 */
 
+#define EM_RISCV 243 /* RISC-V */
+
 /*
  * This is an interim value that we will use until the committee comes
  * up with a final number.
include/sysemu/arch_init.h +1 -0
index 1c9dad1..8684aac 100644
@@ -23,6 +23,7 @@ enum {
     QEMU_ARCH_UNICORE32 = (1 << 14),
     QEMU_ARCH_MOXIE = (1 << 15),
     QEMU_ARCH_TRICORE = (1 << 16),
+    QEMU_ARCH_RISCV = (1 << 17),
 };
 
 extern const uint32_t arch_type;
qapi-schema.json +13 -1
index e507061..11cd848 100644
@@ -832,7 +832,7 @@
 # Since: 2.6
 ##
 { 'enum': 'CpuInfoArch',
-  'data': ['x86', 'sparc', 'ppc', 'mips', 'tricore', 'other' ] }
+  'data': ['x86', 'sparc', 'ppc', 'mips', 'tricore', 'riscv', 'other' ] }
 
 ##
 # @CpuInfo:
@@ -867,6 +867,7 @@
             'ppc': 'CpuInfoPPC',
             'mips': 'CpuInfoMIPS',
             'tricore': 'CpuInfoTricore',
+            'riscv': 'CpuInfoRISCV',
             'other': 'CpuInfoOther' } }
 
 ##
@@ -927,6 +928,17 @@
 { 'struct': 'CpuInfoTricore', 'data': { 'PC': 'int' } }
 
 ##
+# @CpuInfoRISCV:
+#
+# Additional information about a virtual RISCV CPU
+#
+# @PC: the instruction pointer
+#
+# Since 2.6
+##
+{ 'struct': 'CpuInfoRISCV', 'data': { 'pc': 'int' } }
+
+##
 # @CpuInfoOther:
 #
 # No additional information is available about the virtual CPU
Signature · 1 line
2.9.3
#2 lore raw

Re: [Qemu-devel] [PATCH 01/18] target-riscv: Add RISC-V target stubs and Maintainer

qapi-schema.json line 835

Quoted 13 lines · Sagar Karandikar

Only files that live outside of target-riscv and hw/riscv, excluding configure and default-configs changes.

---

+++ b/qapi-schema.json

qapi-schema.json +1 -1
@@ -832,7 +832,7 @@
 # Since: 2.6
 ##
 { 'enum': 'CpuInfoArch',
-  'data': ['x86', 'sparc', 'ppc', 'mips', 'tricore', 'other' ] }
+  'data': ['x86', 'sparc', 'ppc', 'mips', 'tricore', 'riscv', 'other' ] }

Missing documentation that 'riscv' was added in 2.8. Enums aren't always the best example, but BlockdevDriver in qapi/block-core.json shows a good way of how to do it.

qapi-schema.json line 937

Quoted 11 lines
qapi-schema.json +7 -0
@@ -927,6 +928,17 @@
 { 'struct': 'CpuInfoTricore', 'data': { 'PC': 'int' } }
 
 ##
+# @CpuInfoRISCV:
+#
+# Additional information about a virtual RISCV CPU
+#
+# @PC: the instruction pointer
+#
+# Since 2.6

s/2.6/2.8/

And can we please NOT abuse the fact that CpuInfo is already whitelisted for allowing non-lowercase names?...

qapi-schema.json line 939

Quoted 2 lines
qapi-schema.json +2 -0
+##
+{ 'struct': 'CpuInfoRISCV', 'data': { 'pc': 'int' } }

Oh, you already did. Your documentation is wrong, then, as it documents 'PC' while the code uses 'pc'.

Signature · 2 lines
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org
#3 lore raw

PATCH 2/18 target-riscv: Add RISC-V Target stubs inside target-riscv/

In reply to Sagar Karandikar
---
 target-riscv/Makefile.objs |   1 +
 target-riscv/cpu.c         | 154 ++++++++++++++
 target-riscv/cpu.h         | 497 +++++++++++++++++++++++++++++++++++++++++++++
 target-riscv/helper.c      |  59 ++++++
 target-riscv/helper.h      |   0
 target-riscv/op_helper.c   |  44 ++++
 target-riscv/translate.c   | 131 ++++++++++++
 7 files changed, 886 insertions(+)
 create mode 100644 target-riscv/Makefile.objs
 create mode 100644 target-riscv/cpu.c
 create mode 100644 target-riscv/cpu.h
 create mode 100644 target-riscv/helper.c
 create mode 100644 target-riscv/helper.h
 create mode 100644 target-riscv/op_helper.c
 create mode 100644 target-riscv/translate.c
target-riscv/Makefile.objs new file +1 -0
new file mode 100644
index 0000000..cb448a8
@@ -0,0 +1 @@
+obj-y += translate.o op_helper.o helper.o cpu.o
target-riscv/cpu.c new file +154 -0

154 lines not on this page · raw message

target-riscv/cpu.h new file +497 -0

497 lines not on this page · raw message

target-riscv/helper.c new file +59 -0

59 lines not on this page · raw message

target-riscv/helper.h new file +0 -0
new file mode 100644
index 0000000..e69de29
target-riscv/op_helper.c new file +44 -0

44 lines not on this page · raw message

target-riscv/translate.c new file +131 -0

131 lines not on this page · raw message

Signature · 1 line
2.9.3
#4 lore raw

Re: [Qemu-devel] [PATCH 02/18] target-riscv: Add RISC-V Target stubs inside target-riscv/

target-riscv/cpu.h line 22

Quoted 8 lines · Sagar Karandikar
target-riscv/cpu.h new file +8 -0
+/* QEMU addressing/paging config */
+#define TARGET_PAGE_BITS 12 /* 4 KiB Pages */
+#if defined(TARGET_RISCV64)
+#define TARGET_LONG_BITS 64 /* this defs TCGv as TCGv_i64 in tcg/tcg-op.h */
+#define TARGET_PHYS_ADDR_SPACE_BITS 50
+#define TARGET_VIRT_ADDR_SPACE_BITS 39
+#elif defined(TARGET_RISCV32)
+#define TARGET_LONG_BITS 32 /* this defs TCGv as TCGv_i64 in tcg/tcg-op.h */

Typo, and there's not really a need for that comment anyway.

Quoted 1 line

+#define PGSHIFT 12

Just use TARGET_PAGE_BITS, surely.

Quoted 21 lines
target-riscv/cpu.h new file +21 -0
+#define MSTATUS_UIE         0x00000001
+#define MSTATUS_SIE         0x00000002
+#define MSTATUS_HIE         0x00000004
+#define MSTATUS_MIE         0x00000008
+#define MSTATUS_UPIE        0x00000010
+#define MSTATUS_SPIE        0x00000020
+#define MSTATUS_HPIE        0x00000040
+#define MSTATUS_MPIE        0x00000080
+#define MSTATUS_SPP         0x00000100
+#define MSTATUS_HPP         0x00000600
+#define MSTATUS_MPP         0x00001800
+#define MSTATUS_FS          0x00006000
+#define MSTATUS_XS          0x00018000
+#define MSTATUS_MPRV        0x00020000
+#define MSTATUS_PUM         0x00040000
+#define MSTATUS_MXR         0x00080000
+#define MSTATUS_VM          0x1F000000
+
+#define MSTATUS32_SD        0x80000000
+#define MSTATUS64_SD        0x8000000000000000
+

target-riscv/cpu.h line 185

Quoted 10 lines
target-riscv/cpu.h new file +10 -0
+#define SSTATUS_UIE         0x00000001
+#define SSTATUS_SIE         0x00000002
+#define SSTATUS_UPIE        0x00000010
+#define SSTATUS_SPIE        0x00000020
+#define SSTATUS_SPP         0x00000100
+#define SSTATUS_FS          0x00006000
+#define SSTATUS_XS          0x00018000
+#define SSTATUS_PUM         0x00040000
+#define SSTATUS32_SD        0x80000000
+#define SSTATUS64_SD        0x8000000000000000

Given that the status bits for lesser privs are the same as MSTATUS, with some omissions, reproducing these is not ideal. Perhaps better to define a SSTATUS_MASK that lists the MSTATUS bits that are controlable.

target-riscv/cpu.h line 421

Quoted 7 lines
target-riscv/cpu.h new file +7 -0
+/*
+ * ctz in Spike returns 0 if val == 0, wrap helper
+ */
+static int ctz(target_ulong val)
+{
+    return val ? ctz64(val) : 0;
+}

Does this really belong here? I don't see it used by op_helper, only ...

Quoted 13 lines
target-riscv/cpu.h new file +13 -0
+
+/*
+ * Return RISC-V IRQ number if an interrupt should be taken, else -1.
+ * Used in cpu-exec.c
+ *
+ * Adapted from Spike's processor_t::take_interrupt()
+ */
+static inline int cpu_riscv_hw_interrupts_pending(CPURISCVState *env)
+{
+    target_ulong pending_interrupts = env->csr[CSR_MIP] & env->csr[CSR_MIE];
+
+    target_ulong mie = get_field(env->csr[CSR_MSTATUS], MSTATUS_MIE);
+    target_ulong m_enabled = env->priv < PRV_M || (env->priv == PRV_M && mie);

target-riscv/cpu.h line 444

Quoted 10 lines
target-riscv/cpu.h new file +10 -0
+    target_ulong enabled_interrupts = pending_interrupts &
+                                      ~env->csr[CSR_MIDELEG] & -m_enabled;
+
+    target_ulong sie = get_field(env->csr[CSR_MSTATUS], MSTATUS_SIE);
+    target_ulong s_enabled = env->priv < PRV_S || (env->priv == PRV_S && sie);
+    enabled_interrupts |= pending_interrupts & env->csr[CSR_MIDELEG] &
+                          -s_enabled;
+
+    if (enabled_interrupts) {
+        target_ulong counted = ctz(enabled_interrupts);

... here, where we've already eliminated 0. So, surely you could just use ctz64 directly.

Quoted 29 lines
target-riscv/cpu.h new file +29 -0
+        if (counted == IRQ_HOST) {
+            /* we're handing it to the cpu now, so get rid of the qemu irq */
+            qemu_irq_lower(HTIF_IRQ);
+        } else if (counted == IRQ_M_TIMER) {
+            /* we're handing it to the cpu now, so get rid of the qemu irq */
+            qemu_irq_lower(TIMER_IRQ);
+        } else if (counted == IRQ_S_TIMER || counted == IRQ_H_TIMER) {
+            /* don't lower irq here */
+        }
+        return counted;
+    } else {
+        return EXCP_NONE; /* indicates no pending interrupt */
+    }
+}
+
+#include "exec/cpu-all.h"
+
+void riscv_tcg_init(void);
+RISCVCPU *cpu_riscv_init(const char *cpu_model);
+int cpu_riscv_signal_handler(int host_signum, void *pinfo, void *puc);
+
+#define cpu_init(cpu_model) CPU(cpu_riscv_init(cpu_model))
+
+/* hw/riscv/riscv_rtc.c  - supplies instret by approximating */
+uint64_t cpu_riscv_read_instret(CPURISCVState *env);
+
+int riscv_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, MMUAccessType rw,
+                              int mmu_idx);
+#if !defined(CONFIG_USER_ONLY)

target-riscv/cpu.h line 483

Quoted 10 lines
target-riscv/cpu.h new file +10 -0
+hwaddr cpu_riscv_translate_address(CPURISCVState *env, target_ulong address,
+                                   int rw);
+#endif
+
+static inline void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc,
+                                        target_ulong *cs_base, uint32_t *flags)
+{
+    *pc = env->PC;
+    *cs_base = 0;
+    *flags = 0; /* necessary to avoid compiler warning */

At minimum, you'll need to include the priv level in the flags, so that one can only run TBs that were built for the cpu's current priv level.

Quoted 34 lines

+++ b/target-riscv/op_helper.c

target-riscv/op_helper.c new file +32 -0
@@ -0,0 +1,44 @@
+/*
+ * RISC-V Emulation Helpers for QEMU.
+ *
+ * Author: Sagar Karandikar, [email protected]
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include <stdlib.h>
+#include "cpu.h"
+#include "qemu/host-utils.h"
+#include "exec/helper-proto.h"
+
+#ifndef CONFIG_USER_ONLY
+void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
+                                   MMUAccessType access_type, int mmu_idx,
+                                   uintptr_t retaddr)
+{
+}

target-riscv/op_helper.c line 42

Quoted 10 lines
target-riscv/op_helper.c new file +10 -0
+
+void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type,
+        int mmu_idx, uintptr_t retaddr)
+{
+}
+
+void riscv_cpu_unassigned_access(CPUState *cs, hwaddr addr, bool is_write,
+        bool is_exec, int unused, unsigned size)
+{
+}

These are better placed in helper.c, reserving op_helper.c for those functions implementing helpers for "op"s, i.e. instructions.

r~

#5 lore raw

Re: [Qemu-devel] [PATCH 02/18] target-riscv: Add RISC-V Target stubs inside target-riscv/

In reply to Sagar Karandikar

target-riscv/cpu.h line 297

Quoted 8 lines · Sagar Karandikar
target-riscv/cpu.h new file +8 -0
+typedef struct CPURISCVState CPURISCVState;
+struct CPURISCVState {
+    target_ulong gpr[32];
+    uint64_t fpr[32]; /* assume both F and D extensions */
+    target_ulong PC;
+    target_ulong load_res;
+
+    target_ulong csr[4096]; /* RISCV CSR registers */

This is 16k for 32-bit, and 32k for 64-bit, most of which is unused.

I think it would be better to add only the CSRs that you actually need for the implementation.

r~

#6 lore raw

PATCH 3/18 target-riscv: Add initialization for translation

In reply to Sagar Karandikar

Add tcg and cpu model initialization
Add gen_intermediate_code function, dummy decode_opc Add exception helpers necessary for gen_intermediate_code

---
 target-riscv/helper.h    |   4 +
 target-riscv/op_helper.c |  26 +++++
 target-riscv/translate.c | 244 ++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 273 insertions(+), 1 deletion(-)
target-riscv/helper.h +4 -0
index e69de29..0461118 100644
@@ -0,0 +1,4 @@
+/* Exceptions */
+DEF_HELPER_2(raise_exception, noreturn, env, i32)
+DEF_HELPER_1(raise_exception_debug, noreturn, env)
+DEF_HELPER_3(raise_exception_mbadaddr, noreturn, env, i32, tl)
target-riscv/op_helper.c +26 -0
index c77a520..fd1ef3c 100644
@@ -24,6 +24,32 @@
 #include "qemu/host-utils.h"
 #include "exec/helper-proto.h"
 
+/* Exceptions processing helpers */
+static inline void QEMU_NORETURN do_raise_exception_err(CPURISCVState *env,
+                                          uint32_t exception, uintptr_t pc)
+{
+    CPUState *cs = CPU(riscv_env_get_cpu(env));
+    qemu_log_mask(CPU_LOG_INT, "%s: %d\n", __func__, exception);
+    cs->exception_index = exception;
+    cpu_loop_exit_restore(cs, pc);
+}
+
+void helper_raise_exception(CPURISCVState *env, uint32_t exception)
+{
+    do_raise_exception_err(env, exception, 0);
+}
+
+void helper_raise_exception_debug(CPURISCVState *env)
+{
+    do_raise_exception_err(env, EXCP_DEBUG, 0);
+}
+
+void helper_raise_exception_mbadaddr(CPURISCVState *env, uint32_t exception,
+        target_ulong bad_pc) {
+    env->badaddr = bad_pc;
+    do_raise_exception_err(env, exception, 0);
+}
+
 #ifndef CONFIG_USER_ONLY
 void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
                                    MMUAccessType access_type, int mmu_idx,
target-riscv/translate.c +243 -1

276 lines not on this page · raw message

Signature · 1 line
2.9.3
#7 lore raw

Re: [Qemu-devel] [PATCH 03/18] target-riscv: Add initialization for translation

Quoted 6 lines · Sagar Karandikar

RISCVCPU *cpu_riscv_init(const char *cpu_model)
{

target-riscv/translate.c +3 -1
-    return NULL;
+    RISCVCPU *cpu;
+    CPURISCVState *env;
+    const riscv_def_t *def;

target-riscv/translate.c void riscv_cpu_list(FILE *f, fprintf_function cpu_fprintf) · line 356

Quoted 10 lines
target-riscv/translate.c +10 -0
+
+    def = cpu_riscv_find_by_name(cpu_model);
+    if (!def) {
+        return NULL;
+    }
+    cpu = RISCV_CPU(object_new(TYPE_RISCV_CPU));
+    env = &cpu->env;
+    env->cpu_model = def;
+
+    memset(env->csr, 0, 4096 * sizeof(target_ulong));

sizeof(env->csr)?

And besides that, doesn't this more properly belong in a reset function, where that memset will already have been done?

Quoted 8 lines
target-riscv/translate.c +8 -0
+    env->priv = PRV_M;
+
+    /* set mcpuid from def */
+    env->csr[CSR_MISA] = def->init_misa_reg;
+    object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
+
+    /* fpu flags: */
+    set_default_nan_mode(1, &env->fp_status);
#8 lore raw

PATCH 4/18 target-riscv: Add framework for instruction decode

In reply to Sagar Karandikar

Body of decode_opc with LUI, AUIPC, JAL instructions Decode table in instmap.h

---
 target-riscv/instmap.h   | 328 +++++++++++++++++++++++++++++++++++++++++++++++
 target-riscv/translate.c |  64 +++++++++
 2 files changed, 392 insertions(+)
 create mode 100644 target-riscv/instmap.h
target-riscv/instmap.h new file +328 -0
new file mode 100644
index 0000000..24f53c3
@@ -0,0 +1,328 @@
+/*
+ * RISC-V emulation for qemu: Instruction decode helpers
+ *
+ * Author: Sagar Karandikar, [email protected]
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define MASK_OP_MAJOR(op)  (op & 0x7F)
+enum {
+    /* rv32i, rv64i, rv32m */
+    OPC_RISC_LUI    = (0x37),
+    OPC_RISC_AUIPC  = (0x17),
+    OPC_RISC_JAL    = (0x6F),
+    OPC_RISC_JALR   = (0x67),
+    OPC_RISC_BRANCH = (0x63),
+    OPC_RISC_LOAD   = (0x03),
+    OPC_RISC_STORE  = (0x23),
+    OPC_RISC_ARITH_IMM  = (0x13),
+    OPC_RISC_ARITH      = (0x33),
+    OPC_RISC_FENCE      = (0x0F),
+    OPC_RISC_SYSTEM     = (0x73),
+
+    /* rv64i, rv64m */
+    OPC_RISC_ARITH_IMM_W = (0x1B),
+    OPC_RISC_ARITH_W = (0x3B),
+
+    /* rv32a, rv64a */
+    OPC_RISC_ATOMIC = (0x2F),
+
+    /* floating point */
+    OPC_RISC_FP_LOAD = (0x7),
+    OPC_RISC_FP_STORE = (0x27),
+
+    OPC_RISC_FMADD = (0x43),
+    OPC_RISC_FMSUB = (0x47),
+    OPC_RISC_FNMSUB = (0x4B),
+    OPC_RISC_FNMADD = (0x4F),
+
+    OPC_RISC_FP_ARITH = (0x53),
+};
+
+#define MASK_OP_ARITH(op)   (MASK_OP_MAJOR(op) | (op & ((0x7 << 12) | \
+                            (0x7F << 25))))
+enum {
+    OPC_RISC_ADD   = OPC_RISC_ARITH | (0x0 << 12) | (0x00 << 25),
+    OPC_RISC_SUB   = OPC_RISC_ARITH | (0x0 << 12) | (0x20 << 25),
+    OPC_RISC_SLL   = OPC_RISC_ARITH | (0x1 << 12) | (0x00 << 25),
+    OPC_RISC_SLT   = OPC_RISC_ARITH | (0x2 << 12) | (0x00 << 25),
+    OPC_RISC_SLTU  = OPC_RISC_ARITH | (0x3 << 12) | (0x00 << 25),
+    OPC_RISC_XOR   = OPC_RISC_ARITH | (0x4 << 12) | (0x00 << 25),
+    OPC_RISC_SRL   = OPC_RISC_ARITH | (0x5 << 12) | (0x00 << 25),
+    OPC_RISC_SRA   = OPC_RISC_ARITH | (0x5 << 12) | (0x20 << 25),
+    OPC_RISC_OR    = OPC_RISC_ARITH | (0x6 << 12) | (0x00 << 25),
+    OPC_RISC_AND   = OPC_RISC_ARITH | (0x7 << 12) | (0x00 << 25),
+
+    /* RV64M */
+    OPC_RISC_MUL    = OPC_RISC_ARITH | (0x0 << 12) | (0x01 << 25),
+    OPC_RISC_MULH   = OPC_RISC_ARITH | (0x1 << 12) | (0x01 << 25),
+    OPC_RISC_MULHSU = OPC_RISC_ARITH | (0x2 << 12) | (0x01 << 25),
+    OPC_RISC_MULHU  = OPC_RISC_ARITH | (0x3 << 12) | (0x01 << 25),
+
+    OPC_RISC_DIV    = OPC_RISC_ARITH | (0x4 << 12) | (0x01 << 25),
+    OPC_RISC_DIVU   = OPC_RISC_ARITH | (0x5 << 12) | (0x01 << 25),
+    OPC_RISC_REM    = OPC_RISC_ARITH | (0x6 << 12) | (0x01 << 25),
+    OPC_RISC_REMU   = OPC_RISC_ARITH | (0x7 << 12) | (0x01 << 25),
+};
+
+
+#define MASK_OP_ARITH_IMM(op)   (MASK_OP_MAJOR(op) | (op & (0x7 << 12)))
+enum {
+    OPC_RISC_ADDI   = OPC_RISC_ARITH_IMM | (0x0 << 12),
+    OPC_RISC_SLTI   = OPC_RISC_ARITH_IMM | (0x2 << 12),
+    OPC_RISC_SLTIU  = OPC_RISC_ARITH_IMM | (0x3 << 12),
+    OPC_RISC_XORI   = OPC_RISC_ARITH_IMM | (0x4 << 12),
+    OPC_RISC_ORI    = OPC_RISC_ARITH_IMM | (0x6 << 12),
+    OPC_RISC_ANDI   = OPC_RISC_ARITH_IMM | (0x7 << 12),
+    OPC_RISC_SLLI   = OPC_RISC_ARITH_IMM | (0x1 << 12), /* additional part of
+                                                           IMM */
+    OPC_RISC_SHIFT_RIGHT_I = OPC_RISC_ARITH_IMM | (0x5 << 12) /* SRAI, SRLI */
+};
+
+#define MASK_OP_BRANCH(op)     (MASK_OP_MAJOR(op) | (op & (0x7 << 12)))
+enum {
+    OPC_RISC_BEQ  = OPC_RISC_BRANCH  | (0x0  << 12),
+    OPC_RISC_BNE  = OPC_RISC_BRANCH  | (0x1  << 12),
+    OPC_RISC_BLT  = OPC_RISC_BRANCH  | (0x4  << 12),
+    OPC_RISC_BGE  = OPC_RISC_BRANCH  | (0x5  << 12),
+    OPC_RISC_BLTU = OPC_RISC_BRANCH  | (0x6  << 12),
+    OPC_RISC_BGEU = OPC_RISC_BRANCH  | (0x7  << 12)
+};
+
+enum {
+    OPC_RISC_ADDIW   = OPC_RISC_ARITH_IMM_W | (0x0 << 12),
+    OPC_RISC_SLLIW   = OPC_RISC_ARITH_IMM_W | (0x1 << 12), /* additional part of
+                                                              IMM */
+    OPC_RISC_SHIFT_RIGHT_IW = OPC_RISC_ARITH_IMM_W | (0x5 << 12) /* SRAI, SRLI
+                                                                  */
+};
+
+enum {
+    OPC_RISC_ADDW   = OPC_RISC_ARITH_W | (0x0 << 12) | (0x00 << 25),
+    OPC_RISC_SUBW   = OPC_RISC_ARITH_W | (0x0 << 12) | (0x20 << 25),
+    OPC_RISC_SLLW   = OPC_RISC_ARITH_W | (0x1 << 12) | (0x00 << 25),
+    OPC_RISC_SRLW   = OPC_RISC_ARITH_W | (0x5 << 12) | (0x00 << 25),
+    OPC_RISC_SRAW   = OPC_RISC_ARITH_W | (0x5 << 12) | (0x20 << 25),
+
+    /* RV64M */
+    OPC_RISC_MULW   = OPC_RISC_ARITH_W | (0x0 << 12) | (0x01 << 25),
+    OPC_RISC_DIVW   = OPC_RISC_ARITH_W | (0x4 << 12) | (0x01 << 25),
+    OPC_RISC_DIVUW  = OPC_RISC_ARITH_W | (0x5 << 12) | (0x01 << 25),
+    OPC_RISC_REMW   = OPC_RISC_ARITH_W | (0x6 << 12) | (0x01 << 25),
+    OPC_RISC_REMUW  = OPC_RISC_ARITH_W | (0x7 << 12) | (0x01 << 25),
+};
+
+#define MASK_OP_LOAD(op)   (MASK_OP_MAJOR(op) | (op & (0x7 << 12)))
+enum {
+    OPC_RISC_LB   = OPC_RISC_LOAD | (0x0 << 12),
+    OPC_RISC_LH   = OPC_RISC_LOAD | (0x1 << 12),
+    OPC_RISC_LW   = OPC_RISC_LOAD | (0x2 << 12),
+    OPC_RISC_LD   = OPC_RISC_LOAD | (0x3 << 12),
+    OPC_RISC_LBU  = OPC_RISC_LOAD | (0x4 << 12),
+    OPC_RISC_LHU  = OPC_RISC_LOAD | (0x5 << 12),
+    OPC_RISC_LWU  = OPC_RISC_LOAD | (0x6 << 12),
+};
+
+#define MASK_OP_STORE(op)   (MASK_OP_MAJOR(op) | (op & (0x7 << 12)))
+enum {
+    OPC_RISC_SB   = OPC_RISC_STORE | (0x0 << 12),
+    OPC_RISC_SH   = OPC_RISC_STORE | (0x1 << 12),
+    OPC_RISC_SW   = OPC_RISC_STORE | (0x2 << 12),
+    OPC_RISC_SD   = OPC_RISC_STORE | (0x3 << 12),
+};
+
+#define MASK_OP_JALR(op)   (MASK_OP_MAJOR(op) | (op & (0x7 << 12)))
+/* no enum since OPC_RISC_JALR is the actual value */
+
+#define MASK_OP_ATOMIC(op)   (MASK_OP_MAJOR(op) | (op & ((0x7 << 12) \
+                                                | (0x7F << 25))))
+#define MASK_OP_ATOMIC_NO_AQ_RL(op)   (MASK_OP_MAJOR(op) | (op & ((0x7 << 12)\
+                                                         | (0x1F << 27))))
+enum {
+    OPC_RISC_LR_W        = OPC_RISC_ATOMIC | (0x2 << 12) | (0x02 << 27),
+    OPC_RISC_SC_W        = OPC_RISC_ATOMIC | (0x2 << 12) | (0x03 << 27),
+    OPC_RISC_AMOSWAP_W   = OPC_RISC_ATOMIC | (0x2 << 12) | (0x01 << 27),
+    OPC_RISC_AMOADD_W    = OPC_RISC_ATOMIC | (0x2 << 12) | (0x00 << 27),
+    OPC_RISC_AMOXOR_W    = OPC_RISC_ATOMIC | (0x2 << 12) | (0x04 << 27),
+    OPC_RISC_AMOAND_W    = OPC_RISC_ATOMIC | (0x2 << 12) | (0x0C << 27),
+    OPC_RISC_AMOOR_W     = OPC_RISC_ATOMIC | (0x2 << 12) | (0x08 << 27),
+    OPC_RISC_AMOMIN_W    = OPC_RISC_ATOMIC | (0x2 << 12) | (0x10 << 27),
+    OPC_RISC_AMOMAX_W    = OPC_RISC_ATOMIC | (0x2 << 12) | (0x14 << 27),
+    OPC_RISC_AMOMINU_W   = OPC_RISC_ATOMIC | (0x2 << 12) | (0x18 << 27),
+    OPC_RISC_AMOMAXU_W   = OPC_RISC_ATOMIC | (0x2 << 12) | (0x1C << 27),
+
+    OPC_RISC_LR_D        = OPC_RISC_ATOMIC | (0x3 << 12) | (0x02 << 27),
+    OPC_RISC_SC_D        = OPC_RISC_ATOMIC | (0x3 << 12) | (0x03 << 27),
+    OPC_RISC_AMOSWAP_D   = OPC_RISC_ATOMIC | (0x3 << 12) | (0x01 << 27),
+    OPC_RISC_AMOADD_D    = OPC_RISC_ATOMIC | (0x3 << 12) | (0x00 << 27),
+    OPC_RISC_AMOXOR_D    = OPC_RISC_ATOMIC | (0x3 << 12) | (0x04 << 27),
+    OPC_RISC_AMOAND_D    = OPC_RISC_ATOMIC | (0x3 << 12) | (0x0C << 27),
+    OPC_RISC_AMOOR_D     = OPC_RISC_ATOMIC | (0x3 << 12) | (0x08 << 27),
+    OPC_RISC_AMOMIN_D    = OPC_RISC_ATOMIC | (0x3 << 12) | (0x10 << 27),
+    OPC_RISC_AMOMAX_D    = OPC_RISC_ATOMIC | (0x3 << 12) | (0x14 << 27),
+    OPC_RISC_AMOMINU_D   = OPC_RISC_ATOMIC | (0x3 << 12) | (0x18 << 27),
+    OPC_RISC_AMOMAXU_D   = OPC_RISC_ATOMIC | (0x3 << 12) | (0x1C << 27),
+};
+
+#define MASK_OP_SYSTEM(op)   (MASK_OP_MAJOR(op) | (op & (0x7 << 12)))
+enum {
+    OPC_RISC_ECALL       = OPC_RISC_SYSTEM | (0x0 << 12),
+    OPC_RISC_EBREAK      = OPC_RISC_SYSTEM | (0x0 << 12),
+    OPC_RISC_ERET        = OPC_RISC_SYSTEM | (0x0 << 12),
+    OPC_RISC_MRTS        = OPC_RISC_SYSTEM | (0x0 << 12),
+    OPC_RISC_MRTH        = OPC_RISC_SYSTEM | (0x0 << 12),
+    OPC_RISC_HRTS        = OPC_RISC_SYSTEM | (0x0 << 12),
+    OPC_RISC_WFI         = OPC_RISC_SYSTEM | (0x0 << 12),
+    OPC_RISC_SFENCEVM    = OPC_RISC_SYSTEM | (0x0 << 12),
+
+    OPC_RISC_CSRRW       = OPC_RISC_SYSTEM | (0x1 << 12),
+    OPC_RISC_CSRRS       = OPC_RISC_SYSTEM | (0x2 << 12),
+    OPC_RISC_CSRRC       = OPC_RISC_SYSTEM | (0x3 << 12),
+    OPC_RISC_CSRRWI      = OPC_RISC_SYSTEM | (0x5 << 12),
+    OPC_RISC_CSRRSI      = OPC_RISC_SYSTEM | (0x6 << 12),
+    OPC_RISC_CSRRCI      = OPC_RISC_SYSTEM | (0x7 << 12),
+};
+
+#define MASK_OP_FP_LOAD(op)   (MASK_OP_MAJOR(op) | (op & (0x7 << 12)))
+enum {
+    OPC_RISC_FLW   = OPC_RISC_FP_LOAD | (0x2 << 12),
+    OPC_RISC_FLD   = OPC_RISC_FP_LOAD | (0x3 << 12),
+};
+
+#define MASK_OP_FP_STORE(op)   (MASK_OP_MAJOR(op) | (op & (0x7 << 12)))
+enum {
+    OPC_RISC_FSW   = OPC_RISC_FP_STORE | (0x2 << 12),
+    OPC_RISC_FSD   = OPC_RISC_FP_STORE | (0x3 << 12),
+};
+
+#define MASK_OP_FP_FMADD(op)   (MASK_OP_MAJOR(op) | (op & (0x3 << 25)))
+enum {
+    OPC_RISC_FMADD_S = OPC_RISC_FMADD | (0x0 << 25),
+    OPC_RISC_FMADD_D = OPC_RISC_FMADD | (0x1 << 25),
+};
+
+#define MASK_OP_FP_FMSUB(op)   (MASK_OP_MAJOR(op) | (op & (0x3 << 25)))
+enum {
+    OPC_RISC_FMSUB_S = OPC_RISC_FMSUB | (0x0 << 25),
+    OPC_RISC_FMSUB_D = OPC_RISC_FMSUB | (0x1 << 25),
+};
+
+#define MASK_OP_FP_FNMADD(op)   (MASK_OP_MAJOR(op) | (op & (0x3 << 25)))
+enum {
+    OPC_RISC_FNMADD_S = OPC_RISC_FNMADD | (0x0 << 25),
+    OPC_RISC_FNMADD_D = OPC_RISC_FNMADD | (0x1 << 25),
+};
+
+#define MASK_OP_FP_FNMSUB(op)   (MASK_OP_MAJOR(op) | (op & (0x3 << 25)))
+enum {
+    OPC_RISC_FNMSUB_S = OPC_RISC_FNMSUB | (0x0 << 25),
+    OPC_RISC_FNMSUB_D = OPC_RISC_FNMSUB | (0x1 << 25),
+};
+
+#define MASK_OP_FP_ARITH(op)   (MASK_OP_MAJOR(op) | (op & (0x7F << 25)))
+enum {
+    /* float */
+    OPC_RISC_FADD_S    = OPC_RISC_FP_ARITH | (0x0 << 25),
+    OPC_RISC_FSUB_S    = OPC_RISC_FP_ARITH | (0x4 << 25),
+    OPC_RISC_FMUL_S    = OPC_RISC_FP_ARITH | (0x8 << 25),
+    OPC_RISC_FDIV_S    = OPC_RISC_FP_ARITH | (0xC << 25),
+
+    OPC_RISC_FSGNJ_S   = OPC_RISC_FP_ARITH | (0x10 << 25),
+    OPC_RISC_FSGNJN_S  = OPC_RISC_FP_ARITH | (0x10 << 25),
+    OPC_RISC_FSGNJX_S  = OPC_RISC_FP_ARITH | (0x10 << 25),
+
+    OPC_RISC_FMIN_S    = OPC_RISC_FP_ARITH | (0x14 << 25),
+    OPC_RISC_FMAX_S    = OPC_RISC_FP_ARITH | (0x14 << 25),
+
+    OPC_RISC_FSQRT_S   = OPC_RISC_FP_ARITH | (0x2C << 25),
+
+    OPC_RISC_FEQ_S     = OPC_RISC_FP_ARITH | (0x50 << 25),
+    OPC_RISC_FLT_S     = OPC_RISC_FP_ARITH | (0x50 << 25),
+    OPC_RISC_FLE_S     = OPC_RISC_FP_ARITH | (0x50 << 25),
+
+    OPC_RISC_FCVT_W_S  = OPC_RISC_FP_ARITH | (0x60 << 25),
+    OPC_RISC_FCVT_WU_S = OPC_RISC_FP_ARITH | (0x60 << 25),
+    OPC_RISC_FCVT_L_S  = OPC_RISC_FP_ARITH | (0x60 << 25),
+    OPC_RISC_FCVT_LU_S = OPC_RISC_FP_ARITH | (0x60 << 25),
+
+    OPC_RISC_FCVT_S_W  = OPC_RISC_FP_ARITH | (0x68 << 25),
+    OPC_RISC_FCVT_S_WU = OPC_RISC_FP_ARITH | (0x68 << 25),
+    OPC_RISC_FCVT_S_L  = OPC_RISC_FP_ARITH | (0x68 << 25),
+    OPC_RISC_FCVT_S_LU = OPC_RISC_FP_ARITH | (0x68 << 25),
+
+    OPC_RISC_FMV_X_S   = OPC_RISC_FP_ARITH | (0x70 << 25),
+    OPC_RISC_FCLASS_S  = OPC_RISC_FP_ARITH | (0x70 << 25),
+
+    OPC_RISC_FMV_S_X   = OPC_RISC_FP_ARITH | (0x78 << 25),
+
+    /* double */
+    OPC_RISC_FADD_D    = OPC_RISC_FP_ARITH | (0x1 << 25),
+    OPC_RISC_FSUB_D    = OPC_RISC_FP_ARITH | (0x5 << 25),
+    OPC_RISC_FMUL_D    = OPC_RISC_FP_ARITH | (0x9 << 25),
+    OPC_RISC_FDIV_D    = OPC_RISC_FP_ARITH | (0xD << 25),
+
+    OPC_RISC_FSGNJ_D   = OPC_RISC_FP_ARITH | (0x11 << 25),
+    OPC_RISC_FSGNJN_D  = OPC_RISC_FP_ARITH | (0x11 << 25),
+    OPC_RISC_FSGNJX_D  = OPC_RISC_FP_ARITH | (0x11 << 25),
+
+    OPC_RISC_FMIN_D    = OPC_RISC_FP_ARITH | (0x15 << 25),
+    OPC_RISC_FMAX_D    = OPC_RISC_FP_ARITH | (0x15 << 25),
+
+    OPC_RISC_FCVT_S_D = OPC_RISC_FP_ARITH | (0x20 << 25),
+
+    OPC_RISC_FCVT_D_S = OPC_RISC_FP_ARITH | (0x21 << 25),
+
+    OPC_RISC_FSQRT_D   = OPC_RISC_FP_ARITH | (0x2D << 25),
+
+    OPC_RISC_FEQ_D     = OPC_RISC_FP_ARITH | (0x51 << 25),
+    OPC_RISC_FLT_D     = OPC_RISC_FP_ARITH | (0x51 << 25),
+    OPC_RISC_FLE_D     = OPC_RISC_FP_ARITH | (0x51 << 25),
+
+    OPC_RISC_FCVT_W_D  = OPC_RISC_FP_ARITH | (0x61 << 25),
+    OPC_RISC_FCVT_WU_D = OPC_RISC_FP_ARITH | (0x61 << 25),
+    OPC_RISC_FCVT_L_D  = OPC_RISC_FP_ARITH | (0x61 << 25),
+    OPC_RISC_FCVT_LU_D = OPC_RISC_FP_ARITH | (0x61 << 25),
+
+    OPC_RISC_FCVT_D_W  = OPC_RISC_FP_ARITH | (0x69 << 25),
+    OPC_RISC_FCVT_D_WU = OPC_RISC_FP_ARITH | (0x69 << 25),
+    OPC_RISC_FCVT_D_L  = OPC_RISC_FP_ARITH | (0x69 << 25),
+    OPC_RISC_FCVT_D_LU = OPC_RISC_FP_ARITH | (0x69 << 25),
+
+    OPC_RISC_FMV_X_D   = OPC_RISC_FP_ARITH | (0x71 << 25),
+    OPC_RISC_FCLASS_D  = OPC_RISC_FP_ARITH | (0x71 << 25),
+
+    OPC_RISC_FMV_D_X   = OPC_RISC_FP_ARITH | (0x79 << 25),
+};
+
+/* THIS BUILDS 13 bit imm (implicit zero is tacked on here), also note that bit
+   #12 is obtained in a special way to get sign extension */
+#define GET_B_IMM(inst)              ((int16_t)((((inst >> 25) & 0x3F) << 5)\
+                                     | ((((int32_t)inst) >> 31) << 12)      \
+                                     | (((inst >> 8) & 0xF) << 1)           \
+                                     | (((inst >> 7) & 0x1) << 11)))
+
+#define GET_STORE_IMM(inst)          ((int16_t)(((((int32_t)inst) >> 25) << 5)\
+                                     | ((inst >> 7) & 0x1F)))
+#define GET_JAL_IMM(inst)            ((int32_t)((inst & 0xFF000) \
+                                     | (((inst >> 20) & 0x1) << 11)\
+                                     | (((inst >> 21) & 0x3FF) << 1)\
+                                     | ((((int32_t)inst) >> 31) << 20)))
+#define GET_RM(inst)                 ((inst >> 12) & 0x7)
+#define GET_RS3(inst)                ((inst >> 27) & 0x1f)
+#define GET_RS1(inst)                ((inst >> 15) & 0x1f)
+#define GET_RS2(inst)                ((inst >> 20) & 0x1f)
+#define GET_RD(inst)                 ((inst >> 7) & 0x1f)
+#define GET_IMM(inst)                ((int16_t)(((int32_t)inst) >> 20))
target-riscv/translate.c +64 -0

76 lines not on this page · raw message

Signature · 1 line
2.9.3
#9 lore raw

Re: [Qemu-devel] [PATCH 04/18] target-riscv: Add framework for instruction decode

Quoted 9 lines · Sagar Karandikar
target-riscv/instmap.h new file +9 -0
+/* THIS BUILDS 13 bit imm (implicit zero is tacked on here), also note that bit
+   #12 is obtained in a special way to get sign extension */
+#define GET_B_IMM(inst)              ((int16_t)((((inst >> 25) & 0x3F) << 5)\
+                                     | ((((int32_t)inst) >> 31) << 12)      \
+                                     | (((inst >> 8) & 0xF) << 1)           \
+                                     | (((inst >> 7) & 0x1) << 11)))
+
+#define GET_STORE_IMM(inst)          ((int16_t)(((((int32_t)inst) >> 25) << 5)\
+                                     | ((inst >> 7) & 0x1F)))

target-riscv/instmap.h line 328

Quoted 10 lines
target-riscv/instmap.h new file +10 -0
+#define GET_JAL_IMM(inst)            ((int32_t)((inst & 0xFF000) \
+                                     | (((inst >> 20) & 0x1) << 11)\
+                                     | (((inst >> 21) & 0x3FF) << 1)\
+                                     | ((((int32_t)inst) >> 31) << 20)))
+#define GET_RM(inst)                 ((inst >> 12) & 0x7)
+#define GET_RS3(inst)                ((inst >> 27) & 0x1f)
+#define GET_RS1(inst)                ((inst >> 15) & 0x1f)
+#define GET_RS2(inst)                ((inst >> 20) & 0x1f)
+#define GET_RD(inst)                 ((inst >> 7) & 0x1f)
+#define GET_IMM(inst)                ((int16_t)(((int32_t)inst) >> 20))

I would prefer that these use extract32 and sextract32. Then you don't need the comment there at the top because it's self-evident.

target-riscv/translate.c static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) · line 147

Quoted 7 lines
target-riscv/translate.c +7 -0
+    switch (op) {
+    case OPC_RISC_LUI:
+        if (rd == 0) {
+            break; /* NOP */
+        }
+        tcg_gen_movi_tl(cpu_gpr[rd], (ctx->opcode & 0xFFFFF000));
+        tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);

This should be done in one movi with the sign-extension in C.

target-riscv/translate.c static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) · line 155

Quoted 8 lines
target-riscv/translate.c +8 -0
+        break;
+    case OPC_RISC_AUIPC:
+        if (rd == 0) {
+            break; /* NOP */
+        }
+        tcg_gen_movi_tl(cpu_gpr[rd], (ctx->opcode & 0xFFFFF000));
+        tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
+        tcg_gen_addi_tl(cpu_gpr[rd], cpu_gpr[rd], ctx->pc);

Likewise.

Quoted 19 lines
target-riscv/translate.c +19 -0
+        break;
+    case OPC_RISC_JAL: {
+            TCGv nextpc = tcg_temp_local_new();
+            TCGv testpc = tcg_temp_local_new();
+            TCGLabel *misaligned = gen_new_label();
+            TCGLabel *done = gen_new_label();
+            ubimm = (target_long) (GET_JAL_IMM(ctx->opcode));
+            tcg_gen_movi_tl(nextpc, ctx->pc + ubimm);
+            /* check misaligned: */
+            tcg_gen_andi_tl(testpc, nextpc, 0x3);
+            tcg_gen_brcondi_tl(TCG_COND_NE, testpc, 0x0, misaligned);
+            if (rd != 0) {
+                tcg_gen_movi_tl(cpu_gpr[rd], ctx->pc + 4);
+            }
+
+#ifdef DISABLE_CHAINING_JAL
+            tcg_gen_mov_tl(cpu_PC, nextpc);
+            tcg_gen_exit_tb(0);
+#else

target-riscv/translate.c static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) · line 184

Quoted 10 lines
target-riscv/translate.c +10 -0
+            gen_goto_tb(ctx, 0, ctx->pc + ubimm); /* must use this for safety */
+#endif
+            tcg_gen_br(done);
+            gen_set_label(misaligned);
+            /* throw exception for misaligned case */
+            generate_exception_mbadaddr(ctx, RISCV_EXCP_INST_ADDR_MIS);
+            gen_set_label(done);
+            ctx->bstate = BS_BRANCH;
+            tcg_temp_free(nextpc);
+            tcg_temp_free(testpc);

Remember that nextpc is a translate-time constant. Therefore this entire misalignment check could be done during translation, and thus there should be no tcg labels nor tcg temporaries allocated.

Why would you ever want to disable chaining JAL (and therefore J)? Do note that there is a -d nochain command-line switch that will disable all chaining for the purposes of debugging...

r~

#10 lore raw

PATCH 5/18 target-riscv: Add Arithmetic instructions

In reply to Sagar Karandikar

Arithmetic Instructions
Arithmetic Immediate Instructions
MULHSU Helper
GPR Helpers necessary for above

---
 target-riscv/helper.h    |   4 +
 target-riscv/op_helper.c |  10 ++
 target-riscv/translate.c | 338 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 352 insertions(+)
target-riscv/helper.h +4 -0
index 0461118..c489222 100644
@@ -2,3 +2,7 @@
 DEF_HELPER_2(raise_exception, noreturn, env, i32)
 DEF_HELPER_1(raise_exception_debug, noreturn, env)
 DEF_HELPER_3(raise_exception_mbadaddr, noreturn, env, i32, tl)
+
+#if defined(TARGET_RISCV64)
+DEF_HELPER_FLAGS_3(mulhsu, TCG_CALL_NO_RWG_SE, tl, env, tl, tl)
+#endif
target-riscv/op_helper.c +10 -0
index fd1ef3c..1a7fb18 100644
@@ -50,6 +50,16 @@ void helper_raise_exception_mbadaddr(CPURISCVState *env, uint32_t exception,
     do_raise_exception_err(env, exception, 0);
 }
 
+#if defined(TARGET_RISCV64)
+target_ulong helper_mulhsu(CPURISCVState *env, target_ulong arg1,
+                          target_ulong arg2)
+{
+    int64_t a = arg1;
+    uint64_t b = arg2;
+    return (int64_t)((__int128_t)a * b >> 64);
+}
+#endif
+
 #ifndef CONFIG_USER_ONLY
 void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
                                    MMUAccessType access_type, int mmu_idx,
target-riscv/translate.c +338 -0

361 lines not on this page · raw message

Signature · 1 line
2.9.3
#11 lore raw

Re: [Qemu-devel] [PATCH 05/18] target-riscv: Add Arithmetic instructions

target-riscv/op_helper.c void helper_raise_exception_mbadaddr(CPURISCVState *env, uint32_t exception, · line 61

Quoted 9 lines · Sagar Karandikar
target-riscv/op_helper.c +9 -0
+#if defined(TARGET_RISCV64)
+target_ulong helper_mulhsu(CPURISCVState *env, target_ulong arg1,
+                          target_ulong arg2)
+{
+    int64_t a = arg1;
+    uint64_t b = arg2;
+    return (int64_t)((__int128_t)a * b >> 64);
+}
+#endif

This won't compile on a 32-bit host, or indeed a 64-bit host without CONFIG_INT128.

But what you should actually be using is tcg_gen_mulu2_i64, with a fixup afterward for the one signed argument. See tcg_gen_muls2_i64 in tcg/tcg-op.c for an example of fixing up an unsigned multiply for two signed inputs; you would need only half of that for a single signed input.

target-riscv/translate.c static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) · line 149

Quoted 11 lines
target-riscv/translate.c +11 -0
+/* Wrapper for setting reg values - need to check of reg is zero since
+ * cpu_gpr[0] is not actually allocated. this is more for safety purposes,
+ * since we usually avoid calling the OP_TYPE_gen function if we see a write to
+ * $zero
+ */
+static inline void gen_set_gpr(int reg_num_dst, TCGv t)
+{
+    if (reg_num_dst != 0) {
+        tcg_gen_mov_tl(cpu_gpr[reg_num_dst], t);
+    }
+}

FWIW, target-alpha used to have lots and lots of checks for the zero register. In the end it was much cleaner to simply allocate a scratch temporary for the zero-register sink. Aside from known patterns, such as canonical nop formations, you'll almost never see such instructions. While it's true that you must do something in order to be architecturally correct, it's better to do something that minimizes the impact to the rest of the translator.

target-riscv/translate.c static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) · line 164

Quoted 2 lines
target-riscv/translate.c +2 -0
+    tcg_gen_shri_i64(t0, t0, 32);
+    tcg_gen_extrl_i64_i32(ret, t0);

This would be tcg_gen_extrh_i64_i32.

target-riscv/translate.c static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) · line 183

Quoted 13 lines
target-riscv/translate.c +13 -0
+static inline void gen_arith(DisasContext *ctx, uint32_t opc, int rd, int rs1,
+        int rs2)
+{
+    TCGv source1, source2, cond1, cond2, zeroreg, resultopt1;
+    cond1 = tcg_temp_new();
+    cond2 = tcg_temp_new();
+    source1 = tcg_temp_new();
+    source2 = tcg_temp_new();
+    zeroreg = tcg_temp_new();
+    resultopt1 = tcg_temp_new();
+    gen_get_gpr(source1, rs1);
+    gen_get_gpr(source2, rs2);
+    tcg_gen_movi_tl(zeroreg, 0); /* hardcoded zero for compare in DIV, etc */

It would be far preferable to allocate this only when needed.

target-riscv/translate.c static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) · line 189

Quoted 6 lines
target-riscv/translate.c +6 -0
+
+    switch (opc) {
+#if defined(TARGET_RISCV64)
+    case OPC_RISC_ADDW:
+#endif
+    case OPC_RISC_ADD:

Can we avoid sprinkling so many ifdefs? Perhaps with something akin to

#ifdef TARGET_RISCV64
#define CASE_OP_32_64(X) case X: case glue(X, W)
#else
#define CASE_OP_32_64(X) case X
#endif

target-riscv/translate.c static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) · line 205

Quoted 8 lines
target-riscv/translate.c +8 -0
+#if defined(TARGET_RISCV64)
+    case OPC_RISC_SLLW:
+        tcg_gen_andi_tl(source2, source2, 0x1F);
+        /* fall through to SLL */
+#endif
+    case OPC_RISC_SLL:
+        tcg_gen_andi_tl(source2, source2, TARGET_LONG_BITS - 1);
+        tcg_gen_shl_tl(source1, source1, source2);

Better to not fall through at this point, to avoid the double and.

target-riscv/translate.c static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) · line 225

Quoted 10 lines
target-riscv/translate.c +10 -0
+#if defined(TARGET_RISCV64)
+    case OPC_RISC_SRLW:
+        /* clear upper 32 */
+        tcg_gen_andi_tl(source1, source1, 0x00000000FFFFFFFFLL);
+        tcg_gen_andi_tl(source2, source2, 0x1F);
+        /* fall through to SRL */
+#endif
+    case OPC_RISC_SRL:
+        tcg_gen_andi_tl(source2, source2, TARGET_LONG_BITS - 1);
+        tcg_gen_shr_tl(source1, source1, source2);

Likewise. Also, tcg_gen_ext32u_tl to clear upper 32.

target-riscv/translate.c static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) · line 237

Quoted 12 lines
target-riscv/translate.c +12 -0
+        break;
+#if defined(TARGET_RISCV64)
+    case OPC_RISC_SRAW:
+        /* first, trick to get it to act like working on 32 bits (get rid of
+        upper 32, sign extend to fill space) */
+        tcg_gen_shli_tl(source1, source1, 32);
+        tcg_gen_sari_tl(source1, source1, 32);
+        tcg_gen_andi_tl(source2, source2, 0x1F);
+        /* fall through to SRA */
+#endif
+    case OPC_RISC_SRA:
+        tcg_gen_andi_tl(source2, source2, TARGET_LONG_BITS - 1);

Likewise. Also, tcg_gen_ext32s_tl to sign-extend.

target-riscv/translate.c static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) · line 250

Quoted 5 lines
target-riscv/translate.c +5 -0
+#if defined(TARGET_RISCV64)
+    case OPC_RISC_MULW:
+#endif
+    case OPC_RISC_MUL:
+        tcg_gen_muls2_tl(source1, source2, source1, source2);

tcg_gen_mul_tl, since source2 is dead.

target-riscv/translate.c static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) · line 271

Quoted 11 lines
target-riscv/translate.c +11 -0
+#if defined(TARGET_RISCV64)
+    case OPC_RISC_DIVW:
+        tcg_gen_ext32s_tl(source1, source1);
+        tcg_gen_ext32s_tl(source2, source2);
+        /* fall through to DIV */
+#endif
+    case OPC_RISC_DIV:
+        /* Handle by altering args to tcg_gen_div to produce req'd results:
+         * For overflow: want source1 in source1 and 1 in source2
+         * For div by zero: want -1 in source1 and 1 in source2 -> -1 result */
+        tcg_gen_movi_tl(resultopt1, (target_ulong)0xFFFFFFFFFFFFFFFF);

You'd need ULL for a constant with so many F's, but a plain -1 works just fine.

Quoted 1 line

+ tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, (target_ulong)(~0L));

Likewise -1.

Review

Quoted 2 lines
(quoted diff) +2 -0
+        tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source1,
+                            1L << (TARGET_LONG_BITS - 1));

ULL, not L, or better as (target_ulong)1.

target-riscv/translate.c static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) · line 295

Quoted 3 lines
target-riscv/translate.c +3 -0
+    case OPC_RISC_DIVU:
+        tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0);
+        tcg_gen_movi_tl(resultopt1, (target_ulong)(~0L));

-1 again.

Quoted 1 line

+ case OPC_RISC_REM:

...

Quoted 1 line

+ case OPC_RISC_REMU:

Similarly.

target-riscv/translate.c static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) · line 366

Quoted 8 lines
target-riscv/translate.c +8 -0
+static inline void gen_arith_imm(DisasContext *ctx, uint32_t opc, int rd,
+        int rs1, int16_t imm)
+{
+    TCGv source1;
+    source1 = tcg_temp_new();
+    gen_get_gpr(source1, rs1);
+    /* lower 12 bits of imm are valid */
+    target_long uimm = (target_long)imm; /* sign ext 16->64 bits */

Better to just make the function argument target_long, surely. I don't understand the "uimm", as this isn't unsigned...

target-riscv/translate.c static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) · line 396

Quoted 6 lines
target-riscv/translate.c +6 -0
+#if defined(TARGET_RISCV64)
+    case OPC_RISC_SLLIW:
+         if ((uimm >= 32)) {
+            kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+         }
+        /* fall through to SLLI */

break after known exception.

target-riscv/translate.c static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) · line 411

Quoted 7 lines
target-riscv/translate.c +7 -0
+#if defined(TARGET_RISCV64)
+    case OPC_RISC_SHIFT_RIGHT_IW:
+        if ((uimm & 0x3ff) >= 32) {
+            kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+        }
+        tcg_gen_shli_tl(source1, source1, 32);
+        extra_shamt = 32;

tcg_gen_ext32{u,s}_tl is better than extra shifts.

r~

#12 lore raw

PATCH 6/18 target-riscv: Add JALR, Branch Instructions

In reply to Sagar Karandikar
---
 target-riscv/translate.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 107 insertions(+)
target-riscv/translate.c +107 -0
index ccfb795..d8044cf 100644
@@ -438,6 +438,106 @@ static inline void gen_arith_imm(DisasContext *ctx, uint32_t opc, int rd,
     tcg_temp_free(source1);
 }
 
+static inline void gen_jalr(DisasContext *ctx, uint32_t opc, int rd, int rs1,
+        int16_t imm)
+{
+    /* no chaining with JALR */
+    TCGLabel *misaligned = gen_new_label();
+    TCGLabel *done = gen_new_label();
+    target_long uimm = (target_long)imm; /* sign ext 16->64 bits */
+    TCGv t0, t1, t2, t3;
+    t0 = tcg_temp_local_new();
+    t1 = tcg_temp_local_new();
+    t2 = tcg_temp_local_new(); /* old_pc */
+    t3 = tcg_temp_local_new();
+
+    switch (opc) {
+    case OPC_RISC_JALR:
+        gen_get_gpr(t0, rs1);
+        tcg_gen_addi_tl(t0, t0, uimm);
+        tcg_gen_andi_tl(t0, t0, (target_ulong)0xFFFFFFFFFFFFFFFEll);
+        tcg_gen_andi_tl(t3, t0, 0x2);
+        tcg_gen_movi_tl(t2, ctx->pc);
+        tcg_gen_brcondi_tl(TCG_COND_NE, t3, 0x0, misaligned);
+        tcg_gen_mov_tl(cpu_PC, t0);
+        tcg_gen_addi_tl(t1, t2, 4);
+        gen_set_gpr(rd, t1);
+        tcg_gen_br(done);
+        gen_set_label(misaligned);
+        generate_exception_mbadaddr(ctx, RISCV_EXCP_INST_ADDR_MIS);
+        gen_set_label(done);
+        tcg_gen_exit_tb(0);
+        ctx->bstate = BS_BRANCH;
+        break;
+    default:
+        kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+        break;
+    }
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    tcg_temp_free(t2);
+    tcg_temp_free(t3);
+}
+
+static inline void gen_branch(DisasContext *ctx, uint32_t opc, int rs1, int rs2,
+        int16_t bimm)
+{
+    TCGLabel *l = gen_new_label();
+    TCGv source1, source2;
+    source1 = tcg_temp_new();
+    source2 = tcg_temp_new();
+    gen_get_gpr(source1, rs1);
+    gen_get_gpr(source2, rs2);
+    target_ulong ubimm = (target_long)bimm; /* sign ext 16->64 bits */
+
+    switch (opc) {
+    case OPC_RISC_BEQ:
+        tcg_gen_brcond_tl(TCG_COND_EQ, source1, source2, l);
+        break;
+    case OPC_RISC_BNE:
+        tcg_gen_brcond_tl(TCG_COND_NE, source1, source2, l);
+        break;
+    case OPC_RISC_BLT:
+        tcg_gen_brcond_tl(TCG_COND_LT, source1, source2, l);
+        break;
+    case OPC_RISC_BGE:
+        tcg_gen_brcond_tl(TCG_COND_GE, source1, source2, l);
+        break;
+    case OPC_RISC_BLTU:
+        tcg_gen_brcond_tl(TCG_COND_LTU, source1, source2, l);
+        break;
+    case OPC_RISC_BGEU:
+        tcg_gen_brcond_tl(TCG_COND_GEU, source1, source2, l);
+        break;
+    default:
+        kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+        break;
+    }
+
+#ifdef DISABLE_CHAINING_BRANCH
+    tcg_gen_movi_tl(cpu_PC, ctx->pc + 4);
+    tcg_gen_exit_tb(0);
+#else
+    gen_goto_tb(ctx, 1, ctx->pc + 4); /* must use this for safety */
+#endif
+    gen_set_label(l); /* branch taken */
+    if ((ctx->pc + ubimm) & 0x3) {
+        /* misaligned */
+        generate_exception_mbadaddr(ctx, RISCV_EXCP_INST_ADDR_MIS);
+        tcg_gen_exit_tb(0);
+    } else {
+#ifdef DISABLE_CHAINING_BRANCH
+        tcg_gen_movi_tl(cpu_PC, ctx->pc + ubimm);
+        tcg_gen_exit_tb(0);
+#else
+        gen_goto_tb(ctx, 0, ctx->pc + ubimm); /* must use this for safety */
+#endif
+    }
+    tcg_temp_free(source1);
+    tcg_temp_free(source2);
+    ctx->bstate = BS_BRANCH;
+}
+
 static void decode_opc(CPURISCVState *env, DisasContext *ctx)
 {
     int rs1;
@@ -504,6 +604,13 @@ static void decode_opc(CPURISCVState *env, DisasContext *ctx)
             tcg_temp_free(testpc);
         }
         break;
+    case OPC_RISC_JALR:
+        gen_jalr(ctx, MASK_OP_JALR(ctx->opcode), rd, rs1, imm);
+        break;
+    case OPC_RISC_BRANCH:
+        gen_branch(ctx, MASK_OP_BRANCH(ctx->opcode), rs1, rs2,
+                   GET_B_IMM(ctx->opcode));
+        break;
     case OPC_RISC_ARITH_IMM:
 #if defined(TARGET_RISCV64)
     case OPC_RISC_ARITH_IMM_W:
Signature · 1 line
2.9.3
#13 lore raw

Re: [Qemu-devel] [PATCH 06/18] target-riscv: Add JALR, Branch Instructions

Quoted 21 lines · Sagar Karandikar
---
 target-riscv/translate.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 107 insertions(+)
target-riscv/translate.c +8 -0
index ccfb795..d8044cf 100644
@@ -438,6 +438,106 @@ static inline void gen_arith_imm(DisasContext *ctx, uint32_t opc, int rd,
     tcg_temp_free(source1);
 }
 
+static inline void gen_jalr(DisasContext *ctx, uint32_t opc, int rd, int rs1,
+        int16_t imm)
+{
+    /* no chaining with JALR */
+    TCGLabel *misaligned = gen_new_label();
+    TCGLabel *done = gen_new_label();
+    target_long uimm = (target_long)imm; /* sign ext 16->64 bits */
+    TCGv t0, t1, t2, t3;

target-riscv/translate.c static inline void gen_arith_imm(DisasContext *ctx, uint32_t opc, int rd, · line 458

Quoted 10 lines
target-riscv/translate.c +10 -0
+    t0 = tcg_temp_local_new();
+    t1 = tcg_temp_local_new();
+    t2 = tcg_temp_local_new(); /* old_pc */
+    t3 = tcg_temp_local_new();
+
+    switch (opc) {
+    case OPC_RISC_JALR:
+        gen_get_gpr(t0, rs1);
+        tcg_gen_addi_tl(t0, t0, uimm);
+        tcg_gen_andi_tl(t0, t0, (target_ulong)0xFFFFFFFFFFFFFFFEll);

-2.

target-riscv/translate.c static inline void gen_arith_imm(DisasContext *ctx, uint32_t opc, int rd, · line 470

Quoted 12 lines
target-riscv/translate.c +12 -0
+        tcg_gen_andi_tl(t3, t0, 0x2);
+        tcg_gen_movi_tl(t2, ctx->pc);
+        tcg_gen_brcondi_tl(TCG_COND_NE, t3, 0x0, misaligned);
+        tcg_gen_mov_tl(cpu_PC, t0);
+        tcg_gen_addi_tl(t1, t2, 4);
+        gen_set_gpr(rd, t1);
+        tcg_gen_br(done);
+        gen_set_label(misaligned);
+        generate_exception_mbadaddr(ctx, RISCV_EXCP_INST_ADDR_MIS);
+        gen_set_label(done);
+        tcg_gen_exit_tb(0);
+        ctx->bstate = BS_BRANCH;

You don't need any temp_local, which will significantly clean up the generated code. Try

  gen_get_gpr(cpu_PC, rs1);
  tcg_gen_addi_tl(cpu_PC, cpu_PC, imm);
  tcg_gen_andi_tl(cpu_PC, cpu_PC, -2);
  tcg_gen_andi_tl(tmp, cpu_PC, 2);
  tcg_gen_brcondi_tl(TCG_COND_NE, tmp, 0, misaligned);

  if (rd != 0) {
    tcg_gen_movi_tl(cpu_gpr[rd], ctx->pc + 4);
  }
  tcg_gen_exit_tb(0);

  tcg_set_label(misaligned);
  generate_exception_mbadaddr(ctx, ...);

Note that cpu_PC will be reset in generate_exception, so we can initialize it early, before the branch.

target-riscv/translate.c static inline void gen_arith_imm(DisasContext *ctx, uint32_t opc, int rd, · line 483

Quoted 2 lines
target-riscv/translate.c +2 -0
+static inline void gen_branch(DisasContext *ctx, uint32_t opc, int rs1, int rs2,
+        int16_t bimm)

Drop the inline markers and let the compiler decide.

r~

#14 lore raw

PATCH 7/18 target-riscv: Add Loads/Stores, FP Loads/Stores

In reply to Sagar Karandikar
---
 target-riscv/translate.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 117 insertions(+)
target-riscv/translate.c +117 -0
index d8044cf..767cdbe 100644
@@ -72,6 +72,10 @@ static const char * const fpr_regnames[] = {
   "fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11"
 };
 
+/* convert riscv funct3 to qemu memop for load/store */
+static int tcg_memop_lookup[] = { MO_SB, MO_TESW, MO_TESL, MO_TEQ, MO_UB,
+    MO_TEUW, MO_TEUL };
+
 static inline void generate_exception(DisasContext *ctx, int excp)
 {
     tcg_gen_movi_tl(cpu_PC, ctx->pc);
@@ -538,6 +542,105 @@ static inline void gen_branch(DisasContext *ctx, uint32_t opc, int rs1, int rs2,
     ctx->bstate = BS_BRANCH;
 }
 
+static inline void gen_load(DisasContext *ctx, uint32_t opc, int rd, int rs1,
+        int16_t imm)
+{
+    target_long uimm = (target_long)imm; /* sign ext 16->64 bits */
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+    gen_get_gpr(t0, rs1);
+    tcg_gen_addi_tl(t0, t0, uimm); /* */
+    int memop = (opc >> 12) & 0x7;
+
+#if defined(TARGET_RISCV64)
+    if (memop == 0x7) {
+#else
+    if (memop == 0x7 || memop == 0x3 || memop == 0x6) {
+#endif
+        kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+    } else {
+        tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, tcg_memop_lookup[memop]);
+    }
+
+    gen_set_gpr(rd, t1);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+
+static inline void gen_store(DisasContext *ctx, uint32_t opc, int rs1, int rs2,
+        int16_t imm)
+{
+    target_long uimm = (target_long)imm; /* sign ext 16->64 bits */
+
+    TCGv t0 = tcg_temp_new();
+    TCGv dat = tcg_temp_new();
+    gen_get_gpr(t0, rs1);
+    tcg_gen_addi_tl(t0, t0, uimm);
+    gen_get_gpr(dat, rs2);
+    int memop = (opc >> 12) & 0x7;
+
+#if defined(TARGET_RISCV64)
+    if (memop > 0x3) {
+#else
+    if (memop > 0x2) {
+#endif
+        kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+    } else {
+        tcg_gen_qemu_st_tl(dat, t0, ctx->mem_idx, tcg_memop_lookup[memop]);
+    }
+
+    tcg_temp_free(t0);
+    tcg_temp_free(dat);
+}
+
+static inline void gen_fp_load(DisasContext *ctx, uint32_t opc, int rd,
+        int rs1, int16_t imm)
+{
+    target_long uimm = (target_long)imm; /* sign ext 16->64 bits */
+    TCGv t0 = tcg_temp_new();
+    gen_get_gpr(t0, rs1);
+    tcg_gen_addi_tl(t0, t0, uimm);
+
+    switch (opc) {
+    case OPC_RISC_FLW:
+        tcg_gen_qemu_ld_i64(cpu_fpr[rd], t0, ctx->mem_idx, MO_TEUL);
+        break;
+    case OPC_RISC_FLD:
+        tcg_gen_qemu_ld_i64(cpu_fpr[rd], t0, ctx->mem_idx, MO_TEQ);
+        break;
+    default:
+        kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+        break;
+    }
+    tcg_temp_free(t0);
+}
+
+static inline void gen_fp_store(DisasContext *ctx, uint32_t opc, int rs1,
+        int rs2, int16_t imm)
+{
+    target_long uimm = (target_long)imm; /* sign ext 16->64 bits */
+
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+    gen_get_gpr(t0, rs1);
+    tcg_gen_addi_tl(t0, t0, uimm);
+
+    switch (opc) {
+    case OPC_RISC_FSW:
+        tcg_gen_qemu_st_i64(cpu_fpr[rs2], t0, ctx->mem_idx, MO_TEUL);
+        break;
+    case OPC_RISC_FSD:
+        tcg_gen_qemu_st_i64(cpu_fpr[rs2], t0, ctx->mem_idx, MO_TEQ);
+        break;
+    default:
+        kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+        break;
+    }
+
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+
 static void decode_opc(CPURISCVState *env, DisasContext *ctx)
 {
     int rs1;
@@ -611,6 +714,13 @@ static void decode_opc(CPURISCVState *env, DisasContext *ctx)
         gen_branch(ctx, MASK_OP_BRANCH(ctx->opcode), rs1, rs2,
                    GET_B_IMM(ctx->opcode));
         break;
+    case OPC_RISC_LOAD:
+        gen_load(ctx, MASK_OP_LOAD(ctx->opcode), rd, rs1, imm);
+        break;
+    case OPC_RISC_STORE:
+        gen_store(ctx, MASK_OP_STORE(ctx->opcode), rs1, rs2,
+                  GET_STORE_IMM(ctx->opcode));
+        break;
     case OPC_RISC_ARITH_IMM:
 #if defined(TARGET_RISCV64)
     case OPC_RISC_ARITH_IMM_W:
@@ -629,6 +739,13 @@ static void decode_opc(CPURISCVState *env, DisasContext *ctx)
         }
         gen_arith(ctx, MASK_OP_ARITH(ctx->opcode), rd, rs1, rs2);
         break;
+    case OPC_RISC_FP_LOAD:
+        gen_fp_load(ctx, MASK_OP_FP_LOAD(ctx->opcode), rd, rs1, imm);
+        break;
+    case OPC_RISC_FP_STORE:
+        gen_fp_store(ctx, MASK_OP_FP_STORE(ctx->opcode), rs1, rs2,
+                     GET_STORE_IMM(ctx->opcode));
+        break;
     default:
         kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
         break;
Signature · 1 line
2.9.3
#15 lore raw

Re: [Qemu-devel] [PATCH 07/18] target-riscv: Add Loads/Stores, FP Loads/Stores

Quoted 10 lines · Sagar Karandikar
---
 target-riscv/translate.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 117 insertions(+)
target-riscv/translate.c +0 -0
index d8044cf..767cdbe 100644

target-riscv/translate.c static const char * const fpr_regnames[] = { · line 77

Quoted 6 lines
target-riscv/translate.c +3 -0
@@ -72,6 +72,10 @@ static const char * const fpr_regnames[] = {
   "fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11"
 };
 
+/* convert riscv funct3 to qemu memop for load/store */
+static int tcg_memop_lookup[] = { MO_SB, MO_TESW, MO_TESL, MO_TEQ, MO_UB,
+    MO_TEUW, MO_TEUL };

Const, and formatting

static const TCGMemOp tcg_memop_lookup[] = {
    ....
};

although...

Quoted 8 lines
target-riscv/translate.c +8 -0
+static inline void gen_load(DisasContext *ctx, uint32_t opc, int rd, int rs1,
+        int16_t imm)
+{
+    target_long uimm = (target_long)imm; /* sign ext 16->64 bits */
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+    gen_get_gpr(t0, rs1);
+    tcg_gen_addi_tl(t0, t0, uimm); /* */

target-riscv/translate.c static inline void gen_branch(DisasContext *ctx, uint32_t opc, int rs1, int rs2, · line 562

Quoted 10 lines
target-riscv/translate.c +10 -0
+    int memop = (opc >> 12) & 0x7;
+
+#if defined(TARGET_RISCV64)
+    if (memop == 0x7) {
+#else
+    if (memop == 0x7 || memop == 0x3 || memop == 0x6) {
+#endif
+        kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+    } else {
+        tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, tcg_memop_lookup[memop]);

... considering the set of if's, maybe better as

static const int tcg_memop_lookup[8] = {
    [0 ... 7] = -1,
    [0] = MO_SB,
    [1] = MO_TESW,
    [2] = MO_TESL,
    [4] = MO_UB,
    [5] = MO_TEUW,
#ifdef TARGET_RISCV64
    [3] = MO_TEQ,
    [6] = MO_TEUL,

#endif
};

and then have

    memop = tcg_memop_lookup[memop];
    if (memop < 0) {
        kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
    } else {
        tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, memop);
    }

r~

#16 lore raw

PATCH 8/18 target-riscv: Add Atomic Instructions

In reply to Sagar Karandikar
---
 target-riscv/translate.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 154 insertions(+)
target-riscv/translate.c +154 -0
index 767cdbe..af82eab 100644
@@ -641,6 +641,157 @@ static inline void gen_fp_store(DisasContext *ctx, uint32_t opc, int rs1,
     tcg_temp_free(t1);
 }
 
+static inline void gen_atomic(DisasContext *ctx, uint32_t opc,
+                      int rd, int rs1, int rs2)
+{
+    /* TODO: handle aq, rl bits? - for now just get rid of them: */
+    opc = MASK_OP_ATOMIC_NO_AQ_RL(opc);
+    TCGv source1, source2, dat;
+    TCGLabel *j = gen_new_label();
+    TCGLabel *done = gen_new_label();
+    source1 = tcg_temp_local_new();
+    source2 = tcg_temp_local_new();
+    dat = tcg_temp_local_new();
+    gen_get_gpr(source1, rs1);
+    gen_get_gpr(source2, rs2);
+
+    switch (opc) {
+        /* all currently implemented as non-atomics */
+    case OPC_RISC_LR_W:
+        /* put addr in load_res */
+        tcg_gen_mov_tl(load_res, source1);
+        tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TESL | MO_ALIGN);
+        break;
+    case OPC_RISC_SC_W:
+        tcg_gen_brcond_tl(TCG_COND_NE, load_res, source1, j);
+        tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEUL | MO_ALIGN);
+        tcg_gen_movi_tl(dat, 0); /*success */
+        tcg_gen_br(done);
+        gen_set_label(j);
+        tcg_gen_movi_tl(dat, 1); /*fail */
+        gen_set_label(done);
+        break;
+    case OPC_RISC_AMOSWAP_W:
+        tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TESL | MO_ALIGN);
+        tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEUL | MO_ALIGN);
+        break;
+    case OPC_RISC_AMOADD_W:
+        tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TESL | MO_ALIGN);
+        tcg_gen_add_tl(source2, dat, source2);
+        tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEUL | MO_ALIGN);
+        break;
+    case OPC_RISC_AMOXOR_W:
+        tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TESL | MO_ALIGN);
+        tcg_gen_xor_tl(source2, dat, source2);
+        tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEUL | MO_ALIGN);
+        break;
+    case OPC_RISC_AMOAND_W:
+        tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TESL | MO_ALIGN);
+        tcg_gen_and_tl(source2, dat, source2);
+        tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEUL | MO_ALIGN);
+        break;
+    case OPC_RISC_AMOOR_W:
+        tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TESL | MO_ALIGN);
+        tcg_gen_or_tl(source2, dat, source2);
+        tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEUL | MO_ALIGN);
+        break;
+    case OPC_RISC_AMOMIN_W:
+        tcg_gen_ext32s_tl(source2, source2); /* since comparing */
+        tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TESL | MO_ALIGN);
+        tcg_gen_movcond_tl(TCG_COND_LT, source2, dat, source2, dat, source2);
+        tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEUL | MO_ALIGN);
+        break;
+    case OPC_RISC_AMOMAX_W:
+        tcg_gen_ext32s_tl(source2, source2); /* since comparing */
+        tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TESL | MO_ALIGN);
+        tcg_gen_movcond_tl(TCG_COND_GT, source2, dat, source2, dat, source2);
+        tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEUL | MO_ALIGN);
+        break;
+    case OPC_RISC_AMOMINU_W:
+        tcg_gen_ext32u_tl(source2, source2); /* since comparing */
+        tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TEUL | MO_ALIGN);
+        tcg_gen_movcond_tl(TCG_COND_LTU, source2, dat, source2, dat, source2);
+        tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEUL | MO_ALIGN);
+        tcg_gen_ext32s_tl(dat, dat); /* since load was TEUL */
+        break;
+    case OPC_RISC_AMOMAXU_W:
+        tcg_gen_ext32u_tl(source2, source2); /* since comparing */
+        tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TEUL | MO_ALIGN);
+        tcg_gen_movcond_tl(TCG_COND_GTU, source2, dat, source2, dat, source2);
+        tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEUL | MO_ALIGN);
+        tcg_gen_ext32s_tl(dat, dat); /* since load was TEUL */
+        break;
+#if defined(TARGET_RISCV64)
+    case OPC_RISC_LR_D:
+        /* put addr in load_res */
+        tcg_gen_mov_tl(load_res, source1);
+        tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN);
+        break;
+    case OPC_RISC_SC_D:
+        tcg_gen_brcond_tl(TCG_COND_NE, load_res, source1, j);
+        tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN);
+        tcg_gen_movi_tl(dat, 0); /* success */
+        tcg_gen_br(done);
+        gen_set_label(j);
+        tcg_gen_movi_tl(dat, 1); /* fail */
+        gen_set_label(done);
+        break;
+    case OPC_RISC_AMOSWAP_D:
+        tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN);
+        tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN);
+        break;
+    case OPC_RISC_AMOADD_D:
+        tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN);
+        tcg_gen_add_tl(source2, dat, source2);
+        tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN);
+        break;
+    case OPC_RISC_AMOXOR_D:
+        tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN);
+        tcg_gen_xor_tl(source2, dat, source2);
+        tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN);
+        break;
+    case OPC_RISC_AMOAND_D:
+        tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN);
+        tcg_gen_and_tl(source2, dat, source2);
+        tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN);
+        break;
+    case OPC_RISC_AMOOR_D:
+        tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN);
+        tcg_gen_or_tl(source2, dat, source2);
+        tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN);
+        break;
+    case OPC_RISC_AMOMIN_D:
+        tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN);
+        tcg_gen_movcond_tl(TCG_COND_LT, source2, dat, source2, dat, source2);
+        tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN);
+        break;
+    case OPC_RISC_AMOMAX_D:
+        tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN);
+        tcg_gen_movcond_tl(TCG_COND_GT, source2, dat, source2, dat, source2);
+        tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN);
+        break;
+    case OPC_RISC_AMOMINU_D:
+        tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN);
+        tcg_gen_movcond_tl(TCG_COND_LTU, source2, dat, source2, dat, source2);
+        tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN);
+        break;
+    case OPC_RISC_AMOMAXU_D:
+        tcg_gen_qemu_ld_tl(dat, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN);
+        tcg_gen_movcond_tl(TCG_COND_GTU, source2, dat, source2, dat, source2);
+        tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEQ | MO_ALIGN);
+        break;
+#endif
+    default:
+        kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+        break;
+    }
+
+    gen_set_gpr(rd, dat);
+    tcg_temp_free(source1);
+    tcg_temp_free(source2);
+    tcg_temp_free(dat);
+}
+
 static void decode_opc(CPURISCVState *env, DisasContext *ctx)
 {
     int rs1;
@@ -746,6 +897,9 @@ static void decode_opc(CPURISCVState *env, DisasContext *ctx)
         gen_fp_store(ctx, MASK_OP_FP_STORE(ctx->opcode), rs1, rs2,
                      GET_STORE_IMM(ctx->opcode));
         break;
+    case OPC_RISC_ATOMIC:
+        gen_atomic(ctx, MASK_OP_ATOMIC(ctx->opcode), rd, rs1, rs2);
+        break;
     default:
         kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
         break;
Signature · 1 line
2.9.3
#17 lore raw

Re: [Qemu-devel] [PATCH 08/18] target-riscv: Add Atomic Instructions

target-riscv/translate.c static inline void gen_fp_store(DisasContext *ctx, uint32_t opc, int rs1, · line 648

Quoted 5 lines · Sagar Karandikar
target-riscv/translate.c +5 -0
+static inline void gen_atomic(DisasContext *ctx, uint32_t opc,
+                      int rd, int rs1, int rs2)
+{
+    /* TODO: handle aq, rl bits? - for now just get rid of them: */
+    opc = MASK_OP_ATOMIC_NO_AQ_RL(opc);

We have already added tcg_gen_mb to insert memory barriers; hopefully the branch containing atomic operations will be merged soon. See

git://github.com/rth7680/qemu.git atomic-4

target-riscv/translate.c static inline void gen_fp_store(DisasContext *ctx, uint32_t opc, int rs1, · line 673

Quoted 9 lines
target-riscv/translate.c +9 -0
+    case OPC_RISC_SC_W:
+        tcg_gen_brcond_tl(TCG_COND_NE, load_res, source1, j);
+        tcg_gen_qemu_st_tl(source2, source1, ctx->mem_idx, MO_TEUL | MO_ALIGN);
+        tcg_gen_movi_tl(dat, 0); /*success */
+        tcg_gen_br(done);
+        gen_set_label(j);
+        tcg_gen_movi_tl(dat, 1); /*fail */
+        gen_set_label(done);
+        break;

I will note that generally SC needs to compare against the value loaded by LR as well as the address used by LR. Please have a look at the AArch64 implementation.

r~

#18 lore raw

PATCH 9/18 target-riscv: Add FMADD, FMSUB, FNMADD, FNMSUB Instructions,

In reply to Sagar Karandikar

Along with FP helper infrastructure, changes to softfloat-specialize

---
 fpu/softfloat-specialize.h |   7 ++-
 target-riscv/Makefile.objs |   2 +-
 target-riscv/fpu_helper.c  | 151 +++++++++++++++++++++++++++++++++++++++++++++
 target-riscv/helper.h      |  10 +++
 target-riscv/translate.c   | 105 +++++++++++++++++++++++++++++++
 5 files changed, 271 insertions(+), 4 deletions(-)
 create mode 100644 target-riscv/fpu_helper.c
fpu/softfloat-specialize.h +4 -3
index f5aed72..fa5986d 100644
@@ -114,7 +114,8 @@ float32 float32_default_nan(float_status *status)
 #if defined(TARGET_SPARC)
     return const_float32(0x7FFFFFFF);
 #elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) || \
-      defined(TARGET_XTENSA) || defined(TARGET_S390X) || defined(TARGET_TRICORE)
+      defined(TARGET_XTENSA) || defined(TARGET_S390X) || \
+      defined(TARGET_TRICORE) || defined(TARGET_RISCV)
     return const_float32(0x7FC00000);
 #else
     if (status->snan_bit_is_one) {
@@ -137,7 +138,7 @@ float64 float64_default_nan(float_status *status)
 #if defined(TARGET_SPARC)
     return const_float64(LIT64(0x7FFFFFFFFFFFFFFF));
 #elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) || \
-      defined(TARGET_S390X)
+      defined(TARGET_S390X) || defined(TARGET_RISCV)
     return const_float64(LIT64(0x7FF8000000000000));
 #else
     if (status->snan_bit_is_one) {
@@ -181,7 +182,7 @@ float128 float128_default_nan(float_status *status)
         r.high = LIT64(0x7FFF7FFFFFFFFFFF);
     } else {
         r.low = LIT64(0x0000000000000000);
-#if defined(TARGET_S390X)
+#if defined(TARGET_S390X) || defined(TARGET_RISCV)
         r.high = LIT64(0x7FFF800000000000);
 #else
         r.high = LIT64(0xFFFF800000000000);
target-riscv/Makefile.objs +1 -1
index cb448a8..0149732 100644
@@ -1 +1 @@
-obj-y += translate.o op_helper.o helper.o cpu.o
+obj-y += translate.o op_helper.o helper.o cpu.o fpu_helper.o
target-riscv/fpu_helper.c new file +151 -0

151 lines not on this page · raw message

target-riscv/helper.h +10 -0
index c489222..586abae5 100644
@@ -6,3 +6,13 @@ DEF_HELPER_3(raise_exception_mbadaddr, noreturn, env, i32, tl)
 #if defined(TARGET_RISCV64)
 DEF_HELPER_FLAGS_3(mulhsu, TCG_CALL_NO_RWG_SE, tl, env, tl, tl)
 #endif
+
+/* Floating Point - fused */
+DEF_HELPER_FLAGS_5(fmadd_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64, i64)
+DEF_HELPER_FLAGS_5(fmadd_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64, i64)
+DEF_HELPER_FLAGS_5(fmsub_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64, i64)
+DEF_HELPER_FLAGS_5(fmsub_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64, i64)
+DEF_HELPER_FLAGS_5(fnmsub_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64, i64)
+DEF_HELPER_FLAGS_5(fnmsub_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64, i64)
+DEF_HELPER_FLAGS_5(fnmadd_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64, i64)
+DEF_HELPER_FLAGS_5(fnmadd_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64, i64)
target-riscv/translate.c +105 -0

117 lines not on this page · raw message

Signature · 1 line
2.9.3
#19 lore raw

Re: [Qemu-devel] [PATCH 09/18] target-riscv: Add FMADD, FMSUB, FNMADD, FNMSUB Instructions,

Quoted 11 lines · Sagar Karandikar
target-riscv/fpu_helper.c new file +11 -0
+/* convert RISC-V rounding mode to IEEE library numbers */
+unsigned int ieee_rm[] = {
+    float_round_nearest_even,
+    float_round_to_zero,
+    float_round_down,
+    float_round_up,
+    float_round_ties_away
+};
+
+/* obtain rm value to use in computation
+ * as the last step, convert rm codes to what the softfloat library expects

target-riscv/fpu_helper.c line 47

Quoted 10 lines
target-riscv/fpu_helper.c new file +10 -0
+ * Adapted from Spike's decode.h:RM
+ */
+#define RM ({                                             \
+if (rm == 7) {                                            \
+    rm = env->csr[CSR_FRM];                               \
+}                                                         \
+if (rm > 4) {                                             \
+    helper_raise_exception(env, RISCV_EXCP_ILLEGAL_INST); \
+}                                                         \
+ieee_rm[rm]; })

You're not doing anything to get the proper guest PC value for the illegal instruction exception. This is, of course, rare, and can be caught during translation, which would be greatly preferred since the fpu signals no other exceptions, and thus all of the fpu helpers can be TCG_CALL_NO_RWG.

This can be done by examining fcsr during cpu_get_tb_cpu_state. Set a flag bit (TB_FLAG_RM_INVALID) when fcsr.rm is invalid. Then during translation, raise an exception if

(1) rm == 7 && TB_FLAG_RM_INVALID
(2) rm >= 5 && rm <= 6

You can improve this rounding mode switching by remembering the mode used by the previous insn. See target-alpha DisasContext.tb_rm.

target-riscv/fpu_helper.c line 73

Quoted 6 lines
target-riscv/fpu_helper.c new file +6 -0
+/* adapted from Spike's decode.h:set_fp_exceptions */
+#define set_fp_exceptions() do { \
+    env->csr[CSR_FFLAGS] |= softfloat_flags_to_riscv(get_float_exception_flags(\
+                            &env->fp_status)); \
+    set_float_exception_flags(0, &env->fp_status); \
+} while (0)

Any reason not to make this a function?

target-riscv/fpu_helper.c line 98

Quoted 6 lines
target-riscv/fpu_helper.c new file +6 -0
+uint64_t helper_fmsub_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+                        uint64_t frs3, uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    frs1 = float32_muladd(frs1, frs2, frs3 ^ (uint32_t)INT32_MIN, 0,
+                          &env->fp_status);

float_muladd_negate_c

target-riscv/fpu_helper.c line 118

Quoted 6 lines
target-riscv/fpu_helper.c new file +6 -0
+uint64_t helper_fnmsub_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+                         uint64_t frs3, uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    frs1 = float32_muladd(frs1 ^ (uint32_t)INT32_MIN, frs2, frs3, 0,
+                          &env->fp_status);

This one is actually computing fnmadd afaics...

target-riscv/fpu_helper.c line 138

Quoted 6 lines
target-riscv/fpu_helper.c new file +6 -0
+uint64_t helper_fnmadd_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+                         uint64_t frs3, uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    frs1 = float32_muladd(frs1 ^ (uint32_t)INT32_MIN, frs2,
+                          frs3 ^ (uint32_t)INT32_MIN, 0, &env->fp_status);

... and this one is actually computing fnmsub. Given that you're passing tests, are you sure that FNMADD and FNMSUB opcodes are not swapped?

Use float_muladd_negate_result for FNMADD.
Use float_muladd_negate_c | float_muladd_negate_result for FNMSUB.

r~

#20 lore raw

Re: [Qemu-devel] [PATCH 09/18] target-riscv: Add FMADD, FMSUB, FNMADD, FNMSUB Instructions,

In reply to Sagar Karandikar
Quoted 5 lines · Sagar Karandikar
target-riscv/fpu_helper.c new file +5 -0
+/* adapted from Spike's decode.h:set_fp_exceptions */
+#define set_fp_exceptions() do { \
+    env->csr[CSR_FFLAGS] |= softfloat_flags_to_riscv(get_float_exception_flags(\
+                            &env->fp_status)); \
+    set_float_exception_flags(0, &env->fp_status); \

target-riscv/fpu_helper.c line 82

Quoted 10 lines
target-riscv/fpu_helper.c new file +10 -0
+} while (0)
+
+uint64_t helper_fmadd_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+                        uint64_t frs3, uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    frs1 = float32_muladd(frs1, frs2, frs3, 0, &env->fp_status);
+    set_fp_exceptions();
+    return frs1;
+}

I should also mention that I think it would be preferable to canonically store the fflags csr in fp_status. This means that you only need to perform this flags conversion when reading or writing the csr, and not upon every fp insn.

The conversion of bits at each fp insn is done on other targets in order to notice when exceptions must be taken. Since riscv has no fp exceptions, this isn't a factor.

r~

#21 lore raw

PATCH 10/18 target-riscv: Add Single Precision Floating-Point Instructions

In reply to Sagar Karandikar
---
 target-riscv/fpu_helper.c | 206 ++++++++++++++++++++++++++++++++++++++++++++++
 target-riscv/helper.h     |  28 +++++++
 target-riscv/translate.c  | 146 ++++++++++++++++++++++++++++++++
 3 files changed, 380 insertions(+)
target-riscv/fpu_helper.c +206 -0
index 9023d10..8d33fa1 100644
@@ -149,3 +149,209 @@ uint64_t helper_fnmadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
     set_fp_exceptions();
     return frs1;
 }
+
+uint64_t helper_fadd_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+                       uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    frs1 = float32_add(frs1, frs2, &env->fp_status);
+    set_fp_exceptions();
+    return frs1;
+}
+
+uint64_t helper_fsub_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+                       uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    frs1 = float32_sub(frs1, frs2, &env->fp_status);
+    set_fp_exceptions();
+    return frs1;
+}
+
+uint64_t helper_fmul_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+                       uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    frs1 = float32_mul(frs1, frs2, &env->fp_status);
+    set_fp_exceptions();
+    return frs1;
+}
+
+uint64_t helper_fdiv_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+                       uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    frs1 = float32_div(frs1, frs2, &env->fp_status);
+    set_fp_exceptions();
+    return frs1;
+}
+
+uint64_t helper_fsgnj_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+    frs1 = (frs1 & ~(uint32_t)INT32_MIN) | (frs2 & (uint32_t)INT32_MIN);
+    return frs1;
+}
+
+uint64_t helper_fsgnjn_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+    frs1 = (frs1 & ~(uint32_t)INT32_MIN) | ((~frs2) & (uint32_t)INT32_MIN);
+    return frs1;
+}
+
+uint64_t helper_fsgnjx_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+    frs1 = frs1 ^ (frs2 & (uint32_t)INT32_MIN);
+    return frs1;
+}
+
+uint64_t helper_fmin_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+    frs1 = float32_is_any_nan(frs2) ||
+           float32_lt_quiet(frs1, frs2, &env->fp_status) ? frs1 : frs2;
+    set_fp_exceptions();
+    return frs1;
+}
+
+uint64_t helper_fmax_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+    frs1 = float32_is_any_nan(frs2) ||
+           float32_le_quiet(frs2, frs1, &env->fp_status) ? frs1 : frs2;
+    set_fp_exceptions();
+    return frs1;
+}
+
+uint64_t helper_fsqrt_s(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    frs1 = float32_sqrt(frs1, &env->fp_status);
+    set_fp_exceptions();
+    return frs1;
+}
+
+target_ulong helper_fle_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+    frs1 = float32_le(frs1, frs2, &env->fp_status);
+    set_fp_exceptions();
+    return frs1;
+}
+
+target_ulong helper_flt_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+    frs1 = float32_lt(frs1, frs2, &env->fp_status);
+    set_fp_exceptions();
+    return frs1;
+}
+
+target_ulong helper_feq_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+    frs1 = float32_eq(frs1, frs2, &env->fp_status);
+    set_fp_exceptions();
+    return frs1;
+}
+
+target_ulong helper_fcvt_w_s(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    frs1 = (int64_t)((int32_t)float32_to_int32(frs1, &env->fp_status));
+    set_fp_exceptions();
+    return frs1;
+}
+
+target_ulong helper_fcvt_wu_s(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    frs1 = (int64_t)((int32_t)float32_to_uint32(frs1, &env->fp_status));
+    set_fp_exceptions();
+    return frs1;
+}
+
+#if defined(TARGET_RISCV64)
+uint64_t helper_fcvt_l_s(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    frs1 = float32_to_int64(frs1, &env->fp_status);
+    set_fp_exceptions();
+    return frs1;
+}
+
+uint64_t helper_fcvt_lu_s(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    frs1 = float32_to_uint64(frs1, &env->fp_status);
+    set_fp_exceptions();
+    return frs1;
+}
+#endif
+
+uint64_t helper_fcvt_s_w(CPURISCVState *env, target_ulong rs1, uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    rs1 = int32_to_float32((int32_t)rs1, &env->fp_status);
+    set_fp_exceptions();
+    return rs1;
+}
+
+uint64_t helper_fcvt_s_wu(CPURISCVState *env, target_ulong rs1, uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    rs1 = uint32_to_float32((uint32_t)rs1, &env->fp_status);
+    set_fp_exceptions();
+    return rs1;
+}
+
+#if defined(TARGET_RISCV64)
+uint64_t helper_fcvt_s_l(CPURISCVState *env, uint64_t rs1, uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    rs1 = int64_to_float32(rs1, &env->fp_status);
+    set_fp_exceptions();
+    return rs1;
+}
+
+uint64_t helper_fcvt_s_lu(CPURISCVState *env, uint64_t rs1, uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    rs1 = uint64_to_float32(rs1, &env->fp_status);
+    set_fp_exceptions();
+    return rs1;
+}
+#endif
+
+/* adapted from spike */
+#define isNaNF32UI(ui) (0xFF000000 < (uint32_t)((uint_fast32_t)ui << 1))
+#define signF32UI(a) ((bool)((uint32_t)a >> 31))
+#define expF32UI(a) ((int_fast16_t)(a >> 23) & 0xFF)
+#define fracF32UI(a) (a & 0x007FFFFF)
+
+union ui32_f32 { uint32_t ui; uint32_t f; };
+
+uint_fast16_t float32_classify(uint32_t a, float_status *status)
+{
+    union ui32_f32 uA;
+    uint_fast32_t uiA;
+
+    uA.f = a;
+    uiA = uA.ui;
+
+    uint_fast16_t infOrNaN = expF32UI(uiA) == 0xFF;
+    uint_fast16_t subnormalOrZero = expF32UI(uiA) == 0;
+    bool sign = signF32UI(uiA);
+
+    return
+        (sign && infOrNaN && fracF32UI(uiA) == 0)           << 0 |
+        (sign && !infOrNaN && !subnormalOrZero)             << 1 |
+        (sign && subnormalOrZero && fracF32UI(uiA))         << 2 |
+        (sign && subnormalOrZero && fracF32UI(uiA) == 0)    << 3 |
+        (!sign && infOrNaN && fracF32UI(uiA) == 0)          << 7 |
+        (!sign && !infOrNaN && !subnormalOrZero)            << 6 |
+        (!sign && subnormalOrZero && fracF32UI(uiA))        << 5 |
+        (!sign && subnormalOrZero && fracF32UI(uiA) == 0)   << 4 |
+        (isNaNF32UI(uiA) &&  float32_is_signaling_nan(uiA, status)) << 8 |
+        (isNaNF32UI(uiA) && !float32_is_signaling_nan(uiA, status)) << 9;
+}
+
+target_ulong helper_fclass_s(CPURISCVState *env, uint64_t frs1)
+{
+    frs1 = float32_classify(frs1, &env->fp_status);
+    return frs1;
+}
target-riscv/helper.h +28 -0
index 586abae5..85b505a 100644
@@ -16,3 +16,31 @@ DEF_HELPER_FLAGS_5(fnmsub_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64, i64)
 DEF_HELPER_FLAGS_5(fnmsub_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64, i64)
 DEF_HELPER_FLAGS_5(fnmadd_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64, i64)
 DEF_HELPER_FLAGS_5(fnmadd_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64, i64)
+
+/* Floating Point - Single Precision */
+DEF_HELPER_FLAGS_4(fadd_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)
+DEF_HELPER_FLAGS_4(fsub_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)
+DEF_HELPER_FLAGS_4(fmul_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)
+DEF_HELPER_FLAGS_4(fdiv_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)
+DEF_HELPER_FLAGS_3(fsgnj_s, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fsgnjn_s, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fsgnjx_s, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fmin_s, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fmax_s, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fsqrt_s, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fle_s, TCG_CALL_NO_RWG, tl, env, i64, i64)
+DEF_HELPER_FLAGS_3(flt_s, TCG_CALL_NO_RWG, tl, env, i64, i64)
+DEF_HELPER_FLAGS_3(feq_s, TCG_CALL_NO_RWG, tl, env, i64, i64)
+DEF_HELPER_FLAGS_3(fcvt_w_s, TCG_CALL_NO_RWG, tl, env, i64, i64)
+DEF_HELPER_FLAGS_3(fcvt_wu_s, TCG_CALL_NO_RWG, tl, env, i64, i64)
+#if defined(TARGET_RISCV64)
+DEF_HELPER_FLAGS_3(fcvt_l_s, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fcvt_lu_s, TCG_CALL_NO_RWG, i64, env, i64, i64)
+#endif
+DEF_HELPER_FLAGS_3(fcvt_s_w, TCG_CALL_NO_RWG, i64, env, tl, i64)
+DEF_HELPER_FLAGS_3(fcvt_s_wu, TCG_CALL_NO_RWG, i64, env, tl, i64)
+#if defined(TARGET_RISCV64)
+DEF_HELPER_FLAGS_3(fcvt_s_l, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fcvt_s_lu, TCG_CALL_NO_RWG, i64, env, i64, i64)
+#endif
+DEF_HELPER_FLAGS_2(fclass_s, TCG_CALL_NO_RWG, tl, env, i64)
target-riscv/translate.c +146 -0

158 lines not on this page · raw message

Signature · 1 line
2.9.3
#22 lore raw

Re: [Qemu-devel] [PATCH 10/18] target-riscv: Add Single Precision Floating-Point Instructions

Quoted 7 lines · Sagar Karandikar
target-riscv/fpu_helper.c +7 -0
+uint64_t helper_fsgnj_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+    frs1 = (frs1 & ~(uint32_t)INT32_MIN) | (frs2 & (uint32_t)INT32_MIN);
+    return frs1;
+}
+
+uint64_t helper_fsgnjn_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)

target-riscv/fpu_helper.c uint64_t helper_fnmadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2, · line 205

Quoted 10 lines
target-riscv/fpu_helper.c +10 -0
+{
+    frs1 = (frs1 & ~(uint32_t)INT32_MIN) | ((~frs2) & (uint32_t)INT32_MIN);
+    return frs1;
+}
+
+uint64_t helper_fsgnjx_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+    frs1 = frs1 ^ (frs2 & (uint32_t)INT32_MIN);
+    return frs1;
+}

These are simple enough to implement inline.

target-riscv/fpu_helper.c uint64_t helper_fnmadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2, · line 213

Quoted 8 lines
target-riscv/fpu_helper.c +8 -0
+
+uint64_t helper_fmin_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+    frs1 = float32_is_any_nan(frs2) ||
+           float32_lt_quiet(frs1, frs2, &env->fp_status) ? frs1 : frs2;
+    set_fp_exceptions();
+    return frs1;
+}

float32_minnum.

target-riscv/fpu_helper.c uint64_t helper_fnmadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2, · line 221

Quoted 8 lines
target-riscv/fpu_helper.c +8 -0
+
+uint64_t helper_fmax_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+    frs1 = float32_is_any_nan(frs2) ||
+           float32_le_quiet(frs2, frs1, &env->fp_status) ? frs1 : frs2;
+    set_fp_exceptions();
+    return frs1;
+}

float32_maxnum.

target-riscv/fpu_helper.c uint64_t helper_fnmadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2, · line 255

Quoted 4 lines
target-riscv/fpu_helper.c +4 -0
+target_ulong helper_fcvt_w_s(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    frs1 = (int64_t)((int32_t)float32_to_int32(frs1, &env->fp_status));

You do not need either of these casts.

target-riscv/fpu_helper.c uint64_t helper_fnmadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2, · line 263

Quoted 4 lines
target-riscv/fpu_helper.c +4 -0
+target_ulong helper_fcvt_wu_s(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    frs1 = (int64_t)((int32_t)float32_to_uint32(frs1, &env->fp_status));

You do not need the cast to int64_t. Also, remove the extra parenthesis.

Quoted 1 line

+union ui32_f32 { uint32_t ui; uint32_t f; };

What's the point of this?

Review

Quoted 2 lines
(quoted diff) +2 -0
+
+uint_fast16_t float32_classify(uint32_t a, float_status *status)

No need for uint_fast16_t. Just use uint32_t.

target-riscv/fpu_helper.c uint64_t helper_fnmadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2, · line 336

Quoted 8 lines
target-riscv/fpu_helper.c +8 -0
+{
+    union ui32_f32 uA;
+    uint_fast32_t uiA;
+
+    uA.f = a;
+    uiA = uA.ui;
+
+    uint_fast16_t infOrNaN = expF32UI(uiA) == 0xFF;

float32_is_infinity or float32_is_any_nan.

Quoted 1 line

+ uint_fast16_t subnormalOrZero = expF32UI(uiA) == 0;

float32_is_zero_or_denormal

Quoted 1 line

+ bool sign = signF32UI(uiA);

float32_is_neg.

r~

#23 lore raw

PATCH 11/18 target-riscv: Add Double Precision Floating-Point Instructions

In reply to Sagar Karandikar
---
 target-riscv/fpu_helper.c | 225 ++++++++++++++++++++++++++++++++++++++++++++++
 target-riscv/helper.h     |  30 +++++++
 target-riscv/translate.c  | 135 ++++++++++++++++++++++++++++
 3 files changed, 390 insertions(+)
target-riscv/fpu_helper.c +225 -0
index 8d33fa1..b3d443e 100644
@@ -355,3 +355,228 @@ target_ulong helper_fclass_s(CPURISCVState *env, uint64_t frs1)
     frs1 = float32_classify(frs1, &env->fp_status);
     return frs1;
 }
+
+uint64_t helper_fadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+                       uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    frs1 = float64_add(frs1, frs2, &env->fp_status);
+    set_fp_exceptions();
+    return frs1;
+}
+
+uint64_t helper_fsub_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+                       uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    frs1 = float64_sub(frs1, frs2, &env->fp_status);
+    set_fp_exceptions();
+    return frs1;
+}
+
+uint64_t helper_fmul_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+                       uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    frs1 = float64_mul(frs1, frs2, &env->fp_status);
+    set_fp_exceptions();
+    return frs1;
+}
+
+uint64_t helper_fdiv_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+                       uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    frs1 = float64_div(frs1, frs2, &env->fp_status);
+    set_fp_exceptions();
+    return frs1;
+}
+
+uint64_t helper_fsgnj_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+    frs1 = (frs1 & ~INT64_MIN) | (frs2 & INT64_MIN);
+    return frs1;
+}
+
+uint64_t helper_fsgnjn_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+    frs1 = (frs1 & ~INT64_MIN) | ((~frs2) & INT64_MIN);
+    return frs1;
+}
+
+uint64_t helper_fsgnjx_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+    frs1 = frs1 ^ (frs2 & INT64_MIN);
+    return frs1;
+}
+
+uint64_t helper_fmin_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+    frs1 = float64_is_any_nan(frs2) ||
+           float64_lt_quiet(frs1, frs2, &env->fp_status) ? frs1 : frs2;
+    set_fp_exceptions();
+    return frs1;
+}
+
+uint64_t helper_fmax_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+    frs1 = float64_is_any_nan(frs2) ||
+           float64_le_quiet(frs2, frs1, &env->fp_status) ? frs1 : frs2;
+    set_fp_exceptions();
+    return frs1;
+}
+
+uint64_t helper_fcvt_s_d(CPURISCVState *env, uint64_t rs1, uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    rs1 = float64_to_float32(rs1, &env->fp_status);
+    set_fp_exceptions();
+    return rs1;
+}
+
+uint64_t helper_fcvt_d_s(CPURISCVState *env, uint64_t rs1, uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    rs1 = float32_to_float64(rs1, &env->fp_status);
+    set_fp_exceptions();
+    return rs1;
+}
+
+uint64_t helper_fsqrt_d(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    frs1 = float64_sqrt(frs1, &env->fp_status);
+    set_fp_exceptions();
+    return frs1;
+}
+
+target_ulong helper_fle_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+    frs1 = float64_le(frs1, frs2, &env->fp_status);
+    set_fp_exceptions();
+    return frs1;
+}
+
+target_ulong helper_flt_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+    frs1 = float64_lt(frs1, frs2, &env->fp_status);
+    set_fp_exceptions();
+    return frs1;
+}
+
+target_ulong helper_feq_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+    frs1 = float64_eq(frs1, frs2, &env->fp_status);
+    set_fp_exceptions();
+    return frs1;
+}
+
+target_ulong helper_fcvt_w_d(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    frs1 = (int64_t)((int32_t)float64_to_int32(frs1, &env->fp_status));
+    set_fp_exceptions();
+    return frs1;
+}
+
+target_ulong helper_fcvt_wu_d(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    frs1 = (int64_t)((int32_t)float64_to_uint32(frs1, &env->fp_status));
+    set_fp_exceptions();
+    return frs1;
+}
+
+#if defined(TARGET_RISCV64)
+uint64_t helper_fcvt_l_d(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    frs1 = float64_to_int64(frs1, &env->fp_status);
+    set_fp_exceptions();
+    return frs1;
+}
+
+uint64_t helper_fcvt_lu_d(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    frs1 = float64_to_uint64(frs1, &env->fp_status);
+    set_fp_exceptions();
+    return frs1;
+}
+#endif
+
+uint64_t helper_fcvt_d_w(CPURISCVState *env, target_ulong rs1, uint64_t rm)
+{
+    uint64_t res;
+    set_float_rounding_mode(RM, &env->fp_status);
+    res = int32_to_float64((int32_t)rs1, &env->fp_status);
+    set_fp_exceptions();
+    return res;
+}
+
+uint64_t helper_fcvt_d_wu(CPURISCVState *env, target_ulong rs1, uint64_t rm)
+{
+    uint64_t res;
+    set_float_rounding_mode(RM, &env->fp_status);
+    res = uint32_to_float64((uint32_t)rs1, &env->fp_status);
+    set_fp_exceptions();
+    return res;
+}
+
+#if defined(TARGET_RISCV64)
+uint64_t helper_fcvt_d_l(CPURISCVState *env, uint64_t rs1, uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    rs1 = int64_to_float64(rs1, &env->fp_status);
+    set_fp_exceptions();
+    return rs1;
+}
+
+uint64_t helper_fcvt_d_lu(CPURISCVState *env, uint64_t rs1, uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    rs1 = uint64_to_float64(rs1, &env->fp_status);
+    set_fp_exceptions();
+    return rs1;
+}
+#endif
+
+/* adapted from spike */
+#define isNaNF64UI(ui) (UINT64_C(0xFFE0000000000000) \
+                       < (uint64_t)((uint_fast64_t)ui << 1))
+#define signF64UI(a) ((bool)((uint64_t) a >> 63))
+#define expF64UI(a) ((int_fast16_t)(a >> 52) & 0x7FF)
+#define fracF64UI(a) (a & UINT64_C(0x000FFFFFFFFFFFFF))
+
+union ui64_f64 { uint64_t ui; uint64_t f; };
+
+uint_fast16_t float64_classify(uint64_t a, float_status *status)
+{
+    union ui64_f64 uA;
+    uint_fast64_t uiA;
+
+    uA.f = a;
+    uiA = uA.ui;
+
+    uint_fast16_t infOrNaN = expF64UI(uiA) == 0x7FF;
+    uint_fast16_t subnormalOrZero = expF64UI(uiA) == 0;
+    bool sign = signF64UI(uiA);
+
+    return
+        (sign && infOrNaN && fracF64UI(uiA) == 0)        << 0 |
+        (sign && !infOrNaN && !subnormalOrZero)            << 1 |
+        (sign && subnormalOrZero && fracF64UI(uiA))        << 2 |
+        (sign && subnormalOrZero && fracF64UI(uiA) == 0)   << 3 |
+        (!sign && infOrNaN && fracF64UI(uiA) == 0)         << 7 |
+        (!sign && !infOrNaN && !subnormalOrZero)           << 6 |
+        (!sign && subnormalOrZero && fracF64UI(uiA))       << 5 |
+        (!sign && subnormalOrZero && fracF64UI(uiA) == 0)  << 4 |
+        (isNaNF64UI(uiA) &&  float64_is_signaling_nan(uiA, status)) << 8 |
+        (isNaNF64UI(uiA) && !float64_is_signaling_nan(uiA, status)) << 9;
+}
+
+target_ulong helper_fclass_d(CPURISCVState *env, uint64_t frs1)
+{
+    frs1 = float64_classify(frs1, &env->fp_status);
+    return frs1;
+}
target-riscv/helper.h +30 -0
index 85b505a..eeb1caf 100644
@@ -44,3 +44,33 @@ DEF_HELPER_FLAGS_3(fcvt_s_l, TCG_CALL_NO_RWG, i64, env, i64, i64)
 DEF_HELPER_FLAGS_3(fcvt_s_lu, TCG_CALL_NO_RWG, i64, env, i64, i64)
 #endif
 DEF_HELPER_FLAGS_2(fclass_s, TCG_CALL_NO_RWG, tl, env, i64)
+
+/* Floating Point - Double Precision */
+DEF_HELPER_FLAGS_4(fadd_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)
+DEF_HELPER_FLAGS_4(fsub_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)
+DEF_HELPER_FLAGS_4(fmul_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)
+DEF_HELPER_FLAGS_4(fdiv_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)
+DEF_HELPER_FLAGS_3(fsgnj_d, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fsgnjn_d, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fsgnjx_d, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fmin_d, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fmax_d, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fcvt_s_d, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fcvt_d_s, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fsqrt_d, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fle_d, TCG_CALL_NO_RWG, tl, env, i64, i64)
+DEF_HELPER_FLAGS_3(flt_d, TCG_CALL_NO_RWG, tl, env, i64, i64)
+DEF_HELPER_FLAGS_3(feq_d, TCG_CALL_NO_RWG, tl, env, i64, i64)
+DEF_HELPER_FLAGS_3(fcvt_w_d, TCG_CALL_NO_RWG, tl, env, i64, i64)
+DEF_HELPER_FLAGS_3(fcvt_wu_d, TCG_CALL_NO_RWG, tl, env, i64, i64)
+#if defined(TARGET_RISCV64)
+DEF_HELPER_FLAGS_3(fcvt_l_d, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fcvt_lu_d, TCG_CALL_NO_RWG, i64, env, i64, i64)
+#endif
+DEF_HELPER_FLAGS_3(fcvt_d_w, TCG_CALL_NO_RWG, i64, env, tl, i64)
+DEF_HELPER_FLAGS_3(fcvt_d_wu, TCG_CALL_NO_RWG, i64, env, tl, i64)
+#if defined(TARGET_RISCV64)
+DEF_HELPER_FLAGS_3(fcvt_d_l, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fcvt_d_lu, TCG_CALL_NO_RWG, i64, env, i64, i64)
+#endif
+DEF_HELPER_FLAGS_2(fclass_d, TCG_CALL_NO_RWG, tl, env, i64)
target-riscv/translate.c +135 -0

141 lines not on this page · raw message

Signature · 1 line
2.9.3
#24 lore raw

Re: [Qemu-devel] [PATCH 11/18] target-riscv: Add Double Precision Floating-Point Instructions

Quoted 4 lines · Sagar Karandikar
target-riscv/translate.c +4 -0
+    case OPC_RISC_FSGNJ_D:
+        /* also OPC_RISC_FSGNJN_D, OPC_RISC_FSGNJX_D */
+        if (rm == 0x0) {
+            gen_helper_fsgnj_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1],

target-riscv/translate.c static inline void gen_fp_arith(DisasContext *ctx, uint32_t opc, int rd, · line 1048

Quoted 10 lines
target-riscv/translate.c +10 -0
+                               cpu_fpr[rs2]);
+        } else if (rm == 0x1) {
+            gen_helper_fsgnjn_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1],
+                                cpu_fpr[rs2]);
+        } else if (rm == 0x2) {
+            gen_helper_fsgnjx_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1],
+                                cpu_fpr[rs2]);
+        } else {
+            kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+        }

I forgot to mention this for single-precision -- given that FMOV is an alias of FSGNJ, you should special case rs1 == rs2.

r~

#25 lore raw

PATCH 12/18 target-riscv: Add system instructions

In reply to Sagar Karandikar

System instructions, stubs for csr read/write, necessary helpers

---
 target-riscv/helper.h    |  11 ++++
 target-riscv/op_helper.c | 144 +++++++++++++++++++++++++++++++++++++++++++++++
 target-riscv/translate.c | 119 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 274 insertions(+)
target-riscv/helper.h +11 -0
index eeb1caf..a87a0ba 100644
@@ -74,3 +74,14 @@ DEF_HELPER_FLAGS_3(fcvt_d_l, TCG_CALL_NO_RWG, i64, env, i64, i64)
 DEF_HELPER_FLAGS_3(fcvt_d_lu, TCG_CALL_NO_RWG, i64, env, i64, i64)
 #endif
 DEF_HELPER_FLAGS_2(fclass_d, TCG_CALL_NO_RWG, tl, env, i64)
+
+/* Special functions */
+#ifndef CONFIG_USER_ONLY
+DEF_HELPER_4(csrrw, tl, env, tl, tl, tl)
+DEF_HELPER_5(csrrs, tl, env, tl, tl, tl, tl)
+DEF_HELPER_5(csrrc, tl, env, tl, tl, tl, tl)
+DEF_HELPER_2(sret, tl, env, tl)
+DEF_HELPER_2(mret, tl, env, tl)
+DEF_HELPER_1(tlb_flush, void, env)
+DEF_HELPER_1(fence_i, void, env)
+#endif /* !CONFIG_USER_ONLY */
target-riscv/op_helper.c +144 -0

157 lines not on this page · raw message

target-riscv/translate.c +119 -0

131 lines not on this page · raw message

Signature · 1 line
2.9.3
#26 lore raw

Re: [Qemu-devel] [PATCH 12/18] target-riscv: Add system instructions

target-riscv/helper.h DEF_HELPER_FLAGS_3(fcvt_d_l, TCG_CALL_NO_RWG, i64, env, i64, i64) · line 87

Quoted 9 lines · Sagar Karandikar
target-riscv/helper.h +9 -0
+#ifndef CONFIG_USER_ONLY
+DEF_HELPER_4(csrrw, tl, env, tl, tl, tl)
+DEF_HELPER_5(csrrs, tl, env, tl, tl, tl, tl)
+DEF_HELPER_5(csrrc, tl, env, tl, tl, tl, tl)
+DEF_HELPER_2(sret, tl, env, tl)
+DEF_HELPER_2(mret, tl, env, tl)
+DEF_HELPER_1(tlb_flush, void, env)
+DEF_HELPER_1(fence_i, void, env)
+#endif /* !CONFIG_USER_ONLY */

The system emulation spec is still in flux, I think we should only add user-mode emulation for now.

Paolo

#27 lore raw

Re: [Qemu-devel] [PATCH 12/18] target-riscv: Add system instructions

Quoted 16 lines · Paolo Bonzini

target-riscv/helper.h DEF_HELPER_FLAGS_3(fcvt_d_l, TCG_CALL_NO_RWG, i64, env, i64, i64) · line 87

Quoted 9 lines · Sagar Karandikar
target-riscv/helper.h +9 -0
+#ifndef CONFIG_USER_ONLY
+DEF_HELPER_4(csrrw, tl, env, tl, tl, tl)
+DEF_HELPER_5(csrrs, tl, env, tl, tl, tl, tl)
+DEF_HELPER_5(csrrc, tl, env, tl, tl, tl, tl)
+DEF_HELPER_2(sret, tl, env, tl)
+DEF_HELPER_2(mret, tl, env, tl)
+DEF_HELPER_1(tlb_flush, void, env)
+DEF_HELPER_1(fence_i, void, env)
+#endif /* !CONFIG_USER_ONLY */

The system emulation spec is still in flux, I think we should only add user-mode emulation for now.

Hi Paolo,

by user-mode emulation you still mean softmmu and not linux-user, right? So just drop the system instructions for now.

Cheers,
Bastian

#28 lore raw

Re: [Qemu-devel] [PATCH 12/18] target-riscv: Add system instructions

Quoted 18 lines · Bastian Koppelmann
Quoted 16 lines · Paolo Bonzini

target-riscv/helper.h DEF_HELPER_FLAGS_3(fcvt_d_l, TCG_CALL_NO_RWG, i64, env, i64, i64) · line 87

Quoted 9 lines · Sagar Karandikar
target-riscv/helper.h +9 -0
+#ifndef CONFIG_USER_ONLY
+DEF_HELPER_4(csrrw, tl, env, tl, tl, tl)
+DEF_HELPER_5(csrrs, tl, env, tl, tl, tl, tl)
+DEF_HELPER_5(csrrc, tl, env, tl, tl, tl, tl)
+DEF_HELPER_2(sret, tl, env, tl)
+DEF_HELPER_2(mret, tl, env, tl)
+DEF_HELPER_1(tlb_flush, void, env)
+DEF_HELPER_1(fence_i, void, env)
+#endif /* !CONFIG_USER_ONLY */

The system emulation spec is still in flux, I think we should only add user-mode emulation for now.

Quoted 4 lines

Hi Paolo,

by user-mode emulation you still mean softmmu and not linux-user, right? So just drop the system instructions for now.

I don't think that's possible; all RISC-V machines include at least M-mode, whose precise definitions requires the privileged interface specification which hasn't been finalized yet. So only linux-user is stable enough.

In fact, based on some recent discussions on the RISC-V isa-dev mailing list, it looks like some memory protection features _beyond_ the privileged interface specification are in practice required to secure M-mode from the supervisor. I'm not sure what's the point in defining a separate mandatory M-mode (supervisor mode cannot even enable paging without help from M-mode, on the other hand a processor that only has M- and U-modes cannot enable paging) but not providing the tools to actually enforce privilege separation for it.

All in all, while I'm happy that the RISC-V project uses QEMU for development, I don't think that the privileged interface specification is mature enough for inclusion in QEMU. It's very different for linux-user user-mode emulation of course, it's great to have that upstream.

Thanks,

Paolo

#29 lore raw

Re: [Qemu-devel] [PATCH 12/18] target-riscv: Add system instructions

Hi Paolo,

There's a fork that has linux-user support. We'll get it added into the downstream riscv-qemu repo and include that in the next patch set instead of softmmu.

Thanks,
Sagar

Quoted 49 lines · Paolo Bonzini
Quoted 18 lines · Bastian Koppelmann
Quoted 16 lines · Paolo Bonzini

target-riscv/helper.h DEF_HELPER_FLAGS_3(fcvt_d_l, TCG_CALL_NO_RWG, i64, env, i64, i64) · line 87

Quoted 9 lines · Sagar Karandikar
target-riscv/helper.h +9 -0
+#ifndef CONFIG_USER_ONLY
+DEF_HELPER_4(csrrw, tl, env, tl, tl, tl)
+DEF_HELPER_5(csrrs, tl, env, tl, tl, tl, tl)
+DEF_HELPER_5(csrrc, tl, env, tl, tl, tl, tl)
+DEF_HELPER_2(sret, tl, env, tl)
+DEF_HELPER_2(mret, tl, env, tl)
+DEF_HELPER_1(tlb_flush, void, env)
+DEF_HELPER_1(fence_i, void, env)
+#endif /* !CONFIG_USER_ONLY */

The system emulation spec is still in flux, I think we should only add user-mode emulation for now.

Quoted 4 lines

Hi Paolo,

by user-mode emulation you still mean softmmu and not linux-user, right? So just drop the system instructions for now.

I don't think that's possible; all RISC-V machines include at least M-mode, whose precise definitions requires the privileged interface specification which hasn't been finalized yet. So only linux-user is stable enough.

In fact, based on some recent discussions on the RISC-V isa-dev mailing list, it looks like some memory protection features _beyond_ the privileged interface specification are in practice required to secure M-mode from the supervisor. I'm not sure what's the point in defining a separate mandatory M-mode (supervisor mode cannot even enable paging without help from M-mode, on the other hand a processor that only has M- and U-modes cannot enable paging) but not providing the tools to actually enforce privilege separation for it.

All in all, while I'm happy that the RISC-V project uses QEMU for development, I don't think that the privileged interface specification is mature enough for inclusion in QEMU. It's very different for linux-user user-mode emulation of course, it's great to have that upstream.

Thanks,

Paolo

#30 lore raw

Re: [Qemu-devel] [PATCH 12/18] target-riscv: Add system instructions

In reply to Sagar Karandikar

target-riscv/op_helper.c target_ulong helper_mulhsu(CPURISCVState *env, target_ulong arg1, · line 200

Quoted 10 lines · Sagar Karandikar
target-riscv/op_helper.c +10 -0
+void helper_fence_i(CPURISCVState *env)
+{
+    RISCVCPU *cpu = riscv_env_get_cpu(env);
+    CPUState *cs = CPU(cpu);
+    /* Flush QEMU's TLB */
+    tlb_flush(cs, 1);
+    /* ARM port seems to not know if this is okay inside a TB
+       But we need to do it */
+    tb_flush(cs);
+}

You should not need to tb_flush for fence_i. QEMU's internals auto-detect when a memory write invalidates a TB.

r~

#31 lore raw

PATCH 13/18 target-riscv: Add CSR read/write helpers

In reply to Sagar Karandikar
---
 target-riscv/op_helper.c | 324 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 324 insertions(+)
target-riscv/op_helper.c +324 -0
index ee51f02..8449d1b 100644
@@ -39,6 +39,11 @@ void set_privilege(CPURISCVState *env, target_ulong newpriv)
     env->priv = newpriv;
 }
 
+static int validate_vm(target_ulong vm)
+{
+    return vm == VM_SV32 || vm == VM_SV39 || vm == VM_SV48 || vm == VM_MBARE;
+}
+
 /* Exceptions processing helpers */
 static inline void QEMU_NORETURN do_raise_exception_err(CPURISCVState *env,
                                           uint32_t exception, uintptr_t pc)
@@ -83,6 +88,180 @@ target_ulong helper_mulhsu(CPURISCVState *env, target_ulong arg1,
 inline void csr_write_helper(CPURISCVState *env, target_ulong val_to_write,
         target_ulong csrno)
 {
+    #ifdef RISCV_DEBUG_PRINT
+    fprintf(stderr, "Write CSR reg: 0x" TARGET_FMT_lx "\n", csrno);
+    fprintf(stderr, "Write CSR val: 0x" TARGET_FMT_lx "\n", val_to_write);
+    #endif
+
+    uint64_t delegable_ints = MIP_SSIP | MIP_STIP | MIP_SEIP | (1 << IRQ_COP);
+    uint64_t all_ints = delegable_ints | MIP_MSIP | MIP_MTIP;
+
+    switch (csrno) {
+    case CSR_FFLAGS:
+        env->csr[CSR_MSTATUS] |= MSTATUS_FS | MSTATUS64_SD;
+        env->csr[CSR_FFLAGS] = val_to_write & (FSR_AEXC >> FSR_AEXC_SHIFT);
+        break;
+    case CSR_FRM:
+        env->csr[CSR_MSTATUS] |= MSTATUS_FS | MSTATUS64_SD;
+        env->csr[CSR_FRM] = val_to_write & (FSR_RD >> FSR_RD_SHIFT);
+        break;
+    case CSR_FCSR:
+        env->csr[CSR_MSTATUS] |= MSTATUS_FS | MSTATUS64_SD;
+        env->csr[CSR_FFLAGS] = (val_to_write & FSR_AEXC) >> FSR_AEXC_SHIFT;
+        env->csr[CSR_FRM] = (val_to_write & FSR_RD) >> FSR_RD_SHIFT;
+        break;
+    case CSR_MSTATUS: {
+        target_ulong mstatus = env->csr[CSR_MSTATUS];
+        if ((val_to_write ^ mstatus) &
+            (MSTATUS_VM | MSTATUS_MPP | MSTATUS_MPRV | MSTATUS_PUM |
+             MSTATUS_MXR)) {
+            helper_tlb_flush(env);
+        }
+
+        /* no extension support */
+        target_ulong mask = MSTATUS_SIE | MSTATUS_SPIE | MSTATUS_MIE
+            | MSTATUS_MPIE | MSTATUS_SPP | MSTATUS_FS | MSTATUS_MPRV
+            | MSTATUS_PUM | MSTATUS_MXR;
+
+        if (validate_vm(get_field(val_to_write, MSTATUS_VM))) {
+            mask |= MSTATUS_VM;
+        }
+        if (validate_priv(get_field(val_to_write, MSTATUS_MPP))) {
+            mask |= MSTATUS_MPP;
+        }
+
+        mstatus = (mstatus & ~mask) | (val_to_write & mask);
+
+        int dirty = (mstatus & MSTATUS_FS) == MSTATUS_FS;
+        dirty |= (mstatus & MSTATUS_XS) == MSTATUS_XS;
+        mstatus = set_field(mstatus, MSTATUS64_SD, dirty);
+        env->csr[CSR_MSTATUS] = mstatus;
+        break;
+    }
+    case CSR_MIP: {
+        target_ulong mask = MIP_SSIP | MIP_STIP;
+        env->csr[CSR_MIP] = (env->csr[CSR_MIP] & ~mask) |
+            (val_to_write & mask);
+        if (env->csr[CSR_MIP] & MIP_SSIP) {
+            qemu_irq_raise(SSIP_IRQ);
+        } else {
+            qemu_irq_lower(SSIP_IRQ);
+        }
+        if (env->csr[CSR_MIP] & MIP_STIP) {
+            qemu_irq_raise(STIP_IRQ);
+        } else {
+            qemu_irq_lower(STIP_IRQ);
+        }
+        if (env->csr[CSR_MIP] & MIP_MSIP) {
+            qemu_irq_raise(MSIP_IRQ);
+        } else {
+            qemu_irq_lower(MSIP_IRQ);
+        }
+        break;
+    }
+    case CSR_MIE: {
+        env->csr[CSR_MIE] = (env->csr[CSR_MIE] & ~all_ints) |
+            (val_to_write & all_ints);
+        break;
+    }
+    case CSR_MIDELEG:
+        env->csr[CSR_MIDELEG] = (env->csr[CSR_MIDELEG] & ~delegable_ints)
+                                | (val_to_write & delegable_ints);
+        break;
+    case CSR_MEDELEG: {
+        target_ulong mask = 0;
+        mask |= 1ULL << (RISCV_EXCP_INST_ADDR_MIS);
+        mask |= 1ULL << (RISCV_EXCP_INST_ACCESS_FAULT);
+        mask |= 1ULL << (RISCV_EXCP_ILLEGAL_INST);
+        mask |= 1ULL << (RISCV_EXCP_BREAKPOINT);
+        mask |= 1ULL << (RISCV_EXCP_LOAD_ADDR_MIS);
+        mask |= 1ULL << (RISCV_EXCP_LOAD_ACCESS_FAULT);
+        mask |= 1ULL << (RISCV_EXCP_STORE_AMO_ADDR_MIS);
+        mask |= 1ULL << (RISCV_EXCP_STORE_AMO_ACCESS_FAULT);
+        mask |= 1ULL << (RISCV_EXCP_U_ECALL);
+        mask |= 1ULL << (RISCV_EXCP_S_ECALL);
+        mask |= 1ULL << (RISCV_EXCP_H_ECALL);
+        mask |= 1ULL << (RISCV_EXCP_M_ECALL);
+        env->csr[CSR_MEDELEG] = (env->csr[CSR_MEDELEG] & ~mask)
+                                | (val_to_write & mask);
+        break;
+    }
+    case CSR_MUCOUNTEREN:
+        env->csr[CSR_MUCOUNTEREN] = val_to_write & 7;
+        break;
+    case CSR_MSCOUNTEREN:
+        env->csr[CSR_MSCOUNTEREN] = val_to_write & 7;
+        break;
+    case CSR_SSTATUS: {
+        target_ulong ms = env->csr[CSR_MSTATUS];
+        target_ulong mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_SPP
+                            | SSTATUS_FS | SSTATUS_XS | SSTATUS_PUM;
+        ms = (ms & ~mask) | (val_to_write & mask);
+        csr_write_helper(env, ms, CSR_MSTATUS);
+        break;
+    }
+    case CSR_SIP: {
+        target_ulong next_mip = (env->csr[CSR_MIP] & ~env->csr[CSR_MIDELEG])
+                                | (val_to_write & env->csr[CSR_MIDELEG]);
+        csr_write_helper(env, next_mip, CSR_MIP);
+        /* note: stw_phys should be done by the call to set MIP if necessary, */
+        /* so we don't do it here */
+        break;
+    }
+    case CSR_SIE: {
+        target_ulong next_mie = (env->csr[CSR_MIE] & ~env->csr[CSR_MIDELEG])
+                                | (val_to_write & env->csr[CSR_MIDELEG]);
+        csr_write_helper(env, next_mie, CSR_MIE);
+        break;
+    }
+    case CSR_SPTBR: {
+        env->csr[CSR_SPTBR] = val_to_write & (((target_ulong)1 <<
+                              (TARGET_PHYS_ADDR_SPACE_BITS - PGSHIFT)) - 1);
+        break;
+    }
+    case CSR_SEPC:
+        env->csr[CSR_SEPC] = val_to_write;
+        break;
+    case CSR_STVEC:
+        env->csr[CSR_STVEC] = val_to_write >> 2 << 2;
+        break;
+    case CSR_SSCRATCH:
+        env->csr[CSR_SSCRATCH] = val_to_write;
+        break;
+    case CSR_SCAUSE:
+        env->csr[CSR_SCAUSE] = val_to_write;
+        break;
+    case CSR_SBADADDR:
+        env->csr[CSR_SBADADDR] = val_to_write;
+        break;
+    case CSR_MEPC:
+        env->csr[CSR_MEPC] = val_to_write;
+        break;
+    case CSR_MTVEC:
+        env->csr[CSR_MTVEC] = val_to_write >> 2 << 2;
+        break;
+    case CSR_MSCRATCH:
+        env->csr[CSR_MSCRATCH] = val_to_write;
+        break;
+    case CSR_MCAUSE:
+        env->csr[CSR_MCAUSE] = val_to_write;
+        break;
+    case CSR_MBADADDR:
+        env->csr[CSR_MBADADDR] = val_to_write;
+        break;
+    case CSR_DCSR:
+        printf("DEBUG NOT SUPPORTED\n");
+        exit(1);
+        break;
+    case CSR_DPC:
+        printf("DEBUG NOT SUPPORTED\n");
+        exit(1);
+        break;
+    case CSR_DSCRATCH:
+        printf("DEBUG NOT SUPPORTED\n");
+        exit(1);
+        break;
+    }
 }
 
 /*
@@ -92,6 +271,151 @@ inline void csr_write_helper(CPURISCVState *env, target_ulong val_to_write,
  */
 inline target_ulong csr_read_helper(CPURISCVState *env, target_ulong csrno)
 {
+    int csrno2 = (int)csrno;
+    #ifdef RISCV_DEBUG_PRINT
+    fprintf(stderr, "READ CSR 0x%x\n", csrno2);
+    #endif
+
+    switch (csrno2) {
+    case CSR_FFLAGS:
+        return env->csr[CSR_FFLAGS];
+    case CSR_FRM:
+        return env->csr[CSR_FRM];
+    case CSR_FCSR:
+        return env->csr[CSR_FFLAGS] << FSR_AEXC_SHIFT |
+               env->csr[CSR_FRM] << FSR_RD_SHIFT;
+    case CSR_TIME:
+    case CSR_INSTRET:
+    case CSR_CYCLE:
+        if ((env->csr[CSR_MUCOUNTEREN] >> (csrno2 & (63))) & 1) {
+            return csr_read_helper(env, csrno2 + (CSR_MCYCLE - CSR_CYCLE));
+        }
+        break;
+    case CSR_STIME:
+    case CSR_SINSTRET:
+    case CSR_SCYCLE:
+        if ((env->csr[CSR_MSCOUNTEREN] >> (csrno2 & (63))) & 1) {
+            return csr_read_helper(env, csrno2 + (CSR_MCYCLE - CSR_SCYCLE));
+        }
+        break;
+    case CSR_MUCOUNTEREN:
+        return env->csr[CSR_MUCOUNTEREN];
+    case CSR_MSCOUNTEREN:
+        return env->csr[CSR_MSCOUNTEREN];
+    case CSR_MUCYCLE_DELTA:
+        return 0; /* as spike does */
+    case CSR_MUTIME_DELTA:
+        return 0; /* as spike does */
+    case CSR_MUINSTRET_DELTA:
+        return 0; /* as spike does */
+    case CSR_MSCYCLE_DELTA:
+        return 0; /* as spike does */
+    case CSR_MSTIME_DELTA:
+        return 0; /* as spike does */
+    case CSR_MSINSTRET_DELTA:
+        return 0; /* as spike does */
+    case CSR_MUCYCLE_DELTAH:
+        printf("CSR 0x%x unsupported on RV64\n", csrno2);
+        exit(1);
+    case CSR_MUTIME_DELTAH:
+        printf("CSR 0x%x unsupported on RV64\n", csrno2);
+        exit(1);
+    case CSR_MUINSTRET_DELTAH:
+        printf("CSR 0x%x unsupported on RV64\n", csrno2);
+        exit(1);
+    case CSR_MSCYCLE_DELTAH:
+        printf("CSR 0x%x unsupported on RV64\n", csrno2);
+        exit(1);
+    case CSR_MSTIME_DELTAH:
+        printf("CSR 0x%x unsupported on RV64\n", csrno2);
+        exit(1);
+    case CSR_MSINSTRET_DELTAH:
+        printf("CSR 0x%x unsupported on RV64\n", csrno2);
+        exit(1);
+    /* notice the lack of CSR_MTIME - this is handled by throwing an exception
+       and letting the handler read from the RTC */
+    case CSR_MCYCLE:
+        /* Read instret here */
+        break;
+    case CSR_MINSTRET:
+        /* Read instret here */
+        break;
+    case CSR_MCYCLEH:
+        printf("CSR 0x%x unsupported on RV64\n", csrno2);
+        exit(1);
+    case CSR_MINSTRETH:
+        printf("CSR 0x%x unsupported on RV64\n", csrno2);
+        exit(1);
+    case CSR_SSTATUS: {
+        target_ulong mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_SPP
+                            | SSTATUS_FS | SSTATUS_XS | SSTATUS_PUM;
+        target_ulong sstatus = env->csr[CSR_MSTATUS] & mask;
+        if ((sstatus & SSTATUS_FS) == SSTATUS_FS ||
+                (sstatus & SSTATUS_XS) == SSTATUS_XS) {
+            sstatus |= SSTATUS64_SD;
+        }
+        return sstatus;
+    }
+    case CSR_SIP:
+        return env->csr[CSR_MIP] & env->csr[CSR_MIDELEG];
+    case CSR_SIE:
+        return env->csr[CSR_MIE] & env->csr[CSR_MIDELEG];
+    case CSR_SEPC:
+        return env->csr[CSR_SEPC];
+    case CSR_SBADADDR:
+        return env->csr[CSR_SBADADDR];
+    case CSR_STVEC:
+        return env->csr[CSR_STVEC];
+    case CSR_SCAUSE:
+        return env->csr[CSR_SCAUSE];
+    case CSR_SPTBR:
+        return env->csr[CSR_SPTBR];
+    case CSR_SSCRATCH:
+        return env->csr[CSR_SSCRATCH];
+    case CSR_MSTATUS:
+        return env->csr[CSR_MSTATUS];
+    case CSR_MIP:
+        return env->csr[CSR_MIP];
+    case CSR_MIE:
+        return env->csr[CSR_MIE];
+    case CSR_MEPC:
+        return env->csr[CSR_MEPC];
+    case CSR_MSCRATCH:
+        return env->csr[CSR_MSCRATCH];
+    case CSR_MCAUSE:
+        return env->csr[CSR_MCAUSE];
+    case CSR_MBADADDR:
+        return env->csr[CSR_MBADADDR];
+    case CSR_MISA:
+        return env->csr[CSR_MISA];
+    case CSR_MARCHID:
+        return 0; /* as spike does */
+    case CSR_MIMPID:
+        return 0; /* as spike does */
+    case CSR_MVENDORID:
+        return 0; /* as spike does */
+    case CSR_MHARTID:
+        return 0;
+    case CSR_MTVEC:
+        return env->csr[CSR_MTVEC];
+    case CSR_MEDELEG:
+        return env->csr[CSR_MEDELEG];
+    case CSR_MIDELEG:
+        return env->csr[CSR_MIDELEG];
+    case CSR_TDRSELECT:
+        return 0; /* as spike does */
+    case CSR_DCSR:
+        printf("DEBUG NOT IMPLEMENTED\n");
+        exit(1);
+    case CSR_DPC:
+        printf("DEBUG NOT IMPLEMENTED\n");
+        exit(1);
+    case CSR_DSCRATCH:
+        printf("DEBUG NOT IMPLEMENTED\n");
+        exit(1);
+    }
+    /* used by e.g. MTIME read */
+    helper_raise_exception(env, RISCV_EXCP_ILLEGAL_INST);
     return 0;
 }
 
Signature · 1 line
2.9.3
#32 lore raw

PATCH 14/18 target-riscv: softmmu/address translation support

In reply to Sagar Karandikar
---
 target-riscv/helper.c    | 211 ++++++++++++++++++++++++++++++++++++++++++++++-
 target-riscv/op_helper.c |  29 +++++++
 2 files changed, 238 insertions(+), 2 deletions(-)
target-riscv/helper.c +209 -2
index dfdc7bd..2e02351 100644
@@ -36,16 +36,223 @@ bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
     return false;
 }
 
+/* get_physical_address - get the physical address for this virtual address
+ *
+ * Do a page table walk to obtain the physical address corresponding to a
+ * virtual address. Returns 0 if the translation was successful
+ *
+ * Adapted from Spike's mmu_t::translate and mmu_t::walk
+ *
+ */
+static int get_physical_address(CPURISCVState *env, hwaddr *physical,
+                                int *prot, target_ulong address,
+                                MMUAccessType access_type, int mmu_idx)
+{
+    /* NOTE: the env->PC value visible here will not be
+     * correct, but the value visible to the exception handler
+     * (riscv_cpu_do_interrupt) is correct */
+
+    *prot = 0;
+    CPUState *cs = CPU(riscv_env_get_cpu(env));
+
+    target_ulong mode = env->priv;
+    if (access_type != MMU_INST_FETCH) {
+        if (get_field(env->csr[CSR_MSTATUS], MSTATUS_MPRV)) {
+            mode = get_field(env->csr[CSR_MSTATUS], MSTATUS_MPP);
+        }
+    }
+    if (get_field(env->csr[CSR_MSTATUS], MSTATUS_VM) == VM_MBARE) {
+        mode = PRV_M;
+    }
+
+    /* check to make sure that mmu_idx and mode that we get matches */
+    if (unlikely(mode != mmu_idx)) {
+        fprintf(stderr, "MODE, mmu_idx mismatch\n");
+        exit(1);
+    }
+
+    if (mode == PRV_M) {
+        target_ulong msb_mask = (2UL << (TARGET_LONG_BITS - 1)) - 1;
+                                        /*0x7FFFFFFFFFFFFFFF; */
+        *physical = address & msb_mask;
+        *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+        return TRANSLATE_SUCCESS;
+    }
+
+    target_ulong addr = address;
+    int supervisor = mode == PRV_S;
+    int pum = get_field(env->csr[CSR_MSTATUS], MSTATUS_PUM);
+    int mxr = get_field(env->csr[CSR_MSTATUS], MSTATUS_MXR);
+
+    int levels, ptidxbits, ptesize;
+    switch (get_field(env->csr[CSR_MSTATUS], MSTATUS_VM)) {
+    case VM_SV32:
+      levels = 2;
+      ptidxbits = 10;
+      ptesize = 4;
+      break;
+    case VM_SV39:
+      levels = 3;
+      ptidxbits = 9;
+      ptesize = 8;
+      break;
+    case VM_SV48:
+      levels = 4;
+      ptidxbits = 9;
+      ptesize = 8;
+      break;
+    default:
+      printf("unsupported MSTATUS_VM value\n");
+      exit(1);
+    }
+
+    int va_bits = PGSHIFT + levels * ptidxbits;
+    target_ulong mask = (1L << (TARGET_LONG_BITS - (va_bits - 1))) - 1;
+    target_ulong masked_msbs = (addr >> (va_bits - 1)) & mask;
+    if (masked_msbs != 0 && masked_msbs != mask) {
+        return TRANSLATE_FAIL;
+    }
+
+    target_ulong base = env->csr[CSR_SPTBR] << PGSHIFT;
+    int ptshift = (levels - 1) * ptidxbits;
+    int i;
+    for (i = 0; i < levels; i++, ptshift -= ptidxbits) {
+        target_ulong idx = (addr >> (PGSHIFT + ptshift)) &
+                           ((1 << ptidxbits) - 1);
+
+        /* check that physical address of PTE is legal */
+        target_ulong pte_addr = base + idx * ptesize;
+
+        /* PTE must reside in memory */
+        if (!(pte_addr >= DRAM_BASE && pte_addr < (DRAM_BASE + env->memsize))) {
+            printf("PTE was not in DRAM region\n");
+            exit(1);
+            break;
+        }
+
+        target_ulong pte = ldq_phys(cs->as, pte_addr);
+        target_ulong ppn = pte >> PTE_PPN_SHIFT;
+
+        if (PTE_TABLE(pte)) { /* next level of page table */
+            base = ppn << PGSHIFT;
+        } else if ((pte & PTE_U) ? supervisor && pum : !supervisor) {
+            break;
+        } else if (!(pte & PTE_V) || (!(pte & PTE_R) && (pte & PTE_W))) {
+            break;
+        } else if (access_type == MMU_INST_FETCH ? !(pte & PTE_X) :
+                  access_type == MMU_DATA_LOAD ?  !(pte & PTE_R) &&
+                  !(mxr && (pte & PTE_X)) : !((pte & PTE_R) && (pte & PTE_W))) {
+            break;
+        } else {
+            /* set accessed and possibly dirty bits.
+               we only put it in the TLB if it has the right stuff */
+            stq_phys(cs->as, pte_addr, ldq_phys(cs->as, pte_addr) | PTE_A |
+                    ((access_type == MMU_DATA_STORE) * PTE_D));
+
+            /* for superpage mappings, make a fake leaf PTE for the TLB's
+               benefit. */
+            target_ulong vpn = addr >> PGSHIFT;
+            *physical = (ppn | (vpn & ((1L << ptshift) - 1))) << PGSHIFT;
+
+            /* we do not give all prots indicated by the PTE
+             * this is because future accesses need to do things like set the
+             * dirty bit on the PTE
+             *
+             * at this point, we assume that protection checks have occurred */
+            if (supervisor) {
+                if ((pte & PTE_X) && access_type == MMU_INST_FETCH) {
+                    *prot |= PAGE_EXEC;
+                } else if ((pte & PTE_W) && access_type == MMU_DATA_STORE) {
+                    *prot |= PAGE_WRITE;
+                } else if ((pte & PTE_R) && access_type == MMU_DATA_LOAD) {
+                    *prot |= PAGE_READ;
+                } else {
+                    printf("err in translation prots");
+                    exit(1);
+                }
+            } else {
+                if ((pte & PTE_X) && access_type == MMU_INST_FETCH) {
+                    *prot |= PAGE_EXEC;
+                } else if ((pte & PTE_W) && access_type == MMU_DATA_STORE) {
+                    *prot |= PAGE_WRITE;
+                } else if ((pte & PTE_R) && access_type == MMU_DATA_LOAD) {
+                    *prot |= PAGE_READ;
+                } else {
+                    printf("err in translation prots");
+                    exit(1);
+                }
+            }
+            return TRANSLATE_SUCCESS;
+        }
+    }
+    return TRANSLATE_FAIL;
+}
+#endif
+
+static void raise_mmu_exception(CPURISCVState *env, target_ulong address,
+                                MMUAccessType access_type)
+{
+    CPUState *cs = CPU(riscv_env_get_cpu(env));
+    int exception = 0;
+    if (access_type == MMU_INST_FETCH) { /* inst access */
+        exception = RISCV_EXCP_INST_ACCESS_FAULT;
+        env->badaddr = address;
+    } else if (access_type == MMU_DATA_STORE) { /* store access */
+        exception = RISCV_EXCP_STORE_AMO_ACCESS_FAULT;
+        env->badaddr = address;
+    } else if (access_type == MMU_DATA_LOAD) { /* load access */
+        exception = RISCV_EXCP_LOAD_ACCESS_FAULT;
+        env->badaddr = address;
+    } else {
+        fprintf(stderr, "FAIL: invalid access_type\n");
+        exit(1);
+    }
+    cs->exception_index = exception;
+}
+
+#if !defined(CONFIG_USER_ONLY)
 hwaddr riscv_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
 {
-    return 0;
+    RISCVCPU *cpu = RISCV_CPU(cs);
+    hwaddr phys_addr;
+    int prot;
+    int mem_idx = cpu_mmu_index(&cpu->env, false);
+
+    if (get_physical_address(&cpu->env, &phys_addr, &prot, addr, 0, mem_idx)) {
+        return -1;
+    }
+    return phys_addr;
 }
 #endif
 
 int riscv_cpu_handle_mmu_fault(CPUState *cs, vaddr address,
         MMUAccessType access_type, int mmu_idx)
 {
-    return 0;
+    RISCVCPU *cpu = RISCV_CPU(cs);
+    CPURISCVState *env = &cpu->env;
+    hwaddr physical;
+    physical = 0; /* stop gcc complaining */
+    int prot;
+    int ret = 0;
+
+    qemu_log_mask(CPU_LOG_MMU,
+            "%s pc " TARGET_FMT_lx " ad %" VADDR_PRIx " access_type %d mmu_idx \
+             %d\n", __func__, env->PC, address, access_type, mmu_idx);
+
+    ret = get_physical_address(env, &physical, &prot, address, access_type,
+                               mmu_idx);
+    qemu_log_mask(CPU_LOG_MMU,
+            "%s address=%" VADDR_PRIx " ret %d physical " TARGET_FMT_plx
+             " prot %d\n",
+             __func__, address, ret, physical, prot);
+    if (ret == TRANSLATE_SUCCESS) {
+        tlb_set_page(cs, address & TARGET_PAGE_MASK,
+                     physical & TARGET_PAGE_MASK,
+                     prot, mmu_idx, TARGET_PAGE_SIZE);
+    } else if (ret == TRANSLATE_FAIL) {
+        raise_mmu_exception(env, address, access_type);
+    }
+    return ret;
 }
 
 /*
target-riscv/op_helper.c +29 -0
index 8449d1b..1ecdef2 100644
@@ -533,16 +533,45 @@ void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
                                    MMUAccessType access_type, int mmu_idx,
                                    uintptr_t retaddr)
 {
+    RISCVCPU *cpu = RISCV_CPU(cs);
+    CPURISCVState *env = &cpu->env;
+    if (access_type == MMU_INST_FETCH) {
+        fprintf(stderr, "unaligned inst fetch not handled here. should not "
+                "trigger\n");
+        exit(1);
+    } else if (access_type == MMU_DATA_STORE) {
+        cs->exception_index = RISCV_EXCP_STORE_AMO_ADDR_MIS;
+        env->badaddr = addr;
+    } else if (access_type == MMU_DATA_LOAD) {
+        cs->exception_index = RISCV_EXCP_LOAD_ADDR_MIS;
+        env->badaddr = addr;
+    } else {
+        fprintf(stderr, "Invalid MMUAccessType\n");
+        exit(1);
+    }
+    do_raise_exception_err(env, cs->exception_index, retaddr);
 }
 
+/* called by qemu's softmmu to fill the qemu tlb */
 void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type,
         int mmu_idx, uintptr_t retaddr)
 {
+    int ret;
+    ret = riscv_cpu_handle_mmu_fault(cs, addr, access_type, mmu_idx);
+    if (ret == TRANSLATE_FAIL) {
+        RISCVCPU *cpu = RISCV_CPU(cs);
+        CPURISCVState *env = &cpu->env;
+        do_raise_exception_err(env, cs->exception_index, retaddr);
+    }
 }
 
 void riscv_cpu_unassigned_access(CPUState *cs, hwaddr addr, bool is_write,
         bool is_exec, int unused, unsigned size)
 {
+    printf("unassigned address not implemented for riscv\n");
+    printf("are you trying to fetch instructions from an MMIO page?\n");
+    printf("unassigned Address: %016lX\n", addr);
+    exit(1);
 }
 
 #endif /* !CONFIG_USER_ONLY */
Signature · 1 line
2.9.3
#33 lore raw

Re: [Qemu-devel] [PATCH 14/18] target-riscv: softmmu/address translation support

target-riscv/op_helper.c void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr, · line 574

Quoted 4 lines · Sagar Karandikar
target-riscv/op_helper.c +4 -0
+    printf("unassigned address not implemented for riscv\n");
+    printf("are you trying to fetch instructions from an MMIO page?\n");
+    printf("unassigned Address: %016lX\n", addr);
+    exit(1);

All these printf's (and fprintfs above) are going to have to go before this gets accepted. Most of them should simply become qemu_log's.

r~

#34 lore raw

PATCH 15/18 target-riscv: Interrupt Handling

In reply to Sagar Karandikar
---
 target-riscv/helper.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 154 insertions(+)
target-riscv/helper.c +154 -0
index 2e02351..08c53fa 100644
@@ -33,6 +33,16 @@
 
 bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
 {
+    if (interrupt_request & CPU_INTERRUPT_HARD) {
+        RISCVCPU *cpu = RISCV_CPU(cs);
+        CPURISCVState *env = &cpu->env;
+        int interruptno = cpu_riscv_hw_interrupts_pending(env);
+        if (interruptno + 1) {
+            cs->exception_index = 0x70000000U | interruptno;
+            riscv_cpu_do_interrupt(cs);
+            return true;
+        }
+    }
     return false;
 }
 
@@ -255,6 +265,40 @@ int riscv_cpu_handle_mmu_fault(CPUState *cs, vaddr address,
     return ret;
 }
 
+#ifdef RISCV_DEBUG_INTERRUPT
+static const char * const riscv_excp_names[12] = {
+    "misaligned fetch",
+    "fault fetch",
+    "illegal instruction",
+    "Breakpoint",
+    "misaligned load",
+    "fault load",
+    "misaligned store",
+    "fault store",
+    "user_ecall",
+    "supervisor_ecall",
+    "hypervisor_ecall",
+    "machine_ecall",
+};
+
+static const char * const riscv_interrupt_names[14] = {
+    "",
+    "S Soft interrupt",
+    "H Soft interrupt",
+    "M Soft interrupt",
+    "",
+    "S Timer interrupt",
+    "H Timer interrupt",
+    "M Timer interrupt",
+    "",
+    "S Ext interrupt",
+    "H Ext interrupt",
+    "M Ext interrupt",
+    "COP interrupt",
+    "Host interrupt"
+};
+#endif     /* RISCV_DEBUG_INTERRUPT */
+
 /*
  * Handle Traps
  *
@@ -263,4 +307,114 @@ int riscv_cpu_handle_mmu_fault(CPUState *cs, vaddr address,
  */
 void riscv_cpu_do_interrupt(CPUState *cs)
 {
+    RISCVCPU *cpu = RISCV_CPU(cs);
+    CPURISCVState *env = &cpu->env;
+
+    #ifdef RISCV_DEBUG_INTERRUPT
+    if (cs->exception_index & 0x70000000) {
+        fprintf(stderr, "core   0: exception trap_%s, epc 0x" TARGET_FMT_lx "\n"
+                , riscv_interrupt_names[cs->exception_index & 0x0fffffff],
+                env->PC);
+    } else {
+        fprintf(stderr, "core   0: exception trap_%s, epc 0x" TARGET_FMT_lx "\n"
+                , riscv_excp_names[cs->exception_index], env->PC);
+    }
+    #endif
+
+    if (cs->exception_index == RISCV_EXCP_BREAKPOINT) {
+        fprintf(stderr, "debug mode not implemented\n");
+    }
+
+    /* skip dcsr cause check */
+
+    target_ulong fixed_cause = 0;
+    if (cs->exception_index & (0x70000000)) {
+        /* hacky for now. the MSB (bit 63) indicates interrupt but cs->exception
+           index is only 32 bits wide */
+        fixed_cause = cs->exception_index & 0x0FFFFFFF;
+        fixed_cause |= (1L << 63);
+    } else {
+        /* fixup User ECALL -> correct priv ECALL */
+        if (cs->exception_index == RISCV_EXCP_U_ECALL) {
+            switch (env->priv) {
+            case PRV_U:
+                fixed_cause = RISCV_EXCP_U_ECALL;
+                break;
+            case PRV_S:
+                fixed_cause = RISCV_EXCP_S_ECALL;
+                break;
+            case PRV_H:
+                fixed_cause = RISCV_EXCP_H_ECALL;
+                break;
+            case PRV_M:
+                fixed_cause = RISCV_EXCP_M_ECALL;
+                break;
+            }
+        } else {
+            fixed_cause = cs->exception_index;
+        }
+    }
+
+    target_ulong backup_epc = env->PC;
+
+    target_ulong bit = fixed_cause;
+    target_ulong deleg = env->csr[CSR_MEDELEG];
+
+    int hasbadaddr =
+        (fixed_cause == RISCV_EXCP_INST_ADDR_MIS) ||
+        (fixed_cause == RISCV_EXCP_INST_ACCESS_FAULT) ||
+        (fixed_cause == RISCV_EXCP_LOAD_ADDR_MIS) ||
+        (fixed_cause == RISCV_EXCP_STORE_AMO_ADDR_MIS) ||
+        (fixed_cause == RISCV_EXCP_LOAD_ACCESS_FAULT) ||
+        (fixed_cause == RISCV_EXCP_STORE_AMO_ACCESS_FAULT);
+
+    if (bit & ((target_ulong)1 << (TARGET_LONG_BITS - 1))) {
+        deleg = env->csr[CSR_MIDELEG], bit &= ~(1L << (TARGET_LONG_BITS - 1));
+    }
+
+    if (env->priv <= PRV_S && bit < 64 && ((deleg >> bit) & 1)) {
+        /* handle the trap in S-mode */
+        /* No need to check STVEC for misaligned - lower 2 bits cannot be set */
+        env->PC = env->csr[CSR_STVEC];
+        env->csr[CSR_SCAUSE] = fixed_cause;
+        env->csr[CSR_SEPC] = backup_epc;
+
+        if (hasbadaddr) {
+            #ifdef RISCV_DEBUG_INTERRUPT
+            fprintf(stderr, "core   0: badaddr 0x" TARGET_FMT_lx "\n",
+                    env->badaddr);
+            #endif
+            env->csr[CSR_SBADADDR] = env->badaddr;
+        }
+
+        target_ulong s = env->csr[CSR_MSTATUS];
+        s = set_field(s, MSTATUS_SPIE, get_field(s, MSTATUS_UIE << env->priv));
+        s = set_field(s, MSTATUS_SPP, env->priv);
+        s = set_field(s, MSTATUS_SIE, 0);
+        csr_write_helper(env, s, CSR_MSTATUS);
+        set_privilege(env, PRV_S);
+    } else {
+        /* No need to check MTVEC for misaligned - lower 2 bits cannot be set */
+        env->PC = env->csr[CSR_MTVEC];
+        env->csr[CSR_MEPC] = backup_epc;
+        env->csr[CSR_MCAUSE] = fixed_cause;
+
+        if (hasbadaddr) {
+            #ifdef RISCV_DEBUG_INTERRUPT
+            fprintf(stderr, "core   0: badaddr 0x" TARGET_FMT_lx "\n",
+                    env->badaddr);
+            #endif
+            env->csr[CSR_MBADADDR] = env->badaddr;
+        }
+
+        target_ulong s = env->csr[CSR_MSTATUS];
+        s = set_field(s, MSTATUS_MPIE, get_field(s, MSTATUS_UIE << env->priv));
+        s = set_field(s, MSTATUS_MPP, env->priv);
+        s = set_field(s, MSTATUS_MIE, 0);
+        csr_write_helper(env, s, CSR_MSTATUS);
+        set_privilege(env, PRV_M);
+    }
+    /* TODO yield load reservation  */
+
+    cs->exception_index = EXCP_NONE; /* mark handled to qemu */
 }
Signature · 1 line
2.9.3
#35 lore raw

Re: [Qemu-devel] [PATCH 15/18] target-riscv: Interrupt Handling

Quoted 1 line · Sagar Karandikar

+ if (interruptno + 1) {

This is a very odd way to write interruptno != -1. And did you really mean interruptno >= 0?

r~

#36 lore raw

PATCH 16/18 target-riscv: Timer Support

In reply to Sagar Karandikar
---
 hw/riscv/Makefile.objs                |   1 +
 hw/riscv/cpudevs.h                    |  17 +++
 hw/riscv/riscv_rtc.c                  | 230 ++++++++++++++++++++++++++++++++++
 include/hw/riscv/riscv_rtc.h          |  25 ++++
 include/hw/riscv/riscv_rtc_internal.h |   3 +
 target-riscv/op_helper.c              |   4 +-
 6 files changed, 278 insertions(+), 2 deletions(-)
 create mode 100644 hw/riscv/Makefile.objs
 create mode 100644 hw/riscv/cpudevs.h
 create mode 100644 hw/riscv/riscv_rtc.c
 create mode 100644 include/hw/riscv/riscv_rtc.h
 create mode 100644 include/hw/riscv/riscv_rtc_internal.h
hw/riscv/Makefile.objs new file +1 -0
new file mode 100644
index 0000000..79b4553
@@ -0,0 +1 @@
+obj-y += riscv_rtc.o
hw/riscv/cpudevs.h new file +17 -0
new file mode 100644
index 0000000..f2f4195
@@ -0,0 +1,17 @@
+#ifndef HW_RISCV_CPUDEVS_H
+#define HW_RISCV_CPUDEVS_H
+
+#include "target-riscv/cpu.h"
+
+/* Definitions for RISCV CPU internal devices.  */
+
+/* riscv_board.c */
+uint64_t identity_translate(void *opaque, uint64_t addr);
+
+/* riscv_int.c */
+void cpu_riscv_irq_init_cpu(CPURISCVState *env);
+
+/* cputimer.c */
+void cpu_riscv_clock_init(CPURISCVState *);
+
+#endif
hw/riscv/riscv_rtc.c new file +230 -0

230 lines not on this page · raw message

include/hw/riscv/riscv_rtc.h new file +25 -0
new file mode 100644
index 0000000..d5c422c
@@ -0,0 +1,25 @@
+#ifndef HW_RISCV_TIMER_H
+#define HW_RISCV_TIMER_H 1
+
+#include "hw/hw.h"
+#include "sysemu/sysemu.h"
+#include "exec/memory.h"
+#include "target-riscv/cpu.h"
+
+typedef struct TIMERState TIMERState;
+
+struct TIMERState {
+    CPURISCVState *env;
+    MemoryRegion io;
+    uint32_t timecmp_lower;
+    uint64_t temp_rtc_val;
+};
+
+extern const VMStateDescription vmstate_timer_rv;
+extern const MemoryRegionOps timer_io_ops;
+
+/* legacy pre qom */
+TIMERState *timer_mm_init(MemoryRegion *address_space, hwaddr base,
+                          CPURISCVState *env);
+
+#endif
include/hw/riscv/riscv_rtc_internal.h new file +3 -0
new file mode 100644
index 0000000..d13e104
@@ -0,0 +1,3 @@
+uint64_t rtc_read(CPURISCVState *env);
+uint64_t instret_read(CPURISCVState *env);
+void write_timecmp(CPURISCVState *env, uint64_t value);
target-riscv/op_helper.c +2 -2
index 1ecdef2..54d7538 100644
@@ -335,10 +335,10 @@ inline target_ulong csr_read_helper(CPURISCVState *env, target_ulong csrno)
     /* notice the lack of CSR_MTIME - this is handled by throwing an exception
        and letting the handler read from the RTC */
     case CSR_MCYCLE:
-        /* Read instret here */
+        return cpu_riscv_read_instret(env);
         break;
     case CSR_MINSTRET:
-        /* Read instret here */
+        return cpu_riscv_read_instret(env);
         break;
     case CSR_MCYCLEH:
         printf("CSR 0x%x unsupported on RV64\n", csrno2);
Signature · 1 line
2.9.3
#37 lore raw

PATCH 17/18 target-riscv: Add support for Host-Target Interface (HTIF) Devices

In reply to Sagar Karandikar

HTIF devices are currently used for the console and signaling test completion for tests in riscv-tests. These are not part of any RISC-V standard and will be phased out once better device support is available.

---
 hw/riscv/Makefile.objs       |   2 +
 hw/riscv/htif/elf_symb.c     | 286 +++++++++++++++++++++++++++++
 hw/riscv/htif/elf_symb.h     |  80 ++++++++
 hw/riscv/htif/htif.c         | 423 +++++++++++++++++++++++++++++++++++++++++++
 include/hw/riscv/htif/htif.h |  61 +++++++
 5 files changed, 852 insertions(+)
 create mode 100644 hw/riscv/htif/elf_symb.c
 create mode 100644 hw/riscv/htif/elf_symb.h
 create mode 100644 hw/riscv/htif/htif.c
 create mode 100644 include/hw/riscv/htif/htif.h
hw/riscv/Makefile.objs +2 -0
index 79b4553..d830e5d 100644
@@ -1 +1,3 @@
 obj-y += riscv_rtc.o
+obj-y += htif/elf_symb.o
+obj-y += htif/htif.o
hw/riscv/htif/elf_symb.c new file +286 -0

286 lines not on this page · raw message

hw/riscv/htif/elf_symb.h new file +80 -0

80 lines not on this page · raw message

hw/riscv/htif/htif.c new file +423 -0

423 lines not on this page · raw message

include/hw/riscv/htif/htif.h new file +61 -0

61 lines not on this page · raw message

Signature · 1 line
2.9.3
#38 lore raw

PATCH 18/18 target-riscv: Add generic test board, activate target

In reply to Sagar Karandikar
---
 configure                           |   6 +
 default-configs/riscv32-softmmu.mak |  38 ++++++
 default-configs/riscv64-softmmu.mak |  38 ++++++
 hw/riscv/Makefile.objs              |   2 +
 hw/riscv/riscv_board.c              | 264 ++++++++++++++++++++++++++++++++++++
 hw/riscv/riscv_int.c                |  67 +++++++++
 6 files changed, 415 insertions(+)
 create mode 100644 default-configs/riscv32-softmmu.mak
 create mode 100644 default-configs/riscv64-softmmu.mak
 create mode 100644 hw/riscv/riscv_board.c
 create mode 100644 hw/riscv/riscv_int.c
configure +6 -0
index 8fa62ad..e3381b8 100755
@@ -5667,6 +5667,12 @@ case "$target_name" in
     TARGET_BASE_ARCH=mips
     echo "TARGET_ABI_MIPSN64=y" >> $config_target_mak
   ;;
+  riscv32)
+    TARGET_BASE_ARCH=riscv
+  ;;
+  riscv64)
+    TARGET_BASE_ARCH=riscv
+  ;;
   moxie)
   ;;
   or32)
default-configs/riscv32-softmmu.mak new file +38 -0
new file mode 100644
index 0000000..c8b7fa1
@@ -0,0 +1,38 @@
+# Default configuration for riscv-softmmu
+
+#include pci.mak
+#include sound.mak
+#include usb.mak
+#CONFIG_ESP=y
+#CONFIG_VGA=y
+#CONFIG_VGA_PCI=y
+#CONFIG_VGA_ISA=y
+#CONFIG_VGA_ISA_MM=y
+#CONFIG_VGA_CIRRUS=y
+#CONFIG_VMWARE_VGA=y
+CONFIG_SERIAL=y
+#CONFIG_PARALLEL=y
+#CONFIG_I8254=y
+#CONFIG_PCSPK=y
+#CONFIG_PCKBD=y
+#CONFIG_FDC=y
+#CONFIG_ACPI=y
+#CONFIG_APM=y
+#CONFIG_I8257=y
+#CONFIG_PIIX4=y
+#CONFIG_IDE_ISA=y
+#CONFIG_IDE_PIIX=y
+#CONFIG_NE2000_ISA=y
+#CONFIG_RC4030=y
+#CONFIG_DP8393X=y
+#CONFIG_DS1225Y=y
+#CONFIG_MIPSNET=y
+#CONFIG_PFLASH_CFI01=y
+#CONFIG_G364FB=y
+CONFIG_I8259=y
+#CONFIG_JAZZ_LED=y
+#CONFIG_MC146818RTC=y
+#CONFIG_VT82C686=y
+#CONFIG_ISA_TESTDEV=y
+#CONFIG_EMPTY_SLOT=y
+CONFIG_VIRTIO=y
default-configs/riscv64-softmmu.mak new file +38 -0
new file mode 100644
index 0000000..c8b7fa1
@@ -0,0 +1,38 @@
+# Default configuration for riscv-softmmu
+
+#include pci.mak
+#include sound.mak
+#include usb.mak
+#CONFIG_ESP=y
+#CONFIG_VGA=y
+#CONFIG_VGA_PCI=y
+#CONFIG_VGA_ISA=y
+#CONFIG_VGA_ISA_MM=y
+#CONFIG_VGA_CIRRUS=y
+#CONFIG_VMWARE_VGA=y
+CONFIG_SERIAL=y
+#CONFIG_PARALLEL=y
+#CONFIG_I8254=y
+#CONFIG_PCSPK=y
+#CONFIG_PCKBD=y
+#CONFIG_FDC=y
+#CONFIG_ACPI=y
+#CONFIG_APM=y
+#CONFIG_I8257=y
+#CONFIG_PIIX4=y
+#CONFIG_IDE_ISA=y
+#CONFIG_IDE_PIIX=y
+#CONFIG_NE2000_ISA=y
+#CONFIG_RC4030=y
+#CONFIG_DP8393X=y
+#CONFIG_DS1225Y=y
+#CONFIG_MIPSNET=y
+#CONFIG_PFLASH_CFI01=y
+#CONFIG_G364FB=y
+CONFIG_I8259=y
+#CONFIG_JAZZ_LED=y
+#CONFIG_MC146818RTC=y
+#CONFIG_VT82C686=y
+#CONFIG_ISA_TESTDEV=y
+#CONFIG_EMPTY_SLOT=y
+CONFIG_VIRTIO=y
hw/riscv/Makefile.objs +2 -0
index d830e5d..de6017e 100644
@@ -1,3 +1,5 @@
 obj-y += riscv_rtc.o
+obj-y += riscv_int.o
 obj-y += htif/elf_symb.o
 obj-y += htif/htif.o
+obj-y += riscv_board.o
hw/riscv/riscv_board.c new file +264 -0

264 lines not on this page · raw message

hw/riscv/riscv_int.c new file +67 -0

67 lines not on this page · raw message

Signature · 1 line
2.9.3
#40 lore raw
Quoted 7 lines · Paolo Bonzini
Quoted 1 line · Sagar Karandikar

-cpu-qom.h merged into cpu.h

Please follow the model of other targets. RISCVCPUClass and the RISCVCPU typedef should be in cpu-qom.h.

I thought we had this discussion before, and cpu-qom.h is sort of a legacy header, and that new targets shouldn't use it.

r~

#41 lore raw

Am 26.09.2016 um 18:17 schrieb Richard Henderson:

Quoted 9 lines · Paolo Bonzini
Quoted 5 lines · Sagar Karandikar
Quoted 1 line

-cpu-qom.h merged into cpu.h

Please follow the model of other targets. RISCVCPUClass and the RISCVCPU typedef should be in cpu-qom.h.

I thought we had this discussion before, and cpu-qom.h is sort of a legacy header, and that new targets shouldn't use it.

Yes, a concept that didn't quite work out, sadly. Just cpu.h is fine.

Andreas

Signature · 3 lines
SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
#42 lore raw
Quoted 5 lines · Andreas Färber

Am 26.09.2016 um 18:17 schrieb Richard Henderson:

Quoted 4 lines · Paolo Bonzini
Quoted 3 lines · Sagar Karandikar
Quoted 1 line

-cpu-qom.h merged into cpu.h

Quoted 7 lines
Quoted 5 lines
Quoted 2 lines

Please follow the model of other targets. RISCVCPUClass and the RISCVCPU typedef should be in cpu-qom.h.

I thought we had this discussion before, and cpu-qom.h is sort of a legacy header, and that new targets shouldn't use it.

Yes, a concept that didn't quite work out, sadly. Just cpu.h is fine.

Hmm, maybe since 2.7.0 it started working out better? :)

The point of cpu-qom.h is to allow using the RISCVCPU symbol in target- specific header files, without forcing all files including said header to be compiled per-target. See for example

commit 4da6f8d954429c0cd1471d25cb9dbe909607374e
Author: Paolo Bonzini <[email protected]>
Date: Tue Mar 15 13:49:25 2016 +0100

target-i386: make cpu-qom.h not target specific

Make X86CPU an opaque type within cpu-qom.h, and move all definitions of private methods, as well as all type definitions that require knowledge of the layout to cpu.h. This helps making files independent of NEED_CPU_H if they only need to pass around CPU pointers.

You cannot include the definition of struct FooCPU in cpu-qom.h, because
it embeds "CPUFooState env;" and CPUFooState uses target_long. Still it's
a nice improvement, for example it's now possible to compile device models common to arm-softmmu and aarch64-softmmu (or sh4/sh4eb, etc.) just once.

Paolo

#43 lore raw

Am 26.09.2016 um 18:24 schrieb Paolo Bonzini:

Quoted 8 lines · Andreas Färber
Quoted 7 lines

Am 26.09.2016 um 18:17 schrieb Richard Henderson:

Quoted 6 lines · Paolo Bonzini
Quoted 5 lines · Sagar Karandikar
Quoted 1 line

-cpu-qom.h merged into cpu.h

Please follow the model of other targets. RISCVCPUClass and the RISCVCPU typedef should be in cpu-qom.h.

After discussion with Paolo, the key word here is typedef. It doesn't make sense to have the struct RISCVCPU in cpu-qom.h (the old approach) but it makes perfect sense to have struct RISCVCPUClass and typedef RISCVCPU in a separate cpu-qom.h.

Sorry for misunderstanding,
Andreas

Signature · 3 lines
SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
#44 lore raw
Quoted 7 lines · Andreas Färber

Am 26.09.2016 um 18:24 schrieb Paolo Bonzini:

Quoted 6 lines · Andreas Färber
Quoted 5 lines

Am 26.09.2016 um 18:17 schrieb Richard Henderson:

Quoted 4 lines · Paolo Bonzini
Quoted 3 lines · Sagar Karandikar
Quoted 1 line

-cpu-qom.h merged into cpu.h

Quoted 7 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

Please follow the model of other targets. RISCVCPUClass and the RISCVCPU typedef should be in cpu-qom.h.

After discussion with Paolo, the key word here is typedef. It doesn't make sense to have the struct RISCVCPU in cpu-qom.h (the old approach) but it makes perfect sense to have struct RISCVCPUClass and typedef RISCVCPU in a separate cpu-qom.h.

Thanks Andreas, and sorry Sagar for the back-and-forth!

Paolo