target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G)
cover target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G)
This patch set adds support for the RISC-V ISA [1] as a system-mode target. It has been tested booting Linux and FreeBSD, passes the RISC-V assembly test suite, and has had the riscv-torture [2] tester running on it for a while now without any issues arising. This patch set supports RV64G and RV32G.
Potentially useful references:
-RISC-V User Spec: See [3]. This spec is frozen.
-RISC-V Privileged Spec: See [4]. This spec is a draft, we implement v1.9. -Spike, the reference simulator for the ISA: See [5].
The comments from an earlier RFC were addressed:
-We use QEMU's built-in softfloat-cpu-qom.h merged into cpu.h
-remove active_tc/riscv-defs.h that were mirrored from MIPS
-Use DEF_HELPER_FLAGS_* where necessary
-DIV/REM now use movcond instead of branches
-handlers for arithmetic instructions and their "W" counterparts were merged to reduce code duplication
-Updated to use tcg_gen_qemu_ld_tl(..., MO_SB) etc.
[1] https://riscv.org
[2] https://github.com/ucb-bar/riscv-torture
[3] https://content.riscv.org/wp-content/uploads/2016/06/riscv-spec-v2.1.pdf
[4] https://content.riscv.org/wp-content/uploads/2016/07/riscv-privileged-v1.9-1.pdf
[5] https://github.com/riscv/riscv-isa-sim
Sagar Karandikar (18):
target-riscv: Add RISC-V target stubs and Maintainer
target-riscv: Add RISC-V Target stubs inside target-riscv/
target-riscv: Add initialization for translation
target-riscv: Add framework for instruction decode
target-riscv: Add Arithmetic instructions
target-riscv: Add JALR, Branch Instructions
target-riscv: Add Loads/Stores, FP Loads/Stores
target-riscv: Add Atomic Instructions
target-riscv: Add FMADD, FMSUB, FNMADD, FNMSUB Instructions,
target-riscv: Add Single Precision Floating-Point Instructions
target-riscv: Add Double Precision Floating-Point Instructions
target-riscv: Add system instructions
target-riscv: Add CSR read/write helpers
target-riscv: softmmu/address translation support
target-riscv: Interrupt Handling
target-riscv: Timer Support
target-riscv: Add support for Host-Target Interface (HTIF) Devices
target-riscv: Add generic test board, activate target
MAINTAINERS | 7 + arch_init.c | 2 + configure | 6 + cpus.c | 6 + default-configs/riscv32-softmmu.mak | 38 + default-configs/riscv64-softmmu.mak | 38 + fpu/softfloat-specialize.h | 7 +- hw/riscv/Makefile.objs | 5 + hw/riscv/cpudevs.h | 17 + hw/riscv/htif/elf_symb.c | 286 ++++++ hw/riscv/htif/elf_symb.h | 80 ++ hw/riscv/htif/htif.c | 423 +++++++++ hw/riscv/riscv_board.c | 264 ++++++ hw/riscv/riscv_int.c | 67 ++ hw/riscv/riscv_rtc.c | 230 +++++ include/elf.h | 2 + include/hw/riscv/htif/htif.h | 61 ++ include/hw/riscv/riscv_rtc.h | 25 + include/hw/riscv/riscv_rtc_internal.h | 3 + include/sysemu/arch_init.h | 1 + qapi-schema.json | 14 +- target-riscv/Makefile.objs | 1 + target-riscv/cpu.c | 154 +++ target-riscv/cpu.h | 497 ++++++++++ target-riscv/fpu_helper.c | 582 ++++++++++++ target-riscv/helper.c | 420 +++++++++ target-riscv/helper.h | 87 ++ target-riscv/instmap.h | 328 +++++++ target-riscv/op_helper.c | 577 ++++++++++++ target-riscv/translate.c | 1658 +++++++++++++++++++++++++++++++++ 30 files changed, 5882 insertions(+), 4 deletions(-) create mode 100644 default-configs/riscv32-softmmu.mak create mode 100644 default-configs/riscv64-softmmu.mak create mode 100644 hw/riscv/Makefile.objs create mode 100644 hw/riscv/cpudevs.h create mode 100644 hw/riscv/htif/elf_symb.c create mode 100644 hw/riscv/htif/elf_symb.h create mode 100644 hw/riscv/htif/htif.c create mode 100644 hw/riscv/riscv_board.c create mode 100644 hw/riscv/riscv_int.c create mode 100644 hw/riscv/riscv_rtc.c create mode 100644 include/hw/riscv/htif/htif.h create mode 100644 include/hw/riscv/riscv_rtc.h create mode 100644 include/hw/riscv/riscv_rtc_internal.h create mode 100644 target-riscv/Makefile.objs create mode 100644 target-riscv/cpu.c create mode 100644 target-riscv/cpu.h create mode 100644 target-riscv/fpu_helper.c create mode 100644 target-riscv/helper.c create mode 100644 target-riscv/helper.h create mode 100644 target-riscv/instmap.h create mode 100644 target-riscv/op_helper.c create mode 100644 target-riscv/translate.c
Signature · 1 line
2.9.3
PATCH 1/18 target-riscv: Add RISC-V target stubs and Maintainer
Only files that live outside of target-riscv and hw/riscv, excluding configure and default-configs changes.
--- MAINTAINERS | 7 +++++++ arch_init.c | 2 ++ cpus.c | 6 ++++++ include/elf.h | 2 ++ include/sysemu/arch_init.h | 1 + qapi-schema.json | 14 +++++++++++++- 6 files changed, 31 insertions(+), 1 deletion(-)
MAINTAINERS +7 -0
@@ -175,6 +175,13 @@ F: hw/ppc/ F: include/hw/ppc/ F: disas/ppc.c +RISC-V +M: Sagar Karandikar <[email protected]> +M: Bastian Koppelmann <[email protected]> +S: Maintained +F: target-riscv/ +F: hw/riscv/ + S390 M: Richard Henderson <[email protected]> M: Alexander Graf <[email protected]>
arch_init.c +2 -0
@@ -62,6 +62,8 @@ int graphic_depth = 32;#define QEMU_ARCH QEMU_ARCH_MICROBLAZE#elif defined(TARGET_MIPS )#define QEMU_ARCH QEMU_ARCH_MIPS +#elif defined(TARGET_RISCV ) +#define QEMU_ARCH QEMU_ARCH_RISCV#elif defined(TARGET_MOXIE )#define QEMU_ARCH QEMU_ARCH_MOXIE#elif defined(TARGET_OPENRISC )
cpus.c +6 -0
@@ -1618,6 +1618,9 @@ CpuInfoList *qmp_query_cpus(Error **errp)#elif defined(TARGET_SPARC )SPARCCPU *sparc_cpu =SPARC_CPU (cpu);CPUSPARCState *env = &sparc_cpu->env; +#elif defined(TARGET_RISCV ) +RISCVCPU *riscv_cpu =RISCV_CPU (cpu); +CPURISCVState *env = &riscv_cpu->env;#elif defined(TARGET_MIPS )MIPSCPU *mips_cpu =MIPS_CPU (cpu);CPUMIPSState *env = &mips_cpu->env;
@@ -1651,6 +1654,9 @@ CpuInfoList *qmp_query_cpus(Error **errp)#elif defined(TARGET_TRICORE ) info->value->arch =CPU_INFO_ARCH_TRICORE ; info->value->u.tricore.PC = env->PC; +#elif defined(TARGET_RISCV ) + info->value->arch =CPU_INFO_ARCH_RISCV ; + info->value->u.riscv.pc = env->PC;#else info->value->arch =CPU_INFO_ARCH_OTHER ;#endif
include/elf.h +2 -0
@@ -112,6 +112,8 @@ typedef int64_t Elf64_Sxword;#define EM_UNICORE32 110/* UniCore32 */ +#define EM_RISCV 243/* RISC-V */ +/* * This is an interim value that we will use until the committee comes * up with a final number.
include/sysemu/arch_init.h +1 -0
@@ -23,6 +23,7 @@ enum {QEMU_ARCH_UNICORE32 = (1 <<14 ),QEMU_ARCH_MOXIE = (1 <<15 ),QEMU_ARCH_TRICORE = (1 <<16 ), + QEMU_ARCH_RISCV = (1 << 17), };extern const uint32_t arch_type;
qapi-schema.json +13 -1
@@ -832,7 +832,7 @@ # Since: 2.6 ## { 'enum': 'CpuInfoArch', - 'data': ['x86', 'sparc', 'ppc', 'mips', 'tricore', 'other' ] } + 'data': ['x86', 'sparc', 'ppc', 'mips', 'tricore', 'riscv', 'other' ] } ## # @CpuInfo:
@@ -867,6 +867,7 @@ 'ppc': 'CpuInfoPPC', 'mips': 'CpuInfoMIPS', 'tricore': 'CpuInfoTricore', + 'riscv': 'CpuInfoRISCV', 'other': 'CpuInfoOther' } } ##
@@ -927,6 +928,17 @@ { 'struct': 'CpuInfoTricore', 'data': { 'PC': 'int' } } ## +# @CpuInfoRISCV: +# +# Additional information about a virtual RISCV CPU +# +# @PC: the instruction pointer +# +# Since 2.6 +## +{ 'struct': 'CpuInfoRISCV', 'data': { 'pc': 'int' } } + +## # @CpuInfoOther: # # No additional information is available about the virtual CPU
Signature · 1 line
2.9.3
Re: [Qemu-devel] [PATCH 01/18] target-riscv: Add RISC-V target stubs and Maintainer
qapi-schema.json line 835
Quoted 13 lines · Sagar Karandikar
Only files that live outside of target-riscv and hw/riscv, excluding configure and default-configs changes.
Signed-off-by Sagar Karandikar <[email protected]>---
+++
b/qapi-schema.jsonqapi-schema.json +1
-1@@ -832,7 +832,7 @@ # Since: 2.6 ## { 'enum': 'CpuInfoArch', - 'data': ['x86', 'sparc', 'ppc', 'mips', 'tricore', 'other' ] } + 'data': ['x86', 'sparc', 'ppc', 'mips', 'tricore', 'riscv', 'other' ] }
Missing documentation that 'riscv' was added in 2.8. Enums aren't always the best example, but BlockdevDriver in qapi/block-core.json shows a good way of how to do it.
qapi-schema.json line 937
Quoted 11 lines
qapi-schema.json +7
-0@@ -927,6 +928,17 @@ { 'struct': 'CpuInfoTricore', 'data': { 'PC': 'int' } } ## +# @CpuInfoRISCV: +# +# Additional information about a virtual RISCV CPU +# +# @PC: the instruction pointer +# +# Since 2.6
s/2.6/2.8/
And can we please NOT abuse the fact that CpuInfo is already whitelisted for allowing non-lowercase names?...
qapi-schema.json line 939
Quoted 2 lines
qapi-schema.json +2
-0+## +{ 'struct': 'CpuInfoRISCV', 'data': { 'pc': 'int' } }
Oh, you already did. Your documentation is wrong, then, as it documents 'PC' while the code uses 'pc'.
Signature · 2 lines
Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
PATCH 2/18 target-riscv: Add RISC-V Target stubs inside target-riscv/
In reply to Sagar Karandikar--- target-riscv/Makefile.objs | 1 + target-riscv/cpu.c | 154 ++++++++++++++ target-riscv/cpu.h | 497 +++++++++++++++++++++++++++++++++++++++++++++ target-riscv/helper.c | 59 ++++++ target-riscv/helper.h | 0 target-riscv/op_helper.c | 44 ++++ target-riscv/translate.c | 131 ++++++++++++ 7 files changed, 886 insertions(+) create mode 100644 target-riscv/Makefile.objs create mode 100644 target-riscv/cpu.c create mode 100644 target-riscv/cpu.h create mode 100644 target-riscv/helper.c create mode 100644 target-riscv/helper.h create mode 100644 target-riscv/op_helper.c create mode 100644 target-riscv/translate.c
target-riscv/Makefile.objs new file +1 -0
@@ -0,0 +1 @@ +obj-y += translate.o op_helper.o helper.o cpu.o
target-riscv/cpu.c new file +154 -0
154 lines not on this page · raw message
target-riscv/cpu.h new file +497 -0
497 lines not on this page · raw message
target-riscv/helper.c new file +59 -0
59 lines not on this page · raw message
target-riscv/helper.h new file +0 -0
target-riscv/op_helper.c new file +44 -0
44 lines not on this page · raw message
target-riscv/translate.c new file +131 -0
131 lines not on this page · raw message
Signature · 1 line
2.9.3
Re: [Qemu-devel] [PATCH 02/18] target-riscv: Add RISC-V Target stubs inside target-riscv/
target-riscv/cpu.h line 22
Quoted 8 lines · Sagar Karandikar
target-riscv/cpu.h new file +8
-0+/* QEMU addressing/paging config */ +#define TARGET_PAGE_BITS 12/* 4 KiB Pages */ +#if defined(TARGET_RISCV64 ) +#define TARGET_LONG_BITS 64/* this defs TCGv as TCGv_i64 in tcg/tcg-op.h */ +#define TARGET_PHYS_ADDR_SPACE_BITS 50 +#define TARGET_VIRT_ADDR_SPACE_BITS 39 +#elif defined(TARGET_RISCV32 ) +#define TARGET_LONG_BITS 32/* this defs TCGv as TCGv_i64 in tcg/tcg-op.h */
Typo, and there's not really a need for that comment anyway.
Quoted 1 line
+#define PGSHIFT 12
Just use TARGET_PAGE_BITS, surely.
Quoted 21 lines
target-riscv/cpu.h new file +21
-0+#define MSTATUS_UIE 0x00000001 +#define MSTATUS_SIE 0x00000002 +#define MSTATUS_HIE 0x00000004 +#define MSTATUS_MIE 0x00000008 +#define MSTATUS_UPIE 0x00000010 +#define MSTATUS_SPIE 0x00000020 +#define MSTATUS_HPIE 0x00000040 +#define MSTATUS_MPIE 0x00000080 +#define MSTATUS_SPP 0x00000100 +#define MSTATUS_HPP 0x00000600 +#define MSTATUS_MPP 0x00001800 +#define MSTATUS_FS 0x00006000 +#define MSTATUS_XS 0x00018000 +#define MSTATUS_MPRV 0x00020000 +#define MSTATUS_PUM 0x00040000 +#define MSTATUS_MXR 0x00080000 +#define MSTATUS_VM 0x1F000000 + +#define MSTATUS32_SD 0x80000000 +#define MSTATUS64_SD 0x8000000000000000 +
target-riscv/cpu.h line 185
Quoted 10 lines
target-riscv/cpu.h new file +10
-0+#define SSTATUS_UIE 0x00000001 +#define SSTATUS_SIE 0x00000002 +#define SSTATUS_UPIE 0x00000010 +#define SSTATUS_SPIE 0x00000020 +#define SSTATUS_SPP 0x00000100 +#define SSTATUS_FS 0x00006000 +#define SSTATUS_XS 0x00018000 +#define SSTATUS_PUM 0x00040000 +#define SSTATUS32_SD 0x80000000 +#define SSTATUS64_SD 0x8000000000000000
Given that the status bits for lesser privs are the same as MSTATUS, with some omissions, reproducing these is not ideal. Perhaps better to define a SSTATUS_MASK that lists the MSTATUS bits that are controlable.
target-riscv/cpu.h line 421
Quoted 7 lines
target-riscv/cpu.h new file +7
-0+/* +* ctz in Spike returns 0 if val == 0, wrap helper +*/ +static int ctz (target_ulong val) +{ +return val ?ctz64 (val) :0 ; +}
Does this really belong here? I don't see it used by op_helper, only ...
Quoted 13 lines
target-riscv/cpu.h new file +13
-0+ +/* +* Return RISC-V IRQ number if an interrupt should be taken, else -1. +* Used in cpu-exec.c +* +* Adapted from Spike's processor_t::take_interrupt() +*/ +static inline int cpu_riscv_hw_interrupts_pending (CPURISCVState *env) +{ +target_ulong pending_interrupts = env->csr[CSR_MIP ] & env->csr[CSR_MIE ]; + +target_ulong mie =get_field (env->csr[CSR_MSTATUS ],MSTATUS_MIE ); +target_ulong m_enabled = env->priv <PRV_M || (env->priv ==PRV_M && mie);
target-riscv/cpu.h line 444
Quoted 10 lines
target-riscv/cpu.h new file +10
-0+target_ulong enabled_interrupts = pending_interrupts & + ~env->csr[CSR_MIDELEG ] & -m_enabled; + +target_ulong sie =get_field (env->csr[CSR_MSTATUS ],MSTATUS_SIE ); +target_ulong s_enabled = env->priv <PRV_S || (env->priv ==PRV_S && sie); + enabled_interrupts |= pending_interrupts & env->csr[CSR_MIDELEG ] & + -s_enabled; + +if (enabled_interrupts) { +target_ulong counted =ctz (enabled_interrupts);
... here, where we've already eliminated 0. So, surely you could just use ctz64 directly.
Quoted 29 lines
target-riscv/cpu.h new file +29
-0+if (counted ==IRQ_HOST ) { +/* we're handing it to the cpu now, so get rid of the qemu irq */ +qemu_irq_lower (HTIF_IRQ ); + }else if (counted ==IRQ_M_TIMER ) { +/* we're handing it to the cpu now, so get rid of the qemu irq */ +qemu_irq_lower (TIMER_IRQ ); + }else if (counted ==IRQ_S_TIMER || counted ==IRQ_H_TIMER ) { +/* don't lower irq here */ + } +return counted; + }else { +return EXCP_NONE ;/* indicates no pending interrupt */ + } +} + +#include "exec/cpu-all.h" + +void riscv_tcg_init (void ); +RISCVCPU *cpu_riscv_init (const char *cpu_model); +int cpu_riscv_signal_handler (int host_signum,void *pinfo,void *puc); + +#define cpu_init (cpu_model) CPU(cpu_riscv_init(cpu_model)) + +/* hw/riscv/riscv_rtc.c - supplies instret by approximating */ +uint64_t cpu_riscv_read_instret (CPURISCVState *env); + +int riscv_cpu_handle_mmu_fault (CPUState *cpu,vaddr address,MMUAccessType rw, +int mmu_idx); +#if !defined(CONFIG_USER_ONLY )
target-riscv/cpu.h line 483
Quoted 10 lines
target-riscv/cpu.h new file +10
-0+hwaddr cpu_riscv_translate_address (CPURISCVState *env,target_ulong address, +int rw); +#endif + +static inline void cpu_get_tb_cpu_state (CPURISCVState *env,target_ulong *pc, +target_ulong *cs_base,uint32_t *flags) +{ + *pc = env->PC; + *cs_base =0 ; + *flags =0 ;/* necessary to avoid compiler warning */
At minimum, you'll need to include the priv level in the flags, so that one can only run TBs that were built for the cpu's current priv level.
Quoted 34 lines
+++
b/target-riscv/op_helper.ctarget-riscv/op_helper.c new file +32
-0@@ -0,0 +1,44 @@ +/* +* RISC-V Emulation Helpers for QEMU. +* +* Author: Sagar Karandikar, [email protected] +* +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include "qemu/osdep.h" +#include <stdlib.h> +#include "cpu.h" +#include "qemu/host-utils.h" +#include "exec/helper-proto.h" + +#ifndef CONFIG_USER_ONLY +void riscv_cpu_do_unaligned_access (CPUState *cs,vaddr addr, +MMUAccessType access_type,int mmu_idx, +uintptr_t retaddr) +{ +}
target-riscv/op_helper.c line 42
Quoted 10 lines
target-riscv/op_helper.c new file +10
-0+ +void tlb_fill (CPUState *cs,target_ulong addr,MMUAccessType access_type, +int mmu_idx,uintptr_t retaddr) +{ +} + +void riscv_cpu_unassigned_access (CPUState *cs,hwaddr addr,bool is_write, +bool is_exec,int unused,unsigned size) +{ +}
These are better placed in helper.c, reserving op_helper.c for those functions implementing helpers for "op"s, i.e. instructions.
r~
Re: [Qemu-devel] [PATCH 02/18] target-riscv: Add RISC-V Target stubs inside target-riscv/
In reply to Sagar Karandikartarget-riscv/cpu.h line 297
Quoted 8 lines · Sagar Karandikar
target-riscv/cpu.h new file +8
-0+typedef struct CPURISCVState CPURISCVState ; +struct CPURISCVState { +target_ulong gpr[32 ]; +uint64_t fpr[32 ];/* assume both F and D extensions */ +target_ulong PC; +target_ulong load_res; + +target_ulong csr[4096 ];/* RISCV CSR registers */
This is 16k for 32-bit, and 32k for 64-bit, most of which is unused.
I think it would be better to add only the CSRs that you actually need for the implementation.
r~
PATCH 3/18 target-riscv: Add initialization for translation
In reply to Sagar KarandikarAdd tcg and cpu model initialization
Add gen_intermediate_code function, dummy decode_opc Add exception helpers necessary for gen_intermediate_code
--- target-riscv/helper.h | 4 + target-riscv/op_helper.c | 26 +++++ target-riscv/translate.c | 244 ++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 273 insertions(+), 1 deletion(-)
target-riscv/helper.h +4 -0
@@ -0,0 +1,4 @@ +/* Exceptions */ +DEF_HELPER_2(raise_exception, noreturn, env, i32) +DEF_HELPER_1(raise_exception_debug, noreturn, env) +DEF_HELPER_3 (raise_exception_mbadaddr, noreturn, env, i32, tl)
target-riscv/op_helper.c +26 -0
@@ -24,6 +24,32 @@#include "qemu/host-utils.h" #include "exec/helper-proto.h" +/* Exceptions processing helpers */ +static inline void QEMU_NORETURN do_raise_exception_err(CPURISCVState *env, +uint32_t exception,uintptr_t pc) +{ +CPUState *cs =CPU (riscv_env_get_cpu (env)); +qemu_log_mask (CPU_LOG_INT ,"%s: %d\n" , __func__, exception); + cs->exception_index = exception; +cpu_loop_exit_restore (cs, pc); +} + +void helper_raise_exception (CPURISCVState *env,uint32_t exception) +{ +do_raise_exception_err (env, exception,0 ); +} + +void helper_raise_exception_debug (CPURISCVState *env) +{ +do_raise_exception_err (env,EXCP_DEBUG ,0 ); +} + +void helper_raise_exception_mbadaddr (CPURISCVState *env,uint32_t exception, +target_ulong bad_pc) { + env->badaddr = bad_pc; +do_raise_exception_err (env, exception,0 ); +} +#ifndef CONFIG_USER_ONLY void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr, MMUAccessType access_type, int mmu_idx,
target-riscv/translate.c +243 -1
276 lines not on this page · raw message
Signature · 1 line
2.9.3
Re: [Qemu-devel] [PATCH 03/18] target-riscv: Add initialization for translation
Quoted 6 lines · Sagar Karandikar
RISCVCPU *cpu_riscv_init(const char
*cpu_model)
{target-riscv/translate.c +3
-1-return NULL ; +RISCVCPU *cpu; +CPURISCVState *env; +const riscv_def_t *def;
target-riscv/translate.c void riscv_cpu_list(FILE *f, fprintf_function cpu_fprintf) · line 356
Quoted 10 lines
target-riscv/translate.c +10
-0+ + def =cpu_riscv_find_by_name (cpu_model); +if (!def) { +return NULL ; + } + cpu =RISCV_CPU (object_new (TYPE_RISCV_CPU )); + env = &cpu->env; + env->cpu_model = def; + +memset (env->csr,0 ,4096 *sizeof (target_ulong));
sizeof(env->csr)?
And besides that, doesn't this more properly belong in a reset function, where that memset will already have been done?
Quoted 8 lines
target-riscv/translate.c +8
-0+ env->priv =PRV_M ; + +/* set mcpuid from def */ + env->csr[CSR_MISA ] = def->init_misa_reg; +object_property_set_bool (OBJECT (cpu), true,"realized" ,NULL ); + +/* fpu flags: */ +set_default_nan_mode (1 , &env->fp_status);
PATCH 4/18 target-riscv: Add framework for instruction decode
In reply to Sagar KarandikarBody of decode_opc with LUI, AUIPC, JAL instructions Decode table in instmap.h
--- target-riscv/instmap.h | 328 +++++++++++++++++++++++++++++++++++++++++++++++ target-riscv/translate.c | 64 +++++++++ 2 files changed, 392 insertions(+) create mode 100644 target-riscv/instmap.h
target-riscv/instmap.h new file +328 -0
@@ -0,0 +1,328 @@ +/* +* RISC-V emulation for qemu: Instruction decode helpers +* +* Author: Sagar Karandikar, [email protected] +* +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +#define MASK_OP_MAJOR (op) (op & 0x7F) +enum { +/* rv32i, rv64i, rv32m */ +OPC_RISC_LUI = (0x37 ), +OPC_RISC_AUIPC = (0x17 ), +OPC_RISC_JAL = (0x6F ), +OPC_RISC_JALR = (0x67 ), +OPC_RISC_BRANCH = (0x63 ), +OPC_RISC_LOAD = (0x03 ), +OPC_RISC_STORE = (0x23 ), +OPC_RISC_ARITH_IMM = (0x13 ), +OPC_RISC_ARITH = (0x33 ), +OPC_RISC_FENCE = (0x0F ), +OPC_RISC_SYSTEM = (0x73 ), + +/* rv64i, rv64m */ +OPC_RISC_ARITH_IMM_W = (0x1B ), +OPC_RISC_ARITH_W = (0x3B ), + +/* rv32a, rv64a */ +OPC_RISC_ATOMIC = (0x2F ), + +/* floating point */ +OPC_RISC_FP_LOAD = (0x7 ), +OPC_RISC_FP_STORE = (0x27 ), + +OPC_RISC_FMADD = (0x43 ), +OPC_RISC_FMSUB = (0x47 ), +OPC_RISC_FNMSUB = (0x4B ), +OPC_RISC_FNMADD = (0x4F ), + +OPC_RISC_FP_ARITH = (0x53 ), +}; + +#define MASK_OP_ARITH (op) (MASK_OP_MAJOR(op) | (op & ((0x7 << 12) | \ + (0x7F << 25)))) +enum { +OPC_RISC_ADD =OPC_RISC_ARITH | (0x0 <<12 ) | (0x00 <<25 ), +OPC_RISC_SUB =OPC_RISC_ARITH | (0x0 <<12 ) | (0x20 <<25 ), +OPC_RISC_SLL =OPC_RISC_ARITH | (0x1 <<12 ) | (0x00 <<25 ), +OPC_RISC_SLT =OPC_RISC_ARITH | (0x2 <<12 ) | (0x00 <<25 ), +OPC_RISC_SLTU =OPC_RISC_ARITH | (0x3 <<12 ) | (0x00 <<25 ), +OPC_RISC_XOR =OPC_RISC_ARITH | (0x4 <<12 ) | (0x00 <<25 ), +OPC_RISC_SRL =OPC_RISC_ARITH | (0x5 <<12 ) | (0x00 <<25 ), +OPC_RISC_SRA =OPC_RISC_ARITH | (0x5 <<12 ) | (0x20 <<25 ), +OPC_RISC_OR =OPC_RISC_ARITH | (0x6 <<12 ) | (0x00 <<25 ), +OPC_RISC_AND =OPC_RISC_ARITH | (0x7 <<12 ) | (0x00 <<25 ), + +/* RV64M */ +OPC_RISC_MUL =OPC_RISC_ARITH | (0x0 <<12 ) | (0x01 <<25 ), +OPC_RISC_MULH =OPC_RISC_ARITH | (0x1 <<12 ) | (0x01 <<25 ), +OPC_RISC_MULHSU =OPC_RISC_ARITH | (0x2 <<12 ) | (0x01 <<25 ), +OPC_RISC_MULHU =OPC_RISC_ARITH | (0x3 <<12 ) | (0x01 <<25 ), + +OPC_RISC_DIV =OPC_RISC_ARITH | (0x4 <<12 ) | (0x01 <<25 ), +OPC_RISC_DIVU =OPC_RISC_ARITH | (0x5 <<12 ) | (0x01 <<25 ), +OPC_RISC_REM =OPC_RISC_ARITH | (0x6 <<12 ) | (0x01 <<25 ), +OPC_RISC_REMU =OPC_RISC_ARITH | (0x7 <<12 ) | (0x01 <<25 ), +}; + + +#define MASK_OP_ARITH_IMM (op) (MASK_OP_MAJOR(op) | (op & (0x7 << 12))) +enum { +OPC_RISC_ADDI =OPC_RISC_ARITH_IMM | (0x0 <<12 ), +OPC_RISC_SLTI =OPC_RISC_ARITH_IMM | (0x2 <<12 ), +OPC_RISC_SLTIU =OPC_RISC_ARITH_IMM | (0x3 <<12 ), +OPC_RISC_XORI =OPC_RISC_ARITH_IMM | (0x4 <<12 ), +OPC_RISC_ORI =OPC_RISC_ARITH_IMM | (0x6 <<12 ), +OPC_RISC_ANDI =OPC_RISC_ARITH_IMM | (0x7 <<12 ), +OPC_RISC_SLLI =OPC_RISC_ARITH_IMM | (0x1 <<12 ),/* additional part of +IMM */ +OPC_RISC_SHIFT_RIGHT_I =OPC_RISC_ARITH_IMM | (0x5 <<12 )/* SRAI, SRLI */ +}; + +#define MASK_OP_BRANCH (op) (MASK_OP_MAJOR(op) | (op & (0x7 << 12))) +enum { +OPC_RISC_BEQ =OPC_RISC_BRANCH | (0x0 <<12 ), +OPC_RISC_BNE =OPC_RISC_BRANCH | (0x1 <<12 ), +OPC_RISC_BLT =OPC_RISC_BRANCH | (0x4 <<12 ), +OPC_RISC_BGE =OPC_RISC_BRANCH | (0x5 <<12 ), +OPC_RISC_BLTU =OPC_RISC_BRANCH | (0x6 <<12 ), +OPC_RISC_BGEU =OPC_RISC_BRANCH | (0x7 <<12 ) +}; + +enum { +OPC_RISC_ADDIW =OPC_RISC_ARITH_IMM_W | (0x0 <<12 ), +OPC_RISC_SLLIW =OPC_RISC_ARITH_IMM_W | (0x1 <<12 ),/* additional part of +IMM */ +OPC_RISC_SHIFT_RIGHT_IW =OPC_RISC_ARITH_IMM_W | (0x5 <<12 )/* SRAI, SRLI +*/ +}; + +enum { +OPC_RISC_ADDW =OPC_RISC_ARITH_W | (0x0 <<12 ) | (0x00 <<25 ), +OPC_RISC_SUBW =OPC_RISC_ARITH_W | (0x0 <<12 ) | (0x20 <<25 ), +OPC_RISC_SLLW =OPC_RISC_ARITH_W | (0x1 <<12 ) | (0x00 <<25 ), +OPC_RISC_SRLW =OPC_RISC_ARITH_W | (0x5 <<12 ) | (0x00 <<25 ), +OPC_RISC_SRAW =OPC_RISC_ARITH_W | (0x5 <<12 ) | (0x20 <<25 ), + +/* RV64M */ +OPC_RISC_MULW =OPC_RISC_ARITH_W | (0x0 <<12 ) | (0x01 <<25 ), +OPC_RISC_DIVW =OPC_RISC_ARITH_W | (0x4 <<12 ) | (0x01 <<25 ), +OPC_RISC_DIVUW =OPC_RISC_ARITH_W | (0x5 <<12 ) | (0x01 <<25 ), +OPC_RISC_REMW =OPC_RISC_ARITH_W | (0x6 <<12 ) | (0x01 <<25 ), +OPC_RISC_REMUW =OPC_RISC_ARITH_W | (0x7 <<12 ) | (0x01 <<25 ), +}; + +#define MASK_OP_LOAD (op) (MASK_OP_MAJOR(op) | (op & (0x7 << 12))) +enum { +OPC_RISC_LB =OPC_RISC_LOAD | (0x0 <<12 ), +OPC_RISC_LH =OPC_RISC_LOAD | (0x1 <<12 ), +OPC_RISC_LW =OPC_RISC_LOAD | (0x2 <<12 ), +OPC_RISC_LD =OPC_RISC_LOAD | (0x3 <<12 ), +OPC_RISC_LBU =OPC_RISC_LOAD | (0x4 <<12 ), +OPC_RISC_LHU =OPC_RISC_LOAD | (0x5 <<12 ), +OPC_RISC_LWU =OPC_RISC_LOAD | (0x6 <<12 ), +}; + +#define MASK_OP_STORE (op) (MASK_OP_MAJOR(op) | (op & (0x7 << 12))) +enum { +OPC_RISC_SB =OPC_RISC_STORE | (0x0 <<12 ), +OPC_RISC_SH =OPC_RISC_STORE | (0x1 <<12 ), +OPC_RISC_SW =OPC_RISC_STORE | (0x2 <<12 ), +OPC_RISC_SD =OPC_RISC_STORE | (0x3 <<12 ), +}; + +#define MASK_OP_JALR (op) (MASK_OP_MAJOR(op) | (op & (0x7 << 12))) +/* no enum since OPC_RISC_JALR is the actual value */ + +#define MASK_OP_ATOMIC (op) (MASK_OP_MAJOR(op) | (op & ((0x7 << 12) \ + | (0x7F << 25)))) +#define MASK_OP_ATOMIC_NO_AQ_RL (op) (MASK_OP_MAJOR(op) | (op & ((0x7 << 12)\ + | (0x1F << 27)))) +enum { +OPC_RISC_LR_W =OPC_RISC_ATOMIC | (0x2 <<12 ) | (0x02 <<27 ), +OPC_RISC_SC_W =OPC_RISC_ATOMIC | (0x2 <<12 ) | (0x03 <<27 ), +OPC_RISC_AMOSWAP_W =OPC_RISC_ATOMIC | (0x2 <<12 ) | (0x01 <<27 ), +OPC_RISC_AMOADD_W =OPC_RISC_ATOMIC | (0x2 <<12 ) | (0x00 <<27 ), +OPC_RISC_AMOXOR_W =OPC_RISC_ATOMIC | (0x2 <<12 ) | (0x04 <<27 ), +OPC_RISC_AMOAND_W =OPC_RISC_ATOMIC | (0x2 <<12 ) | (0x0C <<27 ), +OPC_RISC_AMOOR_W =OPC_RISC_ATOMIC | (0x2 <<12 ) | (0x08 <<27 ), +OPC_RISC_AMOMIN_W =OPC_RISC_ATOMIC | (0x2 <<12 ) | (0x10 <<27 ), +OPC_RISC_AMOMAX_W =OPC_RISC_ATOMIC | (0x2 <<12 ) | (0x14 <<27 ), +OPC_RISC_AMOMINU_W =OPC_RISC_ATOMIC | (0x2 <<12 ) | (0x18 <<27 ), +OPC_RISC_AMOMAXU_W =OPC_RISC_ATOMIC | (0x2 <<12 ) | (0x1C <<27 ), + +OPC_RISC_LR_D =OPC_RISC_ATOMIC | (0x3 <<12 ) | (0x02 <<27 ), +OPC_RISC_SC_D =OPC_RISC_ATOMIC | (0x3 <<12 ) | (0x03 <<27 ), +OPC_RISC_AMOSWAP_D =OPC_RISC_ATOMIC | (0x3 <<12 ) | (0x01 <<27 ), +OPC_RISC_AMOADD_D =OPC_RISC_ATOMIC | (0x3 <<12 ) | (0x00 <<27 ), +OPC_RISC_AMOXOR_D =OPC_RISC_ATOMIC | (0x3 <<12 ) | (0x04 <<27 ), +OPC_RISC_AMOAND_D =OPC_RISC_ATOMIC | (0x3 <<12 ) | (0x0C <<27 ), +OPC_RISC_AMOOR_D =OPC_RISC_ATOMIC | (0x3 <<12 ) | (0x08 <<27 ), +OPC_RISC_AMOMIN_D =OPC_RISC_ATOMIC | (0x3 <<12 ) | (0x10 <<27 ), +OPC_RISC_AMOMAX_D =OPC_RISC_ATOMIC | (0x3 <<12 ) | (0x14 <<27 ), +OPC_RISC_AMOMINU_D =OPC_RISC_ATOMIC | (0x3 <<12 ) | (0x18 <<27 ), +OPC_RISC_AMOMAXU_D =OPC_RISC_ATOMIC | (0x3 <<12 ) | (0x1C <<27 ), +}; + +#define MASK_OP_SYSTEM (op) (MASK_OP_MAJOR(op) | (op & (0x7 << 12))) +enum { +OPC_RISC_ECALL =OPC_RISC_SYSTEM | (0x0 <<12 ), +OPC_RISC_EBREAK =OPC_RISC_SYSTEM | (0x0 <<12 ), +OPC_RISC_ERET =OPC_RISC_SYSTEM | (0x0 <<12 ), +OPC_RISC_MRTS =OPC_RISC_SYSTEM | (0x0 <<12 ), +OPC_RISC_MRTH =OPC_RISC_SYSTEM | (0x0 <<12 ), +OPC_RISC_HRTS =OPC_RISC_SYSTEM | (0x0 <<12 ), +OPC_RISC_WFI =OPC_RISC_SYSTEM | (0x0 <<12 ), +OPC_RISC_SFENCEVM =OPC_RISC_SYSTEM | (0x0 <<12 ), + +OPC_RISC_CSRRW =OPC_RISC_SYSTEM | (0x1 <<12 ), +OPC_RISC_CSRRS =OPC_RISC_SYSTEM | (0x2 <<12 ), +OPC_RISC_CSRRC =OPC_RISC_SYSTEM | (0x3 <<12 ), +OPC_RISC_CSRRWI =OPC_RISC_SYSTEM | (0x5 <<12 ), +OPC_RISC_CSRRSI =OPC_RISC_SYSTEM | (0x6 <<12 ), +OPC_RISC_CSRRCI =OPC_RISC_SYSTEM | (0x7 <<12 ), +}; + +#define MASK_OP_FP_LOAD (op) (MASK_OP_MAJOR(op) | (op & (0x7 << 12))) +enum { +OPC_RISC_FLW =OPC_RISC_FP_LOAD | (0x2 <<12 ), +OPC_RISC_FLD =OPC_RISC_FP_LOAD | (0x3 <<12 ), +}; + +#define MASK_OP_FP_STORE (op) (MASK_OP_MAJOR(op) | (op & (0x7 << 12))) +enum { +OPC_RISC_FSW =OPC_RISC_FP_STORE | (0x2 <<12 ), +OPC_RISC_FSD =OPC_RISC_FP_STORE | (0x3 <<12 ), +}; + +#define MASK_OP_FP_FMADD (op) (MASK_OP_MAJOR(op) | (op & (0x3 << 25))) +enum { +OPC_RISC_FMADD_S =OPC_RISC_FMADD | (0x0 <<25 ), +OPC_RISC_FMADD_D =OPC_RISC_FMADD | (0x1 <<25 ), +}; + +#define MASK_OP_FP_FMSUB (op) (MASK_OP_MAJOR(op) | (op & (0x3 << 25))) +enum { +OPC_RISC_FMSUB_S =OPC_RISC_FMSUB | (0x0 <<25 ), +OPC_RISC_FMSUB_D =OPC_RISC_FMSUB | (0x1 <<25 ), +}; + +#define MASK_OP_FP_FNMADD (op) (MASK_OP_MAJOR(op) | (op & (0x3 << 25))) +enum { +OPC_RISC_FNMADD_S =OPC_RISC_FNMADD | (0x0 <<25 ), +OPC_RISC_FNMADD_D =OPC_RISC_FNMADD | (0x1 <<25 ), +}; + +#define MASK_OP_FP_FNMSUB (op) (MASK_OP_MAJOR(op) | (op & (0x3 << 25))) +enum { +OPC_RISC_FNMSUB_S =OPC_RISC_FNMSUB | (0x0 <<25 ), +OPC_RISC_FNMSUB_D =OPC_RISC_FNMSUB | (0x1 <<25 ), +}; + +#define MASK_OP_FP_ARITH (op) (MASK_OP_MAJOR(op) | (op & (0x7F << 25))) +enum { +/* float */ +OPC_RISC_FADD_S =OPC_RISC_FP_ARITH | (0x0 <<25 ), +OPC_RISC_FSUB_S =OPC_RISC_FP_ARITH | (0x4 <<25 ), +OPC_RISC_FMUL_S =OPC_RISC_FP_ARITH | (0x8 <<25 ), +OPC_RISC_FDIV_S =OPC_RISC_FP_ARITH | (0xC <<25 ), + +OPC_RISC_FSGNJ_S =OPC_RISC_FP_ARITH | (0x10 <<25 ), +OPC_RISC_FSGNJN_S =OPC_RISC_FP_ARITH | (0x10 <<25 ), +OPC_RISC_FSGNJX_S =OPC_RISC_FP_ARITH | (0x10 <<25 ), + +OPC_RISC_FMIN_S =OPC_RISC_FP_ARITH | (0x14 <<25 ), +OPC_RISC_FMAX_S =OPC_RISC_FP_ARITH | (0x14 <<25 ), + +OPC_RISC_FSQRT_S =OPC_RISC_FP_ARITH | (0x2C <<25 ), + +OPC_RISC_FEQ_S =OPC_RISC_FP_ARITH | (0x50 <<25 ), +OPC_RISC_FLT_S =OPC_RISC_FP_ARITH | (0x50 <<25 ), +OPC_RISC_FLE_S =OPC_RISC_FP_ARITH | (0x50 <<25 ), + +OPC_RISC_FCVT_W_S =OPC_RISC_FP_ARITH | (0x60 <<25 ), +OPC_RISC_FCVT_WU_S =OPC_RISC_FP_ARITH | (0x60 <<25 ), +OPC_RISC_FCVT_L_S =OPC_RISC_FP_ARITH | (0x60 <<25 ), +OPC_RISC_FCVT_LU_S =OPC_RISC_FP_ARITH | (0x60 <<25 ), + +OPC_RISC_FCVT_S_W =OPC_RISC_FP_ARITH | (0x68 <<25 ), +OPC_RISC_FCVT_S_WU =OPC_RISC_FP_ARITH | (0x68 <<25 ), +OPC_RISC_FCVT_S_L =OPC_RISC_FP_ARITH | (0x68 <<25 ), +OPC_RISC_FCVT_S_LU =OPC_RISC_FP_ARITH | (0x68 <<25 ), + +OPC_RISC_FMV_X_S =OPC_RISC_FP_ARITH | (0x70 <<25 ), +OPC_RISC_FCLASS_S =OPC_RISC_FP_ARITH | (0x70 <<25 ), + +OPC_RISC_FMV_S_X =OPC_RISC_FP_ARITH | (0x78 <<25 ), + +/* double */ +OPC_RISC_FADD_D =OPC_RISC_FP_ARITH | (0x1 <<25 ), +OPC_RISC_FSUB_D =OPC_RISC_FP_ARITH | (0x5 <<25 ), +OPC_RISC_FMUL_D =OPC_RISC_FP_ARITH | (0x9 <<25 ), +OPC_RISC_FDIV_D =OPC_RISC_FP_ARITH | (0xD <<25 ), + +OPC_RISC_FSGNJ_D =OPC_RISC_FP_ARITH | (0x11 <<25 ), +OPC_RISC_FSGNJN_D =OPC_RISC_FP_ARITH | (0x11 <<25 ), +OPC_RISC_FSGNJX_D =OPC_RISC_FP_ARITH | (0x11 <<25 ), + +OPC_RISC_FMIN_D =OPC_RISC_FP_ARITH | (0x15 <<25 ), +OPC_RISC_FMAX_D =OPC_RISC_FP_ARITH | (0x15 <<25 ), + +OPC_RISC_FCVT_S_D =OPC_RISC_FP_ARITH | (0x20 <<25 ), + +OPC_RISC_FCVT_D_S =OPC_RISC_FP_ARITH | (0x21 <<25 ), + +OPC_RISC_FSQRT_D =OPC_RISC_FP_ARITH | (0x2D <<25 ), + +OPC_RISC_FEQ_D =OPC_RISC_FP_ARITH | (0x51 <<25 ), +OPC_RISC_FLT_D =OPC_RISC_FP_ARITH | (0x51 <<25 ), +OPC_RISC_FLE_D =OPC_RISC_FP_ARITH | (0x51 <<25 ), + +OPC_RISC_FCVT_W_D =OPC_RISC_FP_ARITH | (0x61 <<25 ), +OPC_RISC_FCVT_WU_D =OPC_RISC_FP_ARITH | (0x61 <<25 ), +OPC_RISC_FCVT_L_D =OPC_RISC_FP_ARITH | (0x61 <<25 ), +OPC_RISC_FCVT_LU_D =OPC_RISC_FP_ARITH | (0x61 <<25 ), + +OPC_RISC_FCVT_D_W =OPC_RISC_FP_ARITH | (0x69 <<25 ), +OPC_RISC_FCVT_D_WU =OPC_RISC_FP_ARITH | (0x69 <<25 ), +OPC_RISC_FCVT_D_L =OPC_RISC_FP_ARITH | (0x69 <<25 ), +OPC_RISC_FCVT_D_LU =OPC_RISC_FP_ARITH | (0x69 <<25 ), + +OPC_RISC_FMV_X_D =OPC_RISC_FP_ARITH | (0x71 <<25 ), +OPC_RISC_FCLASS_D =OPC_RISC_FP_ARITH | (0x71 <<25 ), + +OPC_RISC_FMV_D_X =OPC_RISC_FP_ARITH | (0x79 <<25 ), +}; + +/* THIS BUILDS 13 bit imm (implicit zero is tacked on here), also note that bit +#12 is obtained in a special way to get sign extension */ +#define GET_B_IMM (inst) ((int16_t)((((inst >> 25) & 0x3F) << 5)\ + | ((((int32_t)inst) >> 31) << 12) \ + | (((inst >> 8) & 0xF) << 1) \ + | (((inst >> 7) & 0x1) << 11))) + +#define GET_STORE_IMM (inst) ((int16_t)(((((int32_t)inst) >> 25) << 5)\ + | ((inst >> 7) & 0x1F))) +#define GET_JAL_IMM (inst) ((int32_t)((inst & 0xFF000) \ + | (((inst >> 20) & 0x1) << 11)\ + | (((inst >> 21) & 0x3FF) << 1)\ + | ((((int32_t)inst) >> 31) << 20))) +#define GET_RM (inst) ((inst >> 12) & 0x7) +#define GET_RS3 (inst) ((inst >> 27) & 0x1f) +#define GET_RS1 (inst) ((inst >> 15) & 0x1f) +#define GET_RS2 (inst) ((inst >> 20) & 0x1f) +#define GET_RD (inst) ((inst >> 7) & 0x1f) +#define GET_IMM (inst) ((int16_t)(((int32_t)inst) >> 20))
target-riscv/translate.c +64 -0
76 lines not on this page · raw message
Signature · 1 line
2.9.3
Re: [Qemu-devel] [PATCH 04/18] target-riscv: Add framework for instruction decode
Quoted 9 lines · Sagar Karandikar
target-riscv/instmap.h new file +9
-0+/* THIS BUILDS 13 bit imm (implicit zero is tacked on here), also note that bit +#12 is obtained in a special way to get sign extension */ +#define GET_B_IMM (inst) ((int16_t)((((inst >> 25) & 0x3F) << 5)\ + | ((((int32_t)inst) >> 31) << 12) \ + | (((inst >> 8) & 0xF) << 1) \ + | (((inst >> 7) & 0x1) << 11))) + +#define GET_STORE_IMM (inst) ((int16_t)(((((int32_t)inst) >> 25) << 5)\ + | ((inst >> 7) & 0x1F)))
target-riscv/instmap.h line 328
Quoted 10 lines
target-riscv/instmap.h new file +10
-0+#define GET_JAL_IMM (inst) ((int32_t)((inst & 0xFF000) \ + | (((inst >> 20) & 0x1) << 11)\ + | (((inst >> 21) & 0x3FF) << 1)\ + | ((((int32_t)inst) >> 31) << 20))) +#define GET_RM (inst) ((inst >> 12) & 0x7) +#define GET_RS3 (inst) ((inst >> 27) & 0x1f) +#define GET_RS1 (inst) ((inst >> 15) & 0x1f) +#define GET_RS2 (inst) ((inst >> 20) & 0x1f) +#define GET_RD (inst) ((inst >> 7) & 0x1f) +#define GET_IMM (inst) ((int16_t)(((int32_t)inst) >> 20))
I would prefer that these use extract32 and sextract32. Then you don't need the comment there at the top because it's self-evident.
target-riscv/translate.c static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) · line 147
Quoted 7 lines
target-riscv/translate.c +7
-0+switch (op) { +case OPC_RISC_LUI : +if (rd ==0 ) { +break ;/* NOP */ + } +tcg_gen_movi_tl (cpu_gpr[rd], (ctx->opcode &0xFFFFF000 )); +tcg_gen_ext32s_tl (cpu_gpr[rd], cpu_gpr[rd]);
This should be done in one movi with the sign-extension in C.
target-riscv/translate.c static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) · line 155
Quoted 8 lines
target-riscv/translate.c +8
-0+break ; +case OPC_RISC_AUIPC : +if (rd ==0 ) { +break ;/* NOP */ + } +tcg_gen_movi_tl (cpu_gpr[rd], (ctx->opcode &0xFFFFF000 )); +tcg_gen_ext32s_tl (cpu_gpr[rd], cpu_gpr[rd]); +tcg_gen_addi_tl (cpu_gpr[rd], cpu_gpr[rd], ctx->pc);
Likewise.
Quoted 19 lines
target-riscv/translate.c +19
-0+break ; +case OPC_RISC_JAL : { +TCGv nextpc =tcg_temp_local_new (); +TCGv testpc =tcg_temp_local_new (); +TCGLabel *misaligned =gen_new_label (); +TCGLabel *done =gen_new_label (); + ubimm = (target_long) (GET_JAL_IMM (ctx->opcode)); +tcg_gen_movi_tl (nextpc, ctx->pc + ubimm); +/* check misaligned: */ +tcg_gen_andi_tl (testpc, nextpc,0x3 ); +tcg_gen_brcondi_tl (TCG_COND_NE , testpc,0x0 , misaligned); +if (rd !=0 ) { +tcg_gen_movi_tl (cpu_gpr[rd], ctx->pc +4 ); + } + +#ifdef DISABLE_CHAINING_JAL +tcg_gen_mov_tl (cpu_PC, nextpc); +tcg_gen_exit_tb (0 ); +#else
target-riscv/translate.c static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) · line 184
Quoted 10 lines
target-riscv/translate.c +10
-0+gen_goto_tb (ctx,0 , ctx->pc + ubimm);/* must use this for safety */ +#endif +tcg_gen_br (done); +gen_set_label (misaligned); +/* throw exception for misaligned case */ +generate_exception_mbadaddr (ctx,RISCV_EXCP_INST_ADDR_MIS ); +gen_set_label (done); + ctx->bstate =BS_BRANCH ; +tcg_temp_free (nextpc); +tcg_temp_free (testpc);
Remember that nextpc is a translate-time constant. Therefore this entire misalignment check could be done during translation, and thus there should be no tcg labels nor tcg temporaries allocated.
Why would you ever want to disable chaining JAL (and therefore J)? Do note that there is a -d nochain command-line switch that will disable all chaining for the purposes of debugging...
r~
PATCH 5/18 target-riscv: Add Arithmetic instructions
In reply to Sagar KarandikarArithmetic Instructions
Arithmetic Immediate Instructions
MULHSU Helper
GPR Helpers necessary for above
--- target-riscv/helper.h | 4 + target-riscv/op_helper.c | 10 ++ target-riscv/translate.c | 338 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 352 insertions(+)
target-riscv/helper.h +4 -0
@@ -2,3 +2,7 @@ DEF_HELPER_2(raise_exception, noreturn, env, i32) DEF_HELPER_1(raise_exception_debug, noreturn, env) DEF_HELPER_3(raise_exception_mbadaddr, noreturn, env, i32, tl) + +#if defined(TARGET_RISCV64 ) +DEF_HELPER_FLAGS_3(mulhsu, TCG_CALL_NO_RWG_SE, tl, env, tl, tl) +#endif
target-riscv/op_helper.c +10 -0
@@ -50,6 +50,16 @@ void helper_raise_exception_mbadaddr(CPURISCVState *env, uint32_t exception,do_raise_exception_err (env, exception,0 ); } +#if defined(TARGET_RISCV64 ) +target_ulong helper_mulhsu (CPURISCVState *env,target_ulong arg1, +target_ulong arg2) +{ +int64_t a = arg1; +uint64_t b = arg2; +return (int64_t )((__int128_t )a * b >>64 ); +} +#endif +#ifndef CONFIG_USER_ONLY void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr, MMUAccessType access_type, int mmu_idx,
target-riscv/translate.c +338 -0
361 lines not on this page · raw message
Signature · 1 line
2.9.3
Re: [Qemu-devel] [PATCH 05/18] target-riscv: Add Arithmetic instructions
target-riscv/op_helper.c void helper_raise_exception_mbadaddr(CPURISCVState *env, uint32_t exception, · line 61
Quoted 9 lines · Sagar Karandikar
target-riscv/op_helper.c +9
-0+#if defined(TARGET_RISCV64 ) +target_ulong helper_mulhsu (CPURISCVState *env,target_ulong arg1, +target_ulong arg2) +{ +int64_t a = arg1; +uint64_t b = arg2; +return (int64_t )((__int128_t )a * b >>64 ); +} +#endif
This won't compile on a 32-bit host, or indeed a 64-bit host without CONFIG_INT128.
But what you should actually be using is tcg_gen_mulu2_i64, with a fixup afterward for the one signed argument. See tcg_gen_muls2_i64 in tcg/tcg-op.c for an example of fixing up an unsigned multiply for two signed inputs; you would need only half of that for a single signed input.
target-riscv/translate.c static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) · line 149
Quoted 11 lines
target-riscv/translate.c +11
-0+/* Wrapper for setting reg values - need to check of reg is zero since +* cpu_gpr[0] is not actually allocated. this is more for safety purposes, +* since we usually avoid calling the OP_TYPE_gen function if we see a write to +* $zero +*/ +static inline void gen_set_gpr (int reg_num_dst,TCGv t) +{ +if (reg_num_dst !=0 ) { +tcg_gen_mov_tl (cpu_gpr[reg_num_dst], t); + } +}
FWIW, target-alpha used to have lots and lots of checks for the zero register. In the end it was much cleaner to simply allocate a scratch temporary for the zero-register sink. Aside from known patterns, such as canonical nop formations, you'll almost never see such instructions. While it's true that you must do something in order to be architecturally correct, it's better to do something that minimizes the impact to the rest of the translator.
target-riscv/translate.c static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) · line 164
Quoted 2 lines
target-riscv/translate.c +2
-0+tcg_gen_shri_i64 (t0, t0,32 ); +tcg_gen_extrl_i64_i32 (ret, t0);
This would be tcg_gen_extrh_i64_i32.
target-riscv/translate.c static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) · line 183
Quoted 13 lines
target-riscv/translate.c +13
-0+static inline void gen_arith (DisasContext *ctx,uint32_t opc,int rd,int rs1, +int rs2) +{ +TCGv source1, source2, cond1, cond2, zeroreg, resultopt1; + cond1 =tcg_temp_new (); + cond2 =tcg_temp_new (); + source1 =tcg_temp_new (); + source2 =tcg_temp_new (); + zeroreg =tcg_temp_new (); + resultopt1 =tcg_temp_new (); +gen_get_gpr (source1, rs1); +gen_get_gpr (source2, rs2); +tcg_gen_movi_tl (zeroreg,0 );/* hardcoded zero for compare in DIV, etc */
It would be far preferable to allocate this only when needed.
target-riscv/translate.c static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) · line 189
Quoted 6 lines
target-riscv/translate.c +6
-0+ +switch (opc) { +#if defined(TARGET_RISCV64 ) +case OPC_RISC_ADDW : +#endif +case OPC_RISC_ADD :
Can we avoid sprinkling so many ifdefs? Perhaps with something akin to
#ifdef TARGET_RISCV64
#define CASE_OP_32_64(X) case X: case glue(X, W)
#else
#define CASE_OP_32_64(X) case X
#endif
target-riscv/translate.c static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) · line 205
Quoted 8 lines
target-riscv/translate.c +8
-0+#if defined(TARGET_RISCV64 ) +case OPC_RISC_SLLW : +tcg_gen_andi_tl (source2, source2,0x1F ); +/* fall through to SLL */ +#endif +case OPC_RISC_SLL : +tcg_gen_andi_tl (source2, source2,TARGET_LONG_BITS -1 ); +tcg_gen_shl_tl (source1, source1, source2);
Better to not fall through at this point, to avoid the double and.
target-riscv/translate.c static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) · line 225
Quoted 10 lines
target-riscv/translate.c +10
-0+#if defined(TARGET_RISCV64 ) +case OPC_RISC_SRLW : +/* clear upper 32 */ +tcg_gen_andi_tl (source1, source1,0x00000000FFFFFFFFLL ); +tcg_gen_andi_tl (source2, source2,0x1F ); +/* fall through to SRL */ +#endif +case OPC_RISC_SRL : +tcg_gen_andi_tl (source2, source2,TARGET_LONG_BITS -1 ); +tcg_gen_shr_tl (source1, source1, source2);
Likewise. Also, tcg_gen_ext32u_tl to clear upper 32.
target-riscv/translate.c static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) · line 237
Quoted 12 lines
target-riscv/translate.c +12
-0+break ; +#if defined(TARGET_RISCV64 ) +case OPC_RISC_SRAW : +/* first, trick to get it to act like working on 32 bits (get rid of +upper 32, sign extend to fill space) */ +tcg_gen_shli_tl (source1, source1,32 ); +tcg_gen_sari_tl (source1, source1,32 ); +tcg_gen_andi_tl (source2, source2,0x1F ); +/* fall through to SRA */ +#endif +case OPC_RISC_SRA : +tcg_gen_andi_tl (source2, source2,TARGET_LONG_BITS -1 );
Likewise. Also, tcg_gen_ext32s_tl to sign-extend.
target-riscv/translate.c static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) · line 250
Quoted 5 lines
target-riscv/translate.c +5
-0+#if defined(TARGET_RISCV64 ) +case OPC_RISC_MULW : +#endif +case OPC_RISC_MUL : +tcg_gen_muls2_tl (source1, source2, source1, source2);
tcg_gen_mul_tl, since source2 is dead.
target-riscv/translate.c static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) · line 271
Quoted 11 lines
target-riscv/translate.c +11
-0+#if defined(TARGET_RISCV64 ) +case OPC_RISC_DIVW : +tcg_gen_ext32s_tl (source1, source1); +tcg_gen_ext32s_tl (source2, source2); +/* fall through to DIV */ +#endif +case OPC_RISC_DIV : +/* Handle by altering args to tcg_gen_div to produce req'd results: +* For overflow: want source1 in source1 and 1 in source2 +* For div by zero: want -1 in source1 and 1 in source2 -> -1 result */ +tcg_gen_movi_tl (resultopt1, (target_ulong )0xFFFFFFFFFFFFFFFF );
You'd need ULL for a constant with so many F's, but a plain -1 works just fine.
Quoted 1 line
+
tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, (target_ulong)(~0L));
Likewise -1.
Review
Quoted 2 lines
(quoted diff) +2
-0+ tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source1, + 1L << (TARGET_LONG_BITS - 1));
ULL, not L, or better as (target_ulong)1.
target-riscv/translate.c static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) · line 295
Quoted 3 lines
target-riscv/translate.c +3
-0+case OPC_RISC_DIVU : +tcg_gen_setcondi_tl (TCG_COND_EQ , cond1, source2,0 ); +tcg_gen_movi_tl (resultopt1, (target_ulong)(~0L ));
-1 again.
Quoted 1 line
+ case
OPC_RISC_REM:
...
Quoted 1 line
+ case
OPC_RISC_REMU:
Similarly.
target-riscv/translate.c static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) · line 366
Quoted 8 lines
target-riscv/translate.c +8
-0+static inline void gen_arith_imm (DisasContext *ctx,uint32_t opc,int rd, +int rs1,int16_t imm) +{ +TCGv source1; + source1 =tcg_temp_new (); +gen_get_gpr (source1, rs1); +/* lower 12 bits of imm are valid */ +target_long uimm = (target_long )imm;/* sign ext 16->64 bits */
Better to just make the function argument target_long, surely. I don't understand the "uimm", as this isn't unsigned...
target-riscv/translate.c static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) · line 396
Quoted 6 lines
target-riscv/translate.c +6
-0+#if defined(TARGET_RISCV64 ) +case OPC_RISC_SLLIW : +if ((uimm >=32 )) { +kill_unknown (ctx,RISCV_EXCP_ILLEGAL_INST ); + } +/* fall through to SLLI */
break after known exception.
target-riscv/translate.c static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) · line 411
Quoted 7 lines
target-riscv/translate.c +7
-0+#if defined(TARGET_RISCV64 ) +case OPC_RISC_SHIFT_RIGHT_IW : +if ((uimm &0x3ff ) >=32 ) { +kill_unknown (ctx,RISCV_EXCP_ILLEGAL_INST ); + } +tcg_gen_shli_tl (source1, source1,32 ); + extra_shamt =32 ;
tcg_gen_ext32{u,s}_tl is better than extra shifts.
r~
PATCH 6/18 target-riscv: Add JALR, Branch Instructions
In reply to Sagar Karandikar--- target-riscv/translate.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+)
target-riscv/translate.c +107 -0
@@ -438,6 +438,106 @@ static inline void gen_arith_imm(DisasContext *ctx, uint32_t opc, int rd,tcg_temp_free (source1); } +static inline void gen_jalr (DisasContext *ctx,uint32_t opc,int rd,int rs1, +int16_t imm) +{ +/* no chaining with JALR */ +TCGLabel *misaligned =gen_new_label (); +TCGLabel *done =gen_new_label (); +target_long uimm = (target_long )imm;/* sign ext 16->64 bits */ +TCGv t0, t1, t2, t3; + t0 =tcg_temp_local_new (); + t1 =tcg_temp_local_new (); + t2 =tcg_temp_local_new ();/* old_pc */ + t3 =tcg_temp_local_new (); + +switch (opc) { +case OPC_RISC_JALR : +gen_get_gpr (t0, rs1); +tcg_gen_addi_tl (t0, t0, uimm); +tcg_gen_andi_tl (t0, t0, (target_ulong )0xFFFFFFFFFFFFFFFEll ); +tcg_gen_andi_tl (t3, t0,0x2 ); +tcg_gen_movi_tl (t2, ctx->pc); +tcg_gen_brcondi_tl (TCG_COND_NE , t3,0x0 , misaligned); +tcg_gen_mov_tl (cpu_PC, t0); +tcg_gen_addi_tl (t1, t2,4 ); +gen_set_gpr (rd, t1); +tcg_gen_br (done); +gen_set_label (misaligned); +generate_exception_mbadaddr (ctx,RISCV_EXCP_INST_ADDR_MIS ); +gen_set_label (done); +tcg_gen_exit_tb (0 ); + ctx->bstate =BS_BRANCH ; +break ; +default : +kill_unknown (ctx,RISCV_EXCP_ILLEGAL_INST ); +break ; + } +tcg_temp_free (t0); +tcg_temp_free (t1); +tcg_temp_free (t2); +tcg_temp_free (t3); +} + +static inline void gen_branch (DisasContext *ctx,uint32_t opc,int rs1,int rs2, +int16_t bimm) +{ +TCGLabel *l =gen_new_label (); +TCGv source1, source2; + source1 =tcg_temp_new (); + source2 =tcg_temp_new (); +gen_get_gpr (source1, rs1); +gen_get_gpr (source2, rs2); +target_ulong ubimm = (target_long )bimm;/* sign ext 16->64 bits */ + +switch (opc) { +case OPC_RISC_BEQ : +tcg_gen_brcond_tl (TCG_COND_EQ , source1, source2, l); +break ; +case OPC_RISC_BNE : +tcg_gen_brcond_tl (TCG_COND_NE , source1, source2, l); +break ; +case OPC_RISC_BLT : +tcg_gen_brcond_tl (TCG_COND_LT , source1, source2, l); +break ; +case OPC_RISC_BGE : +tcg_gen_brcond_tl (TCG_COND_GE , source1, source2, l); +break ; +case OPC_RISC_BLTU : +tcg_gen_brcond_tl (TCG_COND_LTU , source1, source2, l); +break ; +case OPC_RISC_BGEU : +tcg_gen_brcond_tl (TCG_COND_GEU , source1, source2, l); +break ; +default : +kill_unknown (ctx,RISCV_EXCP_ILLEGAL_INST ); +break ; + } + +#ifdef DISABLE_CHAINING_BRANCH +tcg_gen_movi_tl (cpu_PC, ctx->pc +4 ); +tcg_gen_exit_tb (0 ); +#else +gen_goto_tb (ctx,1 , ctx->pc +4 );/* must use this for safety */ +#endif +gen_set_label (l);/* branch taken */ +if ((ctx->pc + ubimm) &0x3 ) { +/* misaligned */ +generate_exception_mbadaddr (ctx,RISCV_EXCP_INST_ADDR_MIS ); +tcg_gen_exit_tb (0 ); + }else { +#ifdef DISABLE_CHAINING_BRANCH +tcg_gen_movi_tl (cpu_PC, ctx->pc + ubimm); +tcg_gen_exit_tb (0 ); +#else +gen_goto_tb (ctx,0 , ctx->pc + ubimm);/* must use this for safety */ +#endif + } +tcg_temp_free (source1); +tcg_temp_free (source2); + ctx->bstate =BS_BRANCH ; +} +static void decode_opc (CPURISCVState *env,DisasContext *ctx) {int rs1;
@@ -504,6 +604,13 @@ static void decode_opc(CPURISCVState *env, DisasContext *ctx)tcg_temp_free (testpc); }break ; +case OPC_RISC_JALR : +gen_jalr (ctx,MASK_OP_JALR (ctx->opcode), rd, rs1, imm); +break ; +case OPC_RISC_BRANCH : +gen_branch (ctx,MASK_OP_BRANCH (ctx->opcode), rs1, rs2, +GET_B_IMM (ctx->opcode)); +break ;case OPC_RISC_ARITH_IMM :#if defined(TARGET_RISCV64 )case OPC_RISC_ARITH_IMM_W :
Signature · 1 line
2.9.3
Re: [Qemu-devel] [PATCH 06/18] target-riscv: Add JALR, Branch Instructions
Quoted 21 lines · Sagar Karandikar
Signed-off-by Sagar Karandikar <[email protected]>--- target-riscv/translate.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+)target-riscv/translate.c +8
-0@@ -438,6 +438,106 @@ static inline void gen_arith_imm(DisasContext *ctx, uint32_t opc, int rd,tcg_temp_free (source1); } +static inline void gen_jalr (DisasContext *ctx,uint32_t opc,int rd,int rs1, +int16_t imm) +{ +/* no chaining with JALR */ +TCGLabel *misaligned =gen_new_label (); +TCGLabel *done =gen_new_label (); +target_long uimm = (target_long )imm;/* sign ext 16->64 bits */ +TCGv t0, t1, t2, t3;
target-riscv/translate.c static inline void gen_arith_imm(DisasContext *ctx, uint32_t opc, int rd, · line 458
Quoted 10 lines
target-riscv/translate.c +10
-0+ t0 =tcg_temp_local_new (); + t1 =tcg_temp_local_new (); + t2 =tcg_temp_local_new ();/* old_pc */ + t3 =tcg_temp_local_new (); + +switch (opc) { +case OPC_RISC_JALR : +gen_get_gpr (t0, rs1); +tcg_gen_addi_tl (t0, t0, uimm); +tcg_gen_andi_tl (t0, t0, (target_ulong )0xFFFFFFFFFFFFFFFEll );
-2.
target-riscv/translate.c static inline void gen_arith_imm(DisasContext *ctx, uint32_t opc, int rd, · line 470
Quoted 12 lines
target-riscv/translate.c +12
-0+tcg_gen_andi_tl (t3, t0,0x2 ); +tcg_gen_movi_tl (t2, ctx->pc); +tcg_gen_brcondi_tl (TCG_COND_NE , t3,0x0 , misaligned); +tcg_gen_mov_tl (cpu_PC, t0); +tcg_gen_addi_tl (t1, t2,4 ); +gen_set_gpr (rd, t1); +tcg_gen_br (done); +gen_set_label (misaligned); +generate_exception_mbadaddr (ctx,RISCV_EXCP_INST_ADDR_MIS ); +gen_set_label (done); +tcg_gen_exit_tb (0 ); + ctx->bstate =BS_BRANCH ;
You don't need any temp_local, which will significantly clean up the generated code. Try
gen_get_gpr(cpu_PC, rs1);
tcg_gen_addi_tl(cpu_PC, cpu_PC, imm);
tcg_gen_andi_tl(cpu_PC, cpu_PC, -2);
tcg_gen_andi_tl(tmp, cpu_PC, 2);
tcg_gen_brcondi_tl(TCG_COND_NE, tmp, 0, misaligned);
if (rd != 0) {
tcg_gen_movi_tl(cpu_gpr[rd], ctx->pc + 4);
}
tcg_gen_exit_tb(0);
tcg_set_label(misaligned);
generate_exception_mbadaddr(ctx, ...);Note that cpu_PC will be reset in generate_exception, so we can initialize it early, before the branch.
target-riscv/translate.c static inline void gen_arith_imm(DisasContext *ctx, uint32_t opc, int rd, · line 483
Quoted 2 lines
target-riscv/translate.c +2
-0+static inline void gen_branch (DisasContext *ctx,uint32_t opc,int rs1,int rs2, +int16_t bimm)
Drop the inline markers and let the compiler decide.
r~
PATCH 7/18 target-riscv: Add Loads/Stores, FP Loads/Stores
In reply to Sagar Karandikar--- target-riscv/translate.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+)
target-riscv/translate.c +117 -0
@@ -72,6 +72,10 @@ static const char * const fpr_regnames[] = { "fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11" }; +/* convert riscv funct3 to qemu memop for load/store */ +static int tcg_memop_lookup[] = {MO_SB ,MO_TESW ,MO_TESL ,MO_TEQ ,MO_UB , +MO_TEUW ,MO_TEUL }; +static inline void generate_exception (DisasContext *ctx,int excp) {tcg_gen_movi_tl (cpu_PC, ctx->pc);
@@ -538,6 +542,105 @@ static inline void gen_branch(DisasContext *ctx, uint32_t opc, int rs1, int rs2, ctx->bstate = BS_BRANCH; } +static inline void gen_load(DisasContext *ctx, uint32_t opc, int rd, int rs1, + int16_t imm) +{ + target_long uimm = (target_long)imm; /* sign ext 16->64 bits */ + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + gen_get_gpr(t0, rs1); + tcg_gen_addi_tl(t0, t0, uimm); /* */ + int memop = (opc >> 12) & 0x7; + +#if defined(TARGET_RISCV64) + if (memop == 0x7) { +#else + if (memop == 0x7 || memop == 0x3 || memop == 0x6) { +#endif + kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST); + } else { + tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, tcg_memop_lookup[memop]); + } + + gen_set_gpr(rd, t1); + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +static inline void gen_store(DisasContext *ctx, uint32_t opc, int rs1, int rs2, + int16_t imm) +{ + target_long uimm = (target_long)imm; /* sign ext 16->64 bits */ + + TCGv t0 = tcg_temp_new(); + TCGv dat = tcg_temp_new(); + gen_get_gpr(t0, rs1); + tcg_gen_addi_tl(t0, t0, uimm); + gen_get_gpr(dat, rs2); + int memop = (opc >> 12) & 0x7; + +#if defined(TARGET_RISCV64) + if (memop > 0x3) { +#else + if (memop > 0x2) { +#endif + kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST); + } else { + tcg_gen_qemu_st_tl(dat, t0, ctx->mem_idx, tcg_memop_lookup[memop]); + } + + tcg_temp_free(t0); + tcg_temp_free(dat); +} + +static inline void gen_fp_load(DisasContext *ctx, uint32_t opc, int rd, + int rs1, int16_t imm) +{ + target_long uimm = (target_long)imm; /* sign ext 16->64 bits */ + TCGv t0 = tcg_temp_new(); + gen_get_gpr(t0, rs1); + tcg_gen_addi_tl(t0, t0, uimm); + + switch (opc) { + case OPC_RISC_FLW: + tcg_gen_qemu_ld_i64(cpu_fpr[rd], t0, ctx->mem_idx, MO_TEUL); + break; + case OPC_RISC_FLD: + tcg_gen_qemu_ld_i64(cpu_fpr[rd], t0, ctx->mem_idx, MO_TEQ); + break; + default: + kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST); + break; + } + tcg_temp_free(t0); +} + +static inline void gen_fp_store(DisasContext *ctx, uint32_t opc, int rs1, + int rs2, int16_t imm) +{ + target_long uimm = (target_long)imm; /* sign ext 16->64 bits */ + + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + gen_get_gpr(t0, rs1); + tcg_gen_addi_tl(t0, t0, uimm); + + switch (opc) { + case OPC_RISC_FSW: + tcg_gen_qemu_st_i64(cpu_fpr[rs2], t0, ctx->mem_idx, MO_TEUL); + break; + case OPC_RISC_FSD: + tcg_gen_qemu_st_i64(cpu_fpr[rs2], t0, ctx->mem_idx, MO_TEQ); + break; + default: + kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST); + break; + } + + tcg_temp_free(t0); + tcg_temp_free(t1); +} + static void decode_opc(CPURISCVState *env, DisasContext *ctx) { int rs1;
@@ -611,6 +714,13 @@ static void decode_opc(CPURISCVState *env, DisasContext *ctx)gen_branch (ctx,MASK_OP_BRANCH (ctx->opcode), rs1, rs2,GET_B_IMM (ctx->opcode));break ; +case OPC_RISC_LOAD : +gen_load (ctx,MASK_OP_LOAD (ctx->opcode), rd, rs1, imm); +break ; +case OPC_RISC_STORE : +gen_store (ctx,MASK_OP_STORE (ctx->opcode), rs1, rs2, +GET_STORE_IMM (ctx->opcode)); +break ;case OPC_RISC_ARITH_IMM :#if defined(TARGET_RISCV64 )case OPC_RISC_ARITH_IMM_W :
@@ -629,6 +739,13 @@ static void decode_opc(CPURISCVState *env, DisasContext *ctx) }gen_arith (ctx,MASK_OP_ARITH (ctx->opcode), rd, rs1, rs2);break ; +case OPC_RISC_FP_LOAD : +gen_fp_load (ctx,MASK_OP_FP_LOAD (ctx->opcode), rd, rs1, imm); +break ; +case OPC_RISC_FP_STORE : +gen_fp_store (ctx,MASK_OP_FP_STORE (ctx->opcode), rs1, rs2, +GET_STORE_IMM (ctx->opcode)); +break ;default :kill_unknown (ctx,RISCV_EXCP_ILLEGAL_INST );break ;
Signature · 1 line
2.9.3
Re: [Qemu-devel] [PATCH 07/18] target-riscv: Add Loads/Stores, FP Loads/Stores
Quoted 10 lines · Sagar Karandikar
Signed-off-by Sagar Karandikar <[email protected]>--- target-riscv/translate.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+)target-riscv/translate.c +0
-0
target-riscv/translate.c static const char * const fpr_regnames[] = { · line 77
Quoted 6 lines
target-riscv/translate.c +3
-0@@ -72,6 +72,10 @@ static const char * const fpr_regnames[] = { "fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11" }; +/* convert riscv funct3 to qemu memop for load/store */ +static int tcg_memop_lookup[] = {MO_SB ,MO_TESW ,MO_TESL ,MO_TEQ ,MO_UB , +MO_TEUW ,MO_TEUL };
Const, and formatting
static const TCGMemOp tcg_memop_lookup[] = {
....
};although...
Quoted 8 lines
target-riscv/translate.c +8
-0+static inline void gen_load (DisasContext *ctx,uint32_t opc,int rd,int rs1, +int16_t imm) +{ +target_long uimm = (target_long )imm;/* sign ext 16->64 bits */ +TCGv t0 =tcg_temp_new (); +TCGv t1 =tcg_temp_new (); +gen_get_gpr (t0, rs1); +tcg_gen_addi_tl (t0, t0, uimm);/* */
target-riscv/translate.c static inline void gen_branch(DisasContext *ctx, uint32_t opc, int rs1, int rs2, · line 562
Quoted 10 lines
target-riscv/translate.c +10
-0+int memop = (opc >>12 ) &0x7 ; + +#if defined(TARGET_RISCV64 ) +if (memop ==0x7 ) { +#else +if (memop ==0x7 || memop ==0x3 || memop ==0x6 ) { +#endif +kill_unknown (ctx,RISCV_EXCP_ILLEGAL_INST ); + }else { +tcg_gen_qemu_ld_tl (t1, t0, ctx->mem_idx, tcg_memop_lookup[memop]);
... considering the set of if's, maybe better as
static const int tcg_memop_lookup[8] = {
[0 ... 7] = -1,
[0] = MO_SB,
[1] = MO_TESW,
[2] = MO_TESL,
[4] = MO_UB,
[5] = MO_TEUW,
#ifdef TARGET_RISCV64
[3] = MO_TEQ,
[6] = MO_TEUL,#endif
};
and then have
memop = tcg_memop_lookup[memop];
if (memop < 0) {
kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
} else {
tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, memop);
}r~
PATCH 8/18 target-riscv: Add Atomic Instructions
In reply to Sagar Karandikar--- target-riscv/translate.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+)
target-riscv/translate.c +154 -0
@@ -641,6 +641,157 @@ static inline void gen_fp_store(DisasContext *ctx, uint32_t opc, int rs1,tcg_temp_free (t1); } +static inline void gen_atomic (DisasContext *ctx,uint32_t opc, +int rd,int rs1,int rs2) +{ +/* TODO: handle aq, rl bits? - for now just get rid of them: */ + opc =MASK_OP_ATOMIC_NO_AQ_RL (opc); +TCGv source1, source2, dat; +TCGLabel *j =gen_new_label (); +TCGLabel *done =gen_new_label (); + source1 =tcg_temp_local_new (); + source2 =tcg_temp_local_new (); + dat =tcg_temp_local_new (); +gen_get_gpr (source1, rs1); +gen_get_gpr (source2, rs2); + +switch (opc) { +/* all currently implemented as non-atomics */ +case OPC_RISC_LR_W : +/* put addr in load_res */ +tcg_gen_mov_tl (load_res, source1); +tcg_gen_qemu_ld_tl (dat, source1, ctx->mem_idx,MO_TESL |MO_ALIGN ); +break ; +case OPC_RISC_SC_W : +tcg_gen_brcond_tl (TCG_COND_NE , load_res, source1, j); +tcg_gen_qemu_st_tl (source2, source1, ctx->mem_idx,MO_TEUL |MO_ALIGN ); +tcg_gen_movi_tl (dat,0 );/*success */ +tcg_gen_br (done); +gen_set_label (j); +tcg_gen_movi_tl (dat,1 );/*fail */ +gen_set_label (done); +break ; +case OPC_RISC_AMOSWAP_W : +tcg_gen_qemu_ld_tl (dat, source1, ctx->mem_idx,MO_TESL |MO_ALIGN ); +tcg_gen_qemu_st_tl (source2, source1, ctx->mem_idx,MO_TEUL |MO_ALIGN ); +break ; +case OPC_RISC_AMOADD_W : +tcg_gen_qemu_ld_tl (dat, source1, ctx->mem_idx,MO_TESL |MO_ALIGN ); +tcg_gen_add_tl (source2, dat, source2); +tcg_gen_qemu_st_tl (source2, source1, ctx->mem_idx,MO_TEUL |MO_ALIGN ); +break ; +case OPC_RISC_AMOXOR_W : +tcg_gen_qemu_ld_tl (dat, source1, ctx->mem_idx,MO_TESL |MO_ALIGN ); +tcg_gen_xor_tl (source2, dat, source2); +tcg_gen_qemu_st_tl (source2, source1, ctx->mem_idx,MO_TEUL |MO_ALIGN ); +break ; +case OPC_RISC_AMOAND_W : +tcg_gen_qemu_ld_tl (dat, source1, ctx->mem_idx,MO_TESL |MO_ALIGN ); +tcg_gen_and_tl (source2, dat, source2); +tcg_gen_qemu_st_tl (source2, source1, ctx->mem_idx,MO_TEUL |MO_ALIGN ); +break ; +case OPC_RISC_AMOOR_W : +tcg_gen_qemu_ld_tl (dat, source1, ctx->mem_idx,MO_TESL |MO_ALIGN ); +tcg_gen_or_tl (source2, dat, source2); +tcg_gen_qemu_st_tl (source2, source1, ctx->mem_idx,MO_TEUL |MO_ALIGN ); +break ; +case OPC_RISC_AMOMIN_W : +tcg_gen_ext32s_tl (source2, source2);/* since comparing */ +tcg_gen_qemu_ld_tl (dat, source1, ctx->mem_idx,MO_TESL |MO_ALIGN ); +tcg_gen_movcond_tl (TCG_COND_LT , source2, dat, source2, dat, source2); +tcg_gen_qemu_st_tl (source2, source1, ctx->mem_idx,MO_TEUL |MO_ALIGN ); +break ; +case OPC_RISC_AMOMAX_W : +tcg_gen_ext32s_tl (source2, source2);/* since comparing */ +tcg_gen_qemu_ld_tl (dat, source1, ctx->mem_idx,MO_TESL |MO_ALIGN ); +tcg_gen_movcond_tl (TCG_COND_GT , source2, dat, source2, dat, source2); +tcg_gen_qemu_st_tl (source2, source1, ctx->mem_idx,MO_TEUL |MO_ALIGN ); +break ; +case OPC_RISC_AMOMINU_W : +tcg_gen_ext32u_tl (source2, source2);/* since comparing */ +tcg_gen_qemu_ld_tl (dat, source1, ctx->mem_idx,MO_TEUL |MO_ALIGN ); +tcg_gen_movcond_tl (TCG_COND_LTU , source2, dat, source2, dat, source2); +tcg_gen_qemu_st_tl (source2, source1, ctx->mem_idx,MO_TEUL |MO_ALIGN ); +tcg_gen_ext32s_tl (dat, dat);/* since load was TEUL */ +break ; +case OPC_RISC_AMOMAXU_W : +tcg_gen_ext32u_tl (source2, source2);/* since comparing */ +tcg_gen_qemu_ld_tl (dat, source1, ctx->mem_idx,MO_TEUL |MO_ALIGN ); +tcg_gen_movcond_tl (TCG_COND_GTU , source2, dat, source2, dat, source2); +tcg_gen_qemu_st_tl (source2, source1, ctx->mem_idx,MO_TEUL |MO_ALIGN ); +tcg_gen_ext32s_tl (dat, dat);/* since load was TEUL */ +break ; +#if defined(TARGET_RISCV64 ) +case OPC_RISC_LR_D : +/* put addr in load_res */ +tcg_gen_mov_tl (load_res, source1); +tcg_gen_qemu_ld_tl (dat, source1, ctx->mem_idx,MO_TEQ |MO_ALIGN ); +break ; +case OPC_RISC_SC_D : +tcg_gen_brcond_tl (TCG_COND_NE , load_res, source1, j); +tcg_gen_qemu_st_tl (source2, source1, ctx->mem_idx,MO_TEQ |MO_ALIGN ); +tcg_gen_movi_tl (dat,0 );/* success */ +tcg_gen_br (done); +gen_set_label (j); +tcg_gen_movi_tl (dat,1 );/* fail */ +gen_set_label (done); +break ; +case OPC_RISC_AMOSWAP_D : +tcg_gen_qemu_ld_tl (dat, source1, ctx->mem_idx,MO_TEQ |MO_ALIGN ); +tcg_gen_qemu_st_tl (source2, source1, ctx->mem_idx,MO_TEQ |MO_ALIGN ); +break ; +case OPC_RISC_AMOADD_D : +tcg_gen_qemu_ld_tl (dat, source1, ctx->mem_idx,MO_TEQ |MO_ALIGN ); +tcg_gen_add_tl (source2, dat, source2); +tcg_gen_qemu_st_tl (source2, source1, ctx->mem_idx,MO_TEQ |MO_ALIGN ); +break ; +case OPC_RISC_AMOXOR_D : +tcg_gen_qemu_ld_tl (dat, source1, ctx->mem_idx,MO_TEQ |MO_ALIGN ); +tcg_gen_xor_tl (source2, dat, source2); +tcg_gen_qemu_st_tl (source2, source1, ctx->mem_idx,MO_TEQ |MO_ALIGN ); +break ; +case OPC_RISC_AMOAND_D : +tcg_gen_qemu_ld_tl (dat, source1, ctx->mem_idx,MO_TEQ |MO_ALIGN ); +tcg_gen_and_tl (source2, dat, source2); +tcg_gen_qemu_st_tl (source2, source1, ctx->mem_idx,MO_TEQ |MO_ALIGN ); +break ; +case OPC_RISC_AMOOR_D : +tcg_gen_qemu_ld_tl (dat, source1, ctx->mem_idx,MO_TEQ |MO_ALIGN ); +tcg_gen_or_tl (source2, dat, source2); +tcg_gen_qemu_st_tl (source2, source1, ctx->mem_idx,MO_TEQ |MO_ALIGN ); +break ; +case OPC_RISC_AMOMIN_D : +tcg_gen_qemu_ld_tl (dat, source1, ctx->mem_idx,MO_TEQ |MO_ALIGN ); +tcg_gen_movcond_tl (TCG_COND_LT , source2, dat, source2, dat, source2); +tcg_gen_qemu_st_tl (source2, source1, ctx->mem_idx,MO_TEQ |MO_ALIGN ); +break ; +case OPC_RISC_AMOMAX_D : +tcg_gen_qemu_ld_tl (dat, source1, ctx->mem_idx,MO_TEQ |MO_ALIGN ); +tcg_gen_movcond_tl (TCG_COND_GT , source2, dat, source2, dat, source2); +tcg_gen_qemu_st_tl (source2, source1, ctx->mem_idx,MO_TEQ |MO_ALIGN ); +break ; +case OPC_RISC_AMOMINU_D : +tcg_gen_qemu_ld_tl (dat, source1, ctx->mem_idx,MO_TEQ |MO_ALIGN ); +tcg_gen_movcond_tl (TCG_COND_LTU , source2, dat, source2, dat, source2); +tcg_gen_qemu_st_tl (source2, source1, ctx->mem_idx,MO_TEQ |MO_ALIGN ); +break ; +case OPC_RISC_AMOMAXU_D : +tcg_gen_qemu_ld_tl (dat, source1, ctx->mem_idx,MO_TEQ |MO_ALIGN ); +tcg_gen_movcond_tl (TCG_COND_GTU , source2, dat, source2, dat, source2); +tcg_gen_qemu_st_tl (source2, source1, ctx->mem_idx,MO_TEQ |MO_ALIGN ); +break ; +#endif +default : +kill_unknown (ctx,RISCV_EXCP_ILLEGAL_INST ); +break ; + } + +gen_set_gpr (rd, dat); +tcg_temp_free (source1); +tcg_temp_free (source2); +tcg_temp_free (dat); +} +static void decode_opc (CPURISCVState *env,DisasContext *ctx) {int rs1;
@@ -746,6 +897,9 @@ static void decode_opc(CPURISCVState *env, DisasContext *ctx)gen_fp_store (ctx,MASK_OP_FP_STORE (ctx->opcode), rs1, rs2,GET_STORE_IMM (ctx->opcode));break ; +case OPC_RISC_ATOMIC : +gen_atomic (ctx,MASK_OP_ATOMIC (ctx->opcode), rd, rs1, rs2); +break ;default :kill_unknown (ctx,RISCV_EXCP_ILLEGAL_INST );break ;
Signature · 1 line
2.9.3
Re: [Qemu-devel] [PATCH 08/18] target-riscv: Add Atomic Instructions
target-riscv/translate.c static inline void gen_fp_store(DisasContext *ctx, uint32_t opc, int rs1, · line 648
Quoted 5 lines · Sagar Karandikar
target-riscv/translate.c +5
-0+static inline void gen_atomic (DisasContext *ctx,uint32_t opc, +int rd,int rs1,int rs2) +{ +/* TODO: handle aq, rl bits? - for now just get rid of them: */ + opc =MASK_OP_ATOMIC_NO_AQ_RL (opc);
We have already added tcg_gen_mb to insert memory barriers; hopefully the branch containing atomic operations will be merged soon. See
git://github.com/rth7680/qemu.git atomic-4
target-riscv/translate.c static inline void gen_fp_store(DisasContext *ctx, uint32_t opc, int rs1, · line 673
Quoted 9 lines
target-riscv/translate.c +9
-0+case OPC_RISC_SC_W : +tcg_gen_brcond_tl (TCG_COND_NE , load_res, source1, j); +tcg_gen_qemu_st_tl (source2, source1, ctx->mem_idx,MO_TEUL |MO_ALIGN ); +tcg_gen_movi_tl (dat,0 );/*success */ +tcg_gen_br (done); +gen_set_label (j); +tcg_gen_movi_tl (dat,1 );/*fail */ +gen_set_label (done); +break ;
I will note that generally SC needs to compare against the value loaded by LR as well as the address used by LR. Please have a look at the AArch64 implementation.
r~
PATCH 9/18 target-riscv: Add FMADD, FMSUB, FNMADD, FNMSUB Instructions,
In reply to Sagar KarandikarAlong with FP helper infrastructure, changes to softfloat-specialize
--- fpu/softfloat-specialize.h | 7 ++- target-riscv/Makefile.objs | 2 +- target-riscv/fpu_helper.c | 151 +++++++++++++++++++++++++++++++++++++++++++++ target-riscv/helper.h | 10 +++ target-riscv/translate.c | 105 +++++++++++++++++++++++++++++++ 5 files changed, 271 insertions(+), 4 deletions(-) create mode 100644 target-riscv/fpu_helper.c
fpu/softfloat-specialize.h +4 -3
@@ -114,7 +114,8 @@ float32 float32_default_nan(float_status *status)#if defined(TARGET_SPARC )return const_float32 (0x7FFFFFFF );#elif defined(TARGET_PPC ) || defined(TARGET_ARM ) || defined(TARGET_ALPHA ) || \ - defined(TARGET_XTENSA ) || defined(TARGET_S390X ) || defined(TARGET_TRICORE ) + defined(TARGET_XTENSA ) || defined(TARGET_S390X ) || \ + defined(TARGET_TRICORE ) || defined(TARGET_RISCV )return const_float32 (0x7FC00000 );#else if (status->snan_bit_is_one) {
@@ -137,7 +138,7 @@ float64 float64_default_nan(float_status *status)#if defined(TARGET_SPARC )return const_float64 (LIT64 (0x7FFFFFFFFFFFFFFF ));#elif defined(TARGET_PPC ) || defined(TARGET_ARM ) || defined(TARGET_ALPHA ) || \ - defined(TARGET_S390X ) + defined(TARGET_S390X ) || defined(TARGET_RISCV )return const_float64 (LIT64 (0x7FF8000000000000 ));#else if (status->snan_bit_is_one) {
@@ -181,7 +182,7 @@ float128 float128_default_nan(float_status *status) r.high =LIT64 (0x7FFF7FFFFFFFFFFF ); }else { r.low =LIT64 (0x0000000000000000 ); -#if defined(TARGET_S390X ) +#if defined(TARGET_S390X ) || defined(TARGET_RISCV ) r.high =LIT64 (0x7FFF800000000000 );#else r.high =LIT64 (0xFFFF800000000000 );
target-riscv/Makefile.objs +1 -1
@@ -1 +1 @@ -obj-y += translate.o op_helper.o helper.o cpu.o +obj-y += translate.o op_helper.o helper.o cpu.o fpu_helper.o
target-riscv/fpu_helper.c new file +151 -0
151 lines not on this page · raw message
target-riscv/helper.h +10 -0
@@ -6,3 +6,13 @@ DEF_HELPER_3(raise_exception_mbadaddr, noreturn, env, i32, tl)#if defined(TARGET_RISCV64 ) DEF_HELPER_FLAGS_3(mulhsu, TCG_CALL_NO_RWG_SE, tl, env, tl, tl)#endif + +/* Floating Point - fused */ +DEF_HELPER_FLAGS_5(fmadd_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_5(fmadd_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_5(fmsub_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_5(fmsub_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_5(fnmsub_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_5(fnmsub_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_5(fnmadd_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_5 (fnmadd_d,TCG_CALL_NO_RWG , i64, env, i64, i64, i64, i64)
target-riscv/translate.c +105 -0
117 lines not on this page · raw message
Signature · 1 line
2.9.3
Re: [Qemu-devel] [PATCH 09/18] target-riscv: Add FMADD, FMSUB, FNMADD, FNMSUB Instructions,
Quoted 11 lines · Sagar Karandikar
target-riscv/fpu_helper.c new file +11
-0+/* convert RISC-V rounding mode to IEEE library numbers */ +unsigned int ieee_rm[] = { + float_round_nearest_even, + float_round_to_zero, + float_round_down, + float_round_up, + float_round_ties_away +}; + +/* obtain rm value to use in computation +* as the last step, convert rm codes to what the softfloat library expects
target-riscv/fpu_helper.c line 47
Quoted 10 lines
target-riscv/fpu_helper.c new file +10
-0+* Adapted from Spike's decode.h:RM +*/ +#define RM ({ \ +if (rm == 7) { \ + rm = env->csr[CSR_FRM]; \ +} \ +if (rm > 4) { \ + helper_raise_exception(env, RISCV_EXCP_ILLEGAL_INST); \ +} \ +ieee_rm[rm]; })
You're not doing anything to get the proper guest PC value for the illegal instruction exception. This is, of course, rare, and can be caught during translation, which would be greatly preferred since the fpu signals no other exceptions, and thus all of the fpu helpers can be TCG_CALL_NO_RWG.
This can be done by examining fcsr during cpu_get_tb_cpu_state. Set a flag bit (TB_FLAG_RM_INVALID) when fcsr.rm is invalid. Then during translation, raise an exception if
(1) rm == 7 && TB_FLAG_RM_INVALID
(2) rm >= 5 && rm <= 6
You can improve this rounding mode switching by remembering the mode used by the previous insn. See target-alpha DisasContext.tb_rm.
target-riscv/fpu_helper.c line 73
Quoted 6 lines
target-riscv/fpu_helper.c new file +6
-0+/* adapted from Spike's decode.h:set_fp_exceptions */ +#define set_fp_exceptions () do { \ + env->csr[CSR_FFLAGS] |= softfloat_flags_to_riscv(get_float_exception_flags(\ + &env->fp_status)); \ + set_float_exception_flags(0, &env->fp_status); \ +} while (0)
Any reason not to make this a function?
target-riscv/fpu_helper.c line 98
Quoted 6 lines
target-riscv/fpu_helper.c new file +6
-0+uint64_t helper_fmsub_s (CPURISCVState *env,uint64_t frs1,uint64_t frs2, +uint64_t frs3,uint64_t rm) +{ +set_float_rounding_mode (RM , &env->fp_status); + frs1 =float32_muladd (frs1, frs2, frs3 ^ (uint32_t )INT32_MIN ,0 , + &env->fp_status);
float_muladd_negate_c
target-riscv/fpu_helper.c line 118
Quoted 6 lines
target-riscv/fpu_helper.c new file +6
-0+uint64_t helper_fnmsub_s (CPURISCVState *env,uint64_t frs1,uint64_t frs2, +uint64_t frs3,uint64_t rm) +{ +set_float_rounding_mode (RM , &env->fp_status); + frs1 =float32_muladd (frs1 ^ (uint32_t )INT32_MIN , frs2, frs3,0 , + &env->fp_status);
This one is actually computing fnmadd afaics...
target-riscv/fpu_helper.c line 138
Quoted 6 lines
target-riscv/fpu_helper.c new file +6
-0+uint64_t helper_fnmadd_s (CPURISCVState *env,uint64_t frs1,uint64_t frs2, +uint64_t frs3,uint64_t rm) +{ +set_float_rounding_mode (RM , &env->fp_status); + frs1 =float32_muladd (frs1 ^ (uint32_t )INT32_MIN , frs2, + frs3 ^ (uint32_t )INT32_MIN ,0 , &env->fp_status);
... and this one is actually computing fnmsub. Given that you're passing tests, are you sure that FNMADD and FNMSUB opcodes are not swapped?
Use float_muladd_negate_result for FNMADD.
Use float_muladd_negate_c | float_muladd_negate_result for FNMSUB.
r~
Re: [Qemu-devel] [PATCH 09/18] target-riscv: Add FMADD, FMSUB, FNMADD, FNMSUB Instructions,
In reply to Sagar KarandikarQuoted 5 lines · Sagar Karandikar
target-riscv/fpu_helper.c new file +5
-0+/* adapted from Spike's decode.h:set_fp_exceptions */ +#define set_fp_exceptions () do { \ + env->csr[CSR_FFLAGS] |= softfloat_flags_to_riscv(get_float_exception_flags(\ + &env->fp_status)); \ + set_float_exception_flags(0, &env->fp_status); \
target-riscv/fpu_helper.c line 82
Quoted 10 lines
target-riscv/fpu_helper.c new file +10
-0+}while (0 ) + +uint64_t helper_fmadd_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2, + uint64_t frs3, uint64_t rm) +{ +set_float_rounding_mode (RM , &env->fp_status); + frs1 =float32_muladd (frs1, frs2, frs3,0 , &env->fp_status); +set_fp_exceptions (); +return frs1; +}
I should also mention that I think it would be preferable to canonically store the fflags csr in fp_status. This means that you only need to perform this flags conversion when reading or writing the csr, and not upon every fp insn.
The conversion of bits at each fp insn is done on other targets in order to notice when exceptions must be taken. Since riscv has no fp exceptions, this isn't a factor.
r~
PATCH 10/18 target-riscv: Add Single Precision Floating-Point Instructions
In reply to Sagar Karandikar--- target-riscv/fpu_helper.c | 206 ++++++++++++++++++++++++++++++++++++++++++++++ target-riscv/helper.h | 28 +++++++ target-riscv/translate.c | 146 ++++++++++++++++++++++++++++++++ 3 files changed, 380 insertions(+)
target-riscv/fpu_helper.c +206 -0
@@ -149,3 +149,209 @@ uint64_t helper_fnmadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2,set_fp_exceptions ();return frs1; } + +uint64_t helper_fadd_s (CPURISCVState *env,uint64_t frs1,uint64_t frs2, +uint64_t rm) +{ +set_float_rounding_mode (RM , &env->fp_status); + frs1 =float32_add (frs1, frs2, &env->fp_status); +set_fp_exceptions (); +return frs1; +} + +uint64_t helper_fsub_s (CPURISCVState *env,uint64_t frs1,uint64_t frs2, +uint64_t rm) +{ +set_float_rounding_mode (RM , &env->fp_status); + frs1 =float32_sub (frs1, frs2, &env->fp_status); +set_fp_exceptions (); +return frs1; +} + +uint64_t helper_fmul_s (CPURISCVState *env,uint64_t frs1,uint64_t frs2, +uint64_t rm) +{ +set_float_rounding_mode (RM , &env->fp_status); + frs1 =float32_mul (frs1, frs2, &env->fp_status); +set_fp_exceptions (); +return frs1; +} + +uint64_t helper_fdiv_s (CPURISCVState *env,uint64_t frs1,uint64_t frs2, +uint64_t rm) +{ +set_float_rounding_mode (RM , &env->fp_status); + frs1 =float32_div (frs1, frs2, &env->fp_status); +set_fp_exceptions (); +return frs1; +} + +uint64_t helper_fsgnj_s (CPURISCVState *env,uint64_t frs1,uint64_t frs2) +{ + frs1 = (frs1 & ~(uint32_t )INT32_MIN ) | (frs2 & (uint32_t )INT32_MIN ); +return frs1; +} + +uint64_t helper_fsgnjn_s (CPURISCVState *env,uint64_t frs1,uint64_t frs2) +{ + frs1 = (frs1 & ~(uint32_t )INT32_MIN ) | ((~frs2) & (uint32_t )INT32_MIN ); +return frs1; +} + +uint64_t helper_fsgnjx_s (CPURISCVState *env,uint64_t frs1,uint64_t frs2) +{ + frs1 = frs1 ^ (frs2 & (uint32_t )INT32_MIN ); +return frs1; +} + +uint64_t helper_fmin_s (CPURISCVState *env,uint64_t frs1,uint64_t frs2) +{ + frs1 =float32_is_any_nan (frs2) || +float32_lt_quiet (frs1, frs2, &env->fp_status) ? frs1 : frs2; +set_fp_exceptions (); +return frs1; +} + +uint64_t helper_fmax_s (CPURISCVState *env,uint64_t frs1,uint64_t frs2) +{ + frs1 =float32_is_any_nan (frs2) || +float32_le_quiet (frs2, frs1, &env->fp_status) ? frs1 : frs2; +set_fp_exceptions (); +return frs1; +} + +uint64_t helper_fsqrt_s (CPURISCVState *env,uint64_t frs1,uint64_t rm) +{ +set_float_rounding_mode (RM , &env->fp_status); + frs1 =float32_sqrt (frs1, &env->fp_status); +set_fp_exceptions (); +return frs1; +} + +target_ulong helper_fle_s (CPURISCVState *env,uint64_t frs1,uint64_t frs2) +{ + frs1 =float32_le (frs1, frs2, &env->fp_status); +set_fp_exceptions (); +return frs1; +} + +target_ulong helper_flt_s (CPURISCVState *env,uint64_t frs1,uint64_t frs2) +{ + frs1 =float32_lt (frs1, frs2, &env->fp_status); +set_fp_exceptions (); +return frs1; +} + +target_ulong helper_feq_s (CPURISCVState *env,uint64_t frs1,uint64_t frs2) +{ + frs1 =float32_eq (frs1, frs2, &env->fp_status); +set_fp_exceptions (); +return frs1; +} + +target_ulong helper_fcvt_w_s (CPURISCVState *env,uint64_t frs1,uint64_t rm) +{ +set_float_rounding_mode (RM , &env->fp_status); + frs1 = (int64_t )((int32_t )float32_to_int32 (frs1, &env->fp_status)); +set_fp_exceptions (); +return frs1; +} + +target_ulong helper_fcvt_wu_s (CPURISCVState *env,uint64_t frs1,uint64_t rm) +{ +set_float_rounding_mode (RM , &env->fp_status); + frs1 = (int64_t )((int32_t )float32_to_uint32 (frs1, &env->fp_status)); +set_fp_exceptions (); +return frs1; +} + +#if defined(TARGET_RISCV64 ) +uint64_t helper_fcvt_l_s (CPURISCVState *env,uint64_t frs1,uint64_t rm) +{ +set_float_rounding_mode (RM , &env->fp_status); + frs1 =float32_to_int64 (frs1, &env->fp_status); +set_fp_exceptions (); +return frs1; +} + +uint64_t helper_fcvt_lu_s (CPURISCVState *env,uint64_t frs1,uint64_t rm) +{ +set_float_rounding_mode (RM , &env->fp_status); + frs1 =float32_to_uint64 (frs1, &env->fp_status); +set_fp_exceptions (); +return frs1; +} +#endif + +uint64_t helper_fcvt_s_w (CPURISCVState *env,target_ulong rs1,uint64_t rm) +{ +set_float_rounding_mode (RM , &env->fp_status); + rs1 =int32_to_float32 ((int32_t )rs1, &env->fp_status); +set_fp_exceptions (); +return rs1; +} + +uint64_t helper_fcvt_s_wu (CPURISCVState *env,target_ulong rs1,uint64_t rm) +{ +set_float_rounding_mode (RM , &env->fp_status); + rs1 =uint32_to_float32 ((uint32_t )rs1, &env->fp_status); +set_fp_exceptions (); +return rs1; +} + +#if defined(TARGET_RISCV64 ) +uint64_t helper_fcvt_s_l (CPURISCVState *env,uint64_t rs1,uint64_t rm) +{ +set_float_rounding_mode (RM , &env->fp_status); + rs1 =int64_to_float32 (rs1, &env->fp_status); +set_fp_exceptions (); +return rs1; +} + +uint64_t helper_fcvt_s_lu (CPURISCVState *env,uint64_t rs1,uint64_t rm) +{ +set_float_rounding_mode (RM , &env->fp_status); + rs1 =uint64_to_float32 (rs1, &env->fp_status); +set_fp_exceptions (); +return rs1; +} +#endif + +/* adapted from spike */ +#define isNaNF32UI (ui) (0xFF000000 < (uint32_t)((uint_fast32_t)ui << 1)) +#define signF32UI (a) ((bool)((uint32_t)a >> 31)) +#define expF32UI (a) ((int_fast16_t)(a >> 23) & 0xFF) +#define fracF32UI (a) (a & 0x007FFFFF) + +union ui32_f32 {uint32_t ui;uint32_t f; }; + +uint_fast16_t float32_classify (uint32_t a,float_status *status) +{ +union ui32_f32 uA; +uint_fast32_t uiA; + + uA.f = a; + uiA = uA.ui; + +uint_fast16_t infOrNaN =expF32UI (uiA) ==0xFF ; +uint_fast16_t subnormalOrZero =expF32UI (uiA) ==0 ; +bool sign =signF32UI (uiA); + +return + (sign && infOrNaN &&fracF32UI (uiA) ==0 ) <<0 | + (sign && !infOrNaN && !subnormalOrZero) <<1 | + (sign && subnormalOrZero &&fracF32UI (uiA)) <<2 | + (sign && subnormalOrZero &&fracF32UI (uiA) ==0 ) <<3 | + (!sign && infOrNaN &&fracF32UI (uiA) ==0 ) <<7 | + (!sign && !infOrNaN && !subnormalOrZero) <<6 | + (!sign && subnormalOrZero &&fracF32UI (uiA)) <<5 | + (!sign && subnormalOrZero &&fracF32UI (uiA) ==0 ) <<4 | + (isNaNF32UI (uiA) &&float32_is_signaling_nan (uiA, status)) <<8 | + (isNaNF32UI (uiA) && !float32_is_signaling_nan (uiA, status)) <<9 ; +} + +target_ulong helper_fclass_s (CPURISCVState *env,uint64_t frs1) +{ + frs1 =float32_classify (frs1, &env->fp_status); +return frs1; +}
target-riscv/helper.h +28 -0
@@ -16,3 +16,31 @@ DEF_HELPER_FLAGS_5(fnmsub_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64, i64) DEF_HELPER_FLAGS_5(fnmsub_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64, i64) DEF_HELPER_FLAGS_5(fnmadd_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64, i64)DEF_HELPER_FLAGS_5 (fnmadd_d,TCG_CALL_NO_RWG , i64, env, i64, i64, i64, i64) + +/* Floating Point - Single Precision */ +DEF_HELPER_FLAGS_4(fadd_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(fsub_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(fmul_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(fdiv_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_3(fsgnj_s, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fsgnjn_s, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fsgnjx_s, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmin_s, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmax_s, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fsqrt_s, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fle_s, TCG_CALL_NO_RWG, tl, env, i64, i64) +DEF_HELPER_FLAGS_3(flt_s, TCG_CALL_NO_RWG, tl, env, i64, i64) +DEF_HELPER_FLAGS_3(feq_s, TCG_CALL_NO_RWG, tl, env, i64, i64) +DEF_HELPER_FLAGS_3(fcvt_w_s, TCG_CALL_NO_RWG, tl, env, i64, i64) +DEF_HELPER_FLAGS_3(fcvt_wu_s, TCG_CALL_NO_RWG, tl, env, i64, i64) +#if defined(TARGET_RISCV64 ) +DEF_HELPER_FLAGS_3(fcvt_l_s, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fcvt_lu_s, TCG_CALL_NO_RWG, i64, env, i64, i64) +#endif +DEF_HELPER_FLAGS_3(fcvt_s_w, TCG_CALL_NO_RWG, i64, env, tl, i64) +DEF_HELPER_FLAGS_3(fcvt_s_wu, TCG_CALL_NO_RWG, i64, env, tl, i64) +#if defined(TARGET_RISCV64 ) +DEF_HELPER_FLAGS_3(fcvt_s_l, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fcvt_s_lu, TCG_CALL_NO_RWG, i64, env, i64, i64) +#endif +DEF_HELPER_FLAGS_2 (fclass_s,TCG_CALL_NO_RWG , tl, env, i64)
target-riscv/translate.c +146 -0
158 lines not on this page · raw message
Signature · 1 line
2.9.3
Re: [Qemu-devel] [PATCH 10/18] target-riscv: Add Single Precision Floating-Point Instructions
Quoted 7 lines · Sagar Karandikar
target-riscv/fpu_helper.c +7
-0+uint64_t helper_fsgnj_s (CPURISCVState *env,uint64_t frs1,uint64_t frs2) +{ + frs1 = (frs1 & ~(uint32_t )INT32_MIN ) | (frs2 & (uint32_t )INT32_MIN ); +return frs1; +} + +uint64_t helper_fsgnjn_s (CPURISCVState *env,uint64_t frs1,uint64_t frs2)
target-riscv/fpu_helper.c uint64_t helper_fnmadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2, · line 205
Quoted 10 lines
target-riscv/fpu_helper.c +10
-0+{ + frs1 = (frs1 & ~(uint32_t )INT32_MIN ) | ((~frs2) & (uint32_t )INT32_MIN ); +return frs1; +} + +uint64_t helper_fsgnjx_s (CPURISCVState *env,uint64_t frs1,uint64_t frs2) +{ + frs1 = frs1 ^ (frs2 & (uint32_t )INT32_MIN ); +return frs1; +}
These are simple enough to implement inline.
target-riscv/fpu_helper.c uint64_t helper_fnmadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2, · line 213
Quoted 8 lines
target-riscv/fpu_helper.c +8
-0+ +uint64_t helper_fmin_s (CPURISCVState *env,uint64_t frs1,uint64_t frs2) +{ + frs1 =float32_is_any_nan (frs2) || +float32_lt_quiet (frs1, frs2, &env->fp_status) ? frs1 : frs2; +set_fp_exceptions (); +return frs1; +}
float32_minnum.
target-riscv/fpu_helper.c uint64_t helper_fnmadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2, · line 221
Quoted 8 lines
target-riscv/fpu_helper.c +8
-0+ +uint64_t helper_fmax_s (CPURISCVState *env,uint64_t frs1,uint64_t frs2) +{ + frs1 =float32_is_any_nan (frs2) || +float32_le_quiet (frs2, frs1, &env->fp_status) ? frs1 : frs2; +set_fp_exceptions (); +return frs1; +}
float32_maxnum.
target-riscv/fpu_helper.c uint64_t helper_fnmadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2, · line 255
Quoted 4 lines
target-riscv/fpu_helper.c +4
-0+target_ulong helper_fcvt_w_s (CPURISCVState *env,uint64_t frs1,uint64_t rm) +{ +set_float_rounding_mode (RM , &env->fp_status); + frs1 = (int64_t )((int32_t )float32_to_int32 (frs1, &env->fp_status));
You do not need either of these casts.
target-riscv/fpu_helper.c uint64_t helper_fnmadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2, · line 263
Quoted 4 lines
target-riscv/fpu_helper.c +4
-0+target_ulong helper_fcvt_wu_s (CPURISCVState *env,uint64_t frs1,uint64_t rm) +{ +set_float_rounding_mode (RM , &env->fp_status); + frs1 = (int64_t )((int32_t )float32_to_uint32 (frs1, &env->fp_status));
You do not need the cast to int64_t. Also, remove the extra parenthesis.
Quoted 1 line
+union
ui32_f32{uint32_tui;uint32_tf; };
What's the point of this?
Review
Quoted 2 lines
(quoted diff) +2
-0+ +uint_fast16_t float32_classify(uint32_t a, float_status *status)
No need for uint_fast16_t. Just use uint32_t.
target-riscv/fpu_helper.c uint64_t helper_fnmadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2, · line 336
Quoted 8 lines
target-riscv/fpu_helper.c +8
-0+{ +union ui32_f32 uA; +uint_fast32_t uiA; + + uA.f = a; + uiA = uA.ui; + +uint_fast16_t infOrNaN =expF32UI (uiA) ==0xFF ;
float32_is_infinity or float32_is_any_nan.
Quoted 1 line
+
uint_fast16_tsubnormalOrZero = expF32UI(uiA) == 0;
float32_is_zero_or_denormal
Quoted 1 line
+ bool sign = signF32UI(uiA);
float32_is_neg.
r~
PATCH 11/18 target-riscv: Add Double Precision Floating-Point Instructions
In reply to Sagar Karandikar--- target-riscv/fpu_helper.c | 225 ++++++++++++++++++++++++++++++++++++++++++++++ target-riscv/helper.h | 30 +++++++ target-riscv/translate.c | 135 ++++++++++++++++++++++++++++ 3 files changed, 390 insertions(+)
target-riscv/fpu_helper.c +225 -0
@@ -355,3 +355,228 @@ target_ulong helper_fclass_s(CPURISCVState *env, uint64_t frs1) frs1 =float32_classify (frs1, &env->fp_status);return frs1; } + +uint64_t helper_fadd_d (CPURISCVState *env,uint64_t frs1,uint64_t frs2, +uint64_t rm) +{ +set_float_rounding_mode (RM , &env->fp_status); + frs1 =float64_add (frs1, frs2, &env->fp_status); +set_fp_exceptions (); +return frs1; +} + +uint64_t helper_fsub_d (CPURISCVState *env,uint64_t frs1,uint64_t frs2, +uint64_t rm) +{ +set_float_rounding_mode (RM , &env->fp_status); + frs1 =float64_sub (frs1, frs2, &env->fp_status); +set_fp_exceptions (); +return frs1; +} + +uint64_t helper_fmul_d (CPURISCVState *env,uint64_t frs1,uint64_t frs2, +uint64_t rm) +{ +set_float_rounding_mode (RM , &env->fp_status); + frs1 =float64_mul (frs1, frs2, &env->fp_status); +set_fp_exceptions (); +return frs1; +} + +uint64_t helper_fdiv_d (CPURISCVState *env,uint64_t frs1,uint64_t frs2, +uint64_t rm) +{ +set_float_rounding_mode (RM , &env->fp_status); + frs1 =float64_div (frs1, frs2, &env->fp_status); +set_fp_exceptions (); +return frs1; +} + +uint64_t helper_fsgnj_d (CPURISCVState *env,uint64_t frs1,uint64_t frs2) +{ + frs1 = (frs1 & ~INT64_MIN ) | (frs2 &INT64_MIN ); +return frs1; +} + +uint64_t helper_fsgnjn_d (CPURISCVState *env,uint64_t frs1,uint64_t frs2) +{ + frs1 = (frs1 & ~INT64_MIN ) | ((~frs2) &INT64_MIN ); +return frs1; +} + +uint64_t helper_fsgnjx_d (CPURISCVState *env,uint64_t frs1,uint64_t frs2) +{ + frs1 = frs1 ^ (frs2 &INT64_MIN ); +return frs1; +} + +uint64_t helper_fmin_d (CPURISCVState *env,uint64_t frs1,uint64_t frs2) +{ + frs1 =float64_is_any_nan (frs2) || +float64_lt_quiet (frs1, frs2, &env->fp_status) ? frs1 : frs2; +set_fp_exceptions (); +return frs1; +} + +uint64_t helper_fmax_d (CPURISCVState *env,uint64_t frs1,uint64_t frs2) +{ + frs1 =float64_is_any_nan (frs2) || +float64_le_quiet (frs2, frs1, &env->fp_status) ? frs1 : frs2; +set_fp_exceptions (); +return frs1; +} + +uint64_t helper_fcvt_s_d (CPURISCVState *env,uint64_t rs1,uint64_t rm) +{ +set_float_rounding_mode (RM , &env->fp_status); + rs1 =float64_to_float32 (rs1, &env->fp_status); +set_fp_exceptions (); +return rs1; +} + +uint64_t helper_fcvt_d_s (CPURISCVState *env,uint64_t rs1,uint64_t rm) +{ +set_float_rounding_mode (RM , &env->fp_status); + rs1 =float32_to_float64 (rs1, &env->fp_status); +set_fp_exceptions (); +return rs1; +} + +uint64_t helper_fsqrt_d (CPURISCVState *env,uint64_t frs1,uint64_t rm) +{ +set_float_rounding_mode (RM , &env->fp_status); + frs1 =float64_sqrt (frs1, &env->fp_status); +set_fp_exceptions (); +return frs1; +} + +target_ulong helper_fle_d (CPURISCVState *env,uint64_t frs1,uint64_t frs2) +{ + frs1 =float64_le (frs1, frs2, &env->fp_status); +set_fp_exceptions (); +return frs1; +} + +target_ulong helper_flt_d (CPURISCVState *env,uint64_t frs1,uint64_t frs2) +{ + frs1 =float64_lt (frs1, frs2, &env->fp_status); +set_fp_exceptions (); +return frs1; +} + +target_ulong helper_feq_d (CPURISCVState *env,uint64_t frs1,uint64_t frs2) +{ + frs1 =float64_eq (frs1, frs2, &env->fp_status); +set_fp_exceptions (); +return frs1; +} + +target_ulong helper_fcvt_w_d (CPURISCVState *env,uint64_t frs1,uint64_t rm) +{ +set_float_rounding_mode (RM , &env->fp_status); + frs1 = (int64_t )((int32_t )float64_to_int32 (frs1, &env->fp_status)); +set_fp_exceptions (); +return frs1; +} + +target_ulong helper_fcvt_wu_d (CPURISCVState *env,uint64_t frs1,uint64_t rm) +{ +set_float_rounding_mode (RM , &env->fp_status); + frs1 = (int64_t )((int32_t )float64_to_uint32 (frs1, &env->fp_status)); +set_fp_exceptions (); +return frs1; +} + +#if defined(TARGET_RISCV64 ) +uint64_t helper_fcvt_l_d (CPURISCVState *env,uint64_t frs1,uint64_t rm) +{ +set_float_rounding_mode (RM , &env->fp_status); + frs1 =float64_to_int64 (frs1, &env->fp_status); +set_fp_exceptions (); +return frs1; +} + +uint64_t helper_fcvt_lu_d (CPURISCVState *env,uint64_t frs1,uint64_t rm) +{ +set_float_rounding_mode (RM , &env->fp_status); + frs1 =float64_to_uint64 (frs1, &env->fp_status); +set_fp_exceptions (); +return frs1; +} +#endif + +uint64_t helper_fcvt_d_w (CPURISCVState *env,target_ulong rs1,uint64_t rm) +{ +uint64_t res; +set_float_rounding_mode (RM , &env->fp_status); + res =int32_to_float64 ((int32_t )rs1, &env->fp_status); +set_fp_exceptions (); +return res; +} + +uint64_t helper_fcvt_d_wu (CPURISCVState *env,target_ulong rs1,uint64_t rm) +{ +uint64_t res; +set_float_rounding_mode (RM , &env->fp_status); + res =uint32_to_float64 ((uint32_t )rs1, &env->fp_status); +set_fp_exceptions (); +return res; +} + +#if defined(TARGET_RISCV64 ) +uint64_t helper_fcvt_d_l (CPURISCVState *env,uint64_t rs1,uint64_t rm) +{ +set_float_rounding_mode (RM , &env->fp_status); + rs1 =int64_to_float64 (rs1, &env->fp_status); +set_fp_exceptions (); +return rs1; +} + +uint64_t helper_fcvt_d_lu (CPURISCVState *env,uint64_t rs1,uint64_t rm) +{ +set_float_rounding_mode (RM , &env->fp_status); + rs1 =uint64_to_float64 (rs1, &env->fp_status); +set_fp_exceptions (); +return rs1; +} +#endif + +/* adapted from spike */ +#define isNaNF64UI (ui) (UINT64_C(0xFFE0000000000000) \ + < (uint64_t)((uint_fast64_t)ui << 1)) +#define signF64UI (a) ((bool)((uint64_t) a >> 63)) +#define expF64UI (a) ((int_fast16_t)(a >> 52) & 0x7FF) +#define fracF64UI (a) (a & UINT64_C(0x000FFFFFFFFFFFFF)) + +union ui64_f64 {uint64_t ui;uint64_t f; }; + +uint_fast16_t float64_classify (uint64_t a,float_status *status) +{ +union ui64_f64 uA; +uint_fast64_t uiA; + + uA.f = a; + uiA = uA.ui; + +uint_fast16_t infOrNaN =expF64UI (uiA) ==0x7FF ; +uint_fast16_t subnormalOrZero =expF64UI (uiA) ==0 ; +bool sign =signF64UI (uiA); + +return + (sign && infOrNaN &&fracF64UI (uiA) ==0 ) <<0 | + (sign && !infOrNaN && !subnormalOrZero) <<1 | + (sign && subnormalOrZero &&fracF64UI (uiA)) <<2 | + (sign && subnormalOrZero &&fracF64UI (uiA) ==0 ) <<3 | + (!sign && infOrNaN &&fracF64UI (uiA) ==0 ) <<7 | + (!sign && !infOrNaN && !subnormalOrZero) <<6 | + (!sign && subnormalOrZero &&fracF64UI (uiA)) <<5 | + (!sign && subnormalOrZero &&fracF64UI (uiA) ==0 ) <<4 | + (isNaNF64UI (uiA) &&float64_is_signaling_nan (uiA, status)) <<8 | + (isNaNF64UI (uiA) && !float64_is_signaling_nan (uiA, status)) <<9 ; +} + +target_ulong helper_fclass_d (CPURISCVState *env,uint64_t frs1) +{ + frs1 =float64_classify (frs1, &env->fp_status); +return frs1; +}
target-riscv/helper.h +30 -0
@@ -44,3 +44,33 @@ DEF_HELPER_FLAGS_3(fcvt_s_l, TCG_CALL_NO_RWG, i64, env, i64, i64) DEF_HELPER_FLAGS_3(fcvt_s_lu, TCG_CALL_NO_RWG, i64, env, i64, i64)#endif DEF_HELPER_FLAGS_2 (fclass_s,TCG_CALL_NO_RWG , tl, env, i64) + +/* Floating Point - Double Precision */ +DEF_HELPER_FLAGS_4(fadd_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(fsub_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(fmul_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(fdiv_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_3(fsgnj_d, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fsgnjn_d, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fsgnjx_d, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmin_d, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmax_d, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fcvt_s_d, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fcvt_d_s, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fsqrt_d, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fle_d, TCG_CALL_NO_RWG, tl, env, i64, i64) +DEF_HELPER_FLAGS_3(flt_d, TCG_CALL_NO_RWG, tl, env, i64, i64) +DEF_HELPER_FLAGS_3(feq_d, TCG_CALL_NO_RWG, tl, env, i64, i64) +DEF_HELPER_FLAGS_3(fcvt_w_d, TCG_CALL_NO_RWG, tl, env, i64, i64) +DEF_HELPER_FLAGS_3(fcvt_wu_d, TCG_CALL_NO_RWG, tl, env, i64, i64) +#if defined(TARGET_RISCV64 ) +DEF_HELPER_FLAGS_3(fcvt_l_d, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fcvt_lu_d, TCG_CALL_NO_RWG, i64, env, i64, i64) +#endif +DEF_HELPER_FLAGS_3(fcvt_d_w, TCG_CALL_NO_RWG, i64, env, tl, i64) +DEF_HELPER_FLAGS_3(fcvt_d_wu, TCG_CALL_NO_RWG, i64, env, tl, i64) +#if defined(TARGET_RISCV64 ) +DEF_HELPER_FLAGS_3(fcvt_d_l, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fcvt_d_lu, TCG_CALL_NO_RWG, i64, env, i64, i64) +#endif +DEF_HELPER_FLAGS_2 (fclass_d,TCG_CALL_NO_RWG , tl, env, i64)
target-riscv/translate.c +135 -0
141 lines not on this page · raw message
Signature · 1 line
2.9.3
Re: [Qemu-devel] [PATCH 11/18] target-riscv: Add Double Precision Floating-Point Instructions
Quoted 4 lines · Sagar Karandikar
target-riscv/translate.c +4
-0+case OPC_RISC_FSGNJ_D : +/* also OPC_RISC_FSGNJN_D, OPC_RISC_FSGNJX_D */ +if (rm ==0x0 ) { + gen_helper_fsgnj_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1],
target-riscv/translate.c static inline void gen_fp_arith(DisasContext *ctx, uint32_t opc, int rd, · line 1048
Quoted 10 lines
target-riscv/translate.c +10
-0+ cpu_fpr[rs2]); + }else if (rm ==0x1 ) { +gen_helper_fsgnjn_d (cpu_fpr[rd], cpu_env, cpu_fpr[rs1], + cpu_fpr[rs2]); + }else if (rm ==0x2 ) { +gen_helper_fsgnjx_d (cpu_fpr[rd], cpu_env, cpu_fpr[rs1], + cpu_fpr[rs2]); + }else { +kill_unknown (ctx,RISCV_EXCP_ILLEGAL_INST ); + }
I forgot to mention this for single-precision -- given that FMOV is an alias of FSGNJ, you should special case rs1 == rs2.
r~
PATCH 12/18 target-riscv: Add system instructions
In reply to Sagar KarandikarSystem instructions, stubs for csr read/write, necessary helpers
--- target-riscv/helper.h | 11 ++++ target-riscv/op_helper.c | 144 +++++++++++++++++++++++++++++++++++++++++++++++ target-riscv/translate.c | 119 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 274 insertions(+)
target-riscv/helper.h +11 -0
@@ -74,3 +74,14 @@ DEF_HELPER_FLAGS_3(fcvt_d_l, TCG_CALL_NO_RWG, i64, env, i64, i64) DEF_HELPER_FLAGS_3(fcvt_d_lu, TCG_CALL_NO_RWG, i64, env, i64, i64)#endif DEF_HELPER_FLAGS_2 (fclass_d,TCG_CALL_NO_RWG , tl, env, i64) + +/* Special functions */ +#ifndef CONFIG_USER_ONLY +DEF_HELPER_4(csrrw, tl, env, tl, tl, tl) +DEF_HELPER_5(csrrs, tl, env, tl, tl, tl, tl) +DEF_HELPER_5(csrrc, tl, env, tl, tl, tl, tl) +DEF_HELPER_2(sret, tl, env, tl) +DEF_HELPER_2(mret, tl, env, tl) +DEF_HELPER_1(tlb_flush, void, env) +DEF_HELPER_1(fence_i, void, env) +#endif /* !CONFIG_USER_ONLY */
target-riscv/op_helper.c +144 -0
157 lines not on this page · raw message
target-riscv/translate.c +119 -0
131 lines not on this page · raw message
Signature · 1 line
2.9.3
Re: [Qemu-devel] [PATCH 12/18] target-riscv: Add system instructions
target-riscv/helper.h DEF_HELPER_FLAGS_3(fcvt_d_l, TCG_CALL_NO_RWG, i64, env, i64, i64) · line 87
Quoted 9 lines · Sagar Karandikar
target-riscv/helper.h +9
-0+#ifndef CONFIG_USER_ONLY +DEF_HELPER_4(csrrw, tl, env, tl, tl, tl) +DEF_HELPER_5(csrrs, tl, env, tl, tl, tl, tl) +DEF_HELPER_5(csrrc, tl, env, tl, tl, tl, tl) +DEF_HELPER_2(sret, tl, env, tl) +DEF_HELPER_2(mret, tl, env, tl) +DEF_HELPER_1(tlb_flush, void, env) +DEF_HELPER_1(fence_i, void, env) +#endif /* !CONFIG_USER_ONLY */
The system emulation spec is still in flux, I think we should only add user-mode emulation for now.
Paolo
Re: [Qemu-devel] [PATCH 12/18] target-riscv: Add system instructions
Quoted 16 lines · Paolo Bonzini
target-riscv/helper.h DEF_HELPER_FLAGS_3(fcvt_d_l, TCG_CALL_NO_RWG, i64, env, i64, i64) · line 87
Quoted 9 lines · Sagar Karandikar
target-riscv/helper.h +9
-0+#ifndef CONFIG_USER_ONLY +DEF_HELPER_4(csrrw, tl, env, tl, tl, tl) +DEF_HELPER_5(csrrs, tl, env, tl, tl, tl, tl) +DEF_HELPER_5(csrrc, tl, env, tl, tl, tl, tl) +DEF_HELPER_2(sret, tl, env, tl) +DEF_HELPER_2(mret, tl, env, tl) +DEF_HELPER_1(tlb_flush, void, env) +DEF_HELPER_1(fence_i, void, env) +#endif /* !CONFIG_USER_ONLY */ The system emulation spec is still in flux, I think we should only add user-mode emulation for now.
Hi Paolo,
by user-mode emulation you still mean softmmu and not linux-user, right? So just drop the system instructions for now.
Cheers,
Bastian
Re: [Qemu-devel] [PATCH 12/18] target-riscv: Add system instructions
Quoted 18 lines · Bastian Koppelmann
Quoted 16 lines · Paolo Bonzini
target-riscv/helper.h DEF_HELPER_FLAGS_3(fcvt_d_l, TCG_CALL_NO_RWG, i64, env, i64, i64) · line 87
Quoted 9 lines · Sagar Karandikar
target-riscv/helper.h +9
-0+#ifndef CONFIG_USER_ONLY +DEF_HELPER_4(csrrw, tl, env, tl, tl, tl) +DEF_HELPER_5(csrrs, tl, env, tl, tl, tl, tl) +DEF_HELPER_5(csrrc, tl, env, tl, tl, tl, tl) +DEF_HELPER_2(sret, tl, env, tl) +DEF_HELPER_2(mret, tl, env, tl) +DEF_HELPER_1(tlb_flush, void, env) +DEF_HELPER_1(fence_i, void, env) +#endif /* !CONFIG_USER_ONLY */ The system emulation spec is still in flux, I think we should only add user-mode emulation for now.
Quoted 4 lines
Hi Paolo,
by user-mode emulation you still mean softmmu and not linux-user, right? So just drop the system instructions for now.
I don't think that's possible; all RISC-V machines include at least M-mode, whose precise definitions requires the privileged interface specification which hasn't been finalized yet. So only linux-user is stable enough.
In fact, based on some recent discussions on the RISC-V isa-dev mailing list, it looks like some memory protection features _beyond_ the privileged interface specification are in practice required to secure M-mode from the supervisor. I'm not sure what's the point in defining a separate mandatory M-mode (supervisor mode cannot even enable paging without help from M-mode, on the other hand a processor that only has M- and U-modes cannot enable paging) but not providing the tools to actually enforce privilege separation for it.
All in all, while I'm happy that the RISC-V project uses QEMU for development, I don't think that the privileged interface specification is mature enough for inclusion in QEMU. It's very different for linux-user user-mode emulation of course, it's great to have that upstream.
Thanks,
Paolo
Re: [Qemu-devel] [PATCH 12/18] target-riscv: Add system instructions
Hi Paolo,
There's a fork that has linux-user support. We'll get it added into the downstream riscv-qemu repo and include that in the next patch set instead of softmmu.
Thanks,
Sagar
Quoted 49 lines · Paolo Bonzini
Quoted 18 lines · Bastian Koppelmann
Quoted 16 lines · Paolo Bonzini
target-riscv/helper.h DEF_HELPER_FLAGS_3(fcvt_d_l, TCG_CALL_NO_RWG, i64, env, i64, i64) · line 87
Quoted 9 lines · Sagar Karandikar
target-riscv/helper.h +9
-0+#ifndef CONFIG_USER_ONLY +DEF_HELPER_4(csrrw, tl, env, tl, tl, tl) +DEF_HELPER_5(csrrs, tl, env, tl, tl, tl, tl) +DEF_HELPER_5(csrrc, tl, env, tl, tl, tl, tl) +DEF_HELPER_2(sret, tl, env, tl) +DEF_HELPER_2(mret, tl, env, tl) +DEF_HELPER_1(tlb_flush, void, env) +DEF_HELPER_1(fence_i, void, env) +#endif /* !CONFIG_USER_ONLY */ The system emulation spec is still in flux, I think we should only add user-mode emulation for now.
Quoted 4 lines
Hi Paolo,
by user-mode emulation you still mean softmmu and not linux-user, right? So just drop the system instructions for now.
I don't think that's possible; all RISC-V machines include at least M-mode, whose precise definitions requires the privileged interface specification which hasn't been finalized yet. So only linux-user is stable enough.
In fact, based on some recent discussions on the RISC-V isa-dev mailing list, it looks like some memory protection features _beyond_ the privileged interface specification are in practice required to secure M-mode from the supervisor. I'm not sure what's the point in defining a separate mandatory M-mode (supervisor mode cannot even enable paging without help from M-mode, on the other hand a processor that only has M- and U-modes cannot enable paging) but not providing the tools to actually enforce privilege separation for it.
All in all, while I'm happy that the RISC-V project uses QEMU for development, I don't think that the privileged interface specification is mature enough for inclusion in QEMU. It's very different for linux-user user-mode emulation of course, it's great to have that upstream.
Thanks,
Paolo
Re: [Qemu-devel] [PATCH 12/18] target-riscv: Add system instructions
In reply to Sagar Karandikartarget-riscv/op_helper.c target_ulong helper_mulhsu(CPURISCVState *env, target_ulong arg1, · line 200
Quoted 10 lines · Sagar Karandikar
target-riscv/op_helper.c +10
-0+void helper_fence_i (CPURISCVState *env) +{ +RISCVCPU *cpu =riscv_env_get_cpu (env); +CPUState *cs =CPU (cpu); +/* Flush QEMU's TLB */ +tlb_flush (cs,1 ); +/* ARM port seems to not know if this is okay inside a TB +But we need to do it */ +tb_flush (cs); +}
You should not need to tb_flush for fence_i. QEMU's internals auto-detect when a memory write invalidates a TB.
r~
PATCH 13/18 target-riscv: Add CSR read/write helpers
In reply to Sagar Karandikar--- target-riscv/op_helper.c | 324 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 324 insertions(+)
target-riscv/op_helper.c +324 -0
@@ -39,6 +39,11 @@ void set_privilege(CPURISCVState *env, target_ulong newpriv) env->priv = newpriv; } +static int validate_vm (target_ulong vm) +{ +return vm ==VM_SV32 || vm ==VM_SV39 || vm ==VM_SV48 || vm ==VM_MBARE ; +} +/* Exceptions processing helpers */ static inline void QEMU_NORETURN do_raise_exception_err(CPURISCVState *env,uint32_t exception,uintptr_t pc)
@@ -83,6 +88,180 @@ target_ulong helper_mulhsu(CPURISCVState *env, target_ulong arg1,inline void csr_write_helper (CPURISCVState *env,target_ulong val_to_write,target_ulong csrno) { +#ifdef RISCV_DEBUG_PRINT +fprintf (stderr,"Write CSR reg: 0x" TARGET_FMT_lx"\n" , csrno); +fprintf (stderr,"Write CSR val: 0x" TARGET_FMT_lx"\n" , val_to_write); +#endif + +uint64_t delegable_ints =MIP_SSIP |MIP_STIP |MIP_SEIP | (1 <<IRQ_COP ); +uint64_t all_ints = delegable_ints |MIP_MSIP |MIP_MTIP ; + +switch (csrno) { +case CSR_FFLAGS : + env->csr[CSR_MSTATUS ] |=MSTATUS_FS |MSTATUS64_SD ; + env->csr[CSR_FFLAGS ] = val_to_write & (FSR_AEXC >>FSR_AEXC_SHIFT ); +break ; +case CSR_FRM : + env->csr[CSR_MSTATUS ] |=MSTATUS_FS |MSTATUS64_SD ; + env->csr[CSR_FRM ] = val_to_write & (FSR_RD >>FSR_RD_SHIFT ); +break ; +case CSR_FCSR : + env->csr[CSR_MSTATUS ] |=MSTATUS_FS |MSTATUS64_SD ; + env->csr[CSR_FFLAGS ] = (val_to_write &FSR_AEXC ) >>FSR_AEXC_SHIFT ; + env->csr[CSR_FRM ] = (val_to_write &FSR_RD ) >>FSR_RD_SHIFT ; +break ; +case CSR_MSTATUS : { +target_ulong mstatus = env->csr[CSR_MSTATUS ]; +if ((val_to_write ^ mstatus) & + (MSTATUS_VM |MSTATUS_MPP |MSTATUS_MPRV |MSTATUS_PUM | +MSTATUS_MXR )) { +helper_tlb_flush (env); + } + +/* no extension support */ +target_ulong mask =MSTATUS_SIE |MSTATUS_SPIE |MSTATUS_MIE + |MSTATUS_MPIE |MSTATUS_SPP |MSTATUS_FS |MSTATUS_MPRV + |MSTATUS_PUM |MSTATUS_MXR ; + +if (validate_vm (get_field (val_to_write,MSTATUS_VM ))) { + mask |=MSTATUS_VM ; + } +if (validate_priv (get_field (val_to_write,MSTATUS_MPP ))) { + mask |=MSTATUS_MPP ; + } + + mstatus = (mstatus & ~mask) | (val_to_write & mask); + +int dirty = (mstatus &MSTATUS_FS ) ==MSTATUS_FS ; + dirty |= (mstatus &MSTATUS_XS ) ==MSTATUS_XS ; + mstatus =set_field (mstatus,MSTATUS64_SD , dirty); + env->csr[CSR_MSTATUS ] = mstatus; +break ; + } +case CSR_MIP : { +target_ulong mask =MIP_SSIP |MIP_STIP ; + env->csr[CSR_MIP ] = (env->csr[CSR_MIP ] & ~mask) | + (val_to_write & mask); +if (env->csr[CSR_MIP ] &MIP_SSIP ) { +qemu_irq_raise (SSIP_IRQ ); + }else { +qemu_irq_lower (SSIP_IRQ ); + } +if (env->csr[CSR_MIP ] &MIP_STIP ) { +qemu_irq_raise (STIP_IRQ ); + }else { +qemu_irq_lower (STIP_IRQ ); + } +if (env->csr[CSR_MIP ] &MIP_MSIP ) { +qemu_irq_raise (MSIP_IRQ ); + }else { +qemu_irq_lower (MSIP_IRQ ); + } +break ; + } +case CSR_MIE : { + env->csr[CSR_MIE ] = (env->csr[CSR_MIE ] & ~all_ints) | + (val_to_write & all_ints); +break ; + } +case CSR_MIDELEG : + env->csr[CSR_MIDELEG ] = (env->csr[CSR_MIDELEG ] & ~delegable_ints) + | (val_to_write & delegable_ints); +break ; +case CSR_MEDELEG : { +target_ulong mask =0 ; + mask |=1ULL << (RISCV_EXCP_INST_ADDR_MIS ); + mask |=1ULL << (RISCV_EXCP_INST_ACCESS_FAULT ); + mask |=1ULL << (RISCV_EXCP_ILLEGAL_INST ); + mask |=1ULL << (RISCV_EXCP_BREAKPOINT ); + mask |=1ULL << (RISCV_EXCP_LOAD_ADDR_MIS ); + mask |=1ULL << (RISCV_EXCP_LOAD_ACCESS_FAULT ); + mask |=1ULL << (RISCV_EXCP_STORE_AMO_ADDR_MIS ); + mask |=1ULL << (RISCV_EXCP_STORE_AMO_ACCESS_FAULT ); + mask |=1ULL << (RISCV_EXCP_U_ECALL ); + mask |=1ULL << (RISCV_EXCP_S_ECALL ); + mask |=1ULL << (RISCV_EXCP_H_ECALL ); + mask |=1ULL << (RISCV_EXCP_M_ECALL ); + env->csr[CSR_MEDELEG ] = (env->csr[CSR_MEDELEG ] & ~mask) + | (val_to_write & mask); +break ; + } +case CSR_MUCOUNTEREN : + env->csr[CSR_MUCOUNTEREN ] = val_to_write &7 ; +break ; +case CSR_MSCOUNTEREN : + env->csr[CSR_MSCOUNTEREN ] = val_to_write &7 ; +break ; +case CSR_SSTATUS : { +target_ulong ms = env->csr[CSR_MSTATUS ]; +target_ulong mask =SSTATUS_SIE |SSTATUS_SPIE |SSTATUS_SPP + |SSTATUS_FS |SSTATUS_XS |SSTATUS_PUM ; + ms = (ms & ~mask) | (val_to_write & mask); +csr_write_helper (env, ms,CSR_MSTATUS ); +break ; + } +case CSR_SIP : { +target_ulong next_mip = (env->csr[CSR_MIP ] & ~env->csr[CSR_MIDELEG ]) + | (val_to_write & env->csr[CSR_MIDELEG ]); +csr_write_helper (env, next_mip,CSR_MIP ); +/* note: stw_phys should be done by the call to set MIP if necessary, */ +/* so we don't do it here */ +break ; + } +case CSR_SIE : { +target_ulong next_mie = (env->csr[CSR_MIE ] & ~env->csr[CSR_MIDELEG ]) + | (val_to_write & env->csr[CSR_MIDELEG ]); +csr_write_helper (env, next_mie,CSR_MIE ); +break ; + } +case CSR_SPTBR : { + env->csr[CSR_SPTBR ] = val_to_write & (((target_ulong )1 << + (TARGET_PHYS_ADDR_SPACE_BITS -PGSHIFT )) -1 ); +break ; + } +case CSR_SEPC : + env->csr[CSR_SEPC ] = val_to_write; +break ; +case CSR_STVEC : + env->csr[CSR_STVEC ] = val_to_write >>2 <<2 ; +break ; +case CSR_SSCRATCH : + env->csr[CSR_SSCRATCH ] = val_to_write; +break ; +case CSR_SCAUSE : + env->csr[CSR_SCAUSE ] = val_to_write; +break ; +case CSR_SBADADDR : + env->csr[CSR_SBADADDR ] = val_to_write; +break ; +case CSR_MEPC : + env->csr[CSR_MEPC ] = val_to_write; +break ; +case CSR_MTVEC : + env->csr[CSR_MTVEC ] = val_to_write >>2 <<2 ; +break ; +case CSR_MSCRATCH : + env->csr[CSR_MSCRATCH ] = val_to_write; +break ; +case CSR_MCAUSE : + env->csr[CSR_MCAUSE ] = val_to_write; +break ; +case CSR_MBADADDR : + env->csr[CSR_MBADADDR ] = val_to_write; +break ; +case CSR_DCSR : +printf ("DEBUG NOT SUPPORTED\n" ); +exit (1 ); +break ; +case CSR_DPC : +printf ("DEBUG NOT SUPPORTED\n" ); +exit (1 ); +break ; +case CSR_DSCRATCH : +printf ("DEBUG NOT SUPPORTED\n" ); +exit (1 ); +break ; + } }/*
@@ -92,6 +271,151 @@ inline void csr_write_helper(CPURISCVState *env, target_ulong val_to_write,*/ inline target_ulong csr_read_helper (CPURISCVState *env,target_ulong csrno) { +int csrno2 = (int )csrno; +#ifdef RISCV_DEBUG_PRINT +fprintf (stderr,"READ CSR 0x%x\n" , csrno2); +#endif + +switch (csrno2) { +case CSR_FFLAGS : +return env->csr[CSR_FFLAGS ]; +case CSR_FRM : +return env->csr[CSR_FRM ]; +case CSR_FCSR : +return env->csr[CSR_FFLAGS ] <<FSR_AEXC_SHIFT | + env->csr[CSR_FRM ] <<FSR_RD_SHIFT ; +case CSR_TIME : +case CSR_INSTRET : +case CSR_CYCLE : +if ((env->csr[CSR_MUCOUNTEREN ] >> (csrno2 & (63 ))) &1 ) { +return csr_read_helper (env, csrno2 + (CSR_MCYCLE -CSR_CYCLE )); + } +break ; +case CSR_STIME : +case CSR_SINSTRET : +case CSR_SCYCLE : +if ((env->csr[CSR_MSCOUNTEREN ] >> (csrno2 & (63 ))) &1 ) { +return csr_read_helper (env, csrno2 + (CSR_MCYCLE -CSR_SCYCLE )); + } +break ; +case CSR_MUCOUNTEREN : +return env->csr[CSR_MUCOUNTEREN ]; +case CSR_MSCOUNTEREN : +return env->csr[CSR_MSCOUNTEREN ]; +case CSR_MUCYCLE_DELTA : +return 0 ;/* as spike does */ +case CSR_MUTIME_DELTA : +return 0 ;/* as spike does */ +case CSR_MUINSTRET_DELTA : +return 0 ;/* as spike does */ +case CSR_MSCYCLE_DELTA : +return 0 ;/* as spike does */ +case CSR_MSTIME_DELTA : +return 0 ;/* as spike does */ +case CSR_MSINSTRET_DELTA : +return 0 ;/* as spike does */ +case CSR_MUCYCLE_DELTAH : +printf ("CSR 0x%x unsupported on RV64\n" , csrno2); +exit (1 ); +case CSR_MUTIME_DELTAH : +printf ("CSR 0x%x unsupported on RV64\n" , csrno2); +exit (1 ); +case CSR_MUINSTRET_DELTAH : +printf ("CSR 0x%x unsupported on RV64\n" , csrno2); +exit (1 ); +case CSR_MSCYCLE_DELTAH : +printf ("CSR 0x%x unsupported on RV64\n" , csrno2); +exit (1 ); +case CSR_MSTIME_DELTAH : +printf ("CSR 0x%x unsupported on RV64\n" , csrno2); +exit (1 ); +case CSR_MSINSTRET_DELTAH : +printf ("CSR 0x%x unsupported on RV64\n" , csrno2); +exit (1 ); +/* notice the lack of CSR_MTIME - this is handled by throwing an exception +and letting the handler read from the RTC */ +case CSR_MCYCLE : +/* Read instret here */ +break ; +case CSR_MINSTRET : +/* Read instret here */ +break ; +case CSR_MCYCLEH : +printf ("CSR 0x%x unsupported on RV64\n" , csrno2); +exit (1 ); +case CSR_MINSTRETH : +printf ("CSR 0x%x unsupported on RV64\n" , csrno2); +exit (1 ); +case CSR_SSTATUS : { +target_ulong mask =SSTATUS_SIE |SSTATUS_SPIE |SSTATUS_SPP + |SSTATUS_FS |SSTATUS_XS |SSTATUS_PUM ; +target_ulong sstatus = env->csr[CSR_MSTATUS ] & mask; +if ((sstatus &SSTATUS_FS ) ==SSTATUS_FS || + (sstatus &SSTATUS_XS ) ==SSTATUS_XS ) { + sstatus |=SSTATUS64_SD ; + } +return sstatus; + } +case CSR_SIP : +return env->csr[CSR_MIP ] & env->csr[CSR_MIDELEG ]; +case CSR_SIE : +return env->csr[CSR_MIE ] & env->csr[CSR_MIDELEG ]; +case CSR_SEPC : +return env->csr[CSR_SEPC ]; +case CSR_SBADADDR : +return env->csr[CSR_SBADADDR ]; +case CSR_STVEC : +return env->csr[CSR_STVEC ]; +case CSR_SCAUSE : +return env->csr[CSR_SCAUSE ]; +case CSR_SPTBR : +return env->csr[CSR_SPTBR ]; +case CSR_SSCRATCH : +return env->csr[CSR_SSCRATCH ]; +case CSR_MSTATUS : +return env->csr[CSR_MSTATUS ]; +case CSR_MIP : +return env->csr[CSR_MIP ]; +case CSR_MIE : +return env->csr[CSR_MIE ]; +case CSR_MEPC : +return env->csr[CSR_MEPC ]; +case CSR_MSCRATCH : +return env->csr[CSR_MSCRATCH ]; +case CSR_MCAUSE : +return env->csr[CSR_MCAUSE ]; +case CSR_MBADADDR : +return env->csr[CSR_MBADADDR ]; +case CSR_MISA : +return env->csr[CSR_MISA ]; +case CSR_MARCHID : +return 0 ;/* as spike does */ +case CSR_MIMPID : +return 0 ;/* as spike does */ +case CSR_MVENDORID : +return 0 ;/* as spike does */ +case CSR_MHARTID : +return 0 ; +case CSR_MTVEC : +return env->csr[CSR_MTVEC ]; +case CSR_MEDELEG : +return env->csr[CSR_MEDELEG ]; +case CSR_MIDELEG : +return env->csr[CSR_MIDELEG ]; +case CSR_TDRSELECT : +return 0 ;/* as spike does */ +case CSR_DCSR : +printf ("DEBUG NOT IMPLEMENTED\n" ); +exit (1 ); +case CSR_DPC : +printf ("DEBUG NOT IMPLEMENTED\n" ); +exit (1 ); +case CSR_DSCRATCH : +printf ("DEBUG NOT IMPLEMENTED\n" ); +exit (1 ); + } +/* used by e.g. MTIME read */ +helper_raise_exception (env,RISCV_EXCP_ILLEGAL_INST );return 0 ; }
Signature · 1 line
2.9.3
PATCH 14/18 target-riscv: softmmu/address translation support
In reply to Sagar Karandikar--- target-riscv/helper.c | 211 ++++++++++++++++++++++++++++++++++++++++++++++- target-riscv/op_helper.c | 29 +++++++ 2 files changed, 238 insertions(+), 2 deletions(-)
target-riscv/helper.c +209 -2
@@ -36,16 +36,223 @@ bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request) return false; } +/* get_physical_address - get the physical address for this virtual address +* +* Do a page table walk to obtain the physical address corresponding to a +* virtual address. Returns 0 if the translation was successful +* +* Adapted from Spike's mmu_t::translate and mmu_t::walk +* +*/ +static int get_physical_address (CPURISCVState *env,hwaddr *physical, +int *prot,target_ulong address, +MMUAccessType access_type,int mmu_idx) +{ +/* NOTE: the env->PC value visible here will not be +* correct, but the value visible to the exception handler +* (riscv_cpu_do_interrupt) is correct */ + + *prot =0 ; +CPUState *cs =CPU (riscv_env_get_cpu (env)); + +target_ulong mode = env->priv; +if (access_type !=MMU_INST_FETCH ) { +if (get_field (env->csr[CSR_MSTATUS ],MSTATUS_MPRV )) { + mode =get_field (env->csr[CSR_MSTATUS ],MSTATUS_MPP ); + } + } +if (get_field (env->csr[CSR_MSTATUS ],MSTATUS_VM ) ==VM_MBARE ) { + mode =PRV_M ; + } + +/* check to make sure that mmu_idx and mode that we get matches */ +if (unlikely (mode != mmu_idx)) { +fprintf (stderr,"MODE, mmu_idx mismatch\n" ); +exit (1 ); + } + +if (mode ==PRV_M ) { +target_ulong msb_mask = (2UL << (TARGET_LONG_BITS -1 )) -1 ; +/*0x7FFFFFFFFFFFFFFF; */ + *physical = address & msb_mask; + *prot =PAGE_READ |PAGE_WRITE |PAGE_EXEC ; +return TRANSLATE_SUCCESS ; + } + +target_ulong addr = address; +int supervisor = mode ==PRV_S ; +int pum =get_field (env->csr[CSR_MSTATUS ],MSTATUS_PUM ); +int mxr =get_field (env->csr[CSR_MSTATUS ],MSTATUS_MXR ); + +int levels, ptidxbits, ptesize; +switch (get_field (env->csr[CSR_MSTATUS ],MSTATUS_VM )) { +case VM_SV32 : + levels =2 ; + ptidxbits =10 ; + ptesize =4 ; +break ; +case VM_SV39 : + levels =3 ; + ptidxbits =9 ; + ptesize =8 ; +break ; +case VM_SV48 : + levels =4 ; + ptidxbits =9 ; + ptesize =8 ; +break ; +default : +printf ("unsupported MSTATUS_VM value\n" ); +exit (1 ); + } + +int va_bits =PGSHIFT + levels * ptidxbits; +target_ulong mask = (1L << (TARGET_LONG_BITS - (va_bits -1 ))) -1 ; +target_ulong masked_msbs = (addr >> (va_bits -1 )) & mask; +if (masked_msbs !=0 && masked_msbs != mask) { +return TRANSLATE_FAIL ; + } + +target_ulong base = env->csr[CSR_SPTBR ] <<PGSHIFT ; +int ptshift = (levels -1 ) * ptidxbits; +int i; +for (i =0 ; i < levels; i++, ptshift -= ptidxbits) { +target_ulong idx = (addr >> (PGSHIFT + ptshift)) & + ((1 << ptidxbits) -1 ); + +/* check that physical address of PTE is legal */ +target_ulong pte_addr = base + idx * ptesize; + +/* PTE must reside in memory */ +if (!(pte_addr >=DRAM_BASE && pte_addr < (DRAM_BASE + env->memsize))) { +printf ("PTE was not in DRAM region\n" ); +exit (1 ); +break ; + } + +target_ulong pte =ldq_phys (cs->as, pte_addr); +target_ulong ppn = pte >>PTE_PPN_SHIFT ; + +if (PTE_TABLE (pte)) {/* next level of page table */ + base = ppn <<PGSHIFT ; + }else if ((pte &PTE_U ) ? supervisor && pum : !supervisor) { +break ; + }else if (!(pte &PTE_V ) || (!(pte &PTE_R ) && (pte &PTE_W ))) { +break ; + }else if (access_type ==MMU_INST_FETCH ? !(pte &PTE_X ) : + access_type ==MMU_DATA_LOAD ? !(pte &PTE_R ) && + !(mxr && (pte &PTE_X )) : !((pte &PTE_R ) && (pte &PTE_W ))) { +break ; + }else { +/* set accessed and possibly dirty bits. +we only put it in the TLB if it has the right stuff */ +stq_phys (cs->as, pte_addr,ldq_phys (cs->as, pte_addr) |PTE_A | + ((access_type ==MMU_DATA_STORE ) *PTE_D )); + +/* for superpage mappings, make a fake leaf PTE for the TLB's +benefit. */ +target_ulong vpn = addr >>PGSHIFT ; + *physical = (ppn | (vpn & ((1L << ptshift) -1 ))) <<PGSHIFT ; + +/* we do not give all prots indicated by the PTE +* this is because future accesses need to do things like set the +* dirty bit on the PTE +* +* at this point, we assume that protection checks have occurred */ +if (supervisor) { +if ((pte &PTE_X ) && access_type ==MMU_INST_FETCH ) { + *prot |=PAGE_EXEC ; + }else if ((pte &PTE_W ) && access_type ==MMU_DATA_STORE ) { + *prot |=PAGE_WRITE ; + }else if ((pte &PTE_R ) && access_type ==MMU_DATA_LOAD ) { + *prot |=PAGE_READ ; + }else { +printf ("err in translation prots" ); +exit (1 ); + } + }else { +if ((pte &PTE_X ) && access_type ==MMU_INST_FETCH ) { + *prot |=PAGE_EXEC ; + }else if ((pte &PTE_W ) && access_type ==MMU_DATA_STORE ) { + *prot |=PAGE_WRITE ; + }else if ((pte &PTE_R ) && access_type ==MMU_DATA_LOAD ) { + *prot |=PAGE_READ ; + }else { +printf ("err in translation prots" ); +exit (1 ); + } + } +return TRANSLATE_SUCCESS ; + } + } +return TRANSLATE_FAIL ; +} +#endif + +static void raise_mmu_exception (CPURISCVState *env,target_ulong address, +MMUAccessType access_type) +{ +CPUState *cs =CPU (riscv_env_get_cpu (env)); +int exception =0 ; +if (access_type ==MMU_INST_FETCH ) {/* inst access */ + exception =RISCV_EXCP_INST_ACCESS_FAULT ; + env->badaddr = address; + }else if (access_type ==MMU_DATA_STORE ) {/* store access */ + exception =RISCV_EXCP_STORE_AMO_ACCESS_FAULT ; + env->badaddr = address; + }else if (access_type ==MMU_DATA_LOAD ) {/* load access */ + exception =RISCV_EXCP_LOAD_ACCESS_FAULT ; + env->badaddr = address; + }else { +fprintf (stderr,"FAIL: invalid access_type\n" ); +exit (1 ); + } + cs->exception_index = exception; +} + +#if !defined(CONFIG_USER_ONLY )hwaddr riscv_cpu_get_phys_page_debug (CPUState *cs,vaddr addr) { -return 0 ; +RISCVCPU *cpu =RISCV_CPU (cs); +hwaddr phys_addr; +int prot; +int mem_idx =cpu_mmu_index (&cpu->env, false); + +if (get_physical_address (&cpu->env, &phys_addr, &prot, addr,0 , mem_idx)) { +return -1 ; + } +return phys_addr; }#endif int riscv_cpu_handle_mmu_fault (CPUState *cs,vaddr address,MMUAccessType access_type,int mmu_idx) { -return 0 ; +RISCVCPU *cpu =RISCV_CPU (cs); +CPURISCVState *env = &cpu->env; +hwaddr physical; + physical =0 ;/* stop gcc complaining */ +int prot; +int ret =0 ; + +qemu_log_mask (CPU_LOG_MMU , +"%s pc " TARGET_FMT_lx" ad %" VADDR_PRIx" access_type %d mmu_idx \ +%d\n" , __func__, env->PC, address, access_type, mmu_idx); + + ret =get_physical_address (env, &physical, &prot, address, access_type, + mmu_idx); +qemu_log_mask (CPU_LOG_MMU , +"%s address=%" VADDR_PRIx" ret %d physical " TARGET_FMT_plx +" prot %d\n" , + __func__, address, ret, physical, prot); +if (ret ==TRANSLATE_SUCCESS ) { +tlb_set_page (cs, address &TARGET_PAGE_MASK , + physical &TARGET_PAGE_MASK , + prot, mmu_idx,TARGET_PAGE_SIZE ); + }else if (ret ==TRANSLATE_FAIL ) { +raise_mmu_exception (env, address, access_type); + } +return ret; }/*
target-riscv/op_helper.c +29 -0
@@ -533,16 +533,45 @@ void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr, MMUAccessType access_type, int mmu_idx, uintptr_t retaddr) { + RISCVCPU *cpu = RISCV_CPU(cs); +CPURISCVState *env = &cpu->env; +if (access_type ==MMU_INST_FETCH ) { +fprintf (stderr,"unaligned inst fetch not handled here. should not " +"trigger\n" ); +exit (1 ); + }else if (access_type ==MMU_DATA_STORE ) { + cs->exception_index =RISCV_EXCP_STORE_AMO_ADDR_MIS ; + env->badaddr = addr; + }else if (access_type ==MMU_DATA_LOAD ) { + cs->exception_index =RISCV_EXCP_LOAD_ADDR_MIS ; + env->badaddr = addr; + }else { +fprintf (stderr,"Invalid MMUAccessType\n" ); +exit (1 ); + } + do_raise_exception_err(env, cs->exception_index, retaddr); } +/* called by qemu's softmmu to fill the qemu tlb */ void tlb_fill (CPUState *cs,target_ulong addr,MMUAccessType access_type,int mmu_idx,uintptr_t retaddr) { +int ret; + ret =riscv_cpu_handle_mmu_fault (cs, addr, access_type, mmu_idx); +if (ret ==TRANSLATE_FAIL ) { +RISCVCPU *cpu =RISCV_CPU (cs); +CPURISCVState *env = &cpu->env; +do_raise_exception_err (env, cs->exception_index, retaddr); + } }void riscv_cpu_unassigned_access (CPUState *cs,hwaddr addr,bool is_write,bool is_exec,int unused,unsigned size) { +printf ("unassigned address not implemented for riscv\n" ); +printf ("are you trying to fetch instructions from an MMIO page?\n" ); +printf ("unassigned Address: %016lX\n" , addr); +exit (1 ); }#endif /* !CONFIG_USER_ONLY */
Signature · 1 line
2.9.3
Re: [Qemu-devel] [PATCH 14/18] target-riscv: softmmu/address translation support
target-riscv/op_helper.c void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr, · line 574
Quoted 4 lines · Sagar Karandikar
target-riscv/op_helper.c +4
-0+printf ("unassigned address not implemented for riscv\n" ); +printf ("are you trying to fetch instructions from an MMIO page?\n" ); +printf ("unassigned Address: %016lX\n" , addr); +exit (1 );
All these printf's (and fprintfs above) are going to have to go before this gets accepted. Most of them should simply become qemu_log's.
r~
PATCH 15/18 target-riscv: Interrupt Handling
In reply to Sagar Karandikar--- target-riscv/helper.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+)
target-riscv/helper.c +154 -0
@@ -33,6 +33,16 @@bool riscv_cpu_exec_interrupt (CPUState *cs,int interrupt_request) { +if (interrupt_request &CPU_INTERRUPT_HARD ) { +RISCVCPU *cpu =RISCV_CPU (cs); +CPURISCVState *env = &cpu->env; +int interruptno =cpu_riscv_hw_interrupts_pending (env); +if (interruptno +1 ) { + cs->exception_index =0x70000000U | interruptno; +riscv_cpu_do_interrupt (cs); +return true; + } + }return false; }
@@ -255,6 +265,40 @@ int riscv_cpu_handle_mmu_fault(CPUState *cs, vaddr address,return ret; } +#ifdef RISCV_DEBUG_INTERRUPT +static const char *const riscv_excp_names[12 ] = { +"misaligned fetch" , +"fault fetch" , +"illegal instruction" , +"Breakpoint" , +"misaligned load" , +"fault load" , +"misaligned store" , +"fault store" , +"user_ecall" , +"supervisor_ecall" , +"hypervisor_ecall" , +"machine_ecall" , +}; + +static const char *const riscv_interrupt_names[14 ] = { +"" , +"S Soft interrupt" , +"H Soft interrupt" , +"M Soft interrupt" , +"" , +"S Timer interrupt" , +"H Timer interrupt" , +"M Timer interrupt" , +"" , +"S Ext interrupt" , +"H Ext interrupt" , +"M Ext interrupt" , +"COP interrupt" , +"Host interrupt" +}; +#endif /* RISCV_DEBUG_INTERRUPT */ +/* * Handle Traps *
@@ -263,4 +307,114 @@ int riscv_cpu_handle_mmu_fault(CPUState *cs, vaddr address,*/ void riscv_cpu_do_interrupt (CPUState *cs) { +RISCVCPU *cpu =RISCV_CPU (cs); +CPURISCVState *env = &cpu->env; + +#ifdef RISCV_DEBUG_INTERRUPT +if (cs->exception_index &0x70000000 ) { +fprintf (stderr,"core 0: exception trap_%s, epc 0x" TARGET_FMT_lx"\n" + , riscv_interrupt_names[cs->exception_index &0x0fffffff ], + env->PC); + }else { +fprintf (stderr,"core 0: exception trap_%s, epc 0x" TARGET_FMT_lx"\n" + , riscv_excp_names[cs->exception_index], env->PC); + } +#endif + +if (cs->exception_index ==RISCV_EXCP_BREAKPOINT ) { +fprintf (stderr,"debug mode not implemented\n" ); + } + +/* skip dcsr cause check */ + +target_ulong fixed_cause =0 ; +if (cs->exception_index & (0x70000000 )) { +/* hacky for now. the MSB (bit 63) indicates interrupt but cs->exception +index is only 32 bits wide */ + fixed_cause = cs->exception_index &0x0FFFFFFF ; + fixed_cause |= (1L <<63 ); + }else { +/* fixup User ECALL -> correct priv ECALL */ +if (cs->exception_index ==RISCV_EXCP_U_ECALL ) { +switch (env->priv) { +case PRV_U : + fixed_cause =RISCV_EXCP_U_ECALL ; +break ; +case PRV_S : + fixed_cause =RISCV_EXCP_S_ECALL ; +break ; +case PRV_H : + fixed_cause =RISCV_EXCP_H_ECALL ; +break ; +case PRV_M : + fixed_cause =RISCV_EXCP_M_ECALL ; +break ; + } + }else { + fixed_cause = cs->exception_index; + } + } + +target_ulong backup_epc = env->PC; + +target_ulong bit = fixed_cause; +target_ulong deleg = env->csr[CSR_MEDELEG ]; + +int hasbadaddr = + (fixed_cause ==RISCV_EXCP_INST_ADDR_MIS ) || + (fixed_cause ==RISCV_EXCP_INST_ACCESS_FAULT ) || + (fixed_cause ==RISCV_EXCP_LOAD_ADDR_MIS ) || + (fixed_cause ==RISCV_EXCP_STORE_AMO_ADDR_MIS ) || + (fixed_cause ==RISCV_EXCP_LOAD_ACCESS_FAULT ) || + (fixed_cause ==RISCV_EXCP_STORE_AMO_ACCESS_FAULT ); + +if (bit & ((target_ulong )1 << (TARGET_LONG_BITS -1 ))) { + deleg = env->csr[CSR_MIDELEG ], bit &= ~(1L << (TARGET_LONG_BITS -1 )); + } + +if (env->priv <=PRV_S && bit <64 && ((deleg >> bit) &1 )) { +/* handle the trap in S-mode */ +/* No need to check STVEC for misaligned - lower 2 bits cannot be set */ + env->PC = env->csr[CSR_STVEC ]; + env->csr[CSR_SCAUSE ] = fixed_cause; + env->csr[CSR_SEPC ] = backup_epc; + +if (hasbadaddr) { +#ifdef RISCV_DEBUG_INTERRUPT +fprintf (stderr,"core 0: badaddr 0x" TARGET_FMT_lx"\n" , + env->badaddr); +#endif + env->csr[CSR_SBADADDR ] = env->badaddr; + } + +target_ulong s = env->csr[CSR_MSTATUS ]; + s =set_field (s,MSTATUS_SPIE ,get_field (s,MSTATUS_UIE << env->priv)); + s =set_field (s,MSTATUS_SPP , env->priv); + s =set_field (s,MSTATUS_SIE ,0 ); +csr_write_helper (env, s,CSR_MSTATUS ); +set_privilege (env,PRV_S ); + }else { +/* No need to check MTVEC for misaligned - lower 2 bits cannot be set */ + env->PC = env->csr[CSR_MTVEC ]; + env->csr[CSR_MEPC ] = backup_epc; + env->csr[CSR_MCAUSE ] = fixed_cause; + +if (hasbadaddr) { +#ifdef RISCV_DEBUG_INTERRUPT +fprintf (stderr,"core 0: badaddr 0x" TARGET_FMT_lx"\n" , + env->badaddr); +#endif + env->csr[CSR_MBADADDR ] = env->badaddr; + } + +target_ulong s = env->csr[CSR_MSTATUS ]; + s =set_field (s,MSTATUS_MPIE ,get_field (s,MSTATUS_UIE << env->priv)); + s =set_field (s,MSTATUS_MPP , env->priv); + s =set_field (s,MSTATUS_MIE ,0 ); +csr_write_helper (env, s,CSR_MSTATUS ); +set_privilege (env,PRV_M ); + } +/* TODO yield load reservation */ + + cs->exception_index =EXCP_NONE ;/* mark handled to qemu */ }
Signature · 1 line
2.9.3
Re: [Qemu-devel] [PATCH 15/18] target-riscv: Interrupt Handling
Quoted 1 line · Sagar Karandikar
+ if (interruptno + 1) {
This is a very odd way to write interruptno != -1. And did you really mean interruptno >= 0?
r~
PATCH 16/18 target-riscv: Timer Support
In reply to Sagar Karandikar--- hw/riscv/Makefile.objs | 1 + hw/riscv/cpudevs.h | 17 +++ hw/riscv/riscv_rtc.c | 230 ++++++++++++++++++++++++++++++++++ include/hw/riscv/riscv_rtc.h | 25 ++++ include/hw/riscv/riscv_rtc_internal.h | 3 + target-riscv/op_helper.c | 4 +- 6 files changed, 278 insertions(+), 2 deletions(-) create mode 100644 hw/riscv/Makefile.objs create mode 100644 hw/riscv/cpudevs.h create mode 100644 hw/riscv/riscv_rtc.c create mode 100644 include/hw/riscv/riscv_rtc.h create mode 100644 include/hw/riscv/riscv_rtc_internal.h
hw/riscv/Makefile.objs new file +1 -0
@@ -0,0 +1 @@ +obj-y += riscv_rtc.o
hw/riscv/cpudevs.h new file +17 -0
@@ -0,0 +1,17 @@ +#ifndef HW_RISCV_CPUDEVS_H +#define HW_RISCV_CPUDEVS_H + +#include "target-riscv/cpu.h" + +/* Definitions for RISCV CPU internal devices. */ + +/* riscv_board.c */ +uint64_t identity_translate (void *opaque,uint64_t addr); + +/* riscv_int.c */ +void cpu_riscv_irq_init_cpu (CPURISCVState *env); + +/* cputimer.c */ +void cpu_riscv_clock_init (CPURISCVState *); + +#endif
hw/riscv/riscv_rtc.c new file +230 -0
230 lines not on this page · raw message
include/hw/riscv/riscv_rtc.h new file +25 -0
@@ -0,0 +1,25 @@ +#ifndef HW_RISCV_TIMER_H +#define HW_RISCV_TIMER_H 1 + +#include "hw/hw.h" +#include "sysemu/sysemu.h" +#include "exec/memory.h" +#include "target-riscv/cpu.h" + +typedef struct TIMERState TIMERState ; + +struct TIMERState { +CPURISCVState *env; +MemoryRegion io; +uint32_t timecmp_lower; +uint64_t temp_rtc_val; +}; + +extern const VMStateDescription vmstate_timer_rv; +extern const MemoryRegionOps timer_io_ops; + +/* legacy pre qom */ +TIMERState *timer_mm_init (MemoryRegion *address_space,hwaddr base, +CPURISCVState *env); + +#endif
include/hw/riscv/riscv_rtc_internal.h new file +3 -0
@@ -0,0 +1,3 @@ +uint64_t rtc_read (CPURISCVState *env); +uint64_t instret_read (CPURISCVState *env); +void write_timecmp (CPURISCVState *env,uint64_t value);
target-riscv/op_helper.c +2 -2
@@ -335,10 +335,10 @@ inline target_ulong csr_read_helper(CPURISCVState *env, target_ulong csrno)/* notice the lack of CSR_MTIME - this is handled by throwing an exception and letting the handler read from the RTC */ case CSR_MCYCLE : -/* Read instret here */ +return cpu_riscv_read_instret (env);break ;case CSR_MINSTRET : -/* Read instret here */ +return cpu_riscv_read_instret (env);break ;case CSR_MCYCLEH :printf ("CSR 0x%x unsupported on RV64\n" , csrno2);
Signature · 1 line
2.9.3
PATCH 17/18 target-riscv: Add support for Host-Target Interface (HTIF) Devices
In reply to Sagar KarandikarHTIF devices are currently used for the console and signaling test completion for tests in riscv-tests. These are not part of any RISC-V standard and will be phased out once better device support is available.
--- hw/riscv/Makefile.objs | 2 + hw/riscv/htif/elf_symb.c | 286 +++++++++++++++++++++++++++++ hw/riscv/htif/elf_symb.h | 80 ++++++++ hw/riscv/htif/htif.c | 423 +++++++++++++++++++++++++++++++++++++++++++ include/hw/riscv/htif/htif.h | 61 +++++++ 5 files changed, 852 insertions(+) create mode 100644 hw/riscv/htif/elf_symb.c create mode 100644 hw/riscv/htif/elf_symb.h create mode 100644 hw/riscv/htif/htif.c create mode 100644 include/hw/riscv/htif/htif.h
hw/riscv/Makefile.objs +2 -0
@@ -1 +1,3 @@ obj-y += riscv_rtc.o +obj-y += htif/elf_symb.o +obj-y += htif/htif.o
hw/riscv/htif/elf_symb.c new file +286 -0
286 lines not on this page · raw message
hw/riscv/htif/elf_symb.h new file +80 -0
80 lines not on this page · raw message
hw/riscv/htif/htif.c new file +423 -0
423 lines not on this page · raw message
include/hw/riscv/htif/htif.h new file +61 -0
61 lines not on this page · raw message
Signature · 1 line
2.9.3
PATCH 18/18 target-riscv: Add generic test board, activate target
In reply to Sagar Karandikar--- configure | 6 + default-configs/riscv32-softmmu.mak | 38 ++++++ default-configs/riscv64-softmmu.mak | 38 ++++++ hw/riscv/Makefile.objs | 2 + hw/riscv/riscv_board.c | 264 ++++++++++++++++++++++++++++++++++++ hw/riscv/riscv_int.c | 67 +++++++++ 6 files changed, 415 insertions(+) create mode 100644 default-configs/riscv32-softmmu.mak create mode 100644 default-configs/riscv64-softmmu.mak create mode 100644 hw/riscv/riscv_board.c create mode 100644 hw/riscv/riscv_int.c
configure +6 -0
@@ -5667,6 +5667,12 @@ case "$target_name" in TARGET_BASE_ARCH=mips echo "TARGET_ABI_MIPSN64=y" >> $config_target_mak ;; + riscv32) + TARGET_BASE_ARCH=riscv + ;; + riscv64) + TARGET_BASE_ARCH=riscv + ;; moxie) ;; or32)
default-configs/riscv32-softmmu.mak new file +38 -0
@@ -0,0 +1,38 @@ +# Default configuration for riscv-softmmu + +#include pci.mak +#include sound.mak +#include usb.mak +#CONFIG_ESP=y +#CONFIG_VGA=y +#CONFIG_VGA_PCI=y +#CONFIG_VGA_ISA=y +#CONFIG_VGA_ISA_MM=y +#CONFIG_VGA_CIRRUS=y +#CONFIG_VMWARE_VGA=y +CONFIG_SERIAL=y +#CONFIG_PARALLEL=y +#CONFIG_I8254=y +#CONFIG_PCSPK=y +#CONFIG_PCKBD=y +#CONFIG_FDC=y +#CONFIG_ACPI=y +#CONFIG_APM=y +#CONFIG_I8257=y +#CONFIG_PIIX4=y +#CONFIG_IDE_ISA=y +#CONFIG_IDE_PIIX=y +#CONFIG_NE2000_ISA=y +#CONFIG_RC4030=y +#CONFIG_DP8393X=y +#CONFIG_DS1225Y=y +#CONFIG_MIPSNET=y +#CONFIG_PFLASH_CFI01=y +#CONFIG_G364FB=y +CONFIG_I8259=y +#CONFIG_JAZZ_LED=y +#CONFIG_MC146818RTC=y +#CONFIG_VT82C686=y +#CONFIG_ISA_TESTDEV=y +#CONFIG_EMPTY_SLOT=y +CONFIG_VIRTIO=y
default-configs/riscv64-softmmu.mak new file +38 -0
@@ -0,0 +1,38 @@ +# Default configuration for riscv-softmmu + +#include pci.mak +#include sound.mak +#include usb.mak +#CONFIG_ESP=y +#CONFIG_VGA=y +#CONFIG_VGA_PCI=y +#CONFIG_VGA_ISA=y +#CONFIG_VGA_ISA_MM=y +#CONFIG_VGA_CIRRUS=y +#CONFIG_VMWARE_VGA=y +CONFIG_SERIAL=y +#CONFIG_PARALLEL=y +#CONFIG_I8254=y +#CONFIG_PCSPK=y +#CONFIG_PCKBD=y +#CONFIG_FDC=y +#CONFIG_ACPI=y +#CONFIG_APM=y +#CONFIG_I8257=y +#CONFIG_PIIX4=y +#CONFIG_IDE_ISA=y +#CONFIG_IDE_PIIX=y +#CONFIG_NE2000_ISA=y +#CONFIG_RC4030=y +#CONFIG_DP8393X=y +#CONFIG_DS1225Y=y +#CONFIG_MIPSNET=y +#CONFIG_PFLASH_CFI01=y +#CONFIG_G364FB=y +CONFIG_I8259=y +#CONFIG_JAZZ_LED=y +#CONFIG_MC146818RTC=y +#CONFIG_VT82C686=y +#CONFIG_ISA_TESTDEV=y +#CONFIG_EMPTY_SLOT=y +CONFIG_VIRTIO=y
hw/riscv/Makefile.objs +2 -0
@@ -1,3 +1,5 @@ obj-y += riscv_rtc.o +obj-y += riscv_int.o obj-y += htif/elf_symb.o obj-y += htif/htif.o +obj-y += riscv_board.o
hw/riscv/riscv_board.c new file +264 -0
264 lines not on this page · raw message
hw/riscv/riscv_int.c new file +67 -0
67 lines not on this page · raw message
Signature · 1 line
2.9.3
Quoted 1 line · Sagar Karandikar
-cpu-qom.hmerged intocpu.h
Please follow the model of other targets. RISCVCPUClass and the RISCVCPU typedef should be in cpu-qom.h.
Paolo
Quoted 7 lines · Paolo Bonzini
Quoted 1 line · Sagar Karandikar
-cpu-qom.hmerged intocpu.hPlease 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~
Am 26.09.2016 um 18:17 schrieb Richard Henderson:
Quoted 9 lines · Paolo Bonzini
Quoted 5 lines · Sagar Karandikar
Quoted 1 line
-cpu-qom.hmerged intocpu.hPlease 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.his sort of a legacy header, and that new targets shouldn't use it.
Yes, a concept that didn't quite work out, sadly. Just cpu.h is fine.
Andreas
Signature · 3 lines
SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany GF: Felix Imendörffer, Jane Smithard, Graham Norton HRB 21284 (AG Nürnberg)
Quoted 5 lines · Andreas Färber
Am 26.09.2016 um 18:17 schrieb Richard Henderson:
Quoted 4 lines · Paolo Bonzini
Quoted 3 lines · Sagar Karandikar
Quoted 1 line
-cpu-qom.hmerged intocpu.h
Quoted 7 lines
Quoted 5 lines
Quoted 2 lines
Please follow the model of other targets. RISCVCPUClass and the RISCVCPU typedef should be in
cpu-qom.h.I thought we had this discussion before, and
cpu-qom.his 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.his fine.
Hmm, maybe since 2.7.0 it started working out better? :)
The point of cpu-qom.h is to allow using the RISCVCPU symbol in target- specific header files, without forcing all files including said header to be compiled per-target. See for example
commit 4da6f8d954429c0cd1471d25cb9dbe909607374e
Author: Paolo Bonzini <[email protected]>
Date: Tue Mar 15 13:49:25 2016 +0100
target-i386: make cpu-qom.h not target specific
Make X86CPU an opaque type within cpu-qom.h, and move all definitions of private methods, as well as all type definitions that require knowledge of the layout to cpu.h. This helps making files independent of NEED_CPU_H if they only need to pass around CPU pointers.
You cannot include the definition of struct FooCPU in cpu-qom.h, because
it embeds "CPUFooState env;" and CPUFooState uses target_long. Still it's
a nice improvement, for example it's now possible to compile device models common to arm-softmmu and aarch64-softmmu (or sh4/sh4eb, etc.) just once.
Paolo
Am 26.09.2016 um 18:24 schrieb Paolo Bonzini:
Quoted 8 lines · Andreas Färber
Quoted 7 lines
Am 26.09.2016 um 18:17 schrieb Richard Henderson:
Quoted 6 lines · Paolo Bonzini
Quoted 5 lines · Sagar Karandikar
Quoted 1 line
-cpu-qom.hmerged intocpu.hPlease follow the model of other targets. RISCVCPUClass and the RISCVCPU typedef should be in
cpu-qom.h.
After discussion with Paolo, the key word here is typedef. It doesn't make sense to have the struct RISCVCPU in cpu-qom.h (the old approach) but it makes perfect sense to have struct RISCVCPUClass and typedef RISCVCPU in a separate cpu-qom.h.
Sorry for misunderstanding,
Andreas
Signature · 3 lines
SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany GF: Felix Imendörffer, Jane Smithard, Graham Norton HRB 21284 (AG Nürnberg)
Quoted 7 lines · Andreas Färber
Am 26.09.2016 um 18:24 schrieb Paolo Bonzini:
Quoted 6 lines · Andreas Färber
Quoted 5 lines
Am 26.09.2016 um 18:17 schrieb Richard Henderson:
Quoted 4 lines · Paolo Bonzini
Quoted 3 lines · Sagar Karandikar
Quoted 1 line
-cpu-qom.hmerged intocpu.h
Quoted 7 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Please follow the model of other targets. RISCVCPUClass and the RISCVCPU typedef should be in
cpu-qom.h.After discussion with Paolo, the key word here is typedef. It doesn't make sense to have the struct RISCVCPU in
cpu-qom.h(the old approach) but it makes perfect sense to have struct RISCVCPUClass and typedef RISCVCPU in a separatecpu-qom.h.
Thanks Andreas, and sorry Sagar for the back-and-forth!
Paolo