All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G)
@ 2016-09-26 10:56 Sagar Karandikar
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 01/18] target-riscv: Add RISC-V target stubs and Maintainer Sagar Karandikar
                   ` (18 more replies)
  0 siblings, 19 replies; 45+ messages in thread
From: Sagar Karandikar @ 2016-09-26 10:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, rth, kbastian, Sagar Karandikar

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

-- 
2.9.3

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

* [Qemu-devel] [PATCH 01/18] target-riscv: Add RISC-V target stubs and Maintainer
  2016-09-26 10:56 [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G) Sagar Karandikar
@ 2016-09-26 10:56 ` Sagar Karandikar
  2016-09-26 19:06   ` Eric Blake
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 02/18] target-riscv: Add RISC-V Target stubs inside target-riscv/ Sagar Karandikar
                   ` (17 subsequent siblings)
  18 siblings, 1 reply; 45+ messages in thread
From: Sagar Karandikar @ 2016-09-26 10:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, rth, kbastian, Sagar Karandikar

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

Signed-off-by: Sagar Karandikar <sagark@eecs.berkeley.edu>
---
 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(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index a3a2ad7..dbbbe0f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -175,6 +175,13 @@ F: hw/ppc/
 F: include/hw/ppc/
 F: disas/ppc.c
 
+RISC-V
+M: Sagar Karandikar <sagark@eecs.berkeley.edu>
+M: Bastian Koppelmann <kbastian@mail.uni-paderborn.de>
+S: Maintained
+F: target-riscv/
+F: hw/riscv/
+
 S390
 M: Richard Henderson <rth@twiddle.net>
 M: Alexander Graf <agraf@suse.de>
diff --git a/arch_init.c b/arch_init.c
index 5cc58b2..c89c45d 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -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)
diff --git a/cpus.c b/cpus.c
index e39ccb7..41ccc29 100644
--- a/cpus.c
+++ b/cpus.c
@@ -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
diff --git a/include/elf.h b/include/elf.h
index 1c2975d..1221359 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -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.
diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h
index 1c9dad1..8684aac 100644
--- a/include/sysemu/arch_init.h
+++ b/include/sysemu/arch_init.h
@@ -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;
diff --git a/qapi-schema.json b/qapi-schema.json
index e507061..11cd848 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -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
-- 
2.9.3

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

* [Qemu-devel] [PATCH 02/18] target-riscv: Add RISC-V Target stubs inside target-riscv/
  2016-09-26 10:56 [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G) Sagar Karandikar
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 01/18] target-riscv: Add RISC-V target stubs and Maintainer Sagar Karandikar
@ 2016-09-26 10:56 ` Sagar Karandikar
  2016-09-26 16:30   ` Richard Henderson
  2016-09-26 21:50   ` Richard Henderson
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 03/18] target-riscv: Add initialization for translation Sagar Karandikar
                   ` (16 subsequent siblings)
  18 siblings, 2 replies; 45+ messages in thread
From: Sagar Karandikar @ 2016-09-26 10:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, rth, kbastian, Sagar Karandikar

Signed-off-by: Sagar Karandikar <sagark@eecs.berkeley.edu>
---
 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

diff --git a/target-riscv/Makefile.objs b/target-riscv/Makefile.objs
new file mode 100644
index 0000000..cb448a8
--- /dev/null
+++ b/target-riscv/Makefile.objs
@@ -0,0 +1 @@
+obj-y += translate.o op_helper.o helper.o cpu.o
diff --git a/target-riscv/cpu.c b/target-riscv/cpu.c
new file mode 100644
index 0000000..0923a75
--- /dev/null
+++ b/target-riscv/cpu.c
@@ -0,0 +1,154 @@
+/*
+ * QEMU RISC-V CPU
+ *
+ * Author: Sagar Karandikar, sagark@eecs.berkeley.edu
+ *
+ * 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.1 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/lgpl-2.1.html>
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "cpu.h"
+#include "qemu-common.h"
+#include "migration/vmstate.h"
+
+static void riscv_cpu_set_pc(CPUState *cs, vaddr value)
+{
+    RISCVCPU *cpu = RISCV_CPU(cs);
+    CPURISCVState *env = &cpu->env;
+    env->PC = value;
+}
+
+static void riscv_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
+{
+    RISCVCPU *cpu = RISCV_CPU(cs);
+    CPURISCVState *env = &cpu->env;
+    env->PC = tb->pc;
+}
+
+static bool riscv_cpu_has_work(CPUState *cs)
+{
+    RISCVCPU *cpu = RISCV_CPU(cs);
+    CPURISCVState *env = &cpu->env;
+    bool has_work = false;
+
+    if (cs->interrupt_request & CPU_INTERRUPT_HARD) {
+        int interruptno = cpu_riscv_hw_interrupts_pending(env);
+        if (interruptno + 1) {
+            has_work = true;
+        }
+    }
+
+    return has_work;
+}
+
+static void riscv_cpu_reset(CPUState *s)
+{
+    RISCVCPU *cpu = RISCV_CPU(s);
+    RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu);
+    CPURISCVState *env = &cpu->env;
+    CPUState *cs = CPU(cpu);
+
+    mcc->parent_reset(s);
+    tlb_flush(s, 1);
+
+    env->priv = PRV_M;
+    env->PC = DEFAULT_RSTVEC;
+    env->csr[CSR_MTVEC] = DEFAULT_MTVEC;
+    cs->exception_index = EXCP_NONE;
+}
+
+static void riscv_cpu_realizefn(DeviceState *dev, Error **errp)
+{
+    CPUState *cs = CPU(dev);
+    RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(dev);
+
+    cpu_reset(cs);
+    qemu_init_vcpu(cs);
+
+    mcc->parent_realize(dev, errp);
+}
+
+static void riscv_cpu_initfn(Object *obj)
+{
+    CPUState *cs = CPU(obj);
+    RISCVCPU *cpu = RISCV_CPU(obj);
+    CPURISCVState *env = &cpu->env;
+
+    cs->env_ptr = env;
+    cpu_exec_init(cs, &error_abort);
+
+    if (tcg_enabled()) {
+        riscv_tcg_init();
+    }
+}
+
+static const VMStateDescription vmstate_riscv_cpu = {
+    .name = "cpu",
+    .unmigratable = 1,
+};
+
+static void riscv_cpu_class_init(ObjectClass *c, void *data)
+{
+    RISCVCPUClass *mcc = RISCV_CPU_CLASS(c);
+    CPUClass *cc = CPU_CLASS(c);
+    DeviceClass *dc = DEVICE_CLASS(c);
+
+    mcc->parent_realize = dc->realize;
+    dc->realize = riscv_cpu_realizefn;
+
+    mcc->parent_reset = cc->reset;
+    cc->reset = riscv_cpu_reset;
+
+    cc->has_work = riscv_cpu_has_work;
+    cc->do_interrupt = riscv_cpu_do_interrupt;
+    cc->cpu_exec_interrupt = riscv_cpu_exec_interrupt;
+    cc->dump_state = riscv_cpu_dump_state;
+    cc->set_pc = riscv_cpu_set_pc;
+    cc->synchronize_from_tb = riscv_cpu_synchronize_from_tb;
+#ifdef CONFIG_USER_ONLY
+    cc->handle_mmu_fault = riscv_cpu_handle_mmu_fault;
+#else
+    cc->do_unassigned_access = riscv_cpu_unassigned_access;
+    cc->do_unaligned_access = riscv_cpu_do_unaligned_access;
+    cc->get_phys_page_debug = riscv_cpu_get_phys_page_debug;
+#endif
+    /* For now, mark unmigratable: */
+    cc->vmsd = &vmstate_riscv_cpu;
+
+    /*
+     * Reason: riscv_cpu_initfn() calls cpu_exec_init(), which saves
+     * the object in cpus -> dangling pointer after final
+     * object_unref().
+     */
+    dc->cannot_destroy_with_object_finalize_yet = true;
+}
+
+static const TypeInfo riscv_cpu_type_info = {
+    .name = TYPE_RISCV_CPU,
+    .parent = TYPE_CPU,
+    .instance_size = sizeof(RISCVCPU),
+    .instance_init = riscv_cpu_initfn,
+    .abstract = false,
+    .class_size = sizeof(RISCVCPUClass),
+    .class_init = riscv_cpu_class_init,
+};
+
+static void riscv_cpu_register_types(void)
+{
+    type_register_static(&riscv_cpu_type_info);
+}
+
+type_init(riscv_cpu_register_types)
diff --git a/target-riscv/cpu.h b/target-riscv/cpu.h
new file mode 100644
index 0000000..1cd47a6
--- /dev/null
+++ b/target-riscv/cpu.h
@@ -0,0 +1,497 @@
+#ifndef RISCV_CPU_H
+#define RISCV_CPU_H
+
+/*#define DEBUG_OP */
+
+/* uncomment for lots of debug printing */
+/* #define RISCV_DEBUG_PRINT */
+
+#define TARGET_HAS_ICE 1
+#define ELF_MACHINE EM_RISCV
+#define CPUArchState struct CPURISCVState
+
+#include "qemu-common.h"
+
+/* 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 */
+#define TARGET_PHYS_ADDR_SPACE_BITS 34
+#define TARGET_VIRT_ADDR_SPACE_BITS 32
+#endif
+
+#include "exec/cpu-defs.h"
+#include "fpu/softfloat.h"
+
+#define TRANSLATE_FAIL -1
+#define TRANSLATE_SUCCESS 0
+#define NB_MMU_MODES 4
+
+struct CPURISCVState;
+
+/* Below taken from Spike's decode.h and encoding.h.
+ * Using these directly drastically simplifies updating to new versions of the
+ * RISC-V privileged specification */
+
+#define get_field(reg, mask) (((reg) & \
+                 (target_ulong)(mask)) / ((mask) & ~((mask) << 1)))
+#define set_field(reg, mask, val) (((reg) & ~(target_ulong)(mask)) | \
+                 (((target_ulong)(val) * ((mask) & ~((mask) << 1))) & \
+                 (target_ulong)(mask)))
+
+#define PGSHIFT 12
+
+#define FP_RD_NE  0
+#define FP_RD_0   1
+#define FP_RD_DN  2
+#define FP_RD_UP  3
+#define FP_RD_NMM 4
+
+#define FSR_RD_SHIFT 5
+#define FSR_RD   (0x7 << FSR_RD_SHIFT)
+
+#define FPEXC_NX 0x01
+#define FPEXC_UF 0x02
+#define FPEXC_OF 0x04
+#define FPEXC_DZ 0x08
+#define FPEXC_NV 0x10
+
+#define FSR_AEXC_SHIFT 0
+#define FSR_NVA  (FPEXC_NV << FSR_AEXC_SHIFT)
+#define FSR_OFA  (FPEXC_OF << FSR_AEXC_SHIFT)
+#define FSR_UFA  (FPEXC_UF << FSR_AEXC_SHIFT)
+#define FSR_DZA  (FPEXC_DZ << FSR_AEXC_SHIFT)
+#define FSR_NXA  (FPEXC_NX << FSR_AEXC_SHIFT)
+#define FSR_AEXC (FSR_NVA | FSR_OFA | FSR_UFA | FSR_DZA | FSR_NXA)
+
+#define CSR_FFLAGS 0x1
+#define CSR_FRM 0x2
+#define CSR_FCSR 0x3
+#define CSR_CYCLE 0xc00
+#define CSR_TIME 0xc01
+#define CSR_INSTRET 0xc02
+#define CSR_SSTATUS 0x100
+#define CSR_SIE 0x104
+#define CSR_STVEC 0x105
+#define CSR_SSCRATCH 0x140
+#define CSR_SEPC 0x141
+#define CSR_SCAUSE 0x142
+#define CSR_SBADADDR 0x143
+#define CSR_SIP 0x144
+#define CSR_SPTBR 0x180
+#define CSR_SCYCLE 0xd00
+#define CSR_STIME 0xd01
+#define CSR_SINSTRET 0xd02
+#define CSR_MSTATUS 0x300
+#define CSR_MEDELEG 0x302
+#define CSR_MIDELEG 0x303
+#define CSR_MIE 0x304
+#define CSR_MTVEC 0x305
+#define CSR_MSCRATCH 0x340
+#define CSR_MEPC 0x341
+#define CSR_MCAUSE 0x342
+#define CSR_MBADADDR 0x343
+#define CSR_MIP 0x344
+#define CSR_MUCOUNTEREN 0x310
+#define CSR_MSCOUNTEREN 0x311
+#define CSR_MUCYCLE_DELTA 0x700
+#define CSR_MUTIME_DELTA 0x701
+#define CSR_MUINSTRET_DELTA 0x702
+#define CSR_MSCYCLE_DELTA 0x704
+#define CSR_MSTIME_DELTA 0x705
+#define CSR_MSINSTRET_DELTA 0x706
+#define CSR_TDRSELECT 0x7a0
+#define CSR_TDRDATA1 0x7a1
+#define CSR_TDRDATA2 0x7a2
+#define CSR_TDRDATA3 0x7a3
+#define CSR_DCSR 0x7b0
+#define CSR_DPC 0x7b1
+#define CSR_DSCRATCH 0x7b2
+#define CSR_MCYCLE 0xf00
+#define CSR_MTIME 0xf01
+#define CSR_MINSTRET 0xf02
+#define CSR_MISA 0xf10
+#define CSR_MVENDORID 0xf11
+#define CSR_MARCHID 0xf12
+#define CSR_MIMPID 0xf13
+#define CSR_MHARTID 0xf14
+#define CSR_MRESET 0x7c2
+#define CSR_CYCLEH 0xc80
+#define CSR_TIMEH 0xc81
+#define CSR_INSTRETH 0xc82
+#define CSR_MUCYCLE_DELTAH 0x780
+#define CSR_MUTIME_DELTAH 0x781
+#define CSR_MUINSTRET_DELTAH 0x782
+#define CSR_MSCYCLE_DELTAH 0x784
+#define CSR_MSTIME_DELTAH 0x785
+#define CSR_MSINSTRET_DELTAH 0x786
+#define CSR_MCYCLEH 0xf80
+#define CSR_MTIMEH 0xf81
+#define CSR_MINSTRETH 0xf82
+
+/* RISCV Exception Codes */
+#define EXCP_NONE                       -1 /* not a real RISCV exception code */
+#define RISCV_EXCP_INST_ADDR_MIS           0x0
+#define RISCV_EXCP_INST_ACCESS_FAULT       0x1
+#define RISCV_EXCP_ILLEGAL_INST            0x2
+#define RISCV_EXCP_BREAKPOINT              0x3
+#define RISCV_EXCP_LOAD_ADDR_MIS           0x4
+#define RISCV_EXCP_LOAD_ACCESS_FAULT       0x5
+#define RISCV_EXCP_STORE_AMO_ADDR_MIS      0x6
+#define RISCV_EXCP_STORE_AMO_ACCESS_FAULT  0x7
+#define RISCV_EXCP_U_ECALL                 0x8 /* for convenience, report all
+                                                  ECALLs as this, handler
+                                                  fixes */
+#define RISCV_EXCP_S_ECALL                 0x9
+#define RISCV_EXCP_H_ECALL                 0xa
+#define RISCV_EXCP_M_ECALL                 0xb
+
+#define IS_RV_INTERRUPT(ival) (ival & (0x1 << 31))
+
+#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
+
+#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
+
+#define DCSR_XDEBUGVER      (3U << 30)
+#define DCSR_NDRESET        (1 << 29)
+#define DCSR_FULLRESET      (1 << 28)
+#define DCSR_HWBPCOUNT      (0xfff << 16)
+#define DCSR_EBREAKM        (1 << 15)
+#define DCSR_EBREAKH        (1 << 14)
+#define DCSR_EBREAKS        (1 << 13)
+#define DCSR_EBREAKU        (1 << 12)
+#define DCSR_STOPCYCLE      (1 << 10)
+#define DCSR_STOPTIME       (1 << 9)
+#define DCSR_CAUSE          (7 << 6)
+#define DCSR_DEBUGINT       (1 << 5)
+#define DCSR_HALT           (1 << 3)
+#define DCSR_STEP           (1 << 2)
+#define DCSR_PRV            (3 << 0)
+
+#define DCSR_CAUSE_NONE     0
+#define DCSR_CAUSE_SWBP     1
+#define DCSR_CAUSE_HWBP     2
+#define DCSR_CAUSE_DEBUGINT 3
+#define DCSR_CAUSE_STEP     4
+#define DCSR_CAUSE_HALT     5
+
+#define MIP_SSIP            (1 << IRQ_S_SOFT)
+#define MIP_HSIP            (1 << IRQ_H_SOFT)
+#define MIP_MSIP            (1 << IRQ_M_SOFT)
+#define MIP_STIP            (1 << IRQ_S_TIMER)
+#define MIP_HTIP            (1 << IRQ_H_TIMER)
+#define MIP_MTIP            (1 << IRQ_M_TIMER)
+#define MIP_SEIP            (1 << IRQ_S_EXT)
+#define MIP_HEIP            (1 << IRQ_H_EXT)
+#define MIP_MEIP            (1 << IRQ_M_EXT)
+
+#define SIP_SSIP MIP_SSIP
+#define SIP_STIP MIP_STIP
+
+#define PRV_U 0
+#define PRV_S 1
+#define PRV_H 2
+#define PRV_M 3
+
+#define VM_MBARE 0
+#define VM_MBB   1
+#define VM_MBBID 2
+#define VM_SV32  8
+#define VM_SV39  9
+#define VM_SV48  10
+
+#define IRQ_S_SOFT   1
+#define IRQ_H_SOFT   2
+#define IRQ_M_SOFT   3
+#define IRQ_S_TIMER  5
+#define IRQ_H_TIMER  6
+#define IRQ_M_TIMER  7
+#define IRQ_S_EXT    9
+#define IRQ_H_EXT    10
+#define IRQ_M_EXT    11
+#define IRQ_COP      12
+#define IRQ_HOST     13
+
+#define DEFAULT_RSTVEC     0x00001000
+#define DEFAULT_NMIVEC     0x00001004
+#define DEFAULT_MTVEC      0x00001010
+#define CONFIG_STRING_ADDR 0x0000100C
+#define EXT_IO_BASE        0x40000000
+#define DRAM_BASE          0x80000000
+
+/* breakpoint control fields */
+#define BPCONTROL_X           0x00000001
+#define BPCONTROL_W           0x00000002
+#define BPCONTROL_R           0x00000004
+#define BPCONTROL_U           0x00000008
+#define BPCONTROL_S           0x00000010
+#define BPCONTROL_H           0x00000020
+#define BPCONTROL_M           0x00000040
+#define BPCONTROL_BPMATCH     0x00000780
+#define BPCONTROL_BPAMASKMAX 0x0F80000000000000
+#define BPCONTROL_TDRTYPE    0xF000000000000000
+
+/* page table entry (PTE) fields */
+#define PTE_V     0x001 /* Valid */
+#define PTE_R     0x002 /* Read */
+#define PTE_W     0x004 /* Write */
+#define PTE_X     0x008 /* Execute */
+#define PTE_U     0x010 /* User */
+#define PTE_G     0x020 /* Global */
+#define PTE_A     0x040 /* Accessed */
+#define PTE_D     0x080 /* Dirty */
+#define PTE_SOFT  0x300 /* Reserved for Software */
+
+#define PTE_PPN_SHIFT 10
+
+#define PTE_TABLE(PTE) (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V)
+/* end Spike decode.h, encoding.h section */
+
+#define SSIP_IRQ (env->irq[0])
+#define STIP_IRQ (env->irq[1])
+#define MSIP_IRQ (env->irq[2])
+#define TIMER_IRQ (env->irq[3])
+#define HTIF_IRQ (env->irq[4])
+
+typedef struct riscv_def_t riscv_def_t;
+
+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 */
+    target_ulong priv;
+    target_ulong badaddr;
+
+    /* temporary htif regs */
+    uint64_t mfromhost;
+    uint64_t mtohost;
+
+    uint64_t timecmp;
+    float_status fp_status;
+
+    /* QEMU */
+    CPU_COMMON
+
+    /* Fields from here on are preserved across CPU reset. */
+    const riscv_def_t *cpu_model;
+    size_t memsize;
+    void *irq[8];
+    QEMUTimer *timer; /* Internal timer */
+};
+
+#ifndef QEMU_RISCV_CPU_QOM_H
+#define QEMU_RISCV_CPU_QOM_H
+
+#include "qom/cpu.h"
+
+#define TYPE_RISCV_CPU "riscv-cpu"
+
+#define RISCV_CPU_CLASS(klass) \
+    OBJECT_CLASS_CHECK(RISCVCPUClass, (klass), TYPE_RISCV_CPU)
+#define RISCV_CPU(obj) \
+    OBJECT_CHECK(RISCVCPU, (obj), TYPE_RISCV_CPU)
+#define RISCV_CPU_GET_CLASS(obj) \
+    OBJECT_GET_CLASS(RISCVCPUClass, (obj), TYPE_RISCV_CPU)
+
+/**
+ * RISCVCPUClass:
+ * @parent_realize: The parent class' realize handler.
+ * @parent_reset: The parent class' reset handler.
+ *
+ * A RISCV CPU model.
+ */
+typedef struct RISCVCPUClass {
+    /*< private >*/
+    CPUClass parent_class;
+    /*< public >*/
+    DeviceRealize parent_realize;
+    void (*parent_reset)(CPUState *cpu);
+} RISCVCPUClass;
+
+/**
+ * RISCVCPU:
+ * @env: #CPURISCVState
+ *
+ * A RISCV CPU.
+ */
+typedef struct RISCVCPU {
+    /*< private >*/
+    CPUState parent_obj;
+    /*< public >*/
+    CPURISCVState env;
+} RISCVCPU;
+
+static inline RISCVCPU *riscv_env_get_cpu(CPURISCVState *env)
+{
+    return container_of(env, RISCVCPU, env);
+}
+
+#define ENV_GET_CPU(e) CPU(riscv_env_get_cpu(e))
+#define ENV_OFFSET offsetof(RISCVCPU, env)
+
+void riscv_cpu_do_interrupt(CPUState *cpu);
+void riscv_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
+                          int flags);
+hwaddr riscv_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
+int riscv_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
+bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request);
+void  riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
+                                    MMUAccessType access_type, int mmu_idx,
+                                    uintptr_t retaddr);
+#endif
+
+#if !defined(CONFIG_USER_ONLY)
+void riscv_cpu_unassigned_access(CPUState *cpu, hwaddr addr, bool is_write,
+        bool is_exec, int unused, unsigned size);
+#endif
+
+void riscv_cpu_list(FILE *f, fprintf_function cpu_fprintf);
+
+#define cpu_signal_handler cpu_riscv_signal_handler
+#define cpu_list riscv_cpu_list
+
+static int ctz(target_ulong val);
+int validate_priv(target_ulong priv);
+void set_privilege(CPURISCVState *env, target_ulong newpriv);
+unsigned int softfloat_flags_to_riscv(unsigned int flag);
+uint_fast16_t float32_classify(uint32_t a, float_status *status);
+uint_fast16_t float64_classify(uint64_t a, float_status *status);
+
+/*
+ * Compute mmu index
+ * Adapted from Spike's mmu_t::translate
+ */
+static inline int cpu_mmu_index(CPURISCVState *env, bool ifetch)
+{
+    target_ulong mode = env->priv;
+    if (!ifetch) {
+        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;
+    }
+    return mode;
+}
+
+/*
+ * ctz in Spike returns 0 if val == 0, wrap helper
+ */
+static int ctz(target_ulong val)
+{
+    return val ? ctz64(val) : 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_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);
+        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)
+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 */
+}
+
+#ifndef CONFIG_USER_ONLY
+void csr_write_helper(CPURISCVState *env, target_ulong val_to_write,
+        target_ulong csrno);
+target_ulong csr_read_helper(CPURISCVState *env, target_ulong csrno);
+#endif
+
+void validate_csr(CPURISCVState *env, uint64_t which, uint64_t write, uint64_t
+        new_pc);
+
+#include "exec/exec-all.h"
+
+#endif /* RISCV_CPU_H */
diff --git a/target-riscv/helper.c b/target-riscv/helper.c
new file mode 100644
index 0000000..dfdc7bd
--- /dev/null
+++ b/target-riscv/helper.c
@@ -0,0 +1,59 @@
+/*
+ *  RISC-V emulation helpers for qemu.
+ *
+ *  Author: Sagar Karandikar, sagark@eecs.berkeley.edu
+ *
+ *
+ * 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 <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <signal.h>
+#include "cpu.h"
+
+/*#define RISCV_DEBUG_INTERRUPT */
+
+#if !defined(CONFIG_USER_ONLY)
+
+bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
+{
+    return false;
+}
+
+hwaddr riscv_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
+{
+    return 0;
+}
+#endif
+
+int riscv_cpu_handle_mmu_fault(CPUState *cs, vaddr address,
+        MMUAccessType access_type, int mmu_idx)
+{
+    return 0;
+}
+
+/*
+ * Handle Traps
+ *
+ * Adapted from Spike's processor_t::take_trap.
+ *
+ */
+void riscv_cpu_do_interrupt(CPUState *cs)
+{
+}
diff --git a/target-riscv/helper.h b/target-riscv/helper.h
new file mode 100644
index 0000000..e69de29
diff --git a/target-riscv/op_helper.c b/target-riscv/op_helper.c
new file mode 100644
index 0000000..c77a520
--- /dev/null
+++ b/target-riscv/op_helper.c
@@ -0,0 +1,44 @@
+/*
+ * RISC-V Emulation Helpers for QEMU.
+ *
+ * Author: Sagar Karandikar, sagark@eecs.berkeley.edu
+ *
+ *
+ * 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)
+{
+}
+
+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)
+{
+}
+
+#endif /* !CONFIG_USER_ONLY */
diff --git a/target-riscv/translate.c b/target-riscv/translate.c
new file mode 100644
index 0000000..b50c662
--- /dev/null
+++ b/target-riscv/translate.c
@@ -0,0 +1,131 @@
+/*
+ * RISC-V emulation for qemu: main translation routines.
+ *
+ * Author: Sagar Karandikar, sagark@eecs.berkeley.edu
+ *
+ *
+ * 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 "cpu.h"
+#include "disas/disas.h"
+#include "tcg-op.h"
+#include "exec/cpu_ldst.h"
+
+#include "exec/helper-proto.h"
+#include "exec/helper-gen.h"
+
+static const char * const regnames[] = {
+  "zero", "ra  ", "sp  ", "gp  ", "tp  ", "t0  ",  "t1  ",  "t2  ",
+  "s0  ", "s1  ", "a0  ", "a1  ", "a2  ", "a3  ",  "a4  ",  "a5  ",
+  "a6  ", "a7  ", "s2  ", "s3  ", "s4  ", "s5  ",  "s6  ",  "s7  ",
+  "s8  ", "s9  ", "s10 ", "s11 ", "t3  ", "t4  ",  "t5  ",  "t6  "
+};
+
+static const char * const fpr_regnames[] = {
+  "ft0", "ft1", "ft2",  "ft3",  "ft4", "ft5", "ft6",  "ft7",
+  "fs0", "fs1", "fa0",  "fa1",  "fa2", "fa3", "fa4",  "fa5",
+  "fa6", "fa7", "fs2",  "fs3",  "fs4", "fs5", "fs6",  "fs7",
+  "fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11"
+};
+
+void gen_intermediate_code(CPURISCVState *env, TranslationBlock *tb)
+{
+}
+
+void riscv_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
+                         int flags)
+{
+    RISCVCPU *cpu = RISCV_CPU(cs);
+    CPURISCVState *env = &cpu->env;
+    int i;
+
+    cpu_fprintf(f, "pc=0x" TARGET_FMT_lx "\n", env->PC);
+    for (i = 0; i < 32; i++) {
+        cpu_fprintf(f, " %s " TARGET_FMT_lx, regnames[i], env->gpr[i]);
+        if ((i & 3) == 3) {
+            cpu_fprintf(f, "\n");
+        }
+    }
+
+    cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "MSTATUS ",
+                env->csr[CSR_MSTATUS]);
+    cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "MIP     ", env->csr[CSR_MIP]);
+    cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "MIE     ", env->csr[CSR_MIE]);
+
+    for (i = 0; i < 32; i++) {
+        if ((i & 3) == 0) {
+            cpu_fprintf(f, "FPR%02d:", i);
+        }
+        cpu_fprintf(f, " %s %016lx", fpr_regnames[i], env->fpr[i]);
+        if ((i & 3) == 3) {
+            cpu_fprintf(f, "\n");
+        }
+    }
+}
+
+void riscv_tcg_init(void)
+{
+}
+
+#define MCPUID_RV64I   (2L << (TARGET_LONG_BITS - 2))
+#define MCPUID_RV32I   (1L << (TARGET_LONG_BITS - 2))
+#define MCPUID_SUPER   (1L << ('S' - 'A'))
+#define MCPUID_USER    (1L << ('U' - 'A'))
+#define MCPUID_I       (1L << ('I' - 'A'))
+#define MCPUID_M       (1L << ('M' - 'A'))
+#define MCPUID_A       (1L << ('A' - 'A'))
+#define MCPUID_F       (1L << ('F' - 'A'))
+#define MCPUID_D       (1L << ('D' - 'A'))
+
+struct riscv_def_t {
+    const char *name;
+    uint64_t init_misa_reg;
+};
+
+/* RISC-V CPU definitions */
+static const riscv_def_t riscv_defs[] = {
+    {
+        .name = "riscv",
+#if defined(TARGET_RISCV64)
+        /* RV64G */
+        .init_misa_reg = MCPUID_RV64I | MCPUID_SUPER | MCPUID_USER | MCPUID_I
+            | MCPUID_M | MCPUID_A | MCPUID_F | MCPUID_D,
+#else
+        /* RV32G */
+        .init_misa_reg = MCPUID_RV32I | MCPUID_SUPER | MCPUID_USER | MCPUID_I
+            | MCPUID_M | MCPUID_A | MCPUID_F | MCPUID_D,
+#endif
+    },
+};
+
+void riscv_cpu_list(FILE *f, fprintf_function cpu_fprintf)
+{
+    int i;
+    for (i = 0; i < ARRAY_SIZE(riscv_defs); i++) {
+        (*cpu_fprintf)(f, "RISCV '%s'\n", riscv_defs[i].name);
+    }
+}
+
+RISCVCPU *cpu_riscv_init(const char *cpu_model)
+{
+    return NULL;
+}
+
+void restore_state_to_opc(CPURISCVState *env, TranslationBlock *tb,
+                          target_ulong *data)
+{
+    env->PC = data[0];
+}
-- 
2.9.3

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

* [Qemu-devel] [PATCH 03/18] target-riscv: Add initialization for translation
  2016-09-26 10:56 [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G) Sagar Karandikar
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 01/18] target-riscv: Add RISC-V target stubs and Maintainer Sagar Karandikar
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 02/18] target-riscv: Add RISC-V Target stubs inside target-riscv/ Sagar Karandikar
@ 2016-09-26 10:56 ` Sagar Karandikar
  2016-09-26 16:34   ` Richard Henderson
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 04/18] target-riscv: Add framework for instruction decode Sagar Karandikar
                   ` (15 subsequent siblings)
  18 siblings, 1 reply; 45+ messages in thread
From: Sagar Karandikar @ 2016-09-26 10:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, rth, kbastian, Sagar Karandikar

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

Signed-off-by: Sagar Karandikar <sagark@eecs.berkeley.edu>
---
 target-riscv/helper.h    |   4 +
 target-riscv/op_helper.c |  26 +++++
 target-riscv/translate.c | 244 ++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 273 insertions(+), 1 deletion(-)

diff --git a/target-riscv/helper.h b/target-riscv/helper.h
index e69de29..0461118 100644
--- a/target-riscv/helper.h
+++ b/target-riscv/helper.h
@@ -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)
diff --git a/target-riscv/op_helper.c b/target-riscv/op_helper.c
index c77a520..fd1ef3c 100644
--- a/target-riscv/op_helper.c
+++ b/target-riscv/op_helper.c
@@ -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,
diff --git a/target-riscv/translate.c b/target-riscv/translate.c
index b50c662..8413c39 100644
--- a/target-riscv/translate.c
+++ b/target-riscv/translate.c
@@ -27,6 +27,35 @@
 #include "exec/helper-proto.h"
 #include "exec/helper-gen.h"
 
+#define RISCV_DEBUG_DISAS 0
+
+/* global register indices */
+static TCGv_ptr cpu_env;
+static TCGv cpu_gpr[32], cpu_PC;
+static TCGv_i64 cpu_fpr[32]; /* assume F and D extensions */
+static TCGv load_res;
+
+#include "exec/gen-icount.h"
+
+typedef struct DisasContext {
+    struct TranslationBlock *tb;
+    target_ulong pc;
+    uint32_t opcode;
+    int singlestep_enabled;
+    int mem_idx;
+    int bstate;
+} DisasContext;
+
+static inline void kill_unknown(DisasContext *ctx, int excp);
+
+enum {
+    BS_NONE     = 0, /* When seen outside of translation while loop, indicates
+                     need to exit tb due to end of page. */
+    BS_STOP     = 1, /* Need to exit tb for syscall, sret, etc. */
+    BS_BRANCH   = 2, /* Need to exit tb for branch, jal, etc. */
+};
+
+
 static const char * const regnames[] = {
   "zero", "ra  ", "sp  ", "gp  ", "tp  ", "t0  ",  "t1  ",  "t2  ",
   "s0  ", "s1  ", "a0  ", "a1  ", "a2  ", "a3  ",  "a4  ",  "a5  ",
@@ -41,8 +70,160 @@ static const char * const fpr_regnames[] = {
   "fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11"
 };
 
+static inline void generate_exception(DisasContext *ctx, int excp)
+{
+    tcg_gen_movi_tl(cpu_PC, ctx->pc);
+    TCGv_i32 helper_tmp = tcg_const_i32(excp);
+    gen_helper_raise_exception(cpu_env, helper_tmp);
+    tcg_temp_free_i32(helper_tmp);
+}
+
+static inline void generate_exception_mbadaddr(DisasContext *ctx, int excp)
+{
+    tcg_gen_movi_tl(cpu_PC, ctx->pc);
+    TCGv_i32 helper_tmp = tcg_const_i32(excp);
+    gen_helper_raise_exception_mbadaddr(cpu_env, helper_tmp, cpu_PC);
+    tcg_temp_free_i32(helper_tmp);
+}
+
+/* unknown instruction */
+static inline void kill_unknown(DisasContext *ctx, int excp)
+{
+    generate_exception(ctx, excp);
+    ctx->bstate = BS_STOP;
+}
+
+static inline bool use_goto_tb(DisasContext *ctx, target_ulong dest)
+{
+    if (unlikely(ctx->singlestep_enabled)) {
+        return false;
+    }
+
+#ifndef CONFIG_USER_ONLY
+    return (ctx->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
+#else
+    return true;
+#endif
+}
+
+static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
+{
+    if (use_goto_tb(ctx, dest)) {
+        /* chaining is only allowed when the jump is to the same page */
+        tcg_gen_goto_tb(n);
+        tcg_gen_movi_tl(cpu_PC, dest);
+        tcg_gen_exit_tb((uintptr_t)ctx->tb + n);
+    } else {
+        tcg_gen_movi_tl(cpu_PC, dest);
+        if (ctx->singlestep_enabled) {
+            gen_helper_raise_exception_debug(cpu_env);
+        }
+        tcg_gen_exit_tb(0);
+    }
+}
+
+static void decode_opc(CPURISCVState *env, DisasContext *ctx)
+{
+}
+
 void gen_intermediate_code(CPURISCVState *env, TranslationBlock *tb)
 {
+    RISCVCPU *cpu = riscv_env_get_cpu(env);
+    CPUState *cs = CPU(cpu);
+    DisasContext ctx;
+    target_ulong pc_start;
+    target_ulong next_page_start;
+    int num_insns;
+    int max_insns;
+    pc_start = tb->pc;
+    next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
+    ctx.pc = pc_start;
+
+    /* once we have GDB, the rest of the translate.c implementation should be
+       ready for singlestep */
+    ctx.singlestep_enabled = cs->singlestep_enabled;
+
+    ctx.tb = tb;
+    ctx.bstate = BS_NONE;
+
+    ctx.mem_idx = cpu_mmu_index(env, false);
+    num_insns = 0;
+    max_insns = tb->cflags & CF_COUNT_MASK;
+    if (max_insns == 0) {
+        max_insns = CF_COUNT_MASK;
+    }
+    if (max_insns > TCG_MAX_INSNS) {
+        max_insns = TCG_MAX_INSNS;
+    }
+    gen_tb_start(tb);
+
+    while (ctx.bstate == BS_NONE) {
+        tcg_gen_insn_start(ctx.pc);
+        num_insns++;
+
+        if (unlikely(cpu_breakpoint_test(cs, ctx.pc, BP_ANY))) {
+            tcg_gen_movi_tl(cpu_PC, ctx.pc);
+            ctx.bstate = BS_BRANCH;
+            gen_helper_raise_exception_debug(cpu_env);
+            /* The address covered by the breakpoint must be included in
+               [tb->pc, tb->pc + tb->size) in order to for it to be
+               properly cleared -- thus we increment the PC here so that
+               the logic setting tb->size below does the right thing.  */
+            ctx.pc += 4;
+            goto done_generating;
+        }
+
+        if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
+            gen_io_start();
+        }
+
+        ctx.opcode = cpu_ldl_code(env, ctx.pc);
+        decode_opc(env, &ctx);
+        ctx.pc += 4;
+
+        if (cs->singlestep_enabled) {
+            break;
+        }
+        if (ctx.pc >= next_page_start) {
+            break;
+        }
+        if (tcg_op_buf_full()) {
+            break;
+        }
+        if (num_insns >= max_insns) {
+            break;
+        }
+        if (singlestep) {
+            break;
+        }
+
+    }
+    if (tb->cflags & CF_LAST_IO) {
+        gen_io_end();
+    }
+    if (cs->singlestep_enabled && ctx.bstate != BS_BRANCH) {
+        if (ctx.bstate == BS_NONE) {
+            tcg_gen_movi_tl(cpu_PC, ctx.pc);
+        }
+        gen_helper_raise_exception_debug(cpu_env);
+    } else {
+        switch (ctx.bstate) {
+        case BS_STOP:
+            gen_goto_tb(&ctx, 0, ctx.pc);
+            break;
+        case BS_NONE: /* handle end of page - DO NOT CHAIN. See gen_goto_tb. */
+            tcg_gen_movi_tl(cpu_PC, ctx.pc);
+            tcg_gen_exit_tb(0);
+            break;
+        case BS_BRANCH: /* ops using BS_BRANCH generate own exit seq */
+        default:
+            break;
+        }
+    }
+done_generating:
+    gen_tb_end(tb, num_insns);
+    tb->size = ctx.pc - pc_start;
+    tb->icount = num_insns;
 }
 
 void riscv_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
@@ -78,6 +259,34 @@ void riscv_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
 
 void riscv_tcg_init(void)
 {
+    int i;
+    static int inited;
+
+    /* Initialize various static tables. */
+    if (inited) {
+        return;
+    }
+
+    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+
+    /* WARNING: cpu_gpr[0] is not allocated ON PURPOSE. Do not use it. */
+    /* Use the gen_set_gpr and gen_get_gpr helper functions when accessing */
+    /* registers, unless you specifically block reads/writes to reg 0 */
+    TCGV_UNUSED(cpu_gpr[0]);
+    for (i = 1; i < 32; i++) {
+        cpu_gpr[i] = tcg_global_mem_new(cpu_env,
+                             offsetof(CPURISCVState, gpr[i]), regnames[i]);
+    }
+
+    for (i = 0; i < 32; i++) {
+        cpu_fpr[i] = tcg_global_mem_new_i64(cpu_env,
+                             offsetof(CPURISCVState, fpr[i]), fpr_regnames[i]);
+    }
+
+    cpu_PC = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, PC), "PC");
+    load_res = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, load_res),
+                             "load_res");
+    inited = 1;
 }
 
 #define MCPUID_RV64I   (2L << (TARGET_LONG_BITS - 2))
@@ -111,6 +320,17 @@ static const riscv_def_t riscv_defs[] = {
     },
 };
 
+static const riscv_def_t *cpu_riscv_find_by_name(const char *name)
+{
+    int i;
+    for (i = 0; i < ARRAY_SIZE(riscv_defs); i++) {
+        if (strcasecmp(name, riscv_defs[i].name) == 0) {
+            return &riscv_defs[i];
+        }
+    }
+    return NULL;
+}
+
 void riscv_cpu_list(FILE *f, fprintf_function cpu_fprintf)
 {
     int i;
@@ -121,7 +341,29 @@ void riscv_cpu_list(FILE *f, fprintf_function cpu_fprintf)
 
 RISCVCPU *cpu_riscv_init(const char *cpu_model)
 {
-    return NULL;
+    RISCVCPU *cpu;
+    CPURISCVState *env;
+    const riscv_def_t *def;
+
+    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));
+    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);
+
+    return cpu;
 }
 
 void restore_state_to_opc(CPURISCVState *env, TranslationBlock *tb,
-- 
2.9.3

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

* [Qemu-devel] [PATCH 04/18] target-riscv: Add framework for instruction decode
  2016-09-26 10:56 [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G) Sagar Karandikar
                   ` (2 preceding siblings ...)
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 03/18] target-riscv: Add initialization for translation Sagar Karandikar
@ 2016-09-26 10:56 ` Sagar Karandikar
  2016-09-26 16:49   ` Richard Henderson
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 05/18] target-riscv: Add Arithmetic instructions Sagar Karandikar
                   ` (14 subsequent siblings)
  18 siblings, 1 reply; 45+ messages in thread
From: Sagar Karandikar @ 2016-09-26 10:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, rth, kbastian, Sagar Karandikar

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

Signed-off-by: Sagar Karandikar <sagark@eecs.berkeley.edu>
---
 target-riscv/instmap.h   | 328 +++++++++++++++++++++++++++++++++++++++++++++++
 target-riscv/translate.c |  64 +++++++++
 2 files changed, 392 insertions(+)
 create mode 100644 target-riscv/instmap.h

diff --git a/target-riscv/instmap.h b/target-riscv/instmap.h
new file mode 100644
index 0000000..24f53c3
--- /dev/null
+++ b/target-riscv/instmap.h
@@ -0,0 +1,328 @@
+/*
+ * RISC-V emulation for qemu: Instruction decode helpers
+ *
+ * Author: Sagar Karandikar, sagark@eecs.berkeley.edu
+ *
+ *
+ * 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))
diff --git a/target-riscv/translate.c b/target-riscv/translate.c
index 8413c39..55f20ee 100644
--- a/target-riscv/translate.c
+++ b/target-riscv/translate.c
@@ -27,6 +27,8 @@
 #include "exec/helper-proto.h"
 #include "exec/helper-gen.h"
 
+#include "instmap.h"
+
 #define RISCV_DEBUG_DISAS 0
 
 /* global register indices */
@@ -124,6 +126,68 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
 
 static void decode_opc(CPURISCVState *env, DisasContext *ctx)
 {
+    int rd;
+    uint32_t op;
+    target_long ubimm;
+
+    /* We do not do misaligned address check here: the address should never be
+     * misaligned at this point. Instructions that set PC must do the check,
+     * since epc must be the address of the instruction that caused us to
+     * perform the misaligned instruction fetch */
+
+    op = MASK_OP_MAJOR(ctx->opcode);
+    rd = GET_RD(ctx->opcode);
+
+    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]);
+        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);
+        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
+            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);
+        }
+        break;
+    default:
+        kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+        break;
+    }
 }
 
 void gen_intermediate_code(CPURISCVState *env, TranslationBlock *tb)
-- 
2.9.3

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

* [Qemu-devel] [PATCH 05/18] target-riscv: Add Arithmetic instructions
  2016-09-26 10:56 [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G) Sagar Karandikar
                   ` (3 preceding siblings ...)
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 04/18] target-riscv: Add framework for instruction decode Sagar Karandikar
@ 2016-09-26 10:56 ` Sagar Karandikar
  2016-09-26 17:31   ` Richard Henderson
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 06/18] target-riscv: Add JALR, Branch Instructions Sagar Karandikar
                   ` (13 subsequent siblings)
  18 siblings, 1 reply; 45+ messages in thread
From: Sagar Karandikar @ 2016-09-26 10:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, rth, kbastian, Sagar Karandikar

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

Signed-off-by: Sagar Karandikar <sagark@eecs.berkeley.edu>
---
 target-riscv/helper.h    |   4 +
 target-riscv/op_helper.c |  10 ++
 target-riscv/translate.c | 338 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 352 insertions(+)

diff --git a/target-riscv/helper.h b/target-riscv/helper.h
index 0461118..c489222 100644
--- a/target-riscv/helper.h
+++ b/target-riscv/helper.h
@@ -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
diff --git a/target-riscv/op_helper.c b/target-riscv/op_helper.c
index fd1ef3c..1a7fb18 100644
--- a/target-riscv/op_helper.c
+++ b/target-riscv/op_helper.c
@@ -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,
diff --git a/target-riscv/translate.c b/target-riscv/translate.c
index 55f20ee..ccfb795 100644
--- a/target-riscv/translate.c
+++ b/target-riscv/translate.c
@@ -124,10 +124,327 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
     }
 }
 
+/* Wrapper for getting reg values - need to check of reg is zero since
+ * cpu_gpr[0] is not actually allocated
+ */
+static inline void gen_get_gpr(TCGv t, int reg_num)
+{
+    if (reg_num == 0) {
+        tcg_gen_movi_tl(t, 0);
+    } else {
+        tcg_gen_mov_tl(t, cpu_gpr[reg_num]);
+    }
+}
+
+/* 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);
+    }
+}
+
+static void gen_mulhsu(TCGv ret, TCGv arg1, TCGv arg2)
+{
+#if defined(TARGET_RISCV64)
+    gen_helper_mulhsu(ret, cpu_env, arg1, arg2);
+#else
+    TCGv_i64 t0 = tcg_temp_new_i64();
+    TCGv_i64 t1 = tcg_temp_new_i64();
+
+    tcg_gen_ext_i32_i64(t0, arg1);
+    tcg_gen_extu_i32_i64(t1, arg2);
+    tcg_gen_mul_i64(t0, t0, t1);
+
+    tcg_gen_shri_i64(t0, t0, 32);
+    tcg_gen_extrl_i64_i32(ret, t0);
+
+    tcg_temp_free_i64(t0);
+    tcg_temp_free_i64(t1);
+#endif
+}
+
+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 */
+
+    switch (opc) {
+#if defined(TARGET_RISCV64)
+    case OPC_RISC_ADDW:
+#endif
+    case OPC_RISC_ADD:
+        tcg_gen_add_tl(source1, source1, source2);
+        break;
+#if defined(TARGET_RISCV64)
+    case OPC_RISC_SUBW:
+#endif
+    case OPC_RISC_SUB:
+        tcg_gen_sub_tl(source1, source1, source2);
+        break;
+#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);
+        break;
+    case OPC_RISC_SLT:
+        tcg_gen_setcond_tl(TCG_COND_LT, source1, source1, source2);
+        break;
+    case OPC_RISC_SLTU:
+        tcg_gen_setcond_tl(TCG_COND_LTU, source1, source1, source2);
+        break;
+    case OPC_RISC_XOR:
+        tcg_gen_xor_tl(source1, source1, source2);
+        break;
+#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);
+        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);
+        tcg_gen_sar_tl(source1, source1, source2);
+        break;
+    case OPC_RISC_OR:
+        tcg_gen_or_tl(source1, source1, source2);
+        break;
+    case OPC_RISC_AND:
+        tcg_gen_and_tl(source1, source1, source2);
+        break;
+#if defined(TARGET_RISCV64)
+    case OPC_RISC_MULW:
+#endif
+    case OPC_RISC_MUL:
+        tcg_gen_muls2_tl(source1, source2, source1, source2);
+        break;
+    case OPC_RISC_MULH:
+        tcg_gen_muls2_tl(source2, source1, source1, source2);
+        break;
+    case OPC_RISC_MULHSU:
+        gen_mulhsu(source1, source1, source2);
+        break;
+    case OPC_RISC_MULHU:
+        tcg_gen_mulu2_tl(source2, source1, source1, source2);
+        break;
+#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);
+        tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, (target_ulong)(~0L));
+        tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source1,
+                            1L << (TARGET_LONG_BITS - 1));
+        tcg_gen_and_tl(cond1, cond1, cond2); /* cond1 = overflow */
+        tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, 0); /* cond2 = div 0 */
+        /* if div by zero, set source1 to -1, otherwise don't change */
+        tcg_gen_movcond_tl(TCG_COND_EQ, source1, cond2, zeroreg, source1,
+                resultopt1);
+        /* if overflow or div by zero, set source2 to 1, else don't change */
+        tcg_gen_or_tl(cond1, cond1, cond2);
+        tcg_gen_movi_tl(resultopt1, (target_ulong)1);
+        tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond1, zeroreg, source2,
+                resultopt1);
+        tcg_gen_div_tl(source1, source1, source2);
+        break;
+#if defined(TARGET_RISCV64)
+    case OPC_RISC_DIVUW:
+        tcg_gen_ext32u_tl(source1, source1);
+        tcg_gen_ext32u_tl(source2, source2);
+        /* fall through to DIVU */
+#endif
+    case OPC_RISC_DIVU:
+        tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0);
+        tcg_gen_movi_tl(resultopt1, (target_ulong)(~0L));
+        tcg_gen_movcond_tl(TCG_COND_EQ, source1, cond1, zeroreg, source1,
+                resultopt1);
+        tcg_gen_movi_tl(resultopt1, (target_ulong)(1L));
+        tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond1, zeroreg, source2,
+                resultopt1);
+        tcg_gen_divu_tl(source1, source1, source2);
+        break;
+#if defined(TARGET_RISCV64)
+    case OPC_RISC_REMW:
+        tcg_gen_ext32s_tl(source1, source1);
+        tcg_gen_ext32s_tl(source2, source2);
+        /* fall through to REM */
+#endif
+    case OPC_RISC_REM:
+        tcg_gen_movi_tl(resultopt1, 1L);
+        tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, (target_ulong)(~0L));
+        tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source1,
+                            1L << (TARGET_LONG_BITS - 1));
+        tcg_gen_and_tl(cond2, cond1, cond2); /* cond1 = overflow */
+        tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0); /* cond2 = div 0 */
+        /* if overflow or div by zero, set source2 to 1, else don't change */
+        tcg_gen_or_tl(cond2, cond1, cond2);
+        tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond2, zeroreg, source2,
+                resultopt1);
+        tcg_gen_rem_tl(resultopt1, source1, source2);
+        /* if div by zero, just return the original dividend */
+        tcg_gen_movcond_tl(TCG_COND_EQ, source1, cond1, zeroreg, resultopt1,
+                source1);
+        break;
+#if defined(TARGET_RISCV64)
+    case OPC_RISC_REMUW:
+        tcg_gen_ext32u_tl(source1, source1);
+        tcg_gen_ext32u_tl(source2, source2);
+        /* fall through to REMU */
+#endif
+    case OPC_RISC_REMU:
+        tcg_gen_movi_tl(resultopt1, 1L);
+        tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0);
+        tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond1, zeroreg, source2,
+                resultopt1);
+        tcg_gen_remu_tl(resultopt1, source1, source2);
+        /* if div by zero, just return the original dividend */
+        tcg_gen_movcond_tl(TCG_COND_EQ, source1, cond1, zeroreg, resultopt1,
+                source1);
+        break;
+    default:
+        kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+        break;
+    }
+
+    if (opc & 0x8) { /* sign extend for W instructions */
+        tcg_gen_ext32s_tl(source1, source1);
+    }
+
+    gen_set_gpr(rd, source1);
+    tcg_temp_free(source1);
+    tcg_temp_free(source2);
+    tcg_temp_free(cond1);
+    tcg_temp_free(cond2);
+    tcg_temp_free(zeroreg);
+    tcg_temp_free(resultopt1);
+}
+
+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 */
+    target_long extra_shamt = 0;
+
+    switch (opc) {
+    case OPC_RISC_ADDI:
+#if defined(TARGET_RISCV64)
+    case OPC_RISC_ADDIW:
+#endif
+        tcg_gen_addi_tl(source1, source1, uimm);
+        break;
+    case OPC_RISC_SLTI:
+        tcg_gen_setcondi_tl(TCG_COND_LT, source1, source1, uimm);
+        break;
+    case OPC_RISC_SLTIU:
+        tcg_gen_setcondi_tl(TCG_COND_LTU, source1, source1, uimm);
+        break;
+    case OPC_RISC_XORI:
+        tcg_gen_xori_tl(source1, source1, uimm);
+        break;
+    case OPC_RISC_ORI:
+        tcg_gen_ori_tl(source1, source1, uimm);
+        break;
+    case OPC_RISC_ANDI:
+        tcg_gen_andi_tl(source1, source1, uimm);
+        break;
+#if defined(TARGET_RISCV64)
+    case OPC_RISC_SLLIW:
+         if ((uimm >= 32)) {
+            kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+         }
+        /* fall through to SLLI */
+#endif
+    case OPC_RISC_SLLI:
+        if (uimm < TARGET_LONG_BITS) {
+            tcg_gen_shli_tl(source1, source1, uimm);
+        } else {
+            kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+        }
+        break;
+#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;
+        /* fall through to SHIFT_RIGHT_I */
+#endif
+    case OPC_RISC_SHIFT_RIGHT_I:
+        /* differentiate on IMM */
+        if ((uimm & 0x3ff) < TARGET_LONG_BITS) {
+            if (uimm & 0x400) {
+                /* SRAI[W] */
+                tcg_gen_sari_tl(source1, source1, (uimm ^ 0x400) + extra_shamt);
+            } else {
+                /* SRLI[W] */
+                tcg_gen_shri_tl(source1, source1, uimm + extra_shamt);
+            }
+        } else {
+            kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+        }
+        break;
+    default:
+        kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+        break;
+    }
+
+    if (opc & 0x8) { /* sign-extend for W instructions */
+        tcg_gen_ext32s_tl(source1, source1);
+    }
+
+    gen_set_gpr(rd, source1);
+    tcg_temp_free(source1);
+}
+
 static void decode_opc(CPURISCVState *env, DisasContext *ctx)
 {
+    int rs1;
+    int rs2;
     int rd;
     uint32_t op;
+    int16_t imm;
     target_long ubimm;
 
     /* We do not do misaligned address check here: the address should never be
@@ -136,7 +453,10 @@ static void decode_opc(CPURISCVState *env, DisasContext *ctx)
      * perform the misaligned instruction fetch */
 
     op = MASK_OP_MAJOR(ctx->opcode);
+    rs1 = GET_RS1(ctx->opcode);
+    rs2 = GET_RS2(ctx->opcode);
     rd = GET_RD(ctx->opcode);
+    imm = GET_IMM(ctx->opcode);
 
     switch (op) {
     case OPC_RISC_LUI:
@@ -184,6 +504,24 @@ static void decode_opc(CPURISCVState *env, DisasContext *ctx)
             tcg_temp_free(testpc);
         }
         break;
+    case OPC_RISC_ARITH_IMM:
+#if defined(TARGET_RISCV64)
+    case OPC_RISC_ARITH_IMM_W:
+#endif
+        if (rd == 0) {
+            break; /* NOP */
+        }
+        gen_arith_imm(ctx, MASK_OP_ARITH_IMM(ctx->opcode), rd, rs1, imm);
+        break;
+    case OPC_RISC_ARITH:
+#if defined(TARGET_RISCV64)
+    case OPC_RISC_ARITH_W:
+#endif
+        if (rd == 0) {
+            break; /* NOP */
+        }
+        gen_arith(ctx, MASK_OP_ARITH(ctx->opcode), rd, rs1, rs2);
+        break;
     default:
         kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
         break;
-- 
2.9.3

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

* [Qemu-devel] [PATCH 06/18] target-riscv: Add JALR, Branch Instructions
  2016-09-26 10:56 [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G) Sagar Karandikar
                   ` (4 preceding siblings ...)
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 05/18] target-riscv: Add Arithmetic instructions Sagar Karandikar
@ 2016-09-26 10:56 ` Sagar Karandikar
  2016-09-26 18:28   ` Richard Henderson
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 07/18] target-riscv: Add Loads/Stores, FP Loads/Stores Sagar Karandikar
                   ` (12 subsequent siblings)
  18 siblings, 1 reply; 45+ messages in thread
From: Sagar Karandikar @ 2016-09-26 10:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, rth, kbastian, Sagar Karandikar

Signed-off-by: Sagar Karandikar <sagark@eecs.berkeley.edu>
---
 target-riscv/translate.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 107 insertions(+)

diff --git a/target-riscv/translate.c b/target-riscv/translate.c
index ccfb795..d8044cf 100644
--- a/target-riscv/translate.c
+++ b/target-riscv/translate.c
@@ -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:
-- 
2.9.3

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

* [Qemu-devel] [PATCH 07/18] target-riscv: Add Loads/Stores, FP Loads/Stores
  2016-09-26 10:56 [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G) Sagar Karandikar
                   ` (5 preceding siblings ...)
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 06/18] target-riscv: Add JALR, Branch Instructions Sagar Karandikar
@ 2016-09-26 10:56 ` Sagar Karandikar
  2016-09-26 20:44   ` Richard Henderson
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 08/18] target-riscv: Add Atomic Instructions Sagar Karandikar
                   ` (11 subsequent siblings)
  18 siblings, 1 reply; 45+ messages in thread
From: Sagar Karandikar @ 2016-09-26 10:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, rth, kbastian, Sagar Karandikar

Signed-off-by: Sagar Karandikar <sagark@eecs.berkeley.edu>
---
 target-riscv/translate.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 117 insertions(+)

diff --git a/target-riscv/translate.c b/target-riscv/translate.c
index d8044cf..767cdbe 100644
--- a/target-riscv/translate.c
+++ b/target-riscv/translate.c
@@ -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;
-- 
2.9.3

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

* [Qemu-devel] [PATCH 08/18] target-riscv: Add Atomic Instructions
  2016-09-26 10:56 [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G) Sagar Karandikar
                   ` (6 preceding siblings ...)
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 07/18] target-riscv: Add Loads/Stores, FP Loads/Stores Sagar Karandikar
@ 2016-09-26 10:56 ` Sagar Karandikar
  2016-09-27 19:30   ` Richard Henderson
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 09/18] target-riscv: Add FMADD, FMSUB, FNMADD, FNMSUB Instructions, Sagar Karandikar
                   ` (10 subsequent siblings)
  18 siblings, 1 reply; 45+ messages in thread
From: Sagar Karandikar @ 2016-09-26 10:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, rth, kbastian, Sagar Karandikar

Signed-off-by: Sagar Karandikar <sagark@eecs.berkeley.edu>
---
 target-riscv/translate.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 154 insertions(+)

diff --git a/target-riscv/translate.c b/target-riscv/translate.c
index 767cdbe..af82eab 100644
--- a/target-riscv/translate.c
+++ b/target-riscv/translate.c
@@ -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;
-- 
2.9.3

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

* [Qemu-devel] [PATCH 09/18] target-riscv: Add FMADD, FMSUB, FNMADD, FNMSUB Instructions,
  2016-09-26 10:56 [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G) Sagar Karandikar
                   ` (7 preceding siblings ...)
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 08/18] target-riscv: Add Atomic Instructions Sagar Karandikar
@ 2016-09-26 10:56 ` Sagar Karandikar
  2016-09-26 21:15   ` Richard Henderson
  2016-09-27 19:20   ` Richard Henderson
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 10/18] target-riscv: Add Single Precision Floating-Point Instructions Sagar Karandikar
                   ` (9 subsequent siblings)
  18 siblings, 2 replies; 45+ messages in thread
From: Sagar Karandikar @ 2016-09-26 10:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, rth, kbastian, Sagar Karandikar

Along with FP helper infrastructure, changes to softfloat-specialize

Signed-off-by: Sagar Karandikar <sagark@eecs.berkeley.edu>
---
 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

diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h
index f5aed72..fa5986d 100644
--- a/fpu/softfloat-specialize.h
+++ b/fpu/softfloat-specialize.h
@@ -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);
diff --git a/target-riscv/Makefile.objs b/target-riscv/Makefile.objs
index cb448a8..0149732 100644
--- a/target-riscv/Makefile.objs
+++ b/target-riscv/Makefile.objs
@@ -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
diff --git a/target-riscv/fpu_helper.c b/target-riscv/fpu_helper.c
new file mode 100644
index 0000000..9023d10
--- /dev/null
+++ b/target-riscv/fpu_helper.c
@@ -0,0 +1,151 @@
+/*
+ * RISC-V FPU Emulation Helpers for QEMU.
+ *
+ * Author: Sagar Karandikar, sagark@eecs.berkeley.edu
+ *
+ *
+ * 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"
+
+/* 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
+ * 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]; })
+
+/* convert softfloat library flag numbers to RISC-V */
+unsigned int softfloat_flags_to_riscv(unsigned int flag)
+{
+    switch (flag) {
+    case float_flag_inexact:
+        return 1;
+    case float_flag_underflow:
+        return 2;
+    case float_flag_overflow:
+        return 4;
+    case float_flag_divbyzero:
+        return 8;
+    case float_flag_invalid:
+        return 16;
+    default:
+        return 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)
+
+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;
+}
+
+uint64_t helper_fmadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+                        uint64_t frs3, uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    frs1 = float64_muladd(frs1, frs2, frs3, 0, &env->fp_status);
+    set_fp_exceptions();
+    return frs1;
+}
+
+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);
+    set_fp_exceptions();
+    return frs1;
+}
+
+uint64_t helper_fmsub_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+                        uint64_t frs3, uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    frs1 = float64_muladd(frs1, frs2, frs3 ^ (uint64_t)INT64_MIN, 0,
+                          &env->fp_status);
+    set_fp_exceptions();
+    return frs1;
+}
+
+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);
+    set_fp_exceptions();
+    return frs1;
+}
+
+uint64_t helper_fnmsub_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+                         uint64_t frs3, uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    frs1 = float64_muladd(frs1 ^ (uint64_t)INT64_MIN, frs2, frs3, 0,
+                          &env->fp_status);
+    set_fp_exceptions();
+    return frs1;
+}
+
+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);
+    set_fp_exceptions();
+    return frs1;
+}
+
+uint64_t helper_fnmadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+                         uint64_t frs3, uint64_t rm)
+{
+    set_float_rounding_mode(RM, &env->fp_status);
+    frs1 = float64_muladd(frs1 ^ (uint64_t)INT64_MIN, frs2,
+                          frs3 ^ (uint64_t)INT64_MIN, 0, &env->fp_status);
+    set_fp_exceptions();
+    return frs1;
+}
diff --git a/target-riscv/helper.h b/target-riscv/helper.h
index c489222..586abae5 100644
--- a/target-riscv/helper.h
+++ b/target-riscv/helper.h
@@ -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)
diff --git a/target-riscv/translate.c b/target-riscv/translate.c
index af82eab..07f24e8 100644
--- a/target-riscv/translate.c
+++ b/target-riscv/translate.c
@@ -792,6 +792,95 @@ static inline void gen_atomic(DisasContext *ctx, uint32_t opc,
     tcg_temp_free(dat);
 }
 
+static inline void gen_fp_fmadd(DisasContext *ctx, uint32_t opc, int rd,
+        int rs1, int rs2, int rs3, int rm)
+{
+    TCGv_i64 rm_reg = tcg_temp_new_i64();
+    tcg_gen_movi_i64(rm_reg, rm);
+
+    switch (opc) {
+    case OPC_RISC_FMADD_S:
+        gen_helper_fmadd_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2],
+                           cpu_fpr[rs3], rm_reg);
+        break;
+    case OPC_RISC_FMADD_D:
+        gen_helper_fmadd_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2],
+                           cpu_fpr[rs3], rm_reg);
+        break;
+    default:
+        kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+        break;
+    }
+    tcg_temp_free_i64(rm_reg);
+
+}
+
+static inline void gen_fp_fmsub(DisasContext *ctx, uint32_t opc, int rd,
+        int rs1, int rs2, int rs3, int rm)
+{
+    TCGv_i64 rm_reg = tcg_temp_new_i64();
+    tcg_gen_movi_i64(rm_reg, rm);
+
+    switch (opc) {
+    case OPC_RISC_FMSUB_S:
+        gen_helper_fmsub_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2],
+                           cpu_fpr[rs3], rm_reg);
+        break;
+    case OPC_RISC_FMSUB_D:
+        gen_helper_fmsub_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2],
+                           cpu_fpr[rs3], rm_reg);
+        break;
+    default:
+        kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+        break;
+    }
+    tcg_temp_free_i64(rm_reg);
+}
+
+static inline void gen_fp_fnmsub(DisasContext *ctx, uint32_t opc, int rd,
+        int rs1, int rs2, int rs3, int rm)
+{
+    TCGv_i64 rm_reg = tcg_temp_new_i64();
+    tcg_gen_movi_i64(rm_reg, rm);
+
+    switch (opc) {
+    case OPC_RISC_FNMSUB_S:
+        gen_helper_fnmsub_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2],
+                            cpu_fpr[rs3], rm_reg);
+        break;
+    case OPC_RISC_FNMSUB_D:
+        gen_helper_fnmsub_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2],
+                            cpu_fpr[rs3], rm_reg);
+        break;
+    default:
+        kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+        break;
+    }
+    tcg_temp_free_i64(rm_reg);
+}
+
+static inline void gen_fp_fnmadd(DisasContext *ctx, uint32_t opc, int rd,
+        int rs1, int rs2, int rs3, int rm)
+{
+    TCGv_i64 rm_reg = tcg_temp_new_i64();
+    tcg_gen_movi_i64(rm_reg, rm);
+
+    switch (opc) {
+    case OPC_RISC_FNMADD_S:
+        gen_helper_fnmadd_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2],
+                            cpu_fpr[rs3], rm_reg);
+        break;
+    case OPC_RISC_FNMADD_D:
+        gen_helper_fnmadd_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2],
+                            cpu_fpr[rs3], rm_reg);
+        break;
+    default:
+        kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+        break;
+    }
+    tcg_temp_free_i64(rm_reg);
+}
+
 static void decode_opc(CPURISCVState *env, DisasContext *ctx)
 {
     int rs1;
@@ -900,6 +989,22 @@ static void decode_opc(CPURISCVState *env, DisasContext *ctx)
     case OPC_RISC_ATOMIC:
         gen_atomic(ctx, MASK_OP_ATOMIC(ctx->opcode), rd, rs1, rs2);
         break;
+    case OPC_RISC_FMADD:
+        gen_fp_fmadd(ctx, MASK_OP_FP_FMADD(ctx->opcode), rd, rs1, rs2,
+                     GET_RS3(ctx->opcode), GET_RM(ctx->opcode));
+        break;
+    case OPC_RISC_FMSUB:
+        gen_fp_fmsub(ctx, MASK_OP_FP_FMSUB(ctx->opcode), rd, rs1, rs2,
+                     GET_RS3(ctx->opcode), GET_RM(ctx->opcode));
+        break;
+    case OPC_RISC_FNMSUB:
+        gen_fp_fnmsub(ctx, MASK_OP_FP_FNMSUB(ctx->opcode), rd, rs1, rs2,
+                      GET_RS3(ctx->opcode), GET_RM(ctx->opcode));
+        break;
+    case OPC_RISC_FNMADD:
+        gen_fp_fnmadd(ctx, MASK_OP_FP_FNMADD(ctx->opcode), rd, rs1, rs2,
+                      GET_RS3(ctx->opcode), GET_RM(ctx->opcode));
+        break;
     default:
         kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
         break;
-- 
2.9.3

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

* [Qemu-devel] [PATCH 10/18] target-riscv: Add Single Precision Floating-Point Instructions
  2016-09-26 10:56 [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G) Sagar Karandikar
                   ` (8 preceding siblings ...)
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 09/18] target-riscv: Add FMADD, FMSUB, FNMADD, FNMSUB Instructions, Sagar Karandikar
@ 2016-09-26 10:56 ` Sagar Karandikar
  2016-09-26 21:35   ` Richard Henderson
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 11/18] target-riscv: Add Double " Sagar Karandikar
                   ` (8 subsequent siblings)
  18 siblings, 1 reply; 45+ messages in thread
From: Sagar Karandikar @ 2016-09-26 10:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, rth, kbastian, Sagar Karandikar

Signed-off-by: Sagar Karandikar <sagark@eecs.berkeley.edu>
---
 target-riscv/fpu_helper.c | 206 ++++++++++++++++++++++++++++++++++++++++++++++
 target-riscv/helper.h     |  28 +++++++
 target-riscv/translate.c  | 146 ++++++++++++++++++++++++++++++++
 3 files changed, 380 insertions(+)

diff --git a/target-riscv/fpu_helper.c b/target-riscv/fpu_helper.c
index 9023d10..8d33fa1 100644
--- a/target-riscv/fpu_helper.c
+++ b/target-riscv/fpu_helper.c
@@ -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;
+}
diff --git a/target-riscv/helper.h b/target-riscv/helper.h
index 586abae5..85b505a 100644
--- a/target-riscv/helper.h
+++ b/target-riscv/helper.h
@@ -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)
diff --git a/target-riscv/translate.c b/target-riscv/translate.c
index 07f24e8..4140769 100644
--- a/target-riscv/translate.c
+++ b/target-riscv/translate.c
@@ -881,6 +881,148 @@ static inline void gen_fp_fnmadd(DisasContext *ctx, uint32_t opc, int rd,
     tcg_temp_free_i64(rm_reg);
 }
 
+static inline void gen_fp_arith(DisasContext *ctx, uint32_t opc, int rd,
+        int rs1, int rs2, int rm)
+{
+    TCGv_i64 rm_reg = tcg_temp_new_i64();
+    TCGv write_int_rd = tcg_temp_new();
+    tcg_gen_movi_i64(rm_reg, rm);
+
+    switch (opc) {
+    case OPC_RISC_FADD_S:
+        gen_helper_fadd_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2],
+                          rm_reg);
+        break;
+    case OPC_RISC_FSUB_S:
+        gen_helper_fsub_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2],
+                          rm_reg);
+        break;
+    case OPC_RISC_FMUL_S:
+        gen_helper_fmul_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2],
+                          rm_reg);
+        break;
+    case OPC_RISC_FDIV_S:
+        gen_helper_fdiv_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2],
+                          rm_reg);
+        break;
+    case OPC_RISC_FSGNJ_S:
+        /* also handles: OPC_RISC_FSGNJN_S, OPC_RISC_FSGNJX_S */
+        if (rm == 0x0) {
+            gen_helper_fsgnj_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1],
+                               cpu_fpr[rs2]);
+        } else if (rm == 0x1) {
+            gen_helper_fsgnjn_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1],
+                                cpu_fpr[rs2]);
+        } else if (rm == 0x2) {
+            gen_helper_fsgnjx_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1],
+                                cpu_fpr[rs2]);
+        } else {
+            kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+        }
+        break;
+    case OPC_RISC_FMIN_S:
+        /* also handles: OPC_RISC_FMAX_S */
+        if (rm == 0x0) {
+            gen_helper_fmin_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
+        } else if (rm == 0x1) {
+            gen_helper_fmax_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
+        } else {
+            kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+        }
+        break;
+    case OPC_RISC_FSQRT_S:
+        gen_helper_fsqrt_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], rm_reg);
+        break;
+    case OPC_RISC_FEQ_S:
+        /* also handles: OPC_RISC_FLT_S, OPC_RISC_FLE_S */
+        if (rm == 0x0) {
+            gen_helper_fle_s(write_int_rd, cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
+        } else if (rm == 0x1) {
+            gen_helper_flt_s(write_int_rd, cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
+        } else if (rm == 0x2) {
+            gen_helper_feq_s(write_int_rd, cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
+        } else {
+            kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+        }
+        gen_set_gpr(rd, write_int_rd);
+        break;
+    case OPC_RISC_FCVT_W_S:
+        /* also OPC_RISC_FCVT_WU_S, OPC_RISC_FCVT_L_S, OPC_RISC_FCVT_LU_S */
+        if (rs2 == 0x0) { /* FCVT_W_S */
+            gen_helper_fcvt_w_s(write_int_rd, cpu_env, cpu_fpr[rs1], rm_reg);
+        } else if (rs2 == 0x1) { /* FCVT_WU_S */
+            gen_helper_fcvt_wu_s(write_int_rd, cpu_env, cpu_fpr[rs1], rm_reg);
+        } else if (rs2 == 0x2) { /* FCVT_L_S */
+#if defined(TARGET_RISCV64)
+            gen_helper_fcvt_l_s(write_int_rd, cpu_env, cpu_fpr[rs1], rm_reg);
+#else
+            kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+#endif
+        } else if (rs2 == 0x3) { /* FCVT_LU_S */
+#if defined(TARGET_RISCV64)
+            gen_helper_fcvt_lu_s(write_int_rd, cpu_env, cpu_fpr[rs1], rm_reg);
+#else
+            kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+#endif
+        } else {
+            kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+        }
+        gen_set_gpr(rd, write_int_rd);
+        break;
+    case OPC_RISC_FCVT_S_W:
+        /* also OPC_RISC_FCVT_S_WU, OPC_RISC_FCVT_S_L, OPC_RISC_FCVT_S_LU */
+        gen_get_gpr(write_int_rd, rs1);
+        if (rs2 == 0) { /* FCVT_S_W */
+            gen_helper_fcvt_s_w(cpu_fpr[rd], cpu_env, write_int_rd, rm_reg);
+        } else if (rs2 == 0x1) { /* FCVT_S_WU */
+            gen_helper_fcvt_s_wu(cpu_fpr[rd], cpu_env, write_int_rd, rm_reg);
+        } else if (rs2 == 0x2) { /* FCVT_S_L */
+#if defined(TARGET_RISCV64)
+            gen_helper_fcvt_s_l(cpu_fpr[rd], cpu_env, write_int_rd, rm_reg);
+#else
+            kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+#endif
+        } else if (rs2 == 0x3) { /* FCVT_S_LU */
+#if defined(TARGET_RISCV64)
+            gen_helper_fcvt_s_lu(cpu_fpr[rd], cpu_env, write_int_rd, rm_reg);
+#else
+            kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+#endif
+        } else {
+            kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+        }
+        break;
+    case OPC_RISC_FMV_X_S:
+        /* also OPC_RISC_FCLASS_S */
+        if (rm == 0x0) { /* FMV */
+#if defined(TARGET_RISCV64)
+            tcg_gen_ext32s_tl(write_int_rd, cpu_fpr[rs1]);
+#else
+            tcg_gen_extrl_i64_i32(write_int_rd, cpu_fpr[rs1]);
+#endif
+        } else if (rm == 0x1) {
+            gen_helper_fclass_s(write_int_rd, cpu_env, cpu_fpr[rs1]);
+        } else {
+            kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+        }
+        gen_set_gpr(rd, write_int_rd);
+        break;
+    case OPC_RISC_FMV_S_X:
+        gen_get_gpr(write_int_rd, rs1);
+#if defined(TARGET_RISCV64)
+        tcg_gen_mov_tl(cpu_fpr[rd], write_int_rd);
+#else
+        tcg_gen_extu_i32_i64(cpu_fpr[rd], write_int_rd);
+#endif
+        break;
+    default:
+        kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+        break;
+    }
+    tcg_temp_free_i64(rm_reg);
+    tcg_temp_free(write_int_rd);
+}
+
 static void decode_opc(CPURISCVState *env, DisasContext *ctx)
 {
     int rs1;
@@ -1005,6 +1147,10 @@ static void decode_opc(CPURISCVState *env, DisasContext *ctx)
         gen_fp_fnmadd(ctx, MASK_OP_FP_FNMADD(ctx->opcode), rd, rs1, rs2,
                       GET_RS3(ctx->opcode), GET_RM(ctx->opcode));
         break;
+    case OPC_RISC_FP_ARITH:
+        gen_fp_arith(ctx, MASK_OP_FP_ARITH(ctx->opcode), rd, rs1, rs2,
+                     GET_RM(ctx->opcode));
+        break;
     default:
         kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
         break;
-- 
2.9.3

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

* [Qemu-devel] [PATCH 11/18] target-riscv: Add Double Precision Floating-Point Instructions
  2016-09-26 10:56 [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G) Sagar Karandikar
                   ` (9 preceding siblings ...)
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 10/18] target-riscv: Add Single Precision Floating-Point Instructions Sagar Karandikar
@ 2016-09-26 10:56 ` Sagar Karandikar
  2016-09-26 21:37   ` Richard Henderson
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 12/18] target-riscv: Add system instructions Sagar Karandikar
                   ` (7 subsequent siblings)
  18 siblings, 1 reply; 45+ messages in thread
From: Sagar Karandikar @ 2016-09-26 10:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, rth, kbastian, Sagar Karandikar

Signed-off-by: Sagar Karandikar <sagark@eecs.berkeley.edu>
---
 target-riscv/fpu_helper.c | 225 ++++++++++++++++++++++++++++++++++++++++++++++
 target-riscv/helper.h     |  30 +++++++
 target-riscv/translate.c  | 135 ++++++++++++++++++++++++++++
 3 files changed, 390 insertions(+)

diff --git a/target-riscv/fpu_helper.c b/target-riscv/fpu_helper.c
index 8d33fa1..b3d443e 100644
--- a/target-riscv/fpu_helper.c
+++ b/target-riscv/fpu_helper.c
@@ -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;
+}
diff --git a/target-riscv/helper.h b/target-riscv/helper.h
index 85b505a..eeb1caf 100644
--- a/target-riscv/helper.h
+++ b/target-riscv/helper.h
@@ -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)
diff --git a/target-riscv/translate.c b/target-riscv/translate.c
index 4140769..de39276 100644
--- a/target-riscv/translate.c
+++ b/target-riscv/translate.c
@@ -1015,6 +1015,141 @@ static inline void gen_fp_arith(DisasContext *ctx, uint32_t opc, int rd,
         tcg_gen_extu_i32_i64(cpu_fpr[rd], write_int_rd);
 #endif
         break;
+    /* double */
+    case OPC_RISC_FADD_D:
+        gen_helper_fadd_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2],
+                          rm_reg);
+        break;
+    case OPC_RISC_FSUB_D:
+        gen_helper_fsub_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2],
+                          rm_reg);
+        break;
+    case OPC_RISC_FMUL_D:
+        gen_helper_fmul_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2],
+                          rm_reg);
+        break;
+    case OPC_RISC_FDIV_D:
+        gen_helper_fdiv_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2],
+                          rm_reg);
+        break;
+    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],
+                               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);
+        }
+        break;
+    case OPC_RISC_FMIN_D:
+        /* also OPC_RISC_FMAX_D */
+        if (rm == 0x0) {
+            gen_helper_fmin_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
+        } else if (rm == 0x1) {
+            gen_helper_fmax_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
+        } else {
+            kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+        }
+        break;
+    case OPC_RISC_FCVT_S_D:
+        if (rs2 == 0x1) {
+            gen_helper_fcvt_s_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], rm_reg);
+        } else {
+            kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+        }
+        break;
+    case OPC_RISC_FCVT_D_S:
+        if (rs2 == 0x0) {
+            gen_helper_fcvt_d_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], rm_reg);
+        } else {
+            kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+        }
+        break;
+    case OPC_RISC_FSQRT_D:
+        gen_helper_fsqrt_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], rm_reg);
+        break;
+    case OPC_RISC_FEQ_D:
+        /* also OPC_RISC_FLT_D, OPC_RISC_FLE_D */
+        if (rm == 0x0) {
+            gen_helper_fle_d(write_int_rd, cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
+        } else if (rm == 0x1) {
+            gen_helper_flt_d(write_int_rd, cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
+        } else if (rm == 0x2) {
+            gen_helper_feq_d(write_int_rd, cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
+        } else {
+            kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+        }
+        gen_set_gpr(rd, write_int_rd);
+        break;
+    case OPC_RISC_FCVT_W_D:
+        /* also OPC_RISC_FCVT_WU_D, OPC_RISC_FCVT_L_D, OPC_RISC_FCVT_LU_D */
+        if (rs2 == 0x0) {
+            gen_helper_fcvt_w_d(write_int_rd, cpu_env, cpu_fpr[rs1], rm_reg);
+        } else if (rs2 == 0x1) {
+            gen_helper_fcvt_wu_d(write_int_rd, cpu_env, cpu_fpr[rs1], rm_reg);
+        } else if (rs2 == 0x2) {
+#if defined(TARGET_RISCV64)
+            gen_helper_fcvt_l_d(write_int_rd, cpu_env, cpu_fpr[rs1], rm_reg);
+#else
+            kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+#endif
+        } else if (rs2 == 0x3) {
+#if defined(TARGET_RISCV64)
+            gen_helper_fcvt_lu_d(write_int_rd, cpu_env, cpu_fpr[rs1], rm_reg);
+#else
+            kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+#endif
+        } else {
+            kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+        }
+        gen_set_gpr(rd, write_int_rd);
+        break;
+    case OPC_RISC_FCVT_D_W:
+        /* also OPC_RISC_FCVT_D_WU, OPC_RISC_FCVT_D_L, OPC_RISC_FCVT_D_LU */
+        gen_get_gpr(write_int_rd, rs1);
+        if (rs2 == 0x0) {
+            gen_helper_fcvt_d_w(cpu_fpr[rd], cpu_env, write_int_rd, rm_reg);
+        } else if (rs2 == 0x1) {
+            gen_helper_fcvt_d_wu(cpu_fpr[rd], cpu_env, write_int_rd, rm_reg);
+        } else if (rs2 == 0x2) {
+#if defined(TARGET_RISCV64)
+            gen_helper_fcvt_d_l(cpu_fpr[rd], cpu_env, write_int_rd, rm_reg);
+#else
+            kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+#endif
+        } else if (rs2 == 0x3) {
+#if defined(TARGET_RISCV64)
+            gen_helper_fcvt_d_lu(cpu_fpr[rd], cpu_env, write_int_rd, rm_reg);
+#else
+            kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+#endif
+        } else {
+            kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+        }
+        break;
+#if defined(TARGET_RISCV64)
+    case OPC_RISC_FMV_X_D:
+        /* also OPC_RISC_FCLASS_D */
+        if (rm == 0x0) { /* FMV */
+            tcg_gen_mov_tl(write_int_rd, cpu_fpr[rs1]);
+        } else if (rm == 0x1) {
+            gen_helper_fclass_d(write_int_rd, cpu_env, cpu_fpr[rs1]);
+        } else {
+            kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+        }
+        gen_set_gpr(rd, write_int_rd);
+        break;
+    case OPC_RISC_FMV_D_X:
+        gen_get_gpr(write_int_rd, rs1);
+        tcg_gen_mov_tl(cpu_fpr[rd], write_int_rd);
+        break;
+#endif
     default:
         kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
         break;
-- 
2.9.3

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

* [Qemu-devel] [PATCH 12/18] target-riscv: Add system instructions
  2016-09-26 10:56 [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G) Sagar Karandikar
                   ` (10 preceding siblings ...)
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 11/18] target-riscv: Add Double " Sagar Karandikar
@ 2016-09-26 10:56 ` Sagar Karandikar
  2016-09-26 12:21   ` Paolo Bonzini
  2016-09-26 21:41   ` Richard Henderson
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 13/18] target-riscv: Add CSR read/write helpers Sagar Karandikar
                   ` (6 subsequent siblings)
  18 siblings, 2 replies; 45+ messages in thread
From: Sagar Karandikar @ 2016-09-26 10:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, rth, kbastian, Sagar Karandikar

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

Signed-off-by: Sagar Karandikar <sagark@eecs.berkeley.edu>
---
 target-riscv/helper.h    |  11 ++++
 target-riscv/op_helper.c | 144 +++++++++++++++++++++++++++++++++++++++++++++++
 target-riscv/translate.c | 119 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 274 insertions(+)

diff --git a/target-riscv/helper.h b/target-riscv/helper.h
index eeb1caf..a87a0ba 100644
--- a/target-riscv/helper.h
+++ b/target-riscv/helper.h
@@ -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 */
diff --git a/target-riscv/op_helper.c b/target-riscv/op_helper.c
index 1a7fb18..ee51f02 100644
--- a/target-riscv/op_helper.c
+++ b/target-riscv/op_helper.c
@@ -24,6 +24,21 @@
 #include "qemu/host-utils.h"
 #include "exec/helper-proto.h"
 
+int validate_priv(target_ulong priv)
+{
+    return priv == PRV_U || priv == PRV_S || priv == PRV_M;
+}
+
+void set_privilege(CPURISCVState *env, target_ulong newpriv)
+{
+    if (!validate_priv(newpriv)) {
+        printf("INVALID PRIV SET\n");
+        exit(1);
+    }
+    helper_tlb_flush(env);
+    env->priv = newpriv;
+}
+
 /* Exceptions processing helpers */
 static inline void QEMU_NORETURN do_raise_exception_err(CPURISCVState *env,
                                           uint32_t exception, uintptr_t pc)
@@ -60,7 +75,136 @@ target_ulong helper_mulhsu(CPURISCVState *env, target_ulong arg1,
 }
 #endif
 
+/*
+ * Handle writes to CSRs and any resulting special behavior
+ *
+ * Adapted from Spike's processor_t::set_csr
+ */
+inline void csr_write_helper(CPURISCVState *env, target_ulong val_to_write,
+        target_ulong csrno)
+{
+}
+
+/*
+ * Handle reads to CSRs and any resulting special behavior
+ *
+ * Adapted from Spike's processor_t::get_csr
+ */
+inline target_ulong csr_read_helper(CPURISCVState *env, target_ulong csrno)
+{
+    return 0;
+}
+
+/*
+ * Check that CSR access is allowed.
+ *
+ * Adapted from Spike's decode.h:validate_csr
+ */
+void validate_csr(CPURISCVState *env, uint64_t which, uint64_t write,
+        uint64_t new_pc) {
+    unsigned csr_priv = get_field((which), 0x300);
+    unsigned csr_read_only = get_field((which), 0xC00) == 3;
+    if (((write) && csr_read_only) || (env->priv < csr_priv)) {
+        do_raise_exception_err(env, RISCV_EXCP_ILLEGAL_INST, new_pc);
+    }
+    return;
+}
+
+target_ulong helper_csrrw(CPURISCVState *env, target_ulong src,
+        target_ulong csr, target_ulong new_pc)
+{
+    validate_csr(env, csr, 1, new_pc);
+    uint64_t csr_backup = csr_read_helper(env, csr);
+    csr_write_helper(env, src, csr);
+    return csr_backup;
+}
+
+target_ulong helper_csrrs(CPURISCVState *env, target_ulong src,
+        target_ulong csr, target_ulong new_pc, target_ulong rs1_pass)
+{
+    validate_csr(env, csr, rs1_pass != 0, new_pc);
+    uint64_t csr_backup = csr_read_helper(env, csr);
+    if (rs1_pass != 0) {
+        csr_write_helper(env, src | csr_backup, csr);
+    }
+    return csr_backup;
+}
+
+target_ulong helper_csrrc(CPURISCVState *env, target_ulong src,
+        target_ulong csr, target_ulong new_pc, target_ulong rs1_pass) {
+    validate_csr(env, csr, rs1_pass != 0, new_pc);
+    uint64_t csr_backup = csr_read_helper(env, csr);
+    if (rs1_pass != 0) {
+        csr_write_helper(env, (~src) & csr_backup, csr);
+    }
+    return csr_backup;
+}
+
+target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
+{
+    if (!(env->priv >= PRV_S)) {
+        helper_raise_exception(env, RISCV_EXCP_ILLEGAL_INST);
+    }
+
+    target_ulong retpc = env->csr[CSR_SEPC];
+    if (retpc & 0x3) {
+        helper_raise_exception(env, RISCV_EXCP_INST_ADDR_MIS);
+    }
+
+    target_ulong mstatus = env->csr[CSR_MSTATUS];
+    target_ulong prev_priv = get_field(mstatus, MSTATUS_SPP);
+    mstatus = set_field(mstatus, MSTATUS_UIE << prev_priv,
+                        get_field(mstatus, MSTATUS_SPIE));
+    mstatus = set_field(mstatus, MSTATUS_SPIE, 0);
+    mstatus = set_field(mstatus, MSTATUS_SPP, PRV_U);
+    set_privilege(env, prev_priv);
+    csr_write_helper(env, mstatus, CSR_MSTATUS);
+
+    return retpc;
+}
+
+target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb)
+{
+    if (!(env->priv >= PRV_M)) {
+        helper_raise_exception(env, RISCV_EXCP_ILLEGAL_INST);
+    }
+
+    target_ulong retpc = env->csr[CSR_MEPC];
+    if (retpc & 0x3) {
+        helper_raise_exception(env, RISCV_EXCP_INST_ADDR_MIS);
+    }
+
+    target_ulong mstatus = env->csr[CSR_MSTATUS];
+    target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP);
+    mstatus = set_field(mstatus, MSTATUS_UIE << prev_priv,
+                        get_field(mstatus, MSTATUS_MPIE));
+    mstatus = set_field(mstatus, MSTATUS_MPIE, 0);
+    mstatus = set_field(mstatus, MSTATUS_MPP, PRV_U);
+    set_privilege(env, prev_priv);
+    csr_write_helper(env, mstatus, CSR_MSTATUS);
+
+    return retpc;
+}
+
 #ifndef CONFIG_USER_ONLY
+
+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);
+}
+
+void helper_tlb_flush(CPURISCVState *env)
+{
+    RISCVCPU *cpu = riscv_env_get_cpu(env);
+    tlb_flush(CPU(cpu), 1);
+}
+
 void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
                                    MMUAccessType access_type, int mmu_idx,
                                    uintptr_t retaddr)
diff --git a/target-riscv/translate.c b/target-riscv/translate.c
index de39276..51d2bf9 100644
--- a/target-riscv/translate.c
+++ b/target-riscv/translate.c
@@ -1158,6 +1158,112 @@ static inline void gen_fp_arith(DisasContext *ctx, uint32_t opc, int rd,
     tcg_temp_free(write_int_rd);
 }
 
+static inline void gen_system(DisasContext *ctx, uint32_t opc,
+                      int rd, int rs1, int csr)
+{
+    TCGv source1, csr_store, dest, rs1_pass, imm_rs1;
+    source1 = tcg_temp_new();
+    csr_store = tcg_temp_new();
+    dest = tcg_temp_new();
+    rs1_pass = tcg_temp_new();
+    imm_rs1 = tcg_temp_new();
+    gen_get_gpr(source1, rs1);
+    tcg_gen_movi_tl(rs1_pass, rs1);
+    tcg_gen_movi_tl(csr_store, csr); /* copy into temp reg to feed to helper */
+
+    switch (opc) {
+    case OPC_RISC_ECALL:
+        switch (csr) {
+        case 0x0: /* ECALL */
+            /* always generates U-level ECALL, fixed in do_interrupt handler */
+            generate_exception(ctx, RISCV_EXCP_U_ECALL);
+            tcg_gen_exit_tb(0); /* no chaining */
+            ctx->bstate = BS_BRANCH;
+            break;
+        case 0x1: /* EBREAK */
+            generate_exception(ctx, RISCV_EXCP_BREAKPOINT);
+            tcg_gen_exit_tb(0); /* no chaining */
+            ctx->bstate = BS_BRANCH;
+            break;
+        case 0x002: /* URET */
+            printf("URET unimplemented\n");
+            exit(1);
+            break;
+        case 0x102: /* SRET */
+            tcg_gen_movi_tl(cpu_PC, ctx->pc);
+            gen_helper_sret(cpu_PC, cpu_env, cpu_PC);
+            tcg_gen_exit_tb(0); /* no chaining */
+            ctx->bstate = BS_BRANCH;
+            break;
+        case 0x202: /* HRET */
+            printf("HRET unimplemented\n");
+            exit(1);
+            break;
+        case 0x302: /* MRET */
+            tcg_gen_movi_tl(cpu_PC, ctx->pc);
+            gen_helper_mret(cpu_PC, cpu_env, cpu_PC);
+            tcg_gen_exit_tb(0); /* no chaining */
+            ctx->bstate = BS_BRANCH;
+            break;
+        case 0x7b2: /* DRET */
+            printf("DRET unimplemented\n");
+            exit(1);
+            break;
+        case 0x105: /* WFI */
+            /* nop for now, as in spike */
+            break;
+        case 0x104: /* SFENCE.VM */
+            gen_helper_tlb_flush(cpu_env);
+            break;
+        default:
+            kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+            break;
+        }
+        break;
+    default:
+        tcg_gen_movi_tl(cpu_PC, ctx->pc);
+        tcg_gen_movi_tl(imm_rs1, rs1);
+        switch (opc) {
+        case OPC_RISC_CSRRW:
+            gen_helper_csrrw(dest, cpu_env, source1, csr_store, cpu_PC);
+            break;
+        case OPC_RISC_CSRRS:
+            gen_helper_csrrs(dest, cpu_env, source1, csr_store, cpu_PC,
+                    rs1_pass);
+            break;
+        case OPC_RISC_CSRRC:
+            gen_helper_csrrc(dest, cpu_env, source1, csr_store, cpu_PC,
+                    rs1_pass);
+            break;
+        case OPC_RISC_CSRRWI:
+            gen_helper_csrrw(dest, cpu_env, imm_rs1, csr_store, cpu_PC);
+            break;
+        case OPC_RISC_CSRRSI:
+            gen_helper_csrrs(dest, cpu_env, imm_rs1, csr_store, cpu_PC,
+                             rs1_pass);
+            break;
+        case OPC_RISC_CSRRCI:
+            gen_helper_csrrc(dest, cpu_env, imm_rs1, csr_store, cpu_PC,
+                             rs1_pass);
+            break;
+        default:
+            kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+            break;
+        }
+        gen_set_gpr(rd, dest);
+        /* end tb since we may be changing priv modes, to get mmu_index right */
+        tcg_gen_movi_tl(cpu_PC, ctx->pc + 4);
+        tcg_gen_exit_tb(0); /* no chaining */
+        ctx->bstate = BS_BRANCH;
+        break;
+    }
+    tcg_temp_free(source1);
+    tcg_temp_free(csr_store);
+    tcg_temp_free(dest);
+    tcg_temp_free(rs1_pass);
+    tcg_temp_free(imm_rs1);
+}
+
 static void decode_opc(CPURISCVState *env, DisasContext *ctx)
 {
     int rs1;
@@ -1286,6 +1392,19 @@ static void decode_opc(CPURISCVState *env, DisasContext *ctx)
         gen_fp_arith(ctx, MASK_OP_FP_ARITH(ctx->opcode), rd, rs1, rs2,
                      GET_RM(ctx->opcode));
         break;
+    case OPC_RISC_FENCE:
+        /* standard fence is nop, fence_i flushes TB (like an icache): */
+        if (ctx->opcode & 0x1000) { /* FENCE_I */
+            gen_helper_fence_i(cpu_env);
+            tcg_gen_movi_tl(cpu_PC, ctx->pc + 4);
+            tcg_gen_exit_tb(0); /* no chaining */
+            ctx->bstate = BS_BRANCH;
+        }
+        break;
+    case OPC_RISC_SYSTEM:
+        gen_system(ctx, MASK_OP_SYSTEM(ctx->opcode), rd, rs1,
+                   (ctx->opcode & 0xFFF00000) >> 20);
+        break;
     default:
         kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
         break;
-- 
2.9.3

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

* [Qemu-devel] [PATCH 13/18] target-riscv: Add CSR read/write helpers
  2016-09-26 10:56 [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G) Sagar Karandikar
                   ` (11 preceding siblings ...)
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 12/18] target-riscv: Add system instructions Sagar Karandikar
@ 2016-09-26 10:56 ` Sagar Karandikar
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 14/18] target-riscv: softmmu/address translation support Sagar Karandikar
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 45+ messages in thread
From: Sagar Karandikar @ 2016-09-26 10:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, rth, kbastian, Sagar Karandikar

Signed-off-by: Sagar Karandikar <sagark@eecs.berkeley.edu>
---
 target-riscv/op_helper.c | 324 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 324 insertions(+)

diff --git a/target-riscv/op_helper.c b/target-riscv/op_helper.c
index ee51f02..8449d1b 100644
--- a/target-riscv/op_helper.c
+++ b/target-riscv/op_helper.c
@@ -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;
 }
 
-- 
2.9.3

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

* [Qemu-devel] [PATCH 14/18] target-riscv: softmmu/address translation support
  2016-09-26 10:56 [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G) Sagar Karandikar
                   ` (12 preceding siblings ...)
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 13/18] target-riscv: Add CSR read/write helpers Sagar Karandikar
@ 2016-09-26 10:56 ` Sagar Karandikar
  2016-09-26 22:04   ` Richard Henderson
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 15/18] target-riscv: Interrupt Handling Sagar Karandikar
                   ` (4 subsequent siblings)
  18 siblings, 1 reply; 45+ messages in thread
From: Sagar Karandikar @ 2016-09-26 10:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, rth, kbastian, Sagar Karandikar

Signed-off-by: Sagar Karandikar <sagark@eecs.berkeley.edu>
---
 target-riscv/helper.c    | 211 ++++++++++++++++++++++++++++++++++++++++++++++-
 target-riscv/op_helper.c |  29 +++++++
 2 files changed, 238 insertions(+), 2 deletions(-)

diff --git a/target-riscv/helper.c b/target-riscv/helper.c
index dfdc7bd..2e02351 100644
--- a/target-riscv/helper.c
+++ b/target-riscv/helper.c
@@ -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;
 }
 
 /*
diff --git a/target-riscv/op_helper.c b/target-riscv/op_helper.c
index 8449d1b..1ecdef2 100644
--- a/target-riscv/op_helper.c
+++ b/target-riscv/op_helper.c
@@ -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 */
-- 
2.9.3

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

* [Qemu-devel] [PATCH 15/18] target-riscv: Interrupt Handling
  2016-09-26 10:56 [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G) Sagar Karandikar
                   ` (13 preceding siblings ...)
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 14/18] target-riscv: softmmu/address translation support Sagar Karandikar
@ 2016-09-26 10:56 ` Sagar Karandikar
  2016-09-26 22:07   ` Richard Henderson
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 16/18] target-riscv: Timer Support Sagar Karandikar
                   ` (3 subsequent siblings)
  18 siblings, 1 reply; 45+ messages in thread
From: Sagar Karandikar @ 2016-09-26 10:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, rth, kbastian, Sagar Karandikar

Signed-off-by: Sagar Karandikar <sagark@eecs.berkeley.edu>
---
 target-riscv/helper.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 154 insertions(+)

diff --git a/target-riscv/helper.c b/target-riscv/helper.c
index 2e02351..08c53fa 100644
--- a/target-riscv/helper.c
+++ b/target-riscv/helper.c
@@ -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 */
 }
-- 
2.9.3

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

* [Qemu-devel] [PATCH 16/18] target-riscv: Timer Support
  2016-09-26 10:56 [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G) Sagar Karandikar
                   ` (14 preceding siblings ...)
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 15/18] target-riscv: Interrupt Handling Sagar Karandikar
@ 2016-09-26 10:56 ` Sagar Karandikar
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 17/18] target-riscv: Add support for Host-Target Interface (HTIF) Devices Sagar Karandikar
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 45+ messages in thread
From: Sagar Karandikar @ 2016-09-26 10:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, rth, kbastian, Sagar Karandikar

Signed-off-by: Sagar Karandikar <sagark@eecs.berkeley.edu>
---
 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

diff --git a/hw/riscv/Makefile.objs b/hw/riscv/Makefile.objs
new file mode 100644
index 0000000..79b4553
--- /dev/null
+++ b/hw/riscv/Makefile.objs
@@ -0,0 +1 @@
+obj-y += riscv_rtc.o
diff --git a/hw/riscv/cpudevs.h b/hw/riscv/cpudevs.h
new file mode 100644
index 0000000..f2f4195
--- /dev/null
+++ b/hw/riscv/cpudevs.h
@@ -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
diff --git a/hw/riscv/riscv_rtc.c b/hw/riscv/riscv_rtc.c
new file mode 100644
index 0000000..178c7ff
--- /dev/null
+++ b/hw/riscv/riscv_rtc.c
@@ -0,0 +1,230 @@
+/*
+ * QEMU RISC-V timer, instret counter support
+ *
+ * Author: Sagar Karandikar, sagark@eecs.berkeley.edu
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/hw.h"
+#include "hw/riscv/cpudevs.h"
+#include "hw/riscv/riscv_rtc_internal.h"
+#include "hw/riscv/riscv_rtc.h"
+#include "qemu/timer.h"
+
+/*#define TIMER_DEBUGGING_RISCV */
+
+/* this is the "right value" for defaults in pk/linux
+   see pk/sbi_entry.S and arch/riscv/kernel/time.c call to
+   clockevents_config_and_register */
+#define TIMER_FREQ (10 * 1000 * 1000)
+/* CPU_FREQ is for instret approximation - say we're running at 1 BIPS */
+#define CPU_FREQ (1000 * 1000 * 1000)
+
+inline uint64_t rtc_read(CPURISCVState *env)
+{
+    return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), TIMER_FREQ,
+                    NANOSECONDS_PER_SECOND);
+}
+
+inline uint64_t instret_read(CPURISCVState *env)
+{
+    return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), CPU_FREQ,
+                    NANOSECONDS_PER_SECOND);
+}
+
+/*
+ * Called when timecmp is written to update the QEMU timer or immediately
+ * trigger timer interrupt if mtimecmp <= current timer value.
+ */
+static inline void cpu_riscv_timer_update(CPURISCVState *env)
+{
+    uint64_t next;
+    uint64_t diff;
+
+    uint64_t rtc_r = rtc_read(env);
+
+    #ifdef TIMER_DEBUGGING_RISCV
+    printf("timer update: mtimecmp %016lx, timew %016lx\n",
+            env->timecmp, rtc_r);
+    #endif
+
+    if (env->timecmp <= rtc_r) {
+        /* if we're setting an MTIMECMP value in the "past",
+           immediately raise the timer interrupt */
+        env->csr[CSR_MIP] |= MIP_MTIP;
+        qemu_irq_raise(env->irq[3]);
+        return;
+    }
+
+    /* otherwise, set up the future timer interrupt */
+    diff = env->timecmp - rtc_r;
+    /* back to ns (note args switched in muldiv64) */
+    next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
+        muldiv64(diff, NANOSECONDS_PER_SECOND, TIMER_FREQ);
+    timer_mod(env->timer, next);
+}
+
+/*
+ * Called by the callback used when the timer set using timer_mod expires.
+ * Should raise the timer interrupt line
+ */
+static inline void cpu_riscv_timer_expire(CPURISCVState *env)
+{
+    /* do not call update here */
+    env->csr[CSR_MIP] |= MIP_MTIP;
+    qemu_irq_raise(env->irq[3]);
+}
+
+/* used in op_helper.c */
+inline uint64_t cpu_riscv_read_instret(CPURISCVState *env)
+{
+    uint64_t retval = instret_read(env);
+    return retval;
+}
+
+inline void write_timecmp(CPURISCVState *env, uint64_t value)
+{
+    #ifdef TIMER_DEBUGGING_RISCV
+    uint64_t rtc_r = rtc_read_with_delta(env);
+    printf("wrote mtimecmp %016lx, timew %016lx\n", value, rtc_r);
+    #endif
+
+    env->timecmp = value;
+    env->csr[CSR_MIP] &= ~MIP_MTIP;
+    cpu_riscv_timer_update(env);
+}
+
+/*
+ * Callback used when the timer set using timer_mod expires.
+ */
+static void riscv_timer_cb(void *opaque)
+{
+    CPURISCVState *env;
+    env = opaque;
+    cpu_riscv_timer_expire(env);
+}
+
+/*
+ * Initialize clock mechanism.
+ */
+void cpu_riscv_clock_init(CPURISCVState *env)
+{
+    env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &riscv_timer_cb, env);
+    env->timecmp = 0;
+}
+
+
+#include "target-riscv/cpu.h"
+
+static void timer_pre_save(void *opaque)
+{
+    return;
+}
+
+static int timer_post_load(void *opaque, int version_id)
+{
+    return 0;
+}
+
+const VMStateDescription vmstate_timer_rv = {
+    .name = "rvtimer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .pre_save = timer_pre_save,
+    .post_load = timer_post_load,
+    .fields      = (VMStateField []) { /* TODO what */
+        VMSTATE_END_OF_LIST()
+    },
+};
+
+/* CPU wants to read rtc or timecmp register */
+static uint64_t timer_mm_read(void *opaque, hwaddr addr, unsigned size)
+{
+    TIMERState *timerstate = opaque;
+    if (addr == 0) {
+        /* rtc */
+        timerstate->temp_rtc_val = rtc_read(timerstate->env);
+        return timerstate->temp_rtc_val & 0xFFFFFFFF;
+    } else if (addr == 4) {
+        /* rtc */
+        return (timerstate->temp_rtc_val >> 32) & 0xFFFFFFFF;
+    } else if (addr == 8) {
+        /* timecmp */
+        printf("TIMECMP READ NOT IMPL\n");
+        exit(1);
+    } else if (addr == 0xc) {
+        /* timecmp */
+        printf("TIMECMP READ NOT IMPL\n");
+        exit(1);
+    } else {
+        printf("Invalid timer register address %016lx\n", (uint64_t)addr);
+        exit(1);
+    }
+}
+
+/* CPU wrote to rtc or timecmp register */
+static void timer_mm_write(void *opaque, hwaddr addr, uint64_t value,
+        unsigned size)
+{
+    TIMERState *timerstate = opaque;
+    if (addr == 0) {
+        /*rtc */
+        printf("RTC WRITE NOT IMPL\n");
+        exit(1);
+    } else if (addr == 4) {
+        /*rtc */
+        printf("RTC WRITE NOT IMPL\n");
+        exit(1);
+    } else if (addr == 8) {
+        /* timecmp */
+        timerstate->timecmp_lower = value & 0xFFFFFFFF;
+    } else if (addr == 0xc) {
+        /* timecmp */
+        write_timecmp(timerstate->env, value << 32 |
+                timerstate->timecmp_lower);
+    } else {
+        printf("Invalid timer register address %016lx\n", (uint64_t)addr);
+        exit(1);
+    }
+}
+
+static const MemoryRegionOps timer_mm_ops[3] = {
+    [DEVICE_LITTLE_ENDIAN] = {
+        .read = timer_mm_read,
+        .write = timer_mm_write,
+        .endianness = DEVICE_LITTLE_ENDIAN,
+    },
+};
+
+TIMERState *timer_mm_init(MemoryRegion *address_space, hwaddr base,
+                          CPURISCVState *env)
+{
+    TIMERState *timerstate;
+    timerstate = g_malloc0(sizeof(TIMERState));
+    timerstate->env = env;
+    timerstate->temp_rtc_val = 0;
+    vmstate_register(NULL, base, &vmstate_timer_rv, timerstate);
+    memory_region_init_io(&timerstate->io, NULL,
+            &timer_mm_ops[DEVICE_LITTLE_ENDIAN],
+            timerstate, "timer", 16 /* 2 64-bit registers */);
+    memory_region_add_subregion(address_space, base, &timerstate->io);
+    return timerstate;
+}
diff --git a/include/hw/riscv/riscv_rtc.h b/include/hw/riscv/riscv_rtc.h
new file mode 100644
index 0000000..d5c422c
--- /dev/null
+++ b/include/hw/riscv/riscv_rtc.h
@@ -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
diff --git a/include/hw/riscv/riscv_rtc_internal.h b/include/hw/riscv/riscv_rtc_internal.h
new file mode 100644
index 0000000..d13e104
--- /dev/null
+++ b/include/hw/riscv/riscv_rtc_internal.h
@@ -0,0 +1,3 @@
+uint64_t rtc_read(CPURISCVState *env);
+uint64_t instret_read(CPURISCVState *env);
+void write_timecmp(CPURISCVState *env, uint64_t value);
diff --git a/target-riscv/op_helper.c b/target-riscv/op_helper.c
index 1ecdef2..54d7538 100644
--- a/target-riscv/op_helper.c
+++ b/target-riscv/op_helper.c
@@ -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);
-- 
2.9.3

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

* [Qemu-devel] [PATCH 17/18] target-riscv: Add support for Host-Target Interface (HTIF) Devices
  2016-09-26 10:56 [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G) Sagar Karandikar
                   ` (15 preceding siblings ...)
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 16/18] target-riscv: Timer Support Sagar Karandikar
@ 2016-09-26 10:56 ` Sagar Karandikar
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 18/18] target-riscv: Add generic test board, activate target Sagar Karandikar
  2016-09-26 12:20 ` [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G) Paolo Bonzini
  18 siblings, 0 replies; 45+ messages in thread
From: Sagar Karandikar @ 2016-09-26 10:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, rth, kbastian, 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.

Signed-off-by: Sagar Karandikar <sagark@eecs.berkeley.edu>
---
 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

diff --git a/hw/riscv/Makefile.objs b/hw/riscv/Makefile.objs
index 79b4553..d830e5d 100644
--- a/hw/riscv/Makefile.objs
+++ b/hw/riscv/Makefile.objs
@@ -1 +1,3 @@
 obj-y += riscv_rtc.o
+obj-y += htif/elf_symb.o
+obj-y += htif/htif.o
diff --git a/hw/riscv/htif/elf_symb.c b/hw/riscv/htif/elf_symb.c
new file mode 100644
index 0000000..dc8efd6
--- /dev/null
+++ b/hw/riscv/htif/elf_symb.c
@@ -0,0 +1,286 @@
+/*
+ * elf.c - A simple package for manipulating symbol tables in elf binaries.
+ *
+ * Taken from
+ * https://www.cs.cmu.edu/afs/cs.cmu.edu/academic/class/15213-f03/www/
+ * ftrace/elf.c
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <glib.h>
+
+#include "elf_symb.h"
+
+/*
+ * elf_open - Map a binary into the address space and extract the
+ * locations of the static and dynamic symbol tables and their string
+ * tables. Return this information in a Elf object file handle that will
+ * be passed to all of the other elf functions.
+ */
+Elf_obj *elf_open(const char *filename)
+{
+    int i, fd;
+    struct stat sbuf;
+    Elf_obj *ep;
+    Elf64_Shdr *shdr;
+
+    ep = g_new(Elf_obj, 1);
+
+    /* Do some consistency checks on the binary */
+    fd = open(filename, O_RDONLY);
+    if (fd == -1) {
+        fprintf(stderr, "Can't open \"%s\": %s\n", filename, strerror(errno));
+        exit(1);
+    }
+    if (fstat(fd, &sbuf) == -1) {
+        fprintf(stderr, "Can't stat \"%s\": %s\n", filename, strerror(errno));
+        exit(1);
+    }
+    if (sbuf.st_size < sizeof(Elf64_Ehdr)) {
+        fprintf(stderr, "\"%s\" is not an ELF binary object\n", filename);
+        exit(1);
+    }
+
+    /* It looks OK, so map the Elf binary into our address space */
+    ep->mlen = sbuf.st_size;
+    ep->maddr = mmap(NULL, ep->mlen, PROT_READ, MAP_SHARED, fd, 0);
+    if (ep->maddr == (void *)-1) {
+        fprintf(stderr, "Can't mmap \"%s\": %s\n", filename, strerror(errno));
+        exit(1);
+    }
+    close(fd);
+
+    /* The Elf binary begins with the Elf header */
+    ep->ehdr = ep->maddr;
+
+    /* Make sure that this is an Elf binary */
+    /*    if (strncmp(ep->ehdr->e_ident, ELFMAG, SELFMAG)) {
+    fprintf(stderr, "\"%s\" is not an ELF binary object\n", filename);
+    exit(1);
+    }*/
+
+    /*
+     * Find the static and dynamic symbol tables and their string
+     * tables in the the mapped binary. The sh_link field in symbol
+     * table section headers gives the section index of the string
+     * table for that symbol table.
+     */
+    shdr = (Elf64_Shdr *)(ep->maddr + ep->ehdr->e_shoff);
+    for (i = 0; i < ep->ehdr->e_shnum; i++) {
+        if (shdr[i].sh_type == SHT_SYMTAB) {   /* Static symbol table */
+            ep->symtab = (Elf64_Sym *)(ep->maddr + shdr[i].sh_offset);
+            ep->symtab_end = (Elf64_Sym *)((char *)ep->symtab +
+                             shdr[i].sh_size);
+            ep->strtab = (char *)(ep->maddr + shdr[shdr[i].sh_link].sh_offset);
+        }
+        if (shdr[i].sh_type == SHT_DYNSYM) {   /* Dynamic symbol table */
+            ep->dsymtab = (Elf64_Sym *)(ep->maddr + shdr[i].sh_offset);
+            ep->dsymtab_end = (Elf64_Sym *)((char *)ep->dsymtab +
+                              shdr[i].sh_size);
+            ep->dstrtab = (char *)(ep->maddr + shdr[shdr[i].sh_link].sh_offset);
+        }
+    }
+    return ep;
+}
+
+/*
+ * elf_open - Map a binary into the address space and extract the
+ * locations of the static and dynamic symbol tables and their string
+ * tables. Return this information in a Elf object file handle that will
+ * be passed to all of the other elf functions.
+ */
+Elf_obj32 *elf_open32(const char *filename)
+{
+    int i, fd;
+    struct stat sbuf;
+    Elf_obj32 *ep;
+    Elf32_Shdr *shdr;
+
+    ep = g_new(Elf_obj32, 1);
+
+    /* Do some consistency checks on the binary */
+    fd = open(filename, O_RDONLY);
+    if (fd == -1) {
+        fprintf(stderr, "Can't open \"%s\": %s\n", filename, strerror(errno));
+        exit(1);
+    }
+    if (fstat(fd, &sbuf) == -1) {
+        fprintf(stderr, "Can't stat \"%s\": %s\n", filename, strerror(errno));
+        exit(1);
+    }
+    if (sbuf.st_size < sizeof(Elf32_Ehdr)) {
+        fprintf(stderr, "\"%s\" is not an ELF binary object\n", filename);
+        exit(1);
+    }
+
+    /* It looks OK, so map the Elf binary into our address space */
+    ep->mlen = sbuf.st_size;
+    ep->maddr = mmap(NULL, ep->mlen, PROT_READ, MAP_SHARED, fd, 0);
+    if (ep->maddr == (void *)-1) {
+        fprintf(stderr, "Can't mmap \"%s\": %s\n", filename, strerror(errno));
+        exit(1);
+    }
+    close(fd);
+
+    /* The Elf binary begins with the Elf header */
+    ep->ehdr = ep->maddr;
+
+    /* Make sure that this is an Elf binary */
+/*    if (strncmp(ep->ehdr->e_ident, ELFMAG, SELFMAG)) {
+    fprintf(stderr, "\"%s\" is not an ELF binary object\n", filename);
+    exit(1);
+    }*/
+
+    /*
+     * Find the static and dynamic symbol tables and their string
+     * tables in the the mapped binary. The sh_link field in symbol
+     * table section headers gives the section index of the string
+     * table for that symbol table.
+     */
+    shdr = (Elf32_Shdr *)(ep->maddr + ep->ehdr->e_shoff);
+    for (i = 0; i < ep->ehdr->e_shnum; i++) {
+        if (shdr[i].sh_type == SHT_SYMTAB) {   /* Static symbol table */
+            ep->symtab = (Elf32_Sym *)(ep->maddr + shdr[i].sh_offset);
+            ep->symtab_end = (Elf32_Sym *)((char *)ep->symtab +
+                             shdr[i].sh_size);
+            ep->strtab = (char *)(ep->maddr + shdr[shdr[i].sh_link].sh_offset);
+        }
+        if (shdr[i].sh_type == SHT_DYNSYM) {   /* Dynamic symbol table */
+            ep->dsymtab = (Elf32_Sym *)(ep->maddr + shdr[i].sh_offset);
+            ep->dsymtab_end = (Elf32_Sym *)((char *)ep->dsymtab +
+                              shdr[i].sh_size);
+            ep->dstrtab = (char *)(ep->maddr + shdr[shdr[i].sh_link].sh_offset);
+        }
+    }
+    return ep;
+}
+
+/*
+ * elf_close - Free up the resources of an  elf object
+ */
+void elf_close(Elf_obj *ep)
+{
+    if (munmap(ep->maddr, ep->mlen) < 0) {
+        perror("munmap");
+        exit(1);
+    }
+    free(ep);
+}
+
+/*
+ * elf_symname - Return ASCII name of a static symbol
+ */
+char *elf_symname(Elf_obj *ep, Elf64_Sym *sym)
+{
+    return &ep->strtab[sym->st_name];
+}
+
+/*
+ * elf_symname - Return ASCII name of a static symbol
+ */
+char *elf_symname32(Elf_obj32 *ep, Elf32_Sym *sym)
+{
+    return &ep->strtab[sym->st_name];
+}
+
+
+/*
+ * elf_dsymname - Return ASCII name of a dynamic symbol
+ */
+char *elf_dsymname(Elf_obj *ep, Elf64_Sym *sym)
+{
+    return &ep->dstrtab[sym->st_name];
+}
+
+/*
+ * elf_firstsym - Return ptr to first symbol in static symbol table
+ */
+Elf64_Sym *elf_firstsym(Elf_obj *ep)
+{
+    return ep->symtab;
+}
+
+/*
+ * elf_firstsym - Return ptr to first symbol in static symbol table
+ */
+Elf32_Sym *elf_firstsym32(Elf_obj32 *ep)
+{
+    return ep->symtab;
+}
+
+
+/*
+ * elf_nextsym - Return ptr to next symbol in static symbol table,
+ * or NULL if no more symbols.
+ */
+Elf64_Sym *elf_nextsym(Elf_obj *ep, Elf64_Sym *sym)
+{
+    sym++;
+    if (sym < ep->symtab_end) {
+        return sym;
+    } else {
+        return NULL;
+    }
+}
+
+/*
+ * elf_nextsym - Return ptr to next symbol in static symbol table,
+ * or NULL if no more symbols.
+ */
+Elf32_Sym *elf_nextsym32(Elf_obj32 *ep, Elf32_Sym *sym)
+{
+    sym++;
+    if (sym < ep->symtab_end) {
+        return sym;
+    } else {
+        return NULL;
+    }
+}
+
+
+/*
+ * elf_firstdsym - Return ptr to first symbol in dynamic symbol table
+ */
+Elf64_Sym *elf_firstdsym(Elf_obj *ep)
+{
+    return ep->dsymtab;
+}
+
+/*
+ * elf_nextdsym - Return ptr to next symbol in dynamic symbol table,
+ * of NULL if no more symbols.
+ */
+Elf64_Sym *elf_nextdsym(Elf_obj *ep, Elf64_Sym *sym)
+{
+    sym++;
+    if (sym < ep->dsymtab_end) {
+        return sym;
+    } else {
+        return NULL;
+    }
+}
+
+/*
+ * elf_isfunc - Return true if symbol is a static function
+ */
+int elf_isfunc(Elf_obj *ep, Elf64_Sym *sym)
+{
+    return ((ELF32_ST_TYPE(sym->st_info) == STT_FUNC) &&
+        (sym->st_shndx != SHT_NULL));
+}
+
+/*
+ * elf_isdfunc - Return true if symbol is a dynamic function
+ */
+int elf_isdfunc(Elf_obj *ep, Elf64_Sym *sym)
+{
+    return ((ELF32_ST_TYPE(sym->st_info) == STT_FUNC));
+}
diff --git a/hw/riscv/htif/elf_symb.h b/hw/riscv/htif/elf_symb.h
new file mode 100644
index 0000000..a438c60
--- /dev/null
+++ b/hw/riscv/htif/elf_symb.h
@@ -0,0 +1,80 @@
+/*
+ * elf.h - A package for manipulating Elf binaries
+ *
+ * Taken from:
+ * https://www.cs.cmu.edu/afs/cs.cmu.edu/academic/class/15213-f03/www/ftrace/
+ * elf.h
+ *
+ */
+
+#ifndef ELF_H
+#define ELF_H
+
+#include <stdint.h>
+#include <elf.h>
+
+/*
+ * This is a handle that is created by elf_open and then used by every
+ * other function in the elf package
+*/
+typedef struct {
+    void *maddr;            /* Start of mapped Elf binary segment in memory */
+    int mlen;               /* Length in bytes of the mapped Elf segment */
+    Elf64_Ehdr *ehdr;       /* Start of main Elf header (same as maddr) */
+    Elf64_Sym *symtab;      /* Start of symbol table */
+    Elf64_Sym *symtab_end;  /* End of symbol table (symtab + size) */
+    char *strtab;           /* Address of string table */
+    Elf64_Sym *dsymtab;     /* Start of dynamic symbol table */
+    Elf64_Sym *dsymtab_end; /* End of dynamic symbol table (dsymtab + size) */
+    char *dstrtab;          /* Address of dynamic string table */
+} Elf_obj;
+
+typedef struct {
+    void *maddr;            /* Start of mapped Elf binary segment in memory */
+    int mlen;               /* Length in bytes of the mapped Elf segment */
+    Elf32_Ehdr *ehdr;       /* Start of main Elf header (same as maddr) */
+    Elf32_Sym *symtab;      /* Start of symbol table */
+    Elf32_Sym *symtab_end;  /* End of symbol table (symtab + size) */
+    char *strtab;           /* Address of string table */
+    Elf32_Sym *dsymtab;     /* Start of dynamic symbol table */
+    Elf32_Sym *dsymtab_end; /* End of dynamic symbol table (dsymtab + size) */
+    char *dstrtab;          /* Address of dynamic string table */
+} Elf_obj32;
+
+/*
+ * Create and destroy Elf object handles
+ */
+Elf_obj *elf_open(const char *filename);
+Elf_obj32 *elf_open32(const char *filename);
+
+void elf_close(Elf_obj *ep);
+
+/*
+ * Functions for manipulating static symbols
+ */
+
+/* Returns pointer to the first symbol */
+Elf64_Sym *elf_firstsym(Elf_obj *ep);
+Elf32_Sym *elf_firstsym32(Elf_obj32 *ep);
+
+/* Returns pointer to the next symbol, or NULL if no more symbols */
+Elf64_Sym *elf_nextsym(Elf_obj *ep, Elf64_Sym *sym);
+Elf32_Sym *elf_nextsym32(Elf_obj32 *ep, Elf32_Sym *sym);
+
+/* Return symbol string name */
+char *elf_symname(Elf_obj *ep, Elf64_Sym *sym);
+char *elf_symname32(Elf_obj32 *ep, Elf32_Sym *sym);
+
+/* True if symbol is a function */
+int elf_isfunc(Elf_obj *ep, Elf64_Sym *sym);
+
+/*
+ * Corresponding functions for manipulating dynamic symbols
+ */
+Elf64_Sym *elf_firstdsym(Elf_obj *ep);
+Elf64_Sym *elf_nextdsym(Elf_obj *ep, Elf64_Sym *sym);
+char *elf_dsymname(Elf_obj *ep, Elf64_Sym *sym);
+int elf_isdfunc(Elf_obj *ep, Elf64_Sym *sym);
+
+
+#endif
diff --git a/hw/riscv/htif/htif.c b/hw/riscv/htif/htif.c
new file mode 100644
index 0000000..6093ebd
--- /dev/null
+++ b/hw/riscv/htif/htif.c
@@ -0,0 +1,423 @@
+/*
+ * QEMU RISC-V Host Target Interface (HTIF) Emulation
+ *
+ * Author: Sagar Karandikar, sagark@eecs.berkeley.edu
+ *
+ * This provides HTIF device emulation for QEMU. At the moment this allows
+ * for identical copies of bbl/linux to run on both spike and QEMU.
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/char/serial.h"
+#include "sysemu/char.h"
+#include "hw/riscv/htif/htif.h"
+#include "qemu/timer.h"
+#include "exec/address-spaces.h"
+#include "qemu/error-report.h"
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <inttypes.h>
+#include "elf_symb.h"
+
+#define ENABLE_CHARDEV
+/*#define DEBUG_CHARDEV */
+/*#define DEBUG_HTIF */
+
+#ifdef ENABLE_CHARDEV
+/*
+ * Called by the char dev to see if HTIF is ready to accept input.
+ */
+static int htif_can_recv(void *opaque)
+{
+    return 1;
+}
+
+/*
+ * Called by the char dev to supply input to HTIF console.
+ * We assume that we will receive one character at a time.
+ */
+static void htif_recv(void *opaque, const uint8_t *buf, int size)
+{
+    if (size != 1) {
+        return;
+    }
+
+    HTIFState *htifstate = opaque;
+
+    #ifdef DEBUG_CHARDEV
+    if (htifstate->env->mfromhost != 0x0) {
+        fprintf(stderr, "recv handler: fromhost was not ready to \
+                         accept input\n");
+        fprintf(stderr, "recv handler: prev value was: %016lx\n",
+                htifstate->env->mfromhost);
+    }
+    #endif
+
+    uint64_t val_written = htifstate->pending_read;
+    uint64_t resp = 0x100 | *buf;
+
+    htifstate->env->mfromhost = (val_written >> 48 << 48) | (resp << 16 >> 16);
+    qemu_irq_raise(htifstate->irq);
+}
+
+/*
+ * Called by the char dev to supply special events to the HTIF console.
+ * Not used for HTIF.
+ */
+static void htif_event(void *opaque, int event)
+{
+    #ifdef DEBUG_CHARDEV
+    fprintf(stderr, "GOT EVENT: %d\n", event);
+    #endif
+}
+#endif
+
+static void htif_pre_save(void *opaque)
+{
+    return;
+}
+
+static int htif_post_load(void *opaque, int version_id)
+{
+    return 0;
+}
+
+const VMStateDescription vmstate_htif = {
+    .name = "htif",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .pre_save = htif_pre_save,
+    .post_load = htif_post_load,
+    .fields      = (VMStateField []) { /* TODO what */
+        VMSTATE_UINT64(tohost_offset, HTIFState),
+        VMSTATE_UINT64(fromhost_offset, HTIFState),
+        VMSTATE_UINT64(tohost_size, HTIFState),
+        VMSTATE_UINT64(fromhost_size, HTIFState),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
+static void dma_strcopy(HTIFState *htifstate, char *str, hwaddr phys_addr)
+{
+    int i = 0;
+    void *base_copy_addr = htifstate->main_mem_ram_ptr + phys_addr;
+    while (*(str + i)) {
+        stb_p((void *)(base_copy_addr + i), *(str + i));
+        i++;
+    }
+    stb_p((void *)(base_copy_addr + i), 0); /* store null term */
+}
+
+static void htif_handle_tohost_write(HTIFState *htifstate, uint64_t val_written)
+{
+    #ifdef DEBUG_HTIF
+    fprintf(stderr, "TOHOST WRITE WITH val 0x%016lx\n", val_written);
+    #endif
+
+    uint8_t device = val_written >> 56;
+    uint8_t cmd = val_written >> 48;
+    uint64_t payload = val_written & 0xFFFFFFFFFFFFULL;
+
+    uint64_t addr = payload >> 8;
+    hwaddr real_addr = (hwaddr)addr;
+    uint8_t what = payload & 0xFF;
+    int resp;
+
+    resp = 0; /* stop gcc complaining */
+    #ifdef DEBUG_HTIF
+    fprintf(stderr, "mtohost write:\n-device: %d\n-cmd: %d\n-what: %02lx\n\
+                     -payload: %016lx\n", device, cmd, payload & 0xFF, payload);
+    #endif
+
+    /*
+     * Currently, there is a fixed mapping of devices:
+     * 0: riscv-tests Pass/Fail Reporting Only (no syscall proxy)
+     * 1: Console
+     */
+    if (unlikely(device == 0x0)) {
+        /* frontend syscall handler, only test pass/fail support */
+        if (cmd == 0x0) {
+            #ifdef DEBUG_HTIF
+            fprintf(stderr, "frontend syscall handler\n");
+            #endif
+            if (payload & 0x1) {
+                /* test result */
+                if (payload >> 1) {
+                    printf("*** FAILED *** (exitcode = %016lx)\n",
+                           payload >> 1);
+                } else {
+                    printf("TEST PASSED\n");
+                }
+                exit(payload >> 1);
+            }
+            fprintf(stderr, "pk syscall proxy not supported\n");
+        } else if (cmd == 0xFF) {
+            /* use what */
+            if (what == 0xFF) {
+                #ifdef DEBUG_HTIF
+                fprintf(stderr, "registering name\n");
+                #endif
+                dma_strcopy(htifstate, (char *)"syscall_proxy", real_addr);
+            } else if (what == 0x0) {
+                #ifdef DEBUG_HTIF
+                fprintf(stderr, "registering syscall cmd\n");
+                #endif
+                dma_strcopy(htifstate, (char *)"syscall", real_addr);
+            } else {
+                #ifdef DEBUG_HTIF
+                fprintf(stderr, "registering end of cmds list\n");
+                #endif
+                dma_strcopy(htifstate, (char *)"", real_addr);
+            }
+            resp = 0x1; /* write to indicate device name placed */
+        } else {
+            fprintf(stderr, "HTIF device %d: UNKNOWN COMMAND\n", device);
+            exit(1);
+        }
+    } else if (likely(device == 0x1)) {
+        /* HTIF Console */
+        if (cmd == 0x0) {
+            /* this should be a queue, but not yet implemented as such */
+            htifstate->pending_read = val_written;
+            htifstate->env->mtohost = 0; /* clear to indicate we read */
+            return;
+        } else if (cmd == 0x1) {
+            #ifdef ENABLE_CHARDEV
+            qemu_chr_fe_write(htifstate->chr, (uint8_t *)&payload, 1);
+            #endif
+            resp = 0x100 | (uint8_t)payload;
+        } else if (cmd == 0xFF) {
+            /* use what */
+            if (what == 0xFF) {
+                #ifdef DEBUG_HTIF
+                fprintf(stderr, "registering name\n");
+                #endif
+                dma_strcopy(htifstate, (char *)"bcd", real_addr);
+            } else if (what == 0x0) {
+                #ifdef DEBUG_HTIF
+                fprintf(stderr, "registering read cmd\n");
+                #endif
+                dma_strcopy(htifstate, (char *)"read", real_addr);
+            } else if (what == 0x1) {
+                #ifdef DEBUG_HTIF
+                fprintf(stderr, "registering write cmd\n");
+                #endif
+                dma_strcopy(htifstate, (char *)"write", real_addr);
+            } else {
+                #ifdef DEBUG_HTIF
+                fprintf(stderr, "registering end of cmds list\n");
+                #endif
+                dma_strcopy(htifstate, (char *)"", real_addr);
+            }
+            resp = 0x1; /* write to indicate device name placed */
+        } else {
+            fprintf(stderr, "HTIF device %d: UNKNOWN COMMAND\n", device);
+            exit(1);
+        }
+    /* all other devices */
+    } else if (device == 0x2 && cmd == 0xFF && what == 0xFF) {
+        #ifdef DEBUG_HTIF
+        fprintf(stderr, "registering no device as last\n");
+        #endif
+        stb_p((void *)(htifstate->main_mem_ram_ptr + real_addr), 0);
+        resp = 0x1; /* write to indicate device name placed */
+    } else {
+        fprintf(stderr, "HTIF UNKNOWN DEVICE OR COMMAND!\n");
+        fprintf(stderr, "-device: %d\n-cmd: %d\n-what: %02lx\n-payload: \
+                         %016lx\n", device, cmd, payload & 0xFF, payload);
+        exit(1);
+    }
+    while (!htifstate->fromhost_inprogress &&
+            htifstate->env->mfromhost != 0x0) {
+        /* wait */
+    }
+    htifstate->env->mfromhost = (val_written >> 48 << 48) | (resp << 16 >> 16);
+    htifstate->env->mtohost = 0; /* clear to indicate we read */
+    if (htifstate->env->mfromhost != 0) {
+        /* raise HTIF interrupt */
+        qemu_irq_raise(htifstate->irq);
+    }
+}
+
+#define TOHOST_OFFSET1 (htifstate->tohost_offset)
+#define TOHOST_OFFSET2 (htifstate->tohost_offset + 4)
+#define FROMHOST_OFFSET1 (htifstate->fromhost_offset)
+#define FROMHOST_OFFSET2 (htifstate->fromhost_offset + 4)
+
+/* CPU wants to read an HTIF register */
+static uint64_t htif_mm_read(void *opaque, hwaddr addr, unsigned size)
+{
+    HTIFState *htifstate = opaque;
+    if (addr == TOHOST_OFFSET1) {
+        return htifstate->env->mtohost & 0xFFFFFFFF;
+    } else if (addr == TOHOST_OFFSET2) {
+        return (htifstate->env->mtohost >> 32) & 0xFFFFFFFF;
+    } else if (addr == FROMHOST_OFFSET1) {
+        return htifstate->env->mfromhost & 0xFFFFFFFF;
+    } else if (addr == FROMHOST_OFFSET2) {
+        return (htifstate->env->mfromhost >> 32) & 0xFFFFFFFF;
+    } else {
+        printf("Invalid htif register address %016lx\n", (uint64_t)addr);
+        exit(1);
+    }
+}
+
+/* CPU wrote to an HTIF register */
+static void htif_mm_write(void *opaque, hwaddr addr,
+                            uint64_t value, unsigned size)
+{
+    HTIFState *htifstate = opaque;
+    if (addr == TOHOST_OFFSET1) {
+        if (htifstate->env->mtohost == 0x0) {
+            htifstate->allow_tohost = 1;
+            htifstate->env->mtohost = value & 0xFFFFFFFF;
+            if (unlikely(htifstate->tohost_size != 8)) {
+#ifdef DEBUG_HTIF
+                fprintf(stderr, "Using non-8 htif width\n");
+#endif
+                /* tests have a zero tohost size in elf symb tab and they
+                   use sw to write to mm_write, so TOHOST_OFFSET2 will never
+                   be written to. Thus, initiate side effects here. */
+                htif_handle_tohost_write(htifstate, htifstate->env->mtohost);
+            }
+        } else {
+            htifstate->allow_tohost = 0;
+        }
+    } else if (addr == TOHOST_OFFSET2) {
+        if (htifstate->allow_tohost) {
+            htifstate->env->mtohost |= value << 32;
+            htif_handle_tohost_write(htifstate, htifstate->env->mtohost);
+        }
+    } else if (addr == FROMHOST_OFFSET1) {
+        htifstate->fromhost_inprogress = 1;
+        htifstate->env->mfromhost = value & 0xFFFFFFFF;
+    } else if (addr == FROMHOST_OFFSET2) {
+        htifstate->env->mfromhost |= value << 32;
+        if (htifstate->env->mfromhost == 0x0) {
+            qemu_irq_lower(htifstate->irq);
+        }
+        htifstate->fromhost_inprogress = 0;
+    } else {
+        printf("Invalid htif register address %016lx\n", (uint64_t)addr);
+        exit(1);
+    }
+}
+
+static const MemoryRegionOps htif_mm_ops[3] = {
+    [DEVICE_LITTLE_ENDIAN] = {
+        .read = htif_mm_read,
+        .write = htif_mm_write,
+        .endianness = DEVICE_LITTLE_ENDIAN,
+    },
+};
+
+HTIFState *htif_mm_init(MemoryRegion *address_space,
+           const char *kernel_filename, qemu_irq irq, MemoryRegion *main_mem,
+           CPURISCVState *env, CharDriverState *chr)
+{
+    uint64_t fromhost_addr = 0;
+    uint64_t fromhost_size = 0; /* for pk vs tests */
+    uint64_t tohost_addr = 0;
+    uint64_t tohost_size = 0; /* for pk vs tests */
+
+    /* get fromhost/tohost addresses from the ELF, as spike/fesvr do */
+    if (NULL != kernel_filename) {
+#if defined(TARGET_RISCV64)
+        Elf_obj *e = elf_open(kernel_filename);
+#else
+        Elf_obj32 *e = elf_open32(kernel_filename);
+#endif
+
+        const char *fromhost = "fromhost";
+        const char *tohost = "tohost";
+
+#if defined(TARGET_RISCV64)
+        Elf64_Sym *curr_sym = elf_firstsym(e);
+#else
+        Elf32_Sym *curr_sym = elf_firstsym32(e);
+#endif
+        while (curr_sym) {
+#if defined(TARGET_RISCV64)
+            char *symname = elf_symname(e, curr_sym);
+#else
+            char *symname = elf_symname32(e, curr_sym);
+#endif
+
+            if (strcmp(fromhost, symname) == 0) {
+                /* get fromhost addr */
+                fromhost_addr = curr_sym->st_value;
+                fromhost_size = curr_sym->st_size; /* this is correctly set to 8
+                                                      by pk */
+            } else if (strcmp(tohost, symname) == 0) {
+                /* get tohost addr */
+                tohost_addr = curr_sym->st_value;
+                tohost_size = curr_sym->st_size; /* this is correctly set to 8
+                                                    by pk */
+            }
+#if defined(TARGET_RISCV64)
+            curr_sym = elf_nextsym(e, curr_sym);
+#else
+            curr_sym = elf_nextsym32(e, curr_sym);
+#endif
+        }
+    }
+
+    /* now setup HTIF device */
+    HTIFState *htifstate;
+
+    htifstate = g_malloc0(sizeof(HTIFState));
+    htifstate->irq = irq;
+    htifstate->address_space = address_space;
+    htifstate->main_mem = main_mem;
+    htifstate->main_mem_ram_ptr = memory_region_get_ram_ptr(main_mem);
+    htifstate->env = env;
+    htifstate->chr = chr;
+    htifstate->pending_read = 0;
+    htifstate->allow_tohost = 0;
+    htifstate->fromhost_inprogress = 0;
+    htifstate->fromhost_size = fromhost_size;
+    htifstate->tohost_size = tohost_size;
+
+#ifdef ENABLE_CHARDEV
+    qemu_chr_add_handlers(htifstate->chr, htif_can_recv, htif_recv, htif_event,
+                          htifstate);
+#endif
+
+    uint64_t base = tohost_addr < fromhost_addr ? tohost_addr : fromhost_addr;
+    uint64_t second = tohost_addr < fromhost_addr ? fromhost_addr : tohost_addr;
+    uint64_t regionwidth = second - base + 8;
+
+    htifstate->tohost_offset = base == tohost_addr ? 0 : tohost_addr -
+                                                         fromhost_addr;
+    htifstate->fromhost_offset = base == fromhost_addr ? 0 : fromhost_addr -
+                                                             tohost_addr;
+
+    vmstate_register(NULL, base, &vmstate_htif, htifstate);
+
+    memory_region_init_io(&htifstate->io, NULL,
+                          &htif_mm_ops[DEVICE_LITTLE_ENDIAN],
+                           htifstate, "htif", regionwidth);
+    memory_region_add_subregion(address_space, base, &htifstate->io);
+
+    return htifstate;
+}
diff --git a/include/hw/riscv/htif/htif.h b/include/hw/riscv/htif/htif.h
new file mode 100644
index 0000000..3499947
--- /dev/null
+++ b/include/hw/riscv/htif/htif.h
@@ -0,0 +1,61 @@
+/*
+ * QEMU RISCV Host Target Interface (HTIF) Emulation
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef HW_RISCV_HTIF_H
+#define HW_RISCV_HTIF_H 1
+
+#include "hw/hw.h"
+#include "sysemu/sysemu.h"
+#include "exec/memory.h"
+#include "target-riscv/cpu.h"
+
+typedef struct HTIFState HTIFState;
+
+struct HTIFState {
+    int allow_tohost;
+    int fromhost_inprogress;
+
+    hwaddr tohost_offset;
+    hwaddr fromhost_offset;
+    uint64_t tohost_size;
+    uint64_t fromhost_size;
+    qemu_irq irq; /* host interrupt line */
+    MemoryRegion io;
+    MemoryRegion *address_space;
+    MemoryRegion *main_mem;
+    void *main_mem_ram_ptr;
+
+    CPURISCVState *env;
+    CharDriverState *chr;
+    uint64_t pending_read;
+};
+
+extern const VMStateDescription vmstate_htif;
+extern const MemoryRegionOps htif_io_ops;
+
+/* legacy pre qom */
+HTIFState *htif_mm_init(MemoryRegion *address_space,
+                        const char *kernel_filename, qemu_irq irq,
+                        MemoryRegion *main_mem,
+                        CPURISCVState *env, CharDriverState *chr);
+
+#endif
-- 
2.9.3

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

* [Qemu-devel] [PATCH 18/18] target-riscv: Add generic test board, activate target
  2016-09-26 10:56 [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G) Sagar Karandikar
                   ` (16 preceding siblings ...)
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 17/18] target-riscv: Add support for Host-Target Interface (HTIF) Devices Sagar Karandikar
@ 2016-09-26 10:56 ` Sagar Karandikar
  2016-09-26 12:20 ` [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G) Paolo Bonzini
  18 siblings, 0 replies; 45+ messages in thread
From: Sagar Karandikar @ 2016-09-26 10:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, rth, kbastian, Sagar Karandikar

Signed-off-by: Sagar Karandikar <sagark@eecs.berkeley.edu>
---
 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

diff --git a/configure b/configure
index 8fa62ad..e3381b8 100755
--- a/configure
+++ b/configure
@@ -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)
diff --git a/default-configs/riscv32-softmmu.mak b/default-configs/riscv32-softmmu.mak
new file mode 100644
index 0000000..c8b7fa1
--- /dev/null
+++ b/default-configs/riscv32-softmmu.mak
@@ -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
diff --git a/default-configs/riscv64-softmmu.mak b/default-configs/riscv64-softmmu.mak
new file mode 100644
index 0000000..c8b7fa1
--- /dev/null
+++ b/default-configs/riscv64-softmmu.mak
@@ -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
diff --git a/hw/riscv/Makefile.objs b/hw/riscv/Makefile.objs
index d830e5d..de6017e 100644
--- a/hw/riscv/Makefile.objs
+++ b/hw/riscv/Makefile.objs
@@ -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
diff --git a/hw/riscv/riscv_board.c b/hw/riscv/riscv_board.c
new file mode 100644
index 0000000..1c136e2
--- /dev/null
+++ b/hw/riscv/riscv_board.c
@@ -0,0 +1,264 @@
+/*
+ * QEMU RISC-V Generic Board Support
+ *
+ * Author: Sagar Karandikar, sagark@eecs.berkeley.edu
+ *
+ * This provides a RISC-V Board with the following devices:
+ *
+ * 0) HTIF Test Pass/Fail Reporting (no syscall proxy)
+ * 1) HTIF Console
+ *
+ * These are created by htif_mm_init below.
+ *
+ * This board currently uses a hardcoded devicetree that indicates one hart.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/hw.h"
+#include "hw/char/serial.h"
+#include "hw/riscv/htif/htif.h"
+#include "hw/riscv/riscv_rtc.h"
+#include "hw/boards.h"
+#include "hw/riscv/cpudevs.h"
+#include "sysemu/char.h"
+#include "sysemu/arch_init.h"
+#include "qemu/log.h"
+#include "hw/loader.h"
+#include "elf.h"
+#include "exec/address-spaces.h"
+#include "hw/sysbus.h"             /* SysBusDevice */
+#include "qemu/host-utils.h"
+#include "sysemu/qtest.h"
+#include "qemu/error-report.h"
+#include "hw/empty_slot.h"
+#include "qemu/error-report.h"
+#include "sysemu/block-backend.h"
+
+#define TYPE_RISCV_BOARD "riscv"
+#define RISCV_BOARD(obj) OBJECT_CHECK(BoardState, (obj), TYPE_RISCV_BOARD)
+
+typedef struct {
+    SysBusDevice parent_obj;
+} BoardState;
+
+static struct _loaderparams {
+    int ram_size;
+    const char *kernel_filename;
+    const char *kernel_cmdline;
+    const char *initrd_filename;
+} loaderparams;
+
+uint64_t identity_translate(void *opaque, uint64_t addr)
+{
+    return addr;
+}
+
+static int64_t load_kernel(void)
+{
+    int64_t kernel_entry, kernel_high;
+    int big_endian;
+    big_endian = 0;
+
+    if (load_elf(loaderparams.kernel_filename, identity_translate, NULL,
+                 (uint64_t *)&kernel_entry, NULL, (uint64_t *)&kernel_high,
+                 big_endian, ELF_MACHINE, 1, 0) < 0) {
+        fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                loaderparams.kernel_filename);
+        exit(1);
+    }
+    return kernel_entry;
+}
+
+static void main_cpu_reset(void *opaque)
+{
+    RISCVCPU *cpu = opaque;
+    cpu_reset(CPU(cpu));
+}
+
+static void riscv_board_init(MachineState *args)
+{
+    ram_addr_t ram_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    MemoryRegion *system_memory = get_system_memory();
+    MemoryRegion *main_mem = g_new(MemoryRegion, 1);
+    RISCVCPU *cpu;
+    CPURISCVState *env;
+    int i;
+    DeviceState *dev = qdev_create(NULL, TYPE_RISCV_BOARD);
+    object_property_set_bool(OBJECT(dev), true, "realized", NULL);
+
+    /* Make sure the first 3 serial ports are associated with a device. */
+    for (i = 0; i < 3; i++) {
+        if (!serial_hds[i]) {
+            char label[32];
+            snprintf(label, sizeof(label), "serial%d", i);
+            serial_hds[i] = qemu_chr_new(label, "null", NULL);
+        }
+    }
+
+    /* init CPUs */
+    if (cpu_model == NULL) {
+        cpu_model = "riscv";
+    }
+
+    for (i = 0; i < smp_cpus; i++) {
+        cpu = cpu_riscv_init(cpu_model);
+        if (cpu == NULL) {
+            fprintf(stderr, "Unable to find CPU definition\n");
+            exit(1);
+        }
+        env = &cpu->env;
+
+        /* Init internal devices */
+        cpu_riscv_irq_init_cpu(env);
+        cpu_riscv_clock_init(env);
+        qemu_register_reset(main_cpu_reset, cpu);
+    }
+    cpu = RISCV_CPU(first_cpu);
+    env = &cpu->env;
+
+    /* register system main memory (actual RAM) */
+    memory_region_init_ram(main_mem, NULL, "riscv_board.ram", 2147483648L +
+                           ram_size, &error_fatal);
+    /* for phys mem size check in page table walk */
+    env->memsize = ram_size;
+    vmstate_register_ram_global(main_mem);
+    memory_region_add_subregion(system_memory, 0x0, main_mem);
+
+    if (kernel_filename) {
+        loaderparams.ram_size = ram_size;
+        loaderparams.kernel_filename = kernel_filename;
+        loaderparams.kernel_cmdline = kernel_cmdline;
+        loaderparams.initrd_filename = initrd_filename;
+        load_kernel();
+    }
+
+    uint32_t reset_vec[8] = {
+        0x297 + 0x80000000 - 0x1000, /* reset vector */
+        0x00028067,                  /* jump to DRAM_BASE */
+        0x00000000,                  /* reserved */
+        0x0,                         /* config string pointer */
+        0, 0, 0, 0                   /* trap vector */
+    };
+    reset_vec[3] = 0x1000 + sizeof(reset_vec); /* config string pointer */
+
+    /* part one of config string - before memory size specified */
+    const char *config_string1 = "platform {\n"
+        "  vendor ucb;\n"
+        "  arch spike;\n"
+        "};\n"
+        "rtc {\n"
+        "  addr 0x" "40000000" ";\n"
+        "};\n"
+        "ram {\n"
+        "  0 {\n"
+        "    addr 0x" "80000000" ";\n"
+        "    size 0x";
+
+
+    /* part two of config string - after memory size specified */
+    const char *config_string2 =  ";\n"
+        "  };\n"
+        "};\n"
+        "core {\n"
+        "  0" " {\n"
+          "    " "0 {\n"
+          "      isa " "rv64imafd" ";\n"
+          "      timecmp 0x" "40000008" ";\n"
+          "      ipi 0x" "40001000" ";\n"
+          "    };\n"
+          "  };\n"
+          "};\n";
+
+    /* build config string with supplied memory size */
+    uint64_t rsz = ram_size;
+    char *ramsize_as_hex_str = malloc(17);
+    sprintf(ramsize_as_hex_str, "%016lx", rsz);
+    char *config_string = malloc(strlen(config_string1) +
+                                  strlen(ramsize_as_hex_str) +
+                                  strlen(config_string2) + 1);
+    config_string[0] = 0;
+    strcat(config_string, config_string1);
+    strcat(config_string, ramsize_as_hex_str);
+    strcat(config_string, config_string2);
+
+    /* copy in the reset vec and configstring */
+    int q;
+    for (q = 0; q < sizeof(reset_vec) / sizeof(reset_vec[0]); q++) {
+        stl_p(memory_region_get_ram_ptr(main_mem) + 0x1000 + q * 4,
+              reset_vec[q]);
+    }
+
+    int confstrlen = strlen(config_string);
+    for (q = 0; q < confstrlen; q++) {
+        stb_p(memory_region_get_ram_ptr(main_mem) + reset_vec[3] + q,
+              config_string[q]);
+    }
+
+    /* add memory mapped htif registers at location specified in the symbol
+       table of the elf being loaded (thus kernel_filename is passed to the
+       init rather than an address) */
+    htif_mm_init(system_memory, kernel_filename, env->irq[4], main_mem,
+            env, serial_hds[0]);
+
+    /* timer device at 0x40000000, as specified in the config string above */
+    timer_mm_init(system_memory, 0x40000000, env);
+
+    /* TODO: VIRTIO */
+}
+
+static int riscv_board_sysbus_device_init(SysBusDevice *sysbusdev)
+{
+    return 0;
+}
+
+static void riscv_board_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+    k->init = riscv_board_sysbus_device_init;
+}
+
+static const TypeInfo riscv_board_device = {
+    .name          = TYPE_RISCV_BOARD,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(BoardState),
+    .class_init    = riscv_board_class_init,
+};
+
+static void riscv_board_machine_init(MachineClass *mc)
+{
+    mc->desc = "RISC-V Generic Board";
+    mc->init = riscv_board_init;
+    mc->max_cpus = 1;
+    mc->is_default = 1;
+}
+
+DEFINE_MACHINE("riscv", riscv_board_machine_init)
+
+static void riscv_board_register_types(void)
+{
+    type_register_static(&riscv_board_device);
+}
+
+type_init(riscv_board_register_types);
diff --git a/hw/riscv/riscv_int.c b/hw/riscv/riscv_int.c
new file mode 100644
index 0000000..9eaf221
--- /dev/null
+++ b/hw/riscv/riscv_int.c
@@ -0,0 +1,67 @@
+/*
+ * QEMU RISC-V - QEMU IRQ Support
+ *
+ * Author: Sagar Karandikar, sagark@eecs.berkeley.edu
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/hw.h"
+#include "hw/riscv/cpudevs.h"
+#include "cpu.h"
+
+static void cpu_riscv_irq_request(void *opaque, int irq, int level)
+{
+    /* These are not the same irq numbers visible to the emulated processor. */
+    RISCVCPU *cpu = opaque;
+    CPURISCVState *env = &cpu->env;
+    CPUState *cs = CPU(cpu);
+
+    /* current irqs:
+       4: Host Interrupt. mfromhost should have a nonzero value
+       3: Machine Timer. MIP_MTIP should have already been set
+       2, 1, 0: Interrupts triggered by the CPU. At least one of
+       MIP_STIP, MIP_SSIP, MIP_MSIP should already be set */
+    if (unlikely(!(irq < 5 && irq >= 0))) {
+        printf("IRQNO: %d\n", irq);
+        fprintf(stderr, "Unused IRQ was raised.\n");
+        exit(1);
+    }
+
+    if (level) {
+        cpu_interrupt(cs, CPU_INTERRUPT_HARD);
+    } else {
+        if (!env->csr[CSR_MIP] && !env->mfromhost) {
+            /* no interrupts pending, no host interrupt for HTIF, reset */
+            cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
+        }
+    }
+}
+
+void cpu_riscv_irq_init_cpu(CPURISCVState *env)
+{
+    qemu_irq *qi;
+    int i;
+
+    qi = qemu_allocate_irqs(cpu_riscv_irq_request, riscv_env_get_cpu(env), 8);
+    for (i = 0; i < 8; i++) {
+        env->irq[i] = qi[i];
+    }
+}
-- 
2.9.3

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

* Re: [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G)
  2016-09-26 10:56 [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G) Sagar Karandikar
                   ` (17 preceding siblings ...)
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 18/18] target-riscv: Add generic test board, activate target Sagar Karandikar
@ 2016-09-26 12:20 ` Paolo Bonzini
  2016-09-26 16:17   ` Richard Henderson
  18 siblings, 1 reply; 45+ messages in thread
From: Paolo Bonzini @ 2016-09-26 12:20 UTC (permalink / raw)
  To: Sagar Karandikar, qemu-devel; +Cc: peter.maydell, kbastian, rth



On 26/09/2016 12:56, Sagar Karandikar wrote:
> -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.

Paolo

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

* Re: [Qemu-devel] [PATCH 12/18] target-riscv: Add system instructions
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 12/18] target-riscv: Add system instructions Sagar Karandikar
@ 2016-09-26 12:21   ` Paolo Bonzini
  2016-09-26 12:38     ` Bastian Koppelmann
  2016-09-26 21:41   ` Richard Henderson
  1 sibling, 1 reply; 45+ messages in thread
From: Paolo Bonzini @ 2016-09-26 12:21 UTC (permalink / raw)
  To: Sagar Karandikar, qemu-devel; +Cc: peter.maydell, kbastian, rth



On 26/09/2016 12:56, Sagar Karandikar wrote:
> +#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

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

* Re: [Qemu-devel] [PATCH 12/18] target-riscv: Add system instructions
  2016-09-26 12:21   ` Paolo Bonzini
@ 2016-09-26 12:38     ` Bastian Koppelmann
  2016-09-26 12:44       ` Paolo Bonzini
  0 siblings, 1 reply; 45+ messages in thread
From: Bastian Koppelmann @ 2016-09-26 12:38 UTC (permalink / raw)
  To: Paolo Bonzini, Sagar Karandikar, qemu-devel; +Cc: peter.maydell, rth

On 09/26/2016 02:21 PM, Paolo Bonzini wrote:
> 
> 
> On 26/09/2016 12:56, Sagar Karandikar wrote:
>> +#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

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

* Re: [Qemu-devel] [PATCH 12/18] target-riscv: Add system instructions
  2016-09-26 12:38     ` Bastian Koppelmann
@ 2016-09-26 12:44       ` Paolo Bonzini
  2016-09-27 18:12         ` Sagar Karandikar
  0 siblings, 1 reply; 45+ messages in thread
From: Paolo Bonzini @ 2016-09-26 12:44 UTC (permalink / raw)
  To: Bastian Koppelmann, Sagar Karandikar, qemu-devel; +Cc: peter.maydell, rth



On 26/09/2016 14:38, Bastian Koppelmann wrote:
> On 09/26/2016 02:21 PM, Paolo Bonzini wrote:
>>
>>
>> On 26/09/2016 12:56, Sagar Karandikar wrote:
>>> +#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.

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

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

* Re: [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G)
  2016-09-26 12:20 ` [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G) Paolo Bonzini
@ 2016-09-26 16:17   ` Richard Henderson
  2016-09-26 16:20     ` Andreas Färber
  0 siblings, 1 reply; 45+ messages in thread
From: Richard Henderson @ 2016-09-26 16:17 UTC (permalink / raw)
  To: Paolo Bonzini, Sagar Karandikar, qemu-devel
  Cc: peter.maydell, kbastian, Andreas Färber

On 09/26/2016 05:20 AM, Paolo Bonzini wrote:
>
>
> On 26/09/2016 12:56, Sagar Karandikar wrote:
>> -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~

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

* Re: [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G)
  2016-09-26 16:17   ` Richard Henderson
@ 2016-09-26 16:20     ` Andreas Färber
  2016-09-26 16:24       ` Paolo Bonzini
  0 siblings, 1 reply; 45+ messages in thread
From: Andreas Färber @ 2016-09-26 16:20 UTC (permalink / raw)
  To: Richard Henderson, Paolo Bonzini, Sagar Karandikar, qemu-devel
  Cc: peter.maydell, kbastian

Am 26.09.2016 um 18:17 schrieb Richard Henderson:
> On 09/26/2016 05:20 AM, Paolo Bonzini wrote:
>> On 26/09/2016 12:56, Sagar Karandikar wrote:
>>> -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

-- 
SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)

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

* Re: [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G)
  2016-09-26 16:20     ` Andreas Färber
@ 2016-09-26 16:24       ` Paolo Bonzini
  2016-09-26 16:35         ` Andreas Färber
  0 siblings, 1 reply; 45+ messages in thread
From: Paolo Bonzini @ 2016-09-26 16:24 UTC (permalink / raw)
  To: Andreas Färber, Richard Henderson, Sagar Karandikar, qemu-devel
  Cc: peter.maydell, kbastian



On 26/09/2016 18:20, Andreas Färber wrote:
> Am 26.09.2016 um 18:17 schrieb Richard Henderson:
>> On 09/26/2016 05:20 AM, Paolo Bonzini wrote:
>>> On 26/09/2016 12:56, Sagar Karandikar wrote:
>>>> -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.

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 <pbonzini@redhat.com>
    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.
    
    Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>


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

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

* Re: [Qemu-devel] [PATCH 02/18] target-riscv: Add RISC-V Target stubs inside target-riscv/
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 02/18] target-riscv: Add RISC-V Target stubs inside target-riscv/ Sagar Karandikar
@ 2016-09-26 16:30   ` Richard Henderson
  2016-09-26 21:50   ` Richard Henderson
  1 sibling, 0 replies; 45+ messages in thread
From: Richard Henderson @ 2016-09-26 16:30 UTC (permalink / raw)
  To: Sagar Karandikar, qemu-devel; +Cc: peter.maydell, kbastian

On 09/26/2016 03:56 AM, Sagar Karandikar wrote:
> +/* 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.

> +#define PGSHIFT 12

Just use TARGET_PAGE_BITS, surely.

> +#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
> +
> +#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.

> +/*
> + * 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 ...

> +
> +/*
> + * 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_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.


> +        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)
> +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.

> +++ b/target-riscv/op_helper.c
> @@ -0,0 +1,44 @@
> +/*
> + * RISC-V Emulation Helpers for QEMU.
> + *
> + * Author: Sagar Karandikar, sagark@eecs.berkeley.edu
> + *
> + *
> + * 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)
> +{
> +}
> +
> +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~

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

* Re: [Qemu-devel] [PATCH 03/18] target-riscv: Add initialization for translation
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 03/18] target-riscv: Add initialization for translation Sagar Karandikar
@ 2016-09-26 16:34   ` Richard Henderson
  0 siblings, 0 replies; 45+ messages in thread
From: Richard Henderson @ 2016-09-26 16:34 UTC (permalink / raw)
  To: Sagar Karandikar, qemu-devel; +Cc: peter.maydell, kbastian

On 09/26/2016 03:56 AM, Sagar Karandikar wrote:
>  RISCVCPU *cpu_riscv_init(const char *cpu_model)
>  {
> -    return NULL;
> +    RISCVCPU *cpu;
> +    CPURISCVState *env;
> +    const riscv_def_t *def;
> +
> +    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?

> +    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);

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

* Re: [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G)
  2016-09-26 16:24       ` Paolo Bonzini
@ 2016-09-26 16:35         ` Andreas Färber
  2016-09-26 16:37           ` Paolo Bonzini
  0 siblings, 1 reply; 45+ messages in thread
From: Andreas Färber @ 2016-09-26 16:35 UTC (permalink / raw)
  To: Richard Henderson, Sagar Karandikar, qemu-devel
  Cc: Paolo Bonzini, peter.maydell, kbastian

Am 26.09.2016 um 18:24 schrieb Paolo Bonzini:
> On 26/09/2016 18:20, Andreas Färber wrote:
>> Am 26.09.2016 um 18:17 schrieb Richard Henderson:
>>> On 09/26/2016 05:20 AM, Paolo Bonzini wrote:
>>>> On 26/09/2016 12:56, Sagar Karandikar wrote:
>>>>> -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

-- 
SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)

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

* Re: [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G)
  2016-09-26 16:35         ` Andreas Färber
@ 2016-09-26 16:37           ` Paolo Bonzini
  0 siblings, 0 replies; 45+ messages in thread
From: Paolo Bonzini @ 2016-09-26 16:37 UTC (permalink / raw)
  To: Andreas Färber, Richard Henderson, Sagar Karandikar, qemu-devel
  Cc: peter.maydell, kbastian



On 26/09/2016 18:35, Andreas Färber wrote:
> Am 26.09.2016 um 18:24 schrieb Paolo Bonzini:
>> On 26/09/2016 18:20, Andreas Färber wrote:
>>> Am 26.09.2016 um 18:17 schrieb Richard Henderson:
>>>> On 09/26/2016 05:20 AM, Paolo Bonzini wrote:
>>>>> On 26/09/2016 12:56, Sagar Karandikar wrote:
>>>>>> -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.

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

Paolo

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

* Re: [Qemu-devel] [PATCH 04/18] target-riscv: Add framework for instruction decode
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 04/18] target-riscv: Add framework for instruction decode Sagar Karandikar
@ 2016-09-26 16:49   ` Richard Henderson
  0 siblings, 0 replies; 45+ messages in thread
From: Richard Henderson @ 2016-09-26 16:49 UTC (permalink / raw)
  To: Sagar Karandikar, qemu-devel; +Cc: peter.maydell, kbastian

On 09/26/2016 03:56 AM, Sagar Karandikar wrote:
> +/* 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))

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.

> +    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.

> +        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.

> +        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
> +            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~

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

* Re: [Qemu-devel] [PATCH 05/18] target-riscv: Add Arithmetic instructions
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 05/18] target-riscv: Add Arithmetic instructions Sagar Karandikar
@ 2016-09-26 17:31   ` Richard Henderson
  0 siblings, 0 replies; 45+ messages in thread
From: Richard Henderson @ 2016-09-26 17:31 UTC (permalink / raw)
  To: Sagar Karandikar, qemu-devel; +Cc: peter.maydell, kbastian

On 09/26/2016 03:56 AM, Sagar Karandikar wrote:
> +#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.

> +/* 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.


> +    tcg_gen_shri_i64(t0, t0, 32);
> +    tcg_gen_extrl_i64_i32(ret, t0);

This would be tcg_gen_extrh_i64_i32.

> +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.

> +
> +    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


> +#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.

> +#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.

> +        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.

> +#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.

> +#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.

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

Likewise -1.

> +        tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source1,
> +                            1L << (TARGET_LONG_BITS - 1));

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


> +    case OPC_RISC_DIVU:
> +        tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0);
> +        tcg_gen_movi_tl(resultopt1, (target_ulong)(~0L));

-1 again.

> +    case OPC_RISC_REM:
...
> +    case OPC_RISC_REMU:

Similarly.

> +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...

> +#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.


> +#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~

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

* Re: [Qemu-devel] [PATCH 06/18] target-riscv: Add JALR, Branch Instructions
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 06/18] target-riscv: Add JALR, Branch Instructions Sagar Karandikar
@ 2016-09-26 18:28   ` Richard Henderson
  0 siblings, 0 replies; 45+ messages in thread
From: Richard Henderson @ 2016-09-26 18:28 UTC (permalink / raw)
  To: Sagar Karandikar, qemu-devel; +Cc: peter.maydell, kbastian

On 09/26/2016 03:56 AM, Sagar Karandikar wrote:
> Signed-off-by: Sagar Karandikar <sagark@eecs.berkeley.edu>
> ---
>  target-riscv/translate.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 107 insertions(+)
>
> diff --git a/target-riscv/translate.c b/target-riscv/translate.c
> index ccfb795..d8044cf 100644
> --- a/target-riscv/translate.c
> +++ b/target-riscv/translate.c
> @@ -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);

-2.

> +        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.

> +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~

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

* Re: [Qemu-devel] [PATCH 01/18] target-riscv: Add RISC-V target stubs and Maintainer
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 01/18] target-riscv: Add RISC-V target stubs and Maintainer Sagar Karandikar
@ 2016-09-26 19:06   ` Eric Blake
  0 siblings, 0 replies; 45+ messages in thread
From: Eric Blake @ 2016-09-26 19:06 UTC (permalink / raw)
  To: Sagar Karandikar, qemu-devel; +Cc: peter.maydell, kbastian, rth

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

On 09/26/2016 05:56 AM, Sagar Karandikar wrote:
> Only files that live outside of target-riscv and hw/riscv, excluding
> configure and default-configs changes.
> 
> Signed-off-by: Sagar Karandikar <sagark@eecs.berkeley.edu>
> ---

> +++ b/qapi-schema.json
> @@ -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.

> @@ -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?...

> +##
> +{ 'struct': 'CpuInfoRISCV', 'data': { 'pc': 'int' } }

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

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

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

* Re: [Qemu-devel] [PATCH 07/18] target-riscv: Add Loads/Stores, FP Loads/Stores
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 07/18] target-riscv: Add Loads/Stores, FP Loads/Stores Sagar Karandikar
@ 2016-09-26 20:44   ` Richard Henderson
  0 siblings, 0 replies; 45+ messages in thread
From: Richard Henderson @ 2016-09-26 20:44 UTC (permalink / raw)
  To: Sagar Karandikar, qemu-devel; +Cc: peter.maydell, kbastian

On 09/26/2016 03:56 AM, Sagar Karandikar wrote:
> Signed-off-by: Sagar Karandikar <sagark@eecs.berkeley.edu>
> ---
>  target-riscv/translate.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 117 insertions(+)
>
> diff --git a/target-riscv/translate.c b/target-riscv/translate.c
> index d8044cf..767cdbe 100644
> --- a/target-riscv/translate.c
> +++ b/target-riscv/translate.c
> @@ -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...

> +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]);

... 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~

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

* Re: [Qemu-devel] [PATCH 09/18] target-riscv: Add FMADD, FMSUB, FNMADD, FNMSUB Instructions,
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 09/18] target-riscv: Add FMADD, FMSUB, FNMADD, FNMSUB Instructions, Sagar Karandikar
@ 2016-09-26 21:15   ` Richard Henderson
  2016-09-27 19:20   ` Richard Henderson
  1 sibling, 0 replies; 45+ messages in thread
From: Richard Henderson @ 2016-09-26 21:15 UTC (permalink / raw)
  To: Sagar Karandikar, qemu-devel; +Cc: peter.maydell, kbastian

On 09/26/2016 03:56 AM, Sagar Karandikar wrote:
> +/* 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
> + * 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.

> +/* 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?

> +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

> +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...

> +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~

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

* Re: [Qemu-devel] [PATCH 10/18] target-riscv: Add Single Precision Floating-Point Instructions
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 10/18] target-riscv: Add Single Precision Floating-Point Instructions Sagar Karandikar
@ 2016-09-26 21:35   ` Richard Henderson
  0 siblings, 0 replies; 45+ messages in thread
From: Richard Henderson @ 2016-09-26 21:35 UTC (permalink / raw)
  To: Sagar Karandikar, qemu-devel; +Cc: peter.maydell, kbastian

On 09/26/2016 03:56 AM, Sagar Karandikar wrote:
> +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;
> +}

These are simple enough to implement inline.

> +
> +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.

> +
> +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_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_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.

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

What's the point of this?

> +
> +uint_fast16_t float32_classify(uint32_t a, float_status *status)

No need for uint_fast16_t.  Just use uint32_t.

> +{
> +    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.

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

float32_is_zero_or_denormal

> +    bool sign = signF32UI(uiA);

float32_is_neg.


r~

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

* Re: [Qemu-devel] [PATCH 11/18] target-riscv: Add Double Precision Floating-Point Instructions
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 11/18] target-riscv: Add Double " Sagar Karandikar
@ 2016-09-26 21:37   ` Richard Henderson
  0 siblings, 0 replies; 45+ messages in thread
From: Richard Henderson @ 2016-09-26 21:37 UTC (permalink / raw)
  To: Sagar Karandikar, qemu-devel; +Cc: peter.maydell, kbastian

On 09/26/2016 03:56 AM, Sagar Karandikar wrote:
> +    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],
> +                               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~

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

* Re: [Qemu-devel] [PATCH 12/18] target-riscv: Add system instructions
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 12/18] target-riscv: Add system instructions Sagar Karandikar
  2016-09-26 12:21   ` Paolo Bonzini
@ 2016-09-26 21:41   ` Richard Henderson
  1 sibling, 0 replies; 45+ messages in thread
From: Richard Henderson @ 2016-09-26 21:41 UTC (permalink / raw)
  To: Sagar Karandikar, qemu-devel; +Cc: peter.maydell, kbastian

On 09/26/2016 03:56 AM, Sagar Karandikar wrote:
> +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~

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

* Re: [Qemu-devel] [PATCH 02/18] target-riscv: Add RISC-V Target stubs inside target-riscv/
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 02/18] target-riscv: Add RISC-V Target stubs inside target-riscv/ Sagar Karandikar
  2016-09-26 16:30   ` Richard Henderson
@ 2016-09-26 21:50   ` Richard Henderson
  1 sibling, 0 replies; 45+ messages in thread
From: Richard Henderson @ 2016-09-26 21:50 UTC (permalink / raw)
  To: Sagar Karandikar, qemu-devel; +Cc: peter.maydell, kbastian

On 09/26/2016 03:56 AM, Sagar Karandikar wrote:
> +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~

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

* Re: [Qemu-devel] [PATCH 14/18] target-riscv: softmmu/address translation support
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 14/18] target-riscv: softmmu/address translation support Sagar Karandikar
@ 2016-09-26 22:04   ` Richard Henderson
  0 siblings, 0 replies; 45+ messages in thread
From: Richard Henderson @ 2016-09-26 22:04 UTC (permalink / raw)
  To: Sagar Karandikar, qemu-devel; +Cc: peter.maydell, kbastian

On 09/26/2016 03:56 AM, Sagar Karandikar wrote:
> +    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~

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

* Re: [Qemu-devel] [PATCH 15/18] target-riscv: Interrupt Handling
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 15/18] target-riscv: Interrupt Handling Sagar Karandikar
@ 2016-09-26 22:07   ` Richard Henderson
  0 siblings, 0 replies; 45+ messages in thread
From: Richard Henderson @ 2016-09-26 22:07 UTC (permalink / raw)
  To: Sagar Karandikar, qemu-devel; +Cc: peter.maydell, kbastian

On 09/26/2016 03:56 AM, Sagar Karandikar wrote:
> +        if (interruptno + 1) {

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


r~

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

* Re: [Qemu-devel] [PATCH 12/18] target-riscv: Add system instructions
  2016-09-26 12:44       ` Paolo Bonzini
@ 2016-09-27 18:12         ` Sagar Karandikar
  0 siblings, 0 replies; 45+ messages in thread
From: Sagar Karandikar @ 2016-09-27 18:12 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: Bastian Koppelmann, qemu-devel, peter.maydell, rth

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

On Mon, Sep 26, 2016 at 5:44 AM, Paolo Bonzini <pbonzini@redhat.com> wrote:

>
>
> On 26/09/2016 14:38, Bastian Koppelmann wrote:
> > On 09/26/2016 02:21 PM, Paolo Bonzini wrote:
> >>
> >>
> >> On 26/09/2016 12:56, Sagar Karandikar wrote:
> >>> +#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.
>
> 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
>

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

* Re: [Qemu-devel] [PATCH 09/18] target-riscv: Add FMADD, FMSUB, FNMADD, FNMSUB Instructions,
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 09/18] target-riscv: Add FMADD, FMSUB, FNMADD, FNMSUB Instructions, Sagar Karandikar
  2016-09-26 21:15   ` Richard Henderson
@ 2016-09-27 19:20   ` Richard Henderson
  1 sibling, 0 replies; 45+ messages in thread
From: Richard Henderson @ 2016-09-27 19:20 UTC (permalink / raw)
  To: Sagar Karandikar, qemu-devel; +Cc: peter.maydell, kbastian

On 09/26/2016 03:56 AM, Sagar Karandikar wrote:
> +/* 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)
> +
> +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~

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

* Re: [Qemu-devel] [PATCH 08/18] target-riscv: Add Atomic Instructions
  2016-09-26 10:56 ` [Qemu-devel] [PATCH 08/18] target-riscv: Add Atomic Instructions Sagar Karandikar
@ 2016-09-27 19:30   ` Richard Henderson
  0 siblings, 0 replies; 45+ messages in thread
From: Richard Henderson @ 2016-09-27 19:30 UTC (permalink / raw)
  To: Sagar Karandikar, qemu-devel; +Cc: peter.maydell, kbastian

On 09/26/2016 03:56 AM, Sagar Karandikar wrote:
> +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


> +    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~

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

end of thread, other threads:[~2016-09-27 19:30 UTC | newest]

Thread overview: 45+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-09-26 10:56 [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G) Sagar Karandikar
2016-09-26 10:56 ` [Qemu-devel] [PATCH 01/18] target-riscv: Add RISC-V target stubs and Maintainer Sagar Karandikar
2016-09-26 19:06   ` Eric Blake
2016-09-26 10:56 ` [Qemu-devel] [PATCH 02/18] target-riscv: Add RISC-V Target stubs inside target-riscv/ Sagar Karandikar
2016-09-26 16:30   ` Richard Henderson
2016-09-26 21:50   ` Richard Henderson
2016-09-26 10:56 ` [Qemu-devel] [PATCH 03/18] target-riscv: Add initialization for translation Sagar Karandikar
2016-09-26 16:34   ` Richard Henderson
2016-09-26 10:56 ` [Qemu-devel] [PATCH 04/18] target-riscv: Add framework for instruction decode Sagar Karandikar
2016-09-26 16:49   ` Richard Henderson
2016-09-26 10:56 ` [Qemu-devel] [PATCH 05/18] target-riscv: Add Arithmetic instructions Sagar Karandikar
2016-09-26 17:31   ` Richard Henderson
2016-09-26 10:56 ` [Qemu-devel] [PATCH 06/18] target-riscv: Add JALR, Branch Instructions Sagar Karandikar
2016-09-26 18:28   ` Richard Henderson
2016-09-26 10:56 ` [Qemu-devel] [PATCH 07/18] target-riscv: Add Loads/Stores, FP Loads/Stores Sagar Karandikar
2016-09-26 20:44   ` Richard Henderson
2016-09-26 10:56 ` [Qemu-devel] [PATCH 08/18] target-riscv: Add Atomic Instructions Sagar Karandikar
2016-09-27 19:30   ` Richard Henderson
2016-09-26 10:56 ` [Qemu-devel] [PATCH 09/18] target-riscv: Add FMADD, FMSUB, FNMADD, FNMSUB Instructions, Sagar Karandikar
2016-09-26 21:15   ` Richard Henderson
2016-09-27 19:20   ` Richard Henderson
2016-09-26 10:56 ` [Qemu-devel] [PATCH 10/18] target-riscv: Add Single Precision Floating-Point Instructions Sagar Karandikar
2016-09-26 21:35   ` Richard Henderson
2016-09-26 10:56 ` [Qemu-devel] [PATCH 11/18] target-riscv: Add Double " Sagar Karandikar
2016-09-26 21:37   ` Richard Henderson
2016-09-26 10:56 ` [Qemu-devel] [PATCH 12/18] target-riscv: Add system instructions Sagar Karandikar
2016-09-26 12:21   ` Paolo Bonzini
2016-09-26 12:38     ` Bastian Koppelmann
2016-09-26 12:44       ` Paolo Bonzini
2016-09-27 18:12         ` Sagar Karandikar
2016-09-26 21:41   ` Richard Henderson
2016-09-26 10:56 ` [Qemu-devel] [PATCH 13/18] target-riscv: Add CSR read/write helpers Sagar Karandikar
2016-09-26 10:56 ` [Qemu-devel] [PATCH 14/18] target-riscv: softmmu/address translation support Sagar Karandikar
2016-09-26 22:04   ` Richard Henderson
2016-09-26 10:56 ` [Qemu-devel] [PATCH 15/18] target-riscv: Interrupt Handling Sagar Karandikar
2016-09-26 22:07   ` Richard Henderson
2016-09-26 10:56 ` [Qemu-devel] [PATCH 16/18] target-riscv: Timer Support Sagar Karandikar
2016-09-26 10:56 ` [Qemu-devel] [PATCH 17/18] target-riscv: Add support for Host-Target Interface (HTIF) Devices Sagar Karandikar
2016-09-26 10:56 ` [Qemu-devel] [PATCH 18/18] target-riscv: Add generic test board, activate target Sagar Karandikar
2016-09-26 12:20 ` [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G) Paolo Bonzini
2016-09-26 16:17   ` Richard Henderson
2016-09-26 16:20     ` Andreas Färber
2016-09-26 16:24       ` Paolo Bonzini
2016-09-26 16:35         ` Andreas Färber
2016-09-26 16:37           ` Paolo Bonzini

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.