* [PATCH v3 00/19] Add LoongArch linux-user emulation support
@ 2021-08-27 7:14 Song Gao
2021-08-27 7:14 ` [PATCH v3 01/19] target/loongarch: Add README Song Gao
` (18 more replies)
0 siblings, 19 replies; 22+ messages in thread
From: Song Gao @ 2021-08-27 7:14 UTC (permalink / raw)
To: qemu-devel
Cc: peter.maydell, thuth, chenhuacai, richard.henderson, f4bug,
maobibo, laurent, yangxiaojuan, alistair.francis, pbonzini,
alex.bennee
Hi,
This series only adds linux-user emulation support for LoongArch.
So there is no introduction of system in docs/system directory,
We'll add that in a future series.
Changes for v3:
* split trans.inc.c.
* remove csr registers.
* delete patchs 2, 4, 5.
* follow Richard's code review comments [1].
* follow Richard's riscv patches [2].
[1]: https://patchew.org/QEMU/1626861198-6133-1-git-send-email-gaosong@loongson.cn/
[2]: https://patchew.org/QEMU/20210823195529.560295-1-richard.henderson@linaro.org/
Changes for v2:
* Patch 1, remove unnecessary introduction;
* Patch 3, follow the ARM/AVR pattern to add new CPU features;
* Patch 6, remove decode_lsx();
* Patches 7-18, delete opcode definition, modify translation function;
* Patches 20-22, split V1 patch20 to V2 patch20-22.
V2: https://patchew.org/QEMU/1626861198-6133-1-git-send-email-gaosong@loongson.cn/
V1: https://patchew.org/QEMU/1624881885-31692-1-git-send-email-gaosong@loongson.cn/
Please review!
thnaks.
Song Gao (19):
target/loongarch: Add README
target/loongarch: Add core definition
target/loongarch: Add main translation routines
target/loongarch: Add fixed point arithmetic instruction translation
target/loongarch: Add fixed point shift instruction translation
target/loongarch: Add fixed point bit instruction translation
target/loongarch: Add fixed point load/store instruction translation
target/loongarch: Add fixed point atomic instruction translation
target/loongarch: Add fixed point extra instruction translation
target/loongarch: Add floating point arithmetic instruction
translation
target/loongarch: Add floating point comparison instruction
translation
target/loongarch: Add floating point conversion instruction
translation
target/loongarch: Add floating point move instruction translation
target/loongarch: Add floating point load/store instruction
translation
target/loongarch: Add branch instruction translation
target/loongarch: Add disassembler
LoongArch Linux User Emulation
default-configs: Add loongarch linux-user support
target/loongarch: Add target build suport
MAINTAINERS | 6 +
configs/targets/loongarch64-linux-user.mak | 3 +
disas/loongarch.c | 2511 +++++++++++++++++++++++++++
disas/meson.build | 1 +
include/disas/dis-asm.h | 2 +
include/elf.h | 2 +
linux-user/elfload.c | 58 +
linux-user/loongarch64/cpu_loop.c | 108 ++
linux-user/loongarch64/signal.c | 178 ++
linux-user/loongarch64/sockbits.h | 1 +
linux-user/loongarch64/syscall_nr.h | 307 ++++
linux-user/loongarch64/target_cpu.h | 36 +
linux-user/loongarch64/target_elf.h | 14 +
linux-user/loongarch64/target_errno_defs.h | 7 +
linux-user/loongarch64/target_fcntl.h | 12 +
linux-user/loongarch64/target_signal.h | 28 +
linux-user/loongarch64/target_structs.h | 49 +
linux-user/loongarch64/target_syscall.h | 46 +
linux-user/loongarch64/termbits.h | 229 +++
linux-user/syscall_defs.h | 10 +-
meson.build | 1 +
target/loongarch/README | 5 +
target/loongarch/cpu-param.h | 19 +
target/loongarch/cpu.c | 286 +++
target/loongarch/cpu.h | 145 ++
target/loongarch/fpu_helper.c | 947 ++++++++++
target/loongarch/helper.h | 102 ++
target/loongarch/insn_trans/trans_arith.c | 334 ++++
target/loongarch/insn_trans/trans_atomic.c | 132 ++
target/loongarch/insn_trans/trans_bit.c | 297 ++++
target/loongarch/insn_trans/trans_branch.c | 84 +
target/loongarch/insn_trans/trans_extra.c | 88 +
target/loongarch/insn_trans/trans_farith.c | 79 +
target/loongarch/insn_trans/trans_fcmp.c | 279 +++
target/loongarch/insn_trans/trans_fcnv.c | 36 +
target/loongarch/insn_trans/trans_fmemory.c | 143 ++
target/loongarch/insn_trans/trans_fmov.c | 159 ++
target/loongarch/insn_trans/trans_memory.c | 263 +++
target/loongarch/insn_trans/trans_shift.c | 154 ++
target/loongarch/insns.decode | 480 +++++
target/loongarch/internals.h | 24 +
target/loongarch/meson.build | 18 +
target/loongarch/op_helper.c | 85 +
target/loongarch/translate.c | 309 ++++
target/loongarch/translate.h | 54 +
target/meson.build | 1 +
46 files changed, 8128 insertions(+), 4 deletions(-)
create mode 100644 configs/targets/loongarch64-linux-user.mak
create mode 100644 disas/loongarch.c
create mode 100644 linux-user/loongarch64/cpu_loop.c
create mode 100644 linux-user/loongarch64/signal.c
create mode 100644 linux-user/loongarch64/sockbits.h
create mode 100644 linux-user/loongarch64/syscall_nr.h
create mode 100644 linux-user/loongarch64/target_cpu.h
create mode 100644 linux-user/loongarch64/target_elf.h
create mode 100644 linux-user/loongarch64/target_errno_defs.h
create mode 100644 linux-user/loongarch64/target_fcntl.h
create mode 100644 linux-user/loongarch64/target_signal.h
create mode 100644 linux-user/loongarch64/target_structs.h
create mode 100644 linux-user/loongarch64/target_syscall.h
create mode 100644 linux-user/loongarch64/termbits.h
create mode 100644 target/loongarch/README
create mode 100644 target/loongarch/cpu-param.h
create mode 100644 target/loongarch/cpu.c
create mode 100644 target/loongarch/cpu.h
create mode 100644 target/loongarch/fpu_helper.c
create mode 100644 target/loongarch/helper.h
create mode 100644 target/loongarch/insn_trans/trans_arith.c
create mode 100644 target/loongarch/insn_trans/trans_atomic.c
create mode 100644 target/loongarch/insn_trans/trans_bit.c
create mode 100644 target/loongarch/insn_trans/trans_branch.c
create mode 100644 target/loongarch/insn_trans/trans_extra.c
create mode 100644 target/loongarch/insn_trans/trans_farith.c
create mode 100644 target/loongarch/insn_trans/trans_fcmp.c
create mode 100644 target/loongarch/insn_trans/trans_fcnv.c
create mode 100644 target/loongarch/insn_trans/trans_fmemory.c
create mode 100644 target/loongarch/insn_trans/trans_fmov.c
create mode 100644 target/loongarch/insn_trans/trans_memory.c
create mode 100644 target/loongarch/insn_trans/trans_shift.c
create mode 100644 target/loongarch/insns.decode
create mode 100644 target/loongarch/internals.h
create mode 100644 target/loongarch/meson.build
create mode 100644 target/loongarch/op_helper.c
create mode 100644 target/loongarch/translate.c
create mode 100644 target/loongarch/translate.h
--
1.8.3.1
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v3 01/19] target/loongarch: Add README
2021-08-27 7:14 [PATCH v3 00/19] Add LoongArch linux-user emulation support Song Gao
@ 2021-08-27 7:14 ` Song Gao
2021-08-27 15:06 ` Peter Xu
2021-08-27 7:14 ` [PATCH v3 02/19] target/loongarch: Add core definition Song Gao
` (17 subsequent siblings)
18 siblings, 1 reply; 22+ messages in thread
From: Song Gao @ 2021-08-27 7:14 UTC (permalink / raw)
To: qemu-devel
Cc: peter.maydell, thuth, chenhuacai, richard.henderson, f4bug,
maobibo, laurent, yangxiaojuan, alistair.francis, pbonzini,
alex.bennee
This patch give an introduction to the LoongArch target.
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
MAINTAINERS | 5 +++++
target/loongarch/README | 5 +++++
2 files changed, 10 insertions(+)
create mode 100644 target/loongarch/README
diff --git a/MAINTAINERS b/MAINTAINERS
index dffcb65..396f970 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -210,6 +210,11 @@ F: disas/hppa.c
F: hw/net/*i82596*
F: include/hw/net/lasi_82596.h
+LoongArch TCG CPUS
+M: Song Gao <gaosong@loongson.cn>
+S: Maintained
+F: target/loongarch/
+
M68K TCG CPUs
M: Laurent Vivier <laurent@vivier.eu>
S: Maintained
diff --git a/target/loongarch/README b/target/loongarch/README
new file mode 100644
index 0000000..fe7a36f
--- /dev/null
+++ b/target/loongarch/README
@@ -0,0 +1,5 @@
+LoongArch is the general processor architecture of Loongson.
+
+The following versions of the LoongArch core are supported
+ core: 3A5000
+ https://github.com/loongson/LoongArch-Documentation/releases/download/LoongArch-Vol1-v3/LoongArch-Vol1-v1.00-EN.pdf
--
1.8.3.1
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v3 02/19] target/loongarch: Add core definition
2021-08-27 7:14 [PATCH v3 00/19] Add LoongArch linux-user emulation support Song Gao
2021-08-27 7:14 ` [PATCH v3 01/19] target/loongarch: Add README Song Gao
@ 2021-08-27 7:14 ` Song Gao
2021-08-27 7:14 ` [PATCH v3 03/19] target/loongarch: Add main translation routines Song Gao
` (16 subsequent siblings)
18 siblings, 0 replies; 22+ messages in thread
From: Song Gao @ 2021-08-27 7:14 UTC (permalink / raw)
To: qemu-devel
Cc: peter.maydell, thuth, chenhuacai, richard.henderson, f4bug,
maobibo, laurent, yangxiaojuan, alistair.francis, pbonzini,
alex.bennee
This patch add target state header, target definitions
and initialization routines.
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
target/loongarch/cpu-param.h | 19 +++
target/loongarch/cpu.c | 285 +++++++++++++++++++++++++++++++++++++++++++
target/loongarch/cpu.h | 145 ++++++++++++++++++++++
target/loongarch/internals.h | 23 ++++
4 files changed, 472 insertions(+)
create mode 100644 target/loongarch/cpu-param.h
create mode 100644 target/loongarch/cpu.c
create mode 100644 target/loongarch/cpu.h
create mode 100644 target/loongarch/internals.h
diff --git a/target/loongarch/cpu-param.h b/target/loongarch/cpu-param.h
new file mode 100644
index 0000000..83f9624
--- /dev/null
+++ b/target/loongarch/cpu-param.h
@@ -0,0 +1,19 @@
+/*
+ * LoongArch cpu parameters for qemu.
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#ifndef LOONGARCH_CPU_PARAM_H
+#define LOONGARCH_CPU_PARAM_H 1
+
+#define TARGET_LONG_BITS 64
+#define TARGET_PHYS_ADDR_SPACE_BITS 48
+#define TARGET_VIRT_ADDR_SPACE_BITS 48
+
+#define TARGET_PAGE_BITS 14
+#define NB_MMU_MODES 4
+
+#endif
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
new file mode 100644
index 0000000..b89bf51
--- /dev/null
+++ b/target/loongarch/cpu.c
@@ -0,0 +1,285 @@
+/*
+ * QEMU LoongArch CPU
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/qemu-print.h"
+#include "qapi/error.h"
+#include "qemu/module.h"
+#include "sysemu/qtest.h"
+#include "exec/exec-all.h"
+#include "qapi/qapi-commands-machine-target.h"
+#include "cpu.h"
+#include "internals.h"
+#include "fpu/softfloat-helpers.h"
+
+const char * const regnames[] = {
+ "r0", "ra", "tp", "sp", "a0", "a1", "a2", "a3",
+ "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
+ "t4", "t5", "t6", "t7", "t8", "x0", "fp", "s0",
+ "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8",
+};
+
+const char * const fregnames[] = {
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
+ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
+ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
+ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
+};
+
+static const char * const excp_names[EXCP_LAST + 1] = {
+ [EXCP_ADE] = "Address error",
+ [EXCP_SYSCALL] = "Syscall",
+ [EXCP_BREAK] = "Break",
+ [EXCP_INE] = "Inst. Not Exist",
+ [EXCP_FPE] = "Floating Point Exception",
+};
+
+const char *loongarch_exception_name(int32_t exception)
+{
+ if (exception < 0 || exception > EXCP_LAST) {
+ return "unknown";
+ }
+ return excp_names[exception];
+}
+
+void QEMU_NORETURN do_raise_exception(CPULoongArchState *env,
+ uint32_t exception,
+ uintptr_t pc)
+{
+ CPUState *cs = env_cpu(env);
+
+ qemu_log_mask(CPU_LOG_INT, "%s: %d (%s)\n",
+ __func__,
+ exception,
+ loongarch_exception_name(exception));
+ cs->exception_index = exception;
+
+ cpu_loop_exit_restore(cs, pc);
+}
+
+static void loongarch_cpu_set_pc(CPUState *cs, vaddr value)
+{
+ LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+ CPULoongArchState *env = &cpu->env;
+
+ env->pc = value;
+}
+
+#ifdef CONFIG_TCG
+static void loongarch_cpu_synchronize_from_tb(CPUState *cs,
+ const TranslationBlock *tb)
+{
+ LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+ CPULoongArchState *env = &cpu->env;
+
+ env->pc = tb->pc;
+}
+#endif /* CONFIG_TCG */
+
+static bool loongarch_cpu_has_work(CPUState *cs)
+{
+ return true;
+}
+
+static void set_loongarch_cpucfg(CPULoongArchState *env)
+{
+ int i;
+
+ for (i = 0; i < 15; i++) {
+ env->cpucfg[i] = 0x0;
+ }
+ env->cpucfg[0] = 0x14c010;
+ env->cpucfg[1] = 0x3f2f2fe;
+ env->cpucfg[2] = 0x60c3cf;
+ env->cpucfg[3] = 0xcff;
+ env->cpucfg[4] = 0x5f5e100;
+ env->cpucfg[5] = 0x10001;
+ env->cpucfg[10] = 0x2c3d;
+ env->cpucfg[11] = 0x6080003;
+ env->cpucfg[12] = 0x6080003;
+ env->cpucfg[13] = 0x60800f;
+ env->cpucfg[14] = 0x60f000f;
+}
+
+/* LoongArch CPU definitions */
+static void loongarch_3a5000_initfn(Object *obj)
+{
+ LoongArchCPU *cpu = LOONGARCH_CPU(obj);
+ CPULoongArchState *env = &cpu->env;
+
+ set_loongarch_cpucfg(env);
+}
+
+static void loongarch_cpu_list_entry(gpointer data, gpointer user_data)
+{
+ const char *typename = object_class_get_name(OBJECT_CLASS(data));
+
+ qemu_printf("%s\n", typename);
+}
+
+void loongarch_cpu_list(void)
+{
+ GSList *list;
+ list = object_class_get_list_sorted(TYPE_LOONGARCH_CPU, false);
+ g_slist_foreach(list, loongarch_cpu_list_entry, NULL);
+ g_slist_free(list);
+}
+
+static void loongarch_cpu_reset(DeviceState *dev)
+{
+ CPUState *cs = CPU(dev);
+ LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+ LoongArchCPUClass *lacc = LOONGARCH_CPU_GET_CLASS(cpu);
+ CPULoongArchState *env = &cpu->env;
+
+ lacc->parent_reset(dev);
+
+ set_loongarch_cpucfg(env);
+ env->fcsr0_mask = 0x1f1f031f;
+ env->fcsr0 = 0x0;
+
+ cs->exception_index = EXCP_NONE;
+}
+
+static void loongarch_cpu_disas_set_info(CPUState *s, disassemble_info *info)
+{
+ info->print_insn = print_insn_loongarch;
+}
+
+static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp)
+{
+ CPUState *cs = CPU(dev);
+ LoongArchCPUClass *lacc = LOONGARCH_CPU_GET_CLASS(dev);
+ Error *local_err = NULL;
+
+ cpu_exec_realizefn(cs, &local_err);
+ if (local_err != NULL) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ cpu_reset(cs);
+ qemu_init_vcpu(cs);
+
+ lacc->parent_realize(dev, errp);
+}
+
+static void loongarch_cpu_initfn(Object *obj)
+{
+ LoongArchCPU *cpu = LOONGARCH_CPU(obj);
+
+ cpu_set_cpustate_pointers(cpu);
+}
+
+static ObjectClass *loongarch_cpu_class_by_name(const char *cpu_model)
+{
+ ObjectClass *oc;
+ char *typename;
+
+ typename = g_strdup_printf(LOONGARCH_CPU_TYPE_NAME("%s"), cpu_model);
+ oc = object_class_by_name(typename);
+ g_free(typename);
+ return oc;
+}
+
+void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags)
+{
+ LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+ CPULoongArchState *env = &cpu->env;
+ int i;
+
+ qemu_fprintf(f, " PC=%016" PRIx64 " ", env->pc);
+ qemu_fprintf(f, " FCSR0 0x%08x fp_status 0x%02x\n", env->fcsr0,
+ get_float_exception_flags(&env->fp_status));
+
+ /* gpr */
+ for (i = 0; i < 32; i++) {
+ if ((i & 3) == 0) {
+ qemu_fprintf(f, " GPR%02d:", i);
+ }
+ qemu_fprintf(f, " %s %016" PRIx64, regnames[i], env->gpr[i]);
+ if ((i & 3) == 3) {
+ qemu_fprintf(f, "\n");
+ }
+ }
+
+ /* fpr */
+ if (flags & CPU_DUMP_FPU) {
+ for (i = 0; i < 32; i++) {
+ qemu_fprintf(f, " %s %016" PRIx64, fregnames[i], env->fpr[i]);
+ if ((i & 3) == 3) {
+ qemu_fprintf(f, "\n");
+ }
+ }
+ }
+}
+
+#ifdef CONFIG_TCG
+#include "hw/core/tcg-cpu-ops.h"
+
+static bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+ MMUAccessType access_type, int mmu_idx,
+ bool probe, uintptr_t retaddr)
+{
+ LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+ CPULoongArchState *env = &cpu->env;
+
+ env->badaddr = address;
+ cs->exception_index = EXCP_ADE;
+ do_raise_exception(env, cs->exception_index, retaddr);
+}
+
+static struct TCGCPUOps loongarch_tcg_ops = {
+ .initialize = loongarch_translate_init,
+ .synchronize_from_tb = loongarch_cpu_synchronize_from_tb,
+ .tlb_fill = loongarch_cpu_tlb_fill,
+};
+#endif /* CONFIG_TCG */
+
+static void loongarch_cpu_class_init(ObjectClass *c, void *data)
+{
+ LoongArchCPUClass *lacc = LOONGARCH_CPU_CLASS(c);
+ CPUClass *cc = CPU_CLASS(c);
+ DeviceClass *dc = DEVICE_CLASS(c);
+
+ device_class_set_parent_realize(dc, loongarch_cpu_realizefn,
+ &lacc->parent_realize);
+ device_class_set_parent_reset(dc, loongarch_cpu_reset, &lacc->parent_reset);
+
+ cc->class_by_name = loongarch_cpu_class_by_name;
+ cc->has_work = loongarch_cpu_has_work;
+ cc->dump_state = loongarch_cpu_dump_state;
+ cc->set_pc = loongarch_cpu_set_pc;
+ cc->disas_set_info = loongarch_cpu_disas_set_info;
+#ifdef CONFIG_TCG
+ cc->tcg_ops = &loongarch_tcg_ops;
+#endif
+}
+
+#define DEFINE_LOONGARCH_CPU_TYPE(model, initfn) \
+ { \
+ .parent = TYPE_LOONGARCH_CPU, \
+ .instance_init = initfn, \
+ .name = LOONGARCH_CPU_TYPE_NAME(model), \
+ }
+
+static const TypeInfo loongarch_cpu_type_infos[] = {
+ {
+ .name = TYPE_LOONGARCH_CPU,
+ .parent = TYPE_CPU,
+ .instance_size = sizeof(LoongArchCPU),
+ .instance_init = loongarch_cpu_initfn,
+
+ .abstract = true,
+ .class_size = sizeof(LoongArchCPUClass),
+ .class_init = loongarch_cpu_class_init,
+ },
+ DEFINE_LOONGARCH_CPU_TYPE("Loongson-3A5000", loongarch_3a5000_initfn),
+};
+
+DEFINE_TYPES(loongarch_cpu_type_infos)
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
new file mode 100644
index 0000000..a0348d0
--- /dev/null
+++ b/target/loongarch/cpu.h
@@ -0,0 +1,145 @@
+/*
+ * QEMU LoongArch CPU
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#ifndef LOONGARCH_CPU_H
+#define LOONGARCH_CPU_H
+
+#include "exec/cpu-defs.h"
+#include "fpu/softfloat-types.h"
+
+#define TCG_GUEST_DEFAULT_MO (0)
+
+#define FCSR0_M1 0x1f /* FCSR1 mask, Enables */
+#define FCSR0_M2 0x1f1f0000 /* FCSR2 mask, Cause and Flags */
+#define FCSR0_M3 0x300 /* FCSR3 mask, Round Mode */
+#define FCSR0_RM 8 /* Round Mode bit num on fcsr0 */
+#define GET_FP_CAUSE(reg) (((reg) >> 24) & 0x1f)
+#define GET_FP_ENABLE(reg) (reg & 0x1f)
+#define GET_FP_FLAGS(reg) (((reg) >> 16) & 0x1f)
+#define SET_FP_CAUSE(reg, v) do { (reg) = ((reg) & ~(0x1f << 24)) | \
+ ((v & 0x1f) << 24); \
+ } while (0)
+#define SET_FP_ENABLE(reg, v) do { (reg) = ((reg) & ~(0x1f) | (v & 0x1f); \
+ } while (0)
+#define SET_FP_FLAGS(reg, v) do { (reg) = ((reg) & ~(0x1f << 16)) | \
+ ((v & 0x1f) << 16); \
+ } while (0)
+#define UPDATE_FP_FLAGS(reg, v) do { (reg) |= ((v & 0x1f) << 16); } while (0)
+
+#define FP_INEXACT 1
+#define FP_UNDERFLOW 2
+#define FP_OVERFLOW 4
+#define FP_DIV0 8
+#define FP_INVALID 16
+
+extern const char * const regnames[];
+extern const char * const fregnames[];
+
+typedef struct CPULoongArchState CPULoongArchState;
+struct CPULoongArchState {
+ uint64_t gpr[32];
+ uint64_t pc;
+
+ uint64_t fpr[32];
+ float_status fp_status;
+ bool cf[8];
+
+ /*
+ * fcsr0
+ * 31:29 |28:24 |23:21 |20:16 |15:10 |9:8 |7:5 |4:0
+ * Cause Flags RM Enables
+ */
+ uint32_t fcsr0;
+ uint32_t fcsr0_mask;
+
+ uint32_t cpucfg[15];
+
+ uint64_t lladdr; /* LL virtual address compared against SC */
+ uint64_t llval;
+
+ uint64_t badaddr;
+};
+
+/**
+ * LoongArchCPU:
+ * @env: #CPULoongArchState
+ * @clock: this CPU input clock (may be connected
+ * to an output clock from another device).
+ *
+ * A LoongArch CPU.
+ */
+struct LoongArchCPU {
+ /*< private >*/
+ CPUState parent_obj;
+ /*< public >*/
+
+ CPUNegativeOffsetState neg;
+ CPULoongArchState env;
+};
+
+#define TYPE_LOONGARCH_CPU "loongarch64-cpu"
+
+OBJECT_DECLARE_TYPE(LoongArchCPU, LoongArchCPUClass,
+ LOONGARCH_CPU)
+
+/**
+ * LoongArchCPUClass:
+ * @parent_realize: The parent class' realize handler.
+ * @parent_reset: The parent class' reset handler.
+ *
+ * A LoongArch CPU model.
+ */
+struct LoongArchCPUClass {
+ /*< private >*/
+ CPUClass parent_class;
+ /*< public >*/
+
+ DeviceRealize parent_realize;
+ DeviceReset parent_reset;
+};
+
+static inline void cpu_get_tb_cpu_state(CPULoongArchState *env,
+ target_ulong *pc,
+ target_ulong *cs_base,
+ uint32_t *flags)
+{
+ *pc = env->pc;
+ *cs_base = 0;
+}
+
+void loongarch_cpu_list(void);
+
+#define cpu_signal_handler cpu_loongarch_signal_handler
+#define cpu_list loongarch_cpu_list
+
+#define MMU_USER_IDX 3
+
+typedef CPULoongArchState CPUArchState;
+typedef LoongArchCPU ArchCPU;
+
+#include "exec/cpu-all.h"
+
+/* Exceptions */
+enum {
+ EXCP_NONE = -1,
+ EXCP_ADE = 0,
+ EXCP_SYSCALL,
+ EXCP_BREAK,
+ EXCP_INE,
+ EXCP_FPE,
+
+ EXCP_LAST = EXCP_FPE,
+};
+
+int cpu_loongarch_signal_handler(int host_signum, void *pinfo, void *puc);
+
+#define LOONGARCH_CPU_TYPE_SUFFIX "-" TYPE_LOONGARCH_CPU
+#define LOONGARCH_CPU_TYPE_NAME(model) model LOONGARCH_CPU_TYPE_SUFFIX
+#define CPU_RESOLVING_TYPE TYPE_LOONGARCH_CPU
+
+#endif /* LOONGARCH_CPU_H */
diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h
new file mode 100644
index 0000000..cfb08df
--- /dev/null
+++ b/target/loongarch/internals.h
@@ -0,0 +1,23 @@
+/*
+ * QEMU LoongArch CPU -- internal functions and types
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#ifndef LOONGARCH_INTERNALS_H
+#define LOONGARCH_INTERNALS_H
+
+
+void loongarch_translate_init(void);
+
+void loongarch_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
+
+void QEMU_NORETURN do_raise_exception(CPULoongArchState *env,
+ uint32_t exception,
+ uintptr_t pc);
+
+const char *loongarch_exception_name(int32_t exception);
+
+#endif
--
1.8.3.1
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v3 03/19] target/loongarch: Add main translation routines
2021-08-27 7:14 [PATCH v3 00/19] Add LoongArch linux-user emulation support Song Gao
2021-08-27 7:14 ` [PATCH v3 01/19] target/loongarch: Add README Song Gao
2021-08-27 7:14 ` [PATCH v3 02/19] target/loongarch: Add core definition Song Gao
@ 2021-08-27 7:14 ` Song Gao
2021-08-27 7:14 ` [PATCH v3 04/19] target/loongarch: Add fixed point arithmetic instruction translation Song Gao
` (15 subsequent siblings)
18 siblings, 0 replies; 22+ messages in thread
From: Song Gao @ 2021-08-27 7:14 UTC (permalink / raw)
To: qemu-devel
Cc: peter.maydell, thuth, chenhuacai, richard.henderson, f4bug,
maobibo, laurent, yangxiaojuan, alistair.francis, pbonzini,
alex.bennee
This patch add main translation routines and
basic functions for translation.
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
target/loongarch/helper.h | 9 +++
target/loongarch/op_helper.c | 22 ++++++
target/loongarch/translate.c | 171 +++++++++++++++++++++++++++++++++++++++++++
target/loongarch/translate.h | 27 +++++++
4 files changed, 229 insertions(+)
create mode 100644 target/loongarch/helper.h
create mode 100644 target/loongarch/op_helper.c
create mode 100644 target/loongarch/translate.c
create mode 100644 target/loongarch/translate.h
diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h
new file mode 100644
index 0000000..09bfcfd
--- /dev/null
+++ b/target/loongarch/helper.h
@@ -0,0 +1,9 @@
+/*
+ * QEMU LoongArch CPU
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+DEF_HELPER_2(raise_exception, noreturn, env, i32)
diff --git a/target/loongarch/op_helper.c b/target/loongarch/op_helper.c
new file mode 100644
index 0000000..4d10b03
--- /dev/null
+++ b/target/loongarch/op_helper.c
@@ -0,0 +1,22 @@
+/*
+ * LoongArch emulation helpers for qemu.
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/main-loop.h"
+#include "cpu.h"
+#include "qemu/host-utils.h"
+#include "exec/helper-proto.h"
+#include "exec/exec-all.h"
+#include "exec/cpu_ldst.h"
+#include "internals.h"
+
+/* Exceptions helpers */
+void helper_raise_exception(CPULoongArchState *env, uint32_t exception)
+{
+ do_raise_exception(env, exception, GETPC());
+}
diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c
new file mode 100644
index 0000000..bdbd7a9
--- /dev/null
+++ b/target/loongarch/translate.c
@@ -0,0 +1,171 @@
+/*
+ * LoongArch emulation for QEMU - main translation routines.
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "tcg/tcg-op.h"
+#include "exec/translator.h"
+#include "exec/helper-proto.h"
+#include "exec/helper-gen.h"
+
+#include "exec/translator.h"
+#include "exec/log.h"
+#include "qemu/qemu-print.h"
+#include "fpu_helper.h"
+#include "translate.h"
+#include "internals.h"
+
+/* global register indices */
+TCGv cpu_gpr[32], cpu_pc;
+static TCGv cpu_lladdr, cpu_llval;
+TCGv_i32 cpu_fcsr0;
+TCGv_i64 cpu_fpr[32];
+
+#define DISAS_STOP DISAS_TARGET_0
+#define DISAS_EXIT DISAS_TARGET_1
+
+void generate_exception(DisasContext *ctx, int excp)
+{
+ tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);
+ gen_helper_raise_exception(cpu_env, tcg_constant_i32(excp));
+ ctx->base.is_jmp = DISAS_NORETURN;
+}
+
+static inline bool use_goto_tb(DisasContext *ctx, target_ulong dest)
+{
+ return true;
+}
+
+static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
+{
+ if (translator_use_goto_tb(&ctx->base, dest)) {
+ tcg_gen_goto_tb(n);
+ tcg_gen_movi_tl(cpu_pc, dest);
+ tcg_gen_exit_tb(ctx->base.tb, n);
+ } else {
+ tcg_gen_movi_tl(cpu_pc, dest);
+ tcg_gen_lookup_and_goto_ptr();
+ }
+}
+
+static void loongarch_tr_init_disas_context(DisasContextBase *dcbase,
+ CPUState *cs)
+{
+ DisasContext *ctx = container_of(dcbase, DisasContext, base);
+ int64_t bound;
+
+ ctx->page_start = ctx->base.pc_first & TARGET_PAGE_MASK;
+ ctx->mem_idx = MMU_USER_IDX ;
+
+ /* Bound the number of insns to execute to those left on the page. */
+ bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4;
+ ctx->base.max_insns = MIN(ctx->base.max_insns, bound);
+}
+
+static void loongarch_tr_tb_start(DisasContextBase *dcbase, CPUState *cs)
+{
+}
+
+static void loongarch_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
+{
+ DisasContext *ctx = container_of(dcbase, DisasContext, base);
+
+ tcg_gen_insn_start(ctx->base.pc_next);
+}
+
+static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
+{
+ CPULoongArchState *env = cs->env_ptr;
+ DisasContext *ctx = container_of(dcbase, DisasContext, base);
+
+ ctx->opcode = cpu_ldl_code(env, ctx->base.pc_next);
+
+ if (!decode(ctx, ctx->opcode)) {
+ qemu_log_mask(LOG_UNIMP, "Error: unkown opcode. 0x%lx: 0x%x\n",
+ ctx->base.pc_next, ctx->opcode);
+ generate_exception(ctx, EXCP_INE);
+ }
+
+ ctx->base.pc_next += 4;
+}
+
+static void loongarch_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
+{
+ DisasContext *ctx = container_of(dcbase, DisasContext, base);
+
+ switch (ctx->base.is_jmp) {
+ case DISAS_STOP:
+ tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);
+ tcg_gen_lookup_and_goto_ptr();
+ break;
+ case DISAS_NEXT:
+ case DISAS_TOO_MANY:
+ gen_goto_tb(ctx, 0, ctx->base.pc_next);
+ break;
+ case DISAS_EXIT:
+ tcg_gen_exit_tb(NULL, 0);
+ break;
+ case DISAS_NORETURN:
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static void loongarch_tr_disas_log(const DisasContextBase *dcbase, CPUState *cs)
+{
+ qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first));
+ log_target_disas(cs, dcbase->pc_first, dcbase->tb->size);
+}
+
+static const TranslatorOps loongarch_tr_ops = {
+ .init_disas_context = loongarch_tr_init_disas_context,
+ .tb_start = loongarch_tr_tb_start,
+ .insn_start = loongarch_tr_insn_start,
+ .translate_insn = loongarch_tr_translate_insn,
+ .tb_stop = loongarch_tr_tb_stop,
+ .disas_log = loongarch_tr_disas_log,
+};
+
+void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns)
+{
+ DisasContext ctx;
+
+ translator_loop(&loongarch_tr_ops, &ctx.base, cs, tb, max_insns);
+}
+
+void loongarch_translate_init(void)
+{
+ int i;
+
+ cpu_gpr[0] = NULL;
+ for (i = 1; i < 32; i++) {
+ cpu_gpr[i] = tcg_global_mem_new(cpu_env,
+ offsetof(CPULoongArchState, gpr[i]),
+ regnames[i]);
+ }
+
+ for (i = 0; i < 32; i++) {
+ int off = offsetof(CPULoongArchState, fpr[i]);
+ cpu_fpr[i] = tcg_global_mem_new_i64(cpu_env, off, fregnames[i]);
+ }
+
+ cpu_pc = tcg_global_mem_new(cpu_env, offsetof(CPULoongArchState, pc), "pc");
+ cpu_fcsr0 = tcg_global_mem_new_i32(cpu_env,
+ offsetof(CPULoongArchState, fcsr0), "fcsr0");
+ cpu_lladdr = tcg_global_mem_new(cpu_env,
+ offsetof(CPULoongArchState, lladdr), "lladdr");
+ cpu_llval = tcg_global_mem_new(cpu_env,
+ offsetof(CPULoongArchState, llval), "llval");
+}
+
+void restore_state_to_opc(CPULoongArchState *env, TranslationBlock *tb,
+ target_ulong *data)
+{
+ env->pc = data[0];
+}
diff --git a/target/loongarch/translate.h b/target/loongarch/translate.h
new file mode 100644
index 0000000..dff7d79
--- /dev/null
+++ b/target/loongarch/translate.h
@@ -0,0 +1,27 @@
+/*
+ * LoongArch translation routines.
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#ifndef TARGET_LOONGARCH_TRANSLATE_H
+#define TARGET_LOONGARCH_TRANSLATE_H
+
+#include "exec/translator.h"
+
+typedef struct DisasContext {
+ DisasContextBase base;
+ target_ulong page_start;
+ uint32_t opcode;
+ int mem_idx;
+} DisasContext;
+
+void generate_exception(DisasContext *ctx, int excp);
+
+extern TCGv cpu_gpr[32], cpu_pc;
+extern TCGv_i32 cpu_fscr0;
+extern TCGv_i64 cpu_fpr[32];
+
+#endif
--
1.8.3.1
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v3 04/19] target/loongarch: Add fixed point arithmetic instruction translation
2021-08-27 7:14 [PATCH v3 00/19] Add LoongArch linux-user emulation support Song Gao
` (2 preceding siblings ...)
2021-08-27 7:14 ` [PATCH v3 03/19] target/loongarch: Add main translation routines Song Gao
@ 2021-08-27 7:14 ` Song Gao
2021-08-27 7:14 ` [PATCH v3 05/19] target/loongarch: Add fixed point shift " Song Gao
` (14 subsequent siblings)
18 siblings, 0 replies; 22+ messages in thread
From: Song Gao @ 2021-08-27 7:14 UTC (permalink / raw)
To: qemu-devel
Cc: peter.maydell, thuth, chenhuacai, richard.henderson, f4bug,
maobibo, laurent, yangxiaojuan, alistair.francis, pbonzini,
alex.bennee
This patch implement fixed point arithemtic instruction translation.
This includes:
- ADD.{W/D}, SUB.{W/D}
- ADDI.{W/D}, ADDU16ID
- ALSL.{W[U]/D}
- LU12I.W, LU32I.D LU52I.D
- SLT[U], SLT[U]I
- PCADDI, PCADDU12I, PCADDU18I, PCALAU12I
- AND, OR, NOR, XOR, ANDN, ORN
- MUL.{W/D}, MULH.{W[U]/D[U]}
- MULW.D.W[U]
- DIV.{W[U]/D[U]}, MOD.{W[U]/D[U]}
- ANDI, ORI, XORI
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
target/loongarch/insn_trans/trans_arith.c | 334 ++++++++++++++++++++++++++++++
target/loongarch/insns.decode | 89 ++++++++
target/loongarch/internals.h | 1 -
target/loongarch/translate.c | 100 ++++++++-
target/loongarch/translate.h | 20 ++
5 files changed, 538 insertions(+), 6 deletions(-)
create mode 100644 target/loongarch/insn_trans/trans_arith.c
create mode 100644 target/loongarch/insns.decode
diff --git a/target/loongarch/insn_trans/trans_arith.c b/target/loongarch/insn_trans/trans_arith.c
new file mode 100644
index 0000000..5f23bcd
--- /dev/null
+++ b/target/loongarch/insn_trans/trans_arith.c
@@ -0,0 +1,334 @@
+/*
+ * LoongArch translate functions
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+static bool gen_r2_si12(DisasContext *ctx, arg_fmt_rdrjsi12 *a,
+ DisasExtend src_ext, DisasExtend dst_ext,
+ void (*func)(TCGv, TCGv, TCGv))
+{
+ ctx->dst_ext = dst_ext;
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv src1 = gpr_src(ctx, a->rj, src_ext);
+ TCGv src2 = tcg_constant_tl(a->si12);
+
+ func(dest, src1, src2);
+
+ if (ctx->dst_ext) {
+ gen_set_gpr(ctx, a->rd, dest);
+ }
+ return true;
+}
+
+static bool gen_r3_sa2(DisasContext *ctx, arg_fmt_rdrjrksa2 *a,
+ DisasExtend src_ext, DisasExtend dst_ext,
+ void (*func)(TCGv, TCGv, TCGv, TCGv, target_long))
+{
+ ctx->dst_ext = dst_ext;
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv src1 = gpr_src(ctx, a->rj, src_ext);
+ TCGv src2 = gpr_src(ctx, a->rk, src_ext);
+ TCGv temp = tcg_temp_new();
+
+ func(dest, src1, src2, temp, a->sa2);
+
+ if (ctx->dst_ext) {
+ gen_set_gpr(ctx, a->rd, dest);
+ }
+ tcg_temp_free(temp);
+ return true;
+}
+
+static bool trans_lu12i_w(DisasContext *ctx, arg_lu12i_w *a)
+{
+ TCGv dest = gpr_dst(ctx, a->rd);
+
+ tcg_gen_movi_tl(dest, a->si20 << 12);
+ return true;
+}
+
+static bool gen_pc(DisasContext *ctx, arg_fmt_rdsi20 *a,
+ void (*func)(DisasContext *ctx, TCGv, target_long))
+{
+ TCGv dest = gpr_dst(ctx, a->rd);
+
+ func(ctx, dest, a->si20);
+ return true;
+}
+
+static bool gen_r2_ui12(DisasContext *ctx, arg_fmt_rdrjui12 *a,
+ void (*func)(TCGv, TCGv, target_long))
+{
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+
+ func(dest, src1, a->ui12);
+ return true;
+}
+
+static void gen_slt(TCGv dest, TCGv src1, TCGv src2)
+{
+ tcg_gen_setcond_tl(TCG_COND_LT, dest, src1, src2);
+}
+
+static void gen_sltu(TCGv dest, TCGv src1, TCGv src2)
+{
+ tcg_gen_setcond_tl(TCG_COND_LTU, dest, src1, src2);
+}
+
+static bool gen_mulh(DisasContext *ctx, arg_add_w *a,
+ void(*func)(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_i32))
+{
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE);
+ TCGv_i32 discard = tcg_temp_new_i32();
+ TCGv_i32 t0 = tcg_temp_new_i32();
+ TCGv_i32 t1 = tcg_temp_new_i32();
+
+ tcg_gen_trunc_tl_i32(t0, src1);
+ tcg_gen_trunc_tl_i32(t1, src2);
+ func(discard, t0, t0, t1);
+ tcg_gen_ext_i32_tl(dest, t0);
+
+ tcg_temp_free_i32(discard);
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(t1);
+ return true;
+}
+
+static bool gen_mulh_d(DisasContext *ctx, arg_add_w *a,
+ void(*func)(TCGv, TCGv, TCGv, TCGv))
+{
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE);
+ TCGv discard = tcg_temp_new();
+
+ func(discard, dest, src1, src2);
+ tcg_temp_free(discard);
+ return true;
+}
+
+static bool gen_mulw_d(DisasContext *ctx, arg_add_w *a,
+ void(*func)(TCGv_i64, TCGv))
+{
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE);
+
+ func(src1, src1);
+ func(src2, src2);
+ tcg_gen_mul_i64(dest, src1, src2);
+ return true;
+}
+
+static bool gen_div_w(DisasContext *ctx, arg_fmt_rdrjrk *a,
+ DisasExtend src_ext, DisasExtend dst_ext,
+ void(*func)(TCGv, TCGv, TCGv))
+{
+ ctx->dst_ext = dst_ext;
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv src1 = gpr_src(ctx, a->rj, src_ext);
+ TCGv src2 = gpr_src(ctx, a->rk, src_ext);
+ TCGv t2 = tcg_temp_new();
+ TCGv t3 = tcg_temp_new();
+
+ tcg_gen_setcondi_tl(TCG_COND_EQ, t2, src1, INT_MIN);
+ tcg_gen_setcondi_tl(TCG_COND_EQ, t3, src2, -1);
+ tcg_gen_and_tl(t2, t2, t3);
+ tcg_gen_setcondi_tl(TCG_COND_EQ, t3, src2, 0);
+ tcg_gen_or_tl(t2, t2, t3);
+ tcg_gen_movi_tl(t3, 0);
+ tcg_gen_movcond_tl(TCG_COND_NE, src2, t2, t3, t2, src2);
+ func(dest, src1, src2);
+
+ if (ctx->dst_ext) {
+ gen_set_gpr(ctx, a->rd, dest);
+ }
+
+ tcg_temp_free(t2);
+ tcg_temp_free(t3);
+ return true;
+}
+
+static bool gen_div_wu(DisasContext *ctx, arg_fmt_rdrjrk *a,
+ DisasExtend src_ext, DisasExtend dst_ext,
+ void(*func)(TCGv, TCGv, TCGv))
+{
+ ctx->dst_ext = dst_ext;
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv src1 = gpr_src(ctx, a->rj, src_ext);
+ TCGv src2 = gpr_src(ctx, a->rk, src_ext);
+ TCGv t2 = tcg_constant_tl(0);
+ TCGv t3 = tcg_constant_tl(1);
+
+ tcg_gen_movcond_tl(TCG_COND_EQ, src1, src1, t2, t3, src1);
+ func(dest, src1, src2);
+
+ if (ctx->dst_ext) {
+ gen_set_gpr(ctx, a->rd, dest);
+ }
+ return true;
+}
+
+static bool gen_div_d(DisasContext *ctx, arg_fmt_rdrjrk *a,
+ void(*func)(TCGv, TCGv, TCGv))
+{
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE);
+ TCGv t2 = tcg_temp_new();
+ TCGv t3 = tcg_temp_new();
+
+ tcg_gen_setcondi_tl(TCG_COND_EQ, t2, src1, -1LL << 63);
+ tcg_gen_setcondi_tl(TCG_COND_EQ, t3, src2, -1LL);
+ tcg_gen_and_tl(t2, t2, t3);
+ tcg_gen_setcondi_tl(TCG_COND_EQ, t3, src2, 0);
+ tcg_gen_or_tl(t2, t2, t3);
+ tcg_gen_movi_tl(t3, 0);
+ tcg_gen_movcond_tl(TCG_COND_NE, src2, t2, t3, t2, src2);
+ func(dest, src1, src2);
+
+ tcg_temp_free(t2);
+ tcg_temp_free(t3);
+
+ return true;
+}
+
+static bool gen_div_du(DisasContext *ctx, arg_fmt_rdrjrk *a,
+ void(*func)(TCGv, TCGv, TCGv))
+{
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE);
+ TCGv t2 = tcg_constant_tl(0);
+ TCGv t3 = tcg_constant_tl(1);
+
+ tcg_gen_movcond_tl(TCG_COND_EQ, src2, src2, t2, t3, src2);
+ func(dest, src1, src2);
+
+ return true;
+}
+
+static void gen_alsl_w(TCGv dest, TCGv src1, TCGv src2,
+ TCGv temp, target_long sa2)
+{
+ tcg_gen_shli_tl(temp, src1, sa2 + 1);
+ tcg_gen_add_tl(dest, temp, src2);
+}
+
+static void gen_alsl_wu(TCGv dest, TCGv src1, TCGv src2,
+ TCGv temp, target_long sa2)
+{
+ tcg_gen_shli_tl(temp, src1, sa2 + 1);
+ tcg_gen_add_tl(dest, temp, src2);
+}
+
+static void gen_alsl_d(TCGv dest, TCGv src1, TCGv src2,
+ TCGv temp, target_long sa2)
+{
+ tcg_gen_shli_tl(temp, src1, sa2 + 1);
+ tcg_gen_add_tl(dest, temp, src2);
+}
+
+static bool trans_lu32i_d(DisasContext *ctx, arg_lu32i_d *a)
+{
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv src1 = gpr_src(ctx, a->rd, EXT_NONE);
+ TCGv src2 = tcg_constant_tl(a->si20);
+
+ tcg_gen_deposit_tl(dest, src1, src2, 32, 32);
+ return true;
+}
+
+static bool trans_lu52i_d(DisasContext *ctx, arg_lu52i_d *a)
+{
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv src2 = tcg_constant_tl(a->si12);
+
+ tcg_gen_deposit_tl(dest, src1, src2, 52, 12);
+ return true;
+}
+
+static void gen_pcaddi(DisasContext *ctx, TCGv dest, target_long si20)
+{
+ target_ulong addr = ctx->base.pc_next + (si20 << 2);
+ tcg_gen_movi_tl(dest, addr);
+}
+
+static void gen_pcalau12i(DisasContext *ctx, TCGv dest, target_long si20)
+{
+
+ target_ulong addr = (ctx->base.pc_next + (si20 << 12)) & ~0xfff;
+ tcg_gen_movi_tl(dest, addr);
+}
+
+static void gen_pcaddu12i(DisasContext *ctx, TCGv dest, target_long si20)
+{
+
+ target_ulong addr = ctx->base.pc_next + (si20 << 12);
+ tcg_gen_movi_tl(dest, addr);
+}
+
+static void gen_pcaddu18i(DisasContext *ctx, TCGv dest, target_long si20)
+{
+ target_ulong addr = ctx->base.pc_next + ((target_ulong)(si20) << 18);
+ tcg_gen_movi_tl(dest, addr);
+}
+
+static bool trans_addu16i_d(DisasContext *ctx, arg_addu16i_d *a)
+{
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+
+ tcg_gen_addi_tl(dest, src1, a->si16 << 16);
+ return true;
+}
+
+TRANS(add_w, gen_r3, EXT_NONE, EXT_NONE, EXT_SIGN, tcg_gen_add_tl)
+TRANS(add_d, gen_r3, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_add_tl)
+TRANS(sub_w, gen_r3, EXT_NONE, EXT_NONE, EXT_SIGN, tcg_gen_sub_tl)
+TRANS(sub_d, gen_r3, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_sub_tl)
+TRANS(and, gen_r3, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_and_tl)
+TRANS(or, gen_r3, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_or_tl)
+TRANS(xor, gen_r3, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_xor_tl)
+TRANS(nor, gen_r3, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_nor_tl)
+TRANS(andn, gen_r3, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_andc_tl)
+TRANS(orn, gen_r3, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_orc_tl)
+TRANS(slt, gen_r3, EXT_NONE, EXT_NONE, EXT_NONE, gen_slt)
+TRANS(sltu, gen_r3, EXT_NONE, EXT_NONE, EXT_NONE, gen_sltu)
+TRANS(mul_w, gen_r3, EXT_SIGN, EXT_SIGN, EXT_SIGN, tcg_gen_mul_tl)
+TRANS(mul_d, gen_r3, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_mul_tl)
+TRANS(mulh_w, gen_mulh, tcg_gen_muls2_i32)
+TRANS(mulh_wu, gen_mulh, tcg_gen_mulu2_i32)
+TRANS(mulh_d, gen_mulh_d, tcg_gen_muls2_tl)
+TRANS(mulh_du, gen_mulh_d, tcg_gen_mulu2_tl)
+TRANS(mulw_d_w, gen_mulw_d, tcg_gen_ext32s_tl)
+TRANS(mulw_d_wu, gen_mulw_d, tcg_gen_ext32u_tl)
+TRANS(div_w, gen_div_w, EXT_SIGN, EXT_SIGN, tcg_gen_div_tl)
+TRANS(mod_w, gen_div_w, EXT_SIGN, EXT_SIGN, tcg_gen_rem_tl)
+TRANS(div_wu, gen_div_wu, EXT_ZERO, EXT_SIGN, tcg_gen_divu_tl)
+TRANS(mod_wu, gen_div_wu, EXT_ZERO, EXT_SIGN, tcg_gen_remu_tl)
+TRANS(div_d, gen_div_d, tcg_gen_div_tl)
+TRANS(mod_d, gen_div_d, tcg_gen_rem_tl)
+TRANS(div_du, gen_div_du, tcg_gen_divu_tl)
+TRANS(mod_du, gen_div_du, tcg_gen_remu_tl)
+TRANS(slti, gen_r2_si12, EXT_NONE, EXT_NONE, gen_slt)
+TRANS(sltui, gen_r2_si12, EXT_NONE, EXT_NONE, gen_sltu)
+TRANS(addi_w, gen_r2_si12, EXT_NONE, EXT_SIGN, tcg_gen_add_tl)
+TRANS(addi_d, gen_r2_si12, EXT_NONE, EXT_NONE, tcg_gen_add_tl)
+TRANS(alsl_w, gen_r3_sa2, EXT_NONE, EXT_SIGN, gen_alsl_w)
+TRANS(alsl_wu, gen_r3_sa2, EXT_NONE, EXT_ZERO, gen_alsl_wu)
+TRANS(alsl_d, gen_r3_sa2, EXT_NONE, EXT_NONE, gen_alsl_d)
+TRANS(pcaddi, gen_pc, gen_pcaddi)
+TRANS(pcalau12i, gen_pc, gen_pcalau12i)
+TRANS(pcaddu12i, gen_pc, gen_pcaddu12i)
+TRANS(pcaddu18i, gen_pc, gen_pcaddu18i)
+TRANS(andi, gen_r2_ui12, tcg_gen_andi_tl)
+TRANS(ori, gen_r2_ui12, tcg_gen_ori_tl)
+TRANS(xori, gen_r2_ui12, tcg_gen_xori_tl)
diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode
new file mode 100644
index 0000000..1e0b755
--- /dev/null
+++ b/target/loongarch/insns.decode
@@ -0,0 +1,89 @@
+#
+# LoongArch instruction decode definitions.
+#
+# Copyright (c) 2021 Loongson Technology Corporation Limited
+#
+# SPDX-License-Identifier: LGPL-2.1+
+#
+
+#
+# Fields
+#
+%rd 0:5
+%rj 5:5
+%rk 10:5
+%sa2 15:2
+%si12 10:s12
+%ui12 10:12
+%si16 10:s16
+%si20 5:s20
+
+#
+# Argument sets
+#
+&fmt_rdrjrk rd rj rk
+&fmt_rdrjsi12 rd rj si12
+&fmt_rdrjrksa2 rd rj rk sa2
+&fmt_rdrjsi16 rd rj si16
+&fmt_rdrjui12 rd rj ui12
+&fmt_rdsi20 rd si20
+
+#
+# Formats
+#
+@fmt_rdrjrk .... ........ ..... ..... ..... ..... &fmt_rdrjrk %rd %rj %rk
+@fmt_rdrjsi12 .... ...... ............ ..... ..... &fmt_rdrjsi12 %rd %rj %si12
+@fmt_rdrjui12 .... ...... ............ ..... ..... &fmt_rdrjui12 %rd %rj %ui12
+@fmt_rdrjrksa2 .... ........ ... .. ..... ..... ..... &fmt_rdrjrksa2 %rd %rj %rk %sa2
+@fmt_rdrjsi16 .... .. ................ ..... ..... &fmt_rdrjsi16 %rd %rj %si16
+@fmt_rdsi20 .... ... .................... ..... &fmt_rdsi20 %rd %si20
+
+#
+# Fixed point arithmetic operation instruction
+#
+add_w 0000 00000001 00000 ..... ..... ..... @fmt_rdrjrk
+add_d 0000 00000001 00001 ..... ..... ..... @fmt_rdrjrk
+sub_w 0000 00000001 00010 ..... ..... ..... @fmt_rdrjrk
+sub_d 0000 00000001 00011 ..... ..... ..... @fmt_rdrjrk
+slt 0000 00000001 00100 ..... ..... ..... @fmt_rdrjrk
+sltu 0000 00000001 00101 ..... ..... ..... @fmt_rdrjrk
+slti 0000 001000 ............ ..... ..... @fmt_rdrjsi12
+sltui 0000 001001 ............ ..... ..... @fmt_rdrjsi12
+nor 0000 00000001 01000 ..... ..... ..... @fmt_rdrjrk
+and 0000 00000001 01001 ..... ..... ..... @fmt_rdrjrk
+or 0000 00000001 01010 ..... ..... ..... @fmt_rdrjrk
+xor 0000 00000001 01011 ..... ..... ..... @fmt_rdrjrk
+orn 0000 00000001 01100 ..... ..... ..... @fmt_rdrjrk
+andn 0000 00000001 01101 ..... ..... ..... @fmt_rdrjrk
+mul_w 0000 00000001 11000 ..... ..... ..... @fmt_rdrjrk
+mulh_w 0000 00000001 11001 ..... ..... ..... @fmt_rdrjrk
+mulh_wu 0000 00000001 11010 ..... ..... ..... @fmt_rdrjrk
+mul_d 0000 00000001 11011 ..... ..... ..... @fmt_rdrjrk
+mulh_d 0000 00000001 11100 ..... ..... ..... @fmt_rdrjrk
+mulh_du 0000 00000001 11101 ..... ..... ..... @fmt_rdrjrk
+mulw_d_w 0000 00000001 11110 ..... ..... ..... @fmt_rdrjrk
+mulw_d_wu 0000 00000001 11111 ..... ..... ..... @fmt_rdrjrk
+div_w 0000 00000010 00000 ..... ..... ..... @fmt_rdrjrk
+mod_w 0000 00000010 00001 ..... ..... ..... @fmt_rdrjrk
+div_wu 0000 00000010 00010 ..... ..... ..... @fmt_rdrjrk
+mod_wu 0000 00000010 00011 ..... ..... ..... @fmt_rdrjrk
+div_d 0000 00000010 00100 ..... ..... ..... @fmt_rdrjrk
+mod_d 0000 00000010 00101 ..... ..... ..... @fmt_rdrjrk
+div_du 0000 00000010 00110 ..... ..... ..... @fmt_rdrjrk
+mod_du 0000 00000010 00111 ..... ..... ..... @fmt_rdrjrk
+alsl_w 0000 00000000 010 .. ..... ..... ..... @fmt_rdrjrksa2
+alsl_wu 0000 00000000 011 .. ..... ..... ..... @fmt_rdrjrksa2
+alsl_d 0000 00000010 110 .. ..... ..... ..... @fmt_rdrjrksa2
+lu12i_w 0001 010 .................... ..... @fmt_rdsi20
+lu32i_d 0001 011 .................... ..... @fmt_rdsi20
+lu52i_d 0000 001100 ............ ..... ..... @fmt_rdrjsi12
+pcaddi 0001 100 .................... ..... @fmt_rdsi20
+pcalau12i 0001 101 .................... ..... @fmt_rdsi20
+pcaddu12i 0001 110 .................... ..... @fmt_rdsi20
+pcaddu18i 0001 111 .................... ..... @fmt_rdsi20
+addi_w 0000 001010 ............ ..... ..... @fmt_rdrjsi12
+addi_d 0000 001011 ............ ..... ..... @fmt_rdrjsi12
+addu16i_d 0001 00 ................ ..... ..... @fmt_rdrjsi16
+andi 0000 001101 ............ ..... ..... @fmt_rdrjui12
+ori 0000 001110 ............ ..... ..... @fmt_rdrjui12
+xori 0000 001111 ............ ..... ..... @fmt_rdrjui12
diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h
index cfb08df..1052cb6 100644
--- a/target/loongarch/internals.h
+++ b/target/loongarch/internals.h
@@ -9,7 +9,6 @@
#ifndef LOONGARCH_INTERNALS_H
#define LOONGARCH_INTERNALS_H
-
void loongarch_translate_init(void);
void loongarch_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c
index bdbd7a9..1806d2c 100644
--- a/target/loongarch/translate.c
+++ b/target/loongarch/translate.c
@@ -36,11 +36,6 @@ void generate_exception(DisasContext *ctx, int excp)
ctx->base.is_jmp = DISAS_NORETURN;
}
-static inline bool use_goto_tb(DisasContext *ctx, target_ulong dest)
-{
- return true;
-}
-
static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
{
if (translator_use_goto_tb(&ctx->base, dest)) {
@@ -65,6 +60,12 @@ static void loongarch_tr_init_disas_context(DisasContextBase *dcbase,
/* Bound the number of insns to execute to those left on the page. */
bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4;
ctx->base.max_insns = MIN(ctx->base.max_insns, bound);
+
+ ctx->dst_ext = EXT_NONE;
+ ctx->ntemp = 0;
+ memset(ctx->temp, 0, sizeof(ctx->temp));
+
+ ctx->zero = tcg_constant_tl(0);
}
static void loongarch_tr_tb_start(DisasContextBase *dcbase, CPUState *cs)
@@ -78,6 +79,87 @@ static void loongarch_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
tcg_gen_insn_start(ctx->base.pc_next);
}
+/*
+ * Wrappers for getting reg values.
+ *
+ * The $zero register does not have cpu_gpr[0] allocated -- we supply the
+ * constant zero as a source, and an uninitialized sink as destination.
+ *
+ * Further, we may provide an extension for word operations.
+ */
+static TCGv temp_new(DisasContext *ctx)
+{
+ assert(ctx->ntemp < ARRAY_SIZE(ctx->temp));
+ return ctx->temp[ctx->ntemp++] = tcg_temp_new();
+}
+
+static TCGv gpr_src(DisasContext *ctx, int reg_num, DisasExtend ext)
+{
+ TCGv t;
+
+ if (reg_num == 0) {
+ return ctx->zero;
+ }
+
+ switch (ext) {
+ case EXT_NONE:
+ return cpu_gpr[reg_num];
+ case EXT_SIGN:
+ t = temp_new(ctx);
+ tcg_gen_ext32s_tl(t, cpu_gpr[reg_num]);
+ return t;
+ case EXT_ZERO:
+ t = temp_new(ctx);
+ tcg_gen_ext32u_tl(t, cpu_gpr[reg_num]);
+ return t;
+ }
+ g_assert_not_reached();
+}
+
+static TCGv gpr_dst(DisasContext *ctx, int reg_num)
+{
+ if (reg_num == 0 || ctx->dst_ext) {
+ return temp_new(ctx);
+ }
+ return cpu_gpr[reg_num];
+}
+
+static void gen_set_gpr(DisasContext *ctx, int reg_num, TCGv t)
+{
+ if (reg_num != 0) {
+ switch (ctx->dst_ext) {
+ case EXT_NONE:
+ return tcg_gen_mov_tl(cpu_gpr[reg_num], t);
+ case EXT_SIGN:
+ return tcg_gen_ext32s_tl(cpu_gpr[reg_num], t);
+ case EXT_ZERO:
+ return tcg_gen_ext32u_tl(cpu_gpr[reg_num], t);
+ }
+ }
+}
+
+#include "decode-insns.c.inc"
+
+/* fmt rd rj rk */
+static bool gen_r3(DisasContext *ctx, arg_fmt_rdrjrk *a,
+ DisasExtend src1_ext, DisasExtend src2_ext,
+ DisasExtend dst_ext, void (*func)(TCGv, TCGv, TCGv))
+{
+ ctx->dst_ext = dst_ext;
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv src1 = gpr_src(ctx, a->rj, src1_ext);
+ TCGv src2 = gpr_src(ctx, a->rk, src2_ext);
+
+ func(dest, src1, src2);
+
+ if (ctx->dst_ext) {
+ gen_set_gpr(ctx, a->rd, dest);
+ }
+ return true;
+}
+
+#include "insn_trans/trans_arith.c"
+
static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
{
CPULoongArchState *env = cs->env_ptr;
@@ -91,6 +173,14 @@ static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
generate_exception(ctx, EXCP_INE);
}
+ ctx->dst_ext = EXT_NONE;
+
+ for (int i = ctx->ntemp - 1; i >= 0; --i) {
+ tcg_temp_free(ctx->temp[i]);
+ ctx->temp[i] = NULL;
+ }
+ ctx->ntemp = 0;
+
ctx->base.pc_next += 4;
}
diff --git a/target/loongarch/translate.h b/target/loongarch/translate.h
index dff7d79..f064fdd 100644
--- a/target/loongarch/translate.h
+++ b/target/loongarch/translate.h
@@ -11,11 +11,31 @@
#include "exec/translator.h"
+#define TRANS(NAME, FUNC, ...) \
+ static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+ { return FUNC(ctx, a, __VA_ARGS__); }
+
+/*
+ * If an operation is being performed on less than TARGET_LONG_BITS,
+ * it may require the inputs to be sign- or zero-extended; which will
+ * depend on the exact operation being performed.
+ */
+typedef enum {
+ EXT_NONE,
+ EXT_SIGN,
+ EXT_ZERO,
+} DisasExtend;
+
typedef struct DisasContext {
DisasContextBase base;
target_ulong page_start;
uint32_t opcode;
int mem_idx;
+ TCGv zero;
+ DisasExtend dst_ext;
+ /* Space for 3 operands plus 1 extra for address computation. */
+ TCGv temp[4];
+ uint8_t ntemp;
} DisasContext;
void generate_exception(DisasContext *ctx, int excp);
--
1.8.3.1
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v3 05/19] target/loongarch: Add fixed point shift instruction translation
2021-08-27 7:14 [PATCH v3 00/19] Add LoongArch linux-user emulation support Song Gao
` (3 preceding siblings ...)
2021-08-27 7:14 ` [PATCH v3 04/19] target/loongarch: Add fixed point arithmetic instruction translation Song Gao
@ 2021-08-27 7:14 ` Song Gao
2021-08-27 7:14 ` [PATCH v3 06/19] target/loongarch: Add fixed point bit " Song Gao
` (13 subsequent siblings)
18 siblings, 0 replies; 22+ messages in thread
From: Song Gao @ 2021-08-27 7:14 UTC (permalink / raw)
To: qemu-devel
Cc: peter.maydell, thuth, chenhuacai, richard.henderson, f4bug,
maobibo, laurent, yangxiaojuan, alistair.francis, pbonzini,
alex.bennee
This patch implement fixed point shift instruction translation.
This includes:
- SLL.W, SRL.W, SRA.W, ROTR.W
- SLLI.W, SRLI.W, SRAI.W, ROTRI.W
- SLL.D, SRL.D, SRA.D, ROTR.D
- SLLI.D, SRLI.D, SRAI.D, ROTRI.D
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
target/loongarch/insn_trans/trans_shift.c | 154 ++++++++++++++++++++++++++++++
target/loongarch/insns.decode | 26 +++++
target/loongarch/translate.c | 1 +
3 files changed, 181 insertions(+)
create mode 100644 target/loongarch/insn_trans/trans_shift.c
diff --git a/target/loongarch/insn_trans/trans_shift.c b/target/loongarch/insn_trans/trans_shift.c
new file mode 100644
index 0000000..5fa1162
--- /dev/null
+++ b/target/loongarch/insn_trans/trans_shift.c
@@ -0,0 +1,154 @@
+/*
+ * LoongArch translate functions
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+static bool gen_r2_ui5(DisasContext *ctx, arg_slli_w *a,
+ void(*func)(TCGv, TCGv, TCGv))
+{
+ ctx->dst_ext = EXT_SIGN;
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_ZERO);
+ TCGv src2 = tcg_constant_tl(a->ui5);
+
+ TCGv t0 = temp_new(ctx);
+
+ tcg_gen_andi_tl(t0, src2, 0x1f);
+ func(dest, src1, t0);
+ gen_set_gpr(ctx, a->rd, dest);
+
+ return true;
+}
+
+static bool gen_r2_ui6(DisasContext *ctx, arg_slli_d *a,
+ void(*func)(TCGv, TCGv, TCGv))
+{
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv src2 = tcg_constant_tl(a->ui6);
+
+ TCGv t0 = temp_new(ctx);
+
+ tcg_gen_andi_tl(t0, src2, 0x7f);
+ func(dest, src1, t0);
+
+ return true;
+}
+
+static void gen_sll_w(TCGv dest, TCGv src1, TCGv src2)
+{
+ TCGv t0 = tcg_temp_new();
+
+ tcg_gen_andi_tl(t0, src2, 0x1f);
+ tcg_gen_shl_tl(dest, src1, t0);
+ tcg_temp_free(t0);
+}
+
+static void gen_srl_w(TCGv dest, TCGv src1, TCGv src2)
+{
+ TCGv t0 = tcg_temp_new();
+ tcg_gen_andi_tl(t0, src2, 0x1f);
+ tcg_gen_shr_tl(dest, src1, t0);
+ tcg_temp_free(t0);
+}
+
+static void gen_sra_w(TCGv dest, TCGv src1, TCGv src2)
+{
+ TCGv t0 = tcg_temp_new();
+ tcg_gen_andi_tl(t0, src2, 0x1f);
+ tcg_gen_sar_tl(dest, src1, t0);
+ tcg_temp_free(t0);
+}
+
+static void gen_sll_d(TCGv dest, TCGv src1, TCGv src2)
+{
+ TCGv t0 = tcg_temp_new();
+ tcg_gen_andi_tl(t0, src2, 0x3f);
+ tcg_gen_shl_tl(dest, src1, t0);
+ tcg_temp_free(t0);
+}
+
+static void gen_srl_d(TCGv dest, TCGv src1, TCGv src2)
+{
+ TCGv t0 = tcg_temp_new();
+ tcg_gen_andi_tl(t0, src2, 0x3f);
+ tcg_gen_shr_tl(dest, src1, t0);
+ tcg_temp_free(t0);
+}
+
+static void gen_sra_d(TCGv dest, TCGv src1, TCGv src2)
+{
+ TCGv t0 = tcg_temp_new();
+ tcg_gen_andi_tl(t0, src2, 0x3f);
+ tcg_gen_sar_tl(dest, src1, t0);
+ tcg_temp_free(t0);
+}
+
+static void gen_rotr_w(TCGv dest, TCGv src1, TCGv src2)
+{
+ TCGv_i32 t1 = tcg_temp_new_i32();
+ TCGv_i32 t2 = tcg_temp_new_i32();
+ TCGv t0 = tcg_temp_new();
+
+ tcg_gen_andi_tl(t0, src2, 0x1f);
+
+ tcg_gen_trunc_tl_i32(t1, src1);
+ tcg_gen_trunc_tl_i32(t2, t0);
+
+ tcg_gen_rotr_i32(t1, t1, t2);
+ tcg_gen_ext_i32_tl(dest, t1);
+
+ tcg_temp_free_i32(t1);
+ tcg_temp_free_i32(t2);
+ tcg_temp_free(t0);
+}
+
+static void gen_rotr_d(TCGv dest, TCGv src1, TCGv src2)
+{
+ TCGv t0 = tcg_temp_new();
+ tcg_gen_andi_tl(t0, src2, 0x3f);
+ tcg_gen_rotr_tl(dest, src1, t0);
+ tcg_temp_free(t0);
+}
+
+static void gen_rotri_w(TCGv dest, TCGv src1, TCGv src2)
+{
+ TCGv_i32 t1 = tcg_temp_new_i32();
+ TCGv_i32 t2 = tcg_temp_new_i32();
+
+ tcg_gen_trunc_tl_i32(t1, src1);
+ tcg_gen_trunc_tl_i32(t2, src2);
+ tcg_gen_rotr_i32(t1, t1, t2);
+ tcg_gen_ext_i32_tl(dest, t1);
+
+ tcg_temp_free_i32(t1);
+ tcg_temp_free_i32(t2);
+}
+
+static bool trans_srai_w(DisasContext *ctx, arg_srai_w *a)
+{
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_ZERO);
+
+ tcg_gen_sextract_tl(dest, src1, a->ui5, 32 - a->ui5);
+ return true;
+}
+
+TRANS(sll_w, gen_r3, EXT_ZERO, EXT_NONE, EXT_SIGN, gen_sll_w)
+TRANS(srl_w, gen_r3, EXT_ZERO, EXT_NONE, EXT_SIGN, gen_srl_w)
+TRANS(sra_w, gen_r3, EXT_ZERO, EXT_NONE, EXT_SIGN, gen_sra_w)
+TRANS(sll_d, gen_r3, EXT_NONE, EXT_NONE, EXT_NONE, gen_sll_d)
+TRANS(srl_d, gen_r3, EXT_NONE, EXT_NONE, EXT_NONE, gen_srl_d)
+TRANS(sra_d, gen_r3, EXT_NONE, EXT_NONE, EXT_NONE, gen_sra_d)
+TRANS(rotr_w, gen_r3, EXT_ZERO, EXT_NONE, EXT_SIGN, gen_rotr_w)
+TRANS(rotr_d, gen_r3, EXT_NONE, EXT_NONE, EXT_NONE, gen_rotr_d)
+TRANS(slli_w, gen_r2_ui5, tcg_gen_shl_tl)
+TRANS(slli_d, gen_r2_ui6, tcg_gen_shl_tl)
+TRANS(srli_w, gen_r2_ui5, tcg_gen_shr_tl)
+TRANS(srli_d, gen_r2_ui6, tcg_gen_shr_tl)
+TRANS(srai_d, gen_r2_ui6, tcg_gen_sar_tl)
+TRANS(rotri_w, gen_r2_ui5, gen_rotri_w)
+TRANS(rotri_d, gen_r2_ui6, tcg_gen_rotr_tl)
diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode
index 1e0b755..9302576 100644
--- a/target/loongarch/insns.decode
+++ b/target/loongarch/insns.decode
@@ -17,6 +17,8 @@
%ui12 10:12
%si16 10:s16
%si20 5:s20
+%ui5 10:5
+%ui6 10:6
#
# Argument sets
@@ -27,6 +29,8 @@
&fmt_rdrjsi16 rd rj si16
&fmt_rdrjui12 rd rj ui12
&fmt_rdsi20 rd si20
+&fmt_rdrjui5 rd rj ui5
+&fmt_rdrjui6 rd rj ui6
#
# Formats
@@ -37,6 +41,8 @@
@fmt_rdrjrksa2 .... ........ ... .. ..... ..... ..... &fmt_rdrjrksa2 %rd %rj %rk %sa2
@fmt_rdrjsi16 .... .. ................ ..... ..... &fmt_rdrjsi16 %rd %rj %si16
@fmt_rdsi20 .... ... .................... ..... &fmt_rdsi20 %rd %si20
+@fmt_rdrjui5 .... ........ ..... ..... ..... ..... &fmt_rdrjui5 %rd %rj %ui5
+@fmt_rdrjui6 .... ........ .... ...... ..... ..... &fmt_rdrjui6 %rd %rj %ui6
#
# Fixed point arithmetic operation instruction
@@ -87,3 +93,23 @@ addu16i_d 0001 00 ................ ..... ..... @fmt_rdrjsi16
andi 0000 001101 ............ ..... ..... @fmt_rdrjui12
ori 0000 001110 ............ ..... ..... @fmt_rdrjui12
xori 0000 001111 ............ ..... ..... @fmt_rdrjui12
+
+#
+# Fixed point shift operation instruction
+#
+sll_w 0000 00000001 01110 ..... ..... ..... @fmt_rdrjrk
+srl_w 0000 00000001 01111 ..... ..... ..... @fmt_rdrjrk
+sra_w 0000 00000001 10000 ..... ..... ..... @fmt_rdrjrk
+sll_d 0000 00000001 10001 ..... ..... ..... @fmt_rdrjrk
+srl_d 0000 00000001 10010 ..... ..... ..... @fmt_rdrjrk
+sra_d 0000 00000001 10011 ..... ..... ..... @fmt_rdrjrk
+rotr_w 0000 00000001 10110 ..... ..... ..... @fmt_rdrjrk
+rotr_d 0000 00000001 10111 ..... ..... ..... @fmt_rdrjrk
+slli_w 0000 00000100 00001 ..... ..... ..... @fmt_rdrjui5
+slli_d 0000 00000100 0001 ...... ..... ..... @fmt_rdrjui6
+srli_w 0000 00000100 01001 ..... ..... ..... @fmt_rdrjui5
+srli_d 0000 00000100 0101 ...... ..... ..... @fmt_rdrjui6
+srai_w 0000 00000100 10001 ..... ..... ..... @fmt_rdrjui5
+srai_d 0000 00000100 1001 ...... ..... ..... @fmt_rdrjui6
+rotri_w 0000 00000100 11001 ..... ..... ..... @fmt_rdrjui5
+rotri_d 0000 00000100 1101 ...... ..... ..... @fmt_rdrjui6
diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c
index 1806d2c..e9cccca 100644
--- a/target/loongarch/translate.c
+++ b/target/loongarch/translate.c
@@ -159,6 +159,7 @@ static bool gen_r3(DisasContext *ctx, arg_fmt_rdrjrk *a,
}
#include "insn_trans/trans_arith.c"
+#include "insn_trans/trans_shift.c"
static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
{
--
1.8.3.1
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v3 06/19] target/loongarch: Add fixed point bit instruction translation
2021-08-27 7:14 [PATCH v3 00/19] Add LoongArch linux-user emulation support Song Gao
` (4 preceding siblings ...)
2021-08-27 7:14 ` [PATCH v3 05/19] target/loongarch: Add fixed point shift " Song Gao
@ 2021-08-27 7:14 ` Song Gao
2021-08-27 7:14 ` [PATCH v3 07/19] target/loongarch: Add fixed point load/store " Song Gao
` (12 subsequent siblings)
18 siblings, 0 replies; 22+ messages in thread
From: Song Gao @ 2021-08-27 7:14 UTC (permalink / raw)
To: qemu-devel
Cc: peter.maydell, thuth, chenhuacai, richard.henderson, f4bug,
maobibo, laurent, yangxiaojuan, alistair.francis, pbonzini,
alex.bennee
This patch implement fixed point bit instruction translation.
This includes:
- EXT.W.{B/H}
- CL{O/Z}.{W/D}, CT{O/Z}.{W/D}
- BYTEPICK.{W/D}
- REVB.{2H/4H/2W/D}
- REVH.{2W/D}
- BITREV.{4B/8B}, BITREV.{W/D}
- BSTRINS.{W/D}, BSTRPICK.{W/D}
- MASKEQZ, MASKNEZ
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
target/loongarch/helper.h | 4 +
target/loongarch/insn_trans/trans_bit.c | 297 ++++++++++++++++++++++++++++++++
target/loongarch/insns.decode | 45 +++++
target/loongarch/op_helper.c | 22 +++
target/loongarch/translate.c | 1 +
5 files changed, 369 insertions(+)
create mode 100644 target/loongarch/insn_trans/trans_bit.c
diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h
index 09bfcfd..e39574e 100644
--- a/target/loongarch/helper.h
+++ b/target/loongarch/helper.h
@@ -7,3 +7,7 @@
*/
DEF_HELPER_2(raise_exception, noreturn, env, i32)
+
+DEF_HELPER_FLAGS_1(bitrev_w, TCG_CALL_NO_RWG_SE, tl, tl)
+DEF_HELPER_FLAGS_1(bitrev_d, TCG_CALL_NO_RWG_SE, tl, tl)
+DEF_HELPER_FLAGS_1(bitswap, TCG_CALL_NO_RWG_SE, tl, tl)
diff --git a/target/loongarch/insn_trans/trans_bit.c b/target/loongarch/insn_trans/trans_bit.c
new file mode 100644
index 0000000..ff29623
--- /dev/null
+++ b/target/loongarch/insn_trans/trans_bit.c
@@ -0,0 +1,297 @@
+/*
+ * LoongArch translate functions
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+/* fmt rd rj */
+static bool gen_r2(DisasContext *ctx, arg_fmt_rdrj *a,
+ DisasExtend src_ext, DisasExtend dst_ext,
+ void (*func)(TCGv, TCGv))
+{
+ ctx->dst_ext = dst_ext;
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv src1 = gpr_src(ctx, a->rj, src_ext);
+
+ func(dest, src1);
+ if (ctx->dst_ext) {
+ gen_set_gpr(ctx, a->rd, dest);
+ }
+ return true;
+}
+
+static bool gen_bpw(DisasContext *ctx, arg_fmt_rdrjrksa2 *a,
+ void (*func)(TCGv, TCGv, TCGv, target_long))
+{
+ ctx->dst_ext = EXT_SIGN;
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE);
+
+ func(dest, src1, src2, a->sa2);
+
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool gen_bpd(DisasContext *ctx, arg_fmt_rdrjrksa3 *a,
+ void (*func)(TCGv, TCGv, TCGv, target_long))
+{
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE);
+
+ func(dest, src1, src2, a->sa3);
+ return true;
+}
+
+static bool gen_r2_bw2(DisasContext *ctx, arg_fmt_rdrjmsbwlsbw *a,
+ void (*func)(TCGv, TCGv, target_long, target_long))
+{
+ ctx->dst_ext = EXT_SIGN;
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+
+ if (a->lsbw > a->msbw) {
+ return false;
+ }
+
+ func(dest, src1, a->msbw, a->lsbw);
+
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool gen_r2_bd2(DisasContext *ctx, arg_fmt_rdrjmsbdlsbd *a,
+ DisasExtend dst_ext,
+ void (*func)(TCGv, TCGv, target_long, target_long))
+{
+ ctx->dst_ext = dst_ext;
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+
+ if (a->lsbd > a->msbd) {
+ return false;
+ }
+
+ func(dest, src1, a->msbd, a->lsbd);
+
+ if (ctx->dst_ext) {
+ gen_set_gpr(ctx, a->rd, dest);
+ }
+ return true;
+}
+
+static void gen_clz_w(TCGv dest, TCGv src1)
+{
+ tcg_gen_ext32u_tl(dest, src1);
+ tcg_gen_clzi_tl(dest, dest, TARGET_LONG_BITS);
+ tcg_gen_subi_tl(dest, dest, TARGET_LONG_BITS - 32);
+}
+
+static void gen_clo_w(TCGv dest, TCGv src1)
+{
+ tcg_gen_not_tl(dest, src1);
+ gen_clz_w(dest, dest);
+}
+
+static void gen_ctz_w(TCGv dest, TCGv src1)
+{
+ tcg_gen_ori_tl(dest, src1, (target_ulong)MAKE_64BIT_MASK(32, 32));
+ tcg_gen_ctzi_tl(dest, dest, 64);
+}
+
+static void gen_cto_w(TCGv dest, TCGv src1)
+{
+ tcg_gen_not_tl(dest, src1);
+ gen_ctz_w(dest, dest);
+}
+
+static void gen_clz_d(TCGv dest, TCGv src1)
+{
+ tcg_gen_clzi_i64(dest, src1, TARGET_LONG_BITS);
+}
+
+static void gen_clo_d(TCGv dest, TCGv src1)
+{
+ tcg_gen_not_tl(dest, src1);
+ gen_clz_d(dest, dest);
+}
+
+static void gen_ctz_d(TCGv dest, TCGv src1)
+{
+ tcg_gen_ctzi_tl(dest, src1, TARGET_LONG_BITS);
+}
+
+static void gen_cto_d(TCGv dest, TCGv src1)
+{
+ tcg_gen_not_tl(dest, src1);
+ gen_ctz_d(dest, dest);
+}
+
+static void gen_revb_2w(TCGv dest, TCGv src1)
+{
+ tcg_gen_bswap64_i64(dest, src1);
+ tcg_gen_rotri_i64(dest, dest, 32);
+}
+
+static bool trans_revb_2h(DisasContext *ctx, arg_revb_2h *a)
+{
+ ctx->dst_ext = EXT_SIGN;
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv mask = tcg_constant_tl(0x00FF00FF);
+ TCGv t0 = tcg_temp_new();
+ TCGv t1 = tcg_temp_new();
+
+ tcg_gen_shri_tl(t0, src1, 8);
+ tcg_gen_and_tl(t0, t0, mask);
+ tcg_gen_and_tl(t1, src1, mask);
+ tcg_gen_shli_tl(t1, t1, 8);
+ tcg_gen_or_tl(dest, t0, t1);
+ gen_set_gpr(ctx, a->rd, dest);
+
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+ return true;
+}
+
+static bool trans_revb_4h(DisasContext *ctx, arg_revb_4h *a)
+{
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv mask = tcg_constant_tl(0x00FF00FF00FF00FFULL);
+ TCGv t0 = tcg_temp_new();
+ TCGv t1 = tcg_temp_new();
+
+ tcg_gen_shri_tl(t0, src1, 8);
+ tcg_gen_and_tl(t0, t0, mask);
+ tcg_gen_and_tl(t1, src1, mask);
+ tcg_gen_shli_tl(t1, t1, 8);
+ tcg_gen_or_tl(dest, t0, t1);
+
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+ return true;
+}
+
+static bool trans_revh_2w(DisasContext *ctx, arg_revh_2w *a)
+{
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv_i64 t0 = tcg_temp_new_i64();
+ TCGv_i64 t1 = tcg_temp_new_i64();
+ TCGv_i64 mask = tcg_constant_i64(0x0000ffff0000ffffull);
+
+ tcg_gen_shri_i64(t0, src1, 16);
+ tcg_gen_and_i64(t1, src1, mask);
+ tcg_gen_and_i64(t0, t0, mask);
+ tcg_gen_shli_i64(t1, t1, 16);
+ tcg_gen_or_i64(dest, t1, t0);
+
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(t1);
+
+ return true;
+}
+
+static bool trans_revh_d(DisasContext *ctx, arg_revh_d *a)
+{
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv t0 = tcg_temp_new();
+ TCGv t1 = tcg_temp_new();
+ TCGv mask = tcg_constant_tl(0x0000FFFF0000FFFFULL);
+
+ tcg_gen_shri_tl(t1, src1, 16);
+ tcg_gen_and_tl(t1, t1, mask);
+ tcg_gen_and_tl(t0, src1, mask);
+ tcg_gen_shli_tl(t0, t0, 16);
+ tcg_gen_or_tl(t0, t0, t1);
+ tcg_gen_shri_tl(t1, t0, 32);
+ tcg_gen_shli_tl(t0, t0, 32);
+ tcg_gen_or_tl(dest, t0, t1);
+
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+
+ return true;
+}
+
+static void gen_maskeqz(TCGv dest, TCGv src1, TCGv src2)
+{
+ TCGv cond1 = tcg_constant_tl(0);
+
+ tcg_gen_movcond_tl(TCG_COND_EQ, dest, src2, cond1, cond1, src1);
+}
+
+static void gen_masknez(TCGv dest, TCGv src1, TCGv src2)
+{
+ TCGv cond1 = tcg_constant_tl(0);
+
+ tcg_gen_movcond_tl(TCG_COND_NE, dest, src2, cond1, cond1, src1);
+}
+
+static void gen_bytepick_w(TCGv dest, TCGv src1, TCGv src2, target_long sa2)
+{
+ tcg_gen_concat_tl_i64(dest, src1, src2);
+ tcg_gen_sextract_i64(dest, dest, (32 - sa2 * 8), 32);
+}
+
+static void gen_bytepick_d(TCGv dest, TCGv src1, TCGv src2, target_long sa3)
+{
+ tcg_gen_extract2_i64(dest, src1, src2, (64 - sa3 * 8));
+}
+
+static void gen_bstrins_w(TCGv dest, TCGv src1,
+ target_long msb, target_long lsb)
+{
+ tcg_gen_deposit_tl(dest, dest, src1, lsb, msb - lsb + 1);
+ tcg_gen_ext32s_tl(dest, dest);
+}
+
+static void gen_bstrpick_w(TCGv dest, TCGv src1,
+ target_long msb, target_long lsb)
+{
+ tcg_gen_extract_tl(dest, src1, lsb, msb - lsb + 1);
+ tcg_gen_ext32s_tl(dest, dest);
+}
+
+static void gen_bstrins_d(TCGv dest, TCGv src1,
+ target_long msb, target_long lsb)
+{
+ tcg_gen_deposit_tl(dest, dest, src1, lsb, msb - lsb + 1);
+}
+
+static void gen_bstrpick_d(TCGv dest, TCGv src1,
+ target_long msb, target_long lsb)
+{
+ tcg_gen_extract_tl(dest, src1, lsb, msb - lsb + 1);
+}
+
+TRANS(ext_w_h, gen_r2, EXT_NONE, EXT_NONE, tcg_gen_ext16s_tl)
+TRANS(ext_w_b, gen_r2, EXT_NONE, EXT_NONE, tcg_gen_ext8s_tl)
+TRANS(clo_w, gen_r2, EXT_NONE, EXT_NONE, gen_clo_w)
+TRANS(clz_w, gen_r2, EXT_ZERO, EXT_NONE, gen_clz_w)
+TRANS(cto_w, gen_r2, EXT_NONE, EXT_NONE, gen_cto_w)
+TRANS(ctz_w, gen_r2, EXT_NONE, EXT_NONE, gen_ctz_w)
+TRANS(clo_d, gen_r2, EXT_NONE, EXT_NONE, gen_clo_d)
+TRANS(clz_d, gen_r2, EXT_NONE, EXT_NONE, gen_clz_d)
+TRANS(cto_d, gen_r2, EXT_NONE, EXT_NONE, gen_cto_d)
+TRANS(ctz_d, gen_r2, EXT_NONE, EXT_NONE, gen_ctz_d)
+TRANS(revb_2w, gen_r2, EXT_NONE, EXT_NONE, gen_revb_2w)
+TRANS(revb_d, gen_r2, EXT_NONE, EXT_NONE, tcg_gen_bswap64_i64)
+TRANS(bitrev_4b, gen_r2, EXT_ZERO, EXT_SIGN, gen_helper_bitswap)
+TRANS(bitrev_8b, gen_r2, EXT_NONE, EXT_NONE, gen_helper_bitswap)
+TRANS(bitrev_w, gen_r2, EXT_NONE, EXT_SIGN, gen_helper_bitrev_w)
+TRANS(bitrev_d, gen_r2, EXT_NONE, EXT_NONE, gen_helper_bitrev_d)
+TRANS(maskeqz, gen_r3, EXT_NONE, EXT_NONE, EXT_NONE, gen_maskeqz)
+TRANS(masknez, gen_r3, EXT_NONE, EXT_NONE, EXT_NONE, gen_masknez)
+TRANS(bytepick_w, gen_bpw, gen_bytepick_w)
+TRANS(bytepick_d, gen_bpd, gen_bytepick_d)
+TRANS(bstrins_w, gen_r2_bw2, gen_bstrins_w)
+TRANS(bstrpick_w, gen_r2_bw2, gen_bstrpick_w)
+TRANS(bstrins_d, gen_r2_bd2, EXT_NONE, gen_bstrins_d)
+TRANS(bstrpick_d, gen_r2_bd2, EXT_ZERO, gen_bstrpick_d)
diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode
index 9302576..ec599a9 100644
--- a/target/loongarch/insns.decode
+++ b/target/loongarch/insns.decode
@@ -13,12 +13,17 @@
%rj 5:5
%rk 10:5
%sa2 15:2
+%sa3 15:3
%si12 10:s12
%ui12 10:12
%si16 10:s16
%si20 5:s20
%ui5 10:5
%ui6 10:6
+%msbw 16:5
+%lsbw 10:5
+%msbd 16:6
+%lsbd 10:6
#
# Argument sets
@@ -31,6 +36,10 @@
&fmt_rdsi20 rd si20
&fmt_rdrjui5 rd rj ui5
&fmt_rdrjui6 rd rj ui6
+&fmt_rdrj rd rj
+&fmt_rdrjrksa3 rd rj rk sa3
+&fmt_rdrjmsbwlsbw rd rj msbw lsbw
+&fmt_rdrjmsbdlsbd rd rj msbd lsbd
#
# Formats
@@ -43,6 +52,10 @@
@fmt_rdsi20 .... ... .................... ..... &fmt_rdsi20 %rd %si20
@fmt_rdrjui5 .... ........ ..... ..... ..... ..... &fmt_rdrjui5 %rd %rj %ui5
@fmt_rdrjui6 .... ........ .... ...... ..... ..... &fmt_rdrjui6 %rd %rj %ui6
+@fmt_rdrj .... ........ ..... ..... ..... ..... &fmt_rdrj %rd %rj
+@fmt_rdrjmsbwlsbw .... ....... ..... . ..... ..... ..... &fmt_rdrjmsbwlsbw %rd %rj %msbw %lsbw
+@fmt_rdrjmsbdlsbd .... ...... ...... ...... ..... ..... &fmt_rdrjmsbdlsbd %rd %rj %msbd %lsbd
+@fmt_rdrjrksa3 .... ........ .. ... ..... ..... ..... &fmt_rdrjrksa3 %rd %rj %rk %sa3
#
# Fixed point arithmetic operation instruction
@@ -113,3 +126,35 @@ srai_w 0000 00000100 10001 ..... ..... ..... @fmt_rdrjui5
srai_d 0000 00000100 1001 ...... ..... ..... @fmt_rdrjui6
rotri_w 0000 00000100 11001 ..... ..... ..... @fmt_rdrjui5
rotri_d 0000 00000100 1101 ...... ..... ..... @fmt_rdrjui6
+
+#
+# Fixed point bit operation instruction
+#
+ext_w_h 0000 00000000 00000 10110 ..... ..... @fmt_rdrj
+ext_w_b 0000 00000000 00000 10111 ..... ..... @fmt_rdrj
+clo_w 0000 00000000 00000 00100 ..... ..... @fmt_rdrj
+clz_w 0000 00000000 00000 00101 ..... ..... @fmt_rdrj
+cto_w 0000 00000000 00000 00110 ..... ..... @fmt_rdrj
+ctz_w 0000 00000000 00000 00111 ..... ..... @fmt_rdrj
+clo_d 0000 00000000 00000 01000 ..... ..... @fmt_rdrj
+clz_d 0000 00000000 00000 01001 ..... ..... @fmt_rdrj
+cto_d 0000 00000000 00000 01010 ..... ..... @fmt_rdrj
+ctz_d 0000 00000000 00000 01011 ..... ..... @fmt_rdrj
+revb_2h 0000 00000000 00000 01100 ..... ..... @fmt_rdrj
+revb_4h 0000 00000000 00000 01101 ..... ..... @fmt_rdrj
+revb_2w 0000 00000000 00000 01110 ..... ..... @fmt_rdrj
+revb_d 0000 00000000 00000 01111 ..... ..... @fmt_rdrj
+revh_2w 0000 00000000 00000 10000 ..... ..... @fmt_rdrj
+revh_d 0000 00000000 00000 10001 ..... ..... @fmt_rdrj
+bitrev_4b 0000 00000000 00000 10010 ..... ..... @fmt_rdrj
+bitrev_8b 0000 00000000 00000 10011 ..... ..... @fmt_rdrj
+bitrev_w 0000 00000000 00000 10100 ..... ..... @fmt_rdrj
+bitrev_d 0000 00000000 00000 10101 ..... ..... @fmt_rdrj
+bytepick_w 0000 00000000 100 .. ..... ..... ..... @fmt_rdrjrksa2
+bytepick_d 0000 00000000 11 ... ..... ..... ..... @fmt_rdrjrksa3
+maskeqz 0000 00000001 00110 ..... ..... ..... @fmt_rdrjrk
+masknez 0000 00000001 00111 ..... ..... ..... @fmt_rdrjrk
+bstrins_w 0000 0000011 ..... 0 ..... ..... ..... @fmt_rdrjmsbwlsbw
+bstrpick_w 0000 0000011 ..... 1 ..... ..... ..... @fmt_rdrjmsbwlsbw
+bstrins_d 0000 000010 ...... ...... ..... ..... @fmt_rdrjmsbdlsbd
+bstrpick_d 0000 000011 ...... ...... ..... ..... @fmt_rdrjmsbdlsbd
diff --git a/target/loongarch/op_helper.c b/target/loongarch/op_helper.c
index 4d10b03..ec04369 100644
--- a/target/loongarch/op_helper.c
+++ b/target/loongarch/op_helper.c
@@ -20,3 +20,25 @@ void helper_raise_exception(CPULoongArchState *env, uint32_t exception)
{
do_raise_exception(env, exception, GETPC());
}
+
+
+target_ulong helper_bitrev_w(target_ulong rj)
+{
+ return (int32_t)revbit32(rj);
+}
+
+target_ulong helper_bitrev_d(target_ulong rj)
+{
+ return revbit64(rj);
+}
+
+target_ulong helper_bitswap(target_ulong v)
+{
+ v = ((v >> 1) & (target_ulong)0x5555555555555555ULL) |
+ ((v & (target_ulong)0x5555555555555555ULL) << 1);
+ v = ((v >> 2) & (target_ulong)0x3333333333333333ULL) |
+ ((v & (target_ulong)0x3333333333333333ULL) << 2);
+ v = ((v >> 4) & (target_ulong)0x0F0F0F0F0F0F0F0FULL) |
+ ((v & (target_ulong)0x0F0F0F0F0F0F0F0FULL) << 4);
+ return v;
+}
diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c
index e9cccca..0f18d06 100644
--- a/target/loongarch/translate.c
+++ b/target/loongarch/translate.c
@@ -160,6 +160,7 @@ static bool gen_r3(DisasContext *ctx, arg_fmt_rdrjrk *a,
#include "insn_trans/trans_arith.c"
#include "insn_trans/trans_shift.c"
+#include "insn_trans/trans_bit.c"
static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
{
--
1.8.3.1
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v3 07/19] target/loongarch: Add fixed point load/store instruction translation
2021-08-27 7:14 [PATCH v3 00/19] Add LoongArch linux-user emulation support Song Gao
` (5 preceding siblings ...)
2021-08-27 7:14 ` [PATCH v3 06/19] target/loongarch: Add fixed point bit " Song Gao
@ 2021-08-27 7:14 ` Song Gao
2021-08-27 7:14 ` [PATCH v3 08/19] target/loongarch: Add fixed point atomic " Song Gao
` (11 subsequent siblings)
18 siblings, 0 replies; 22+ messages in thread
From: Song Gao @ 2021-08-27 7:14 UTC (permalink / raw)
To: qemu-devel
Cc: peter.maydell, thuth, chenhuacai, richard.henderson, f4bug,
maobibo, laurent, yangxiaojuan, alistair.francis, pbonzini,
alex.bennee
This patch implement fixed point load/store instruction translation.
This includes:
- LD.{B[U]/H[U]/W[U]/D}, ST.{B/H/W/D}
- LDX.{B[U]/H[U]/W[U]/D}, STX.{B/H/W/D}
- LDPTR.{W/D}, STPTR.{W/D}
- PRELD
- LD{GT/LE}.{B/H/W/D}, ST{GT/LE}.{B/H/W/D}
- DBAR, IBAR
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
target/loongarch/helper.h | 3 +
target/loongarch/insn_trans/trans_memory.c | 263 +++++++++++++++++++++++++++++
target/loongarch/insns.decode | 58 +++++++
target/loongarch/op_helper.c | 15 ++
target/loongarch/translate.c | 30 ++++
5 files changed, 369 insertions(+)
create mode 100644 target/loongarch/insn_trans/trans_memory.c
diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h
index e39574e..09b5a3d 100644
--- a/target/loongarch/helper.h
+++ b/target/loongarch/helper.h
@@ -11,3 +11,6 @@ DEF_HELPER_2(raise_exception, noreturn, env, i32)
DEF_HELPER_FLAGS_1(bitrev_w, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_1(bitrev_d, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_1(bitswap, TCG_CALL_NO_RWG_SE, tl, tl)
+
+DEF_HELPER_3(asrtle_d, void, env, tl, tl)
+DEF_HELPER_3(asrtgt_d, void, env, tl, tl)
diff --git a/target/loongarch/insn_trans/trans_memory.c b/target/loongarch/insn_trans/trans_memory.c
new file mode 100644
index 0000000..afc5d67
--- /dev/null
+++ b/target/loongarch/insn_trans/trans_memory.c
@@ -0,0 +1,263 @@
+/*
+ * LoongArch translate functions
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+static bool gen_load(DisasContext *ctx, arg_fmt_rdrjsi12 *a,
+ DisasExtend dst_ext, MemOp mop)
+{
+ ctx->dst_ext = dst_ext;
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv addr = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv temp = NULL;
+
+ if (a->si12) {
+ temp = tcg_temp_new();
+ tcg_gen_addi_tl(temp, addr, a->si12);
+ addr = temp;
+ }
+
+ tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, mop);
+
+ if (ctx->dst_ext) {
+ gen_set_gpr(ctx, a->rd, dest);
+ }
+
+ if (temp) {
+ tcg_temp_free(temp);
+ }
+ return true;
+}
+
+static bool gen_store(DisasContext *ctx, arg_fmt_rdrjsi12 *a, MemOp mop)
+{
+ TCGv data = gpr_src(ctx, a->rd, EXT_NONE);
+ TCGv addr = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv temp = NULL;
+
+ if (a->si12) {
+ temp = tcg_temp_new();
+ tcg_gen_addi_tl(temp, addr, a->si12);
+ addr = temp;
+ }
+
+ tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, mop);
+
+ if (temp) {
+ tcg_temp_free(temp);
+ }
+ return true;
+}
+
+static bool gen_loadx(DisasContext *ctx, arg_fmt_rdrjrk *a,
+ DisasExtend dst_ext, MemOp mop)
+{
+ ctx->dst_ext = dst_ext;
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE);
+ TCGv addr = tcg_temp_new();
+
+ tcg_gen_add_tl(addr, src1, src2);
+ tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, mop);
+
+ if (ctx->dst_ext) {
+ gen_set_gpr(ctx, a->rd, dest);
+ }
+
+ tcg_temp_free(addr);
+ return true;
+}
+
+static bool gen_storex(DisasContext *ctx, arg_fmt_rdrjrk *a, MemOp mop)
+{
+ TCGv data = gpr_src(ctx, a->rd, EXT_NONE);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE);
+ TCGv addr = tcg_temp_new();
+
+ tcg_gen_add_tl(addr, src1, src2);
+ tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, mop);
+
+ tcg_temp_free(addr);
+ return true;
+}
+
+static bool gen_load_gt(DisasContext *ctx, arg_fmt_rdrjrk *a,
+ DisasExtend dst_ext, MemOp mop)
+{
+ ctx->dst_ext = dst_ext;
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE);
+ TCGv addr = tcg_temp_new();
+
+ gen_helper_asrtgt_d(cpu_env, src1, src2);
+ tcg_gen_add_tl(addr, src1, src2);
+ tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, mop);
+
+ if (ctx->dst_ext) {
+ gen_set_gpr(ctx, a->rd, dest);
+ }
+ tcg_temp_free(addr);
+ return true;
+}
+
+static bool gen_load_le(DisasContext *ctx, arg_fmt_rdrjrk *a,
+ DisasExtend dst_ext, MemOp mop)
+{
+ ctx->dst_ext = dst_ext;
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE);
+ TCGv addr = tcg_temp_new();
+
+ gen_helper_asrtle_d(cpu_env, src1, src2);
+ tcg_gen_add_tl(addr, src1, src2);
+ tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, mop);
+
+ if (ctx->dst_ext) {
+ gen_set_gpr(ctx, a->rd, dest);
+ }
+ tcg_temp_free(addr);
+ return true;
+}
+
+static bool gen_store_gt(DisasContext *ctx, arg_fmt_rdrjrk *a, MemOp mop)
+{
+ TCGv data = gpr_src(ctx, a->rd, EXT_NONE);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE);
+ TCGv addr = tcg_temp_new();
+
+ gen_helper_asrtgt_d(cpu_env, src1, src2);
+ tcg_gen_add_tl(addr, src1, src2);
+ tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, mop);
+
+ tcg_temp_free(addr);
+ return true;
+}
+
+static bool gen_store_le(DisasContext *ctx, arg_fmt_rdrjrk *a, MemOp mop)
+{
+ TCGv data = gpr_src(ctx, a->rd, EXT_NONE);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE);
+ TCGv addr = tcg_temp_new();
+
+ gen_helper_asrtle_d(cpu_env, src1, src2);
+ tcg_gen_add_tl(addr, src1, src2);
+ tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, mop);
+
+ tcg_temp_free(addr);
+ return true;
+}
+
+static bool trans_preld(DisasContext *ctx, arg_preld *a)
+{
+ return true;
+}
+
+static bool trans_dbar(DisasContext *ctx, arg_dbar * a)
+{
+ gen_loongarch_sync(a->whint);
+ return true;
+}
+
+static bool trans_ibar(DisasContext *ctx, arg_ibar *a)
+{
+ ctx->base.is_jmp = DISAS_STOP;
+ return true;
+}
+
+static bool gen_ldptr(DisasContext *ctx, arg_fmt_rdrjsi14 *a,
+ DisasExtend dst_ext, MemOp mop)
+{
+ ctx->dst_ext = dst_ext;
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv addr = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv temp = NULL;
+
+ if (a->si14) {
+ temp = tcg_temp_new();
+ tcg_gen_addi_tl(temp, addr, a->si14 << 2);
+ addr = temp;
+ }
+
+ tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, mop);
+
+ if (ctx->dst_ext) {
+ gen_set_gpr(ctx, a->rd, dest);
+ }
+
+ if (temp) {
+ tcg_temp_free(temp);
+ }
+ return true;
+}
+
+static bool gen_stptr(DisasContext *ctx, arg_fmt_rdrjsi14 *a, MemOp mop)
+{
+ TCGv data = gpr_src(ctx, a->rd, EXT_NONE);
+ TCGv addr = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv temp = NULL;
+
+ if (a->si14) {
+ temp = tcg_temp_new();
+ tcg_gen_addi_tl(temp, addr, a->si14 << 2);
+ addr = temp;
+ }
+
+ tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, mop);
+
+ if (temp) {
+ tcg_temp_free(temp);
+ }
+ return true;
+}
+
+TRANS(ld_b, gen_load, EXT_SIGN, MO_SB)
+TRANS(ld_h, gen_load, EXT_SIGN, MO_TESW)
+TRANS(ld_w, gen_load, EXT_SIGN, MO_TESL)
+TRANS(ld_d, gen_load, EXT_NONE, MO_TEQ)
+TRANS(st_b, gen_store, MO_SB)
+TRANS(st_h, gen_store, MO_TESW)
+TRANS(st_w, gen_store, MO_TESL)
+TRANS(st_d, gen_store, MO_TEQ)
+TRANS(ld_bu, gen_load, EXT_ZERO, MO_UB)
+TRANS(ld_hu, gen_load, EXT_ZERO, MO_TEUW)
+TRANS(ld_wu, gen_load, EXT_ZERO, MO_TEUL)
+TRANS(ldx_b, gen_loadx, EXT_SIGN, MO_SB)
+TRANS(ldx_h, gen_loadx, EXT_SIGN, MO_TESW)
+TRANS(ldx_w, gen_loadx, EXT_SIGN, MO_TESL)
+TRANS(ldx_d, gen_loadx, EXT_NONE, MO_TEQ)
+TRANS(stx_b, gen_storex, MO_SB)
+TRANS(stx_h, gen_storex, MO_TESW)
+TRANS(stx_w, gen_storex, MO_TESL)
+TRANS(stx_d, gen_storex, MO_TEQ)
+TRANS(ldx_bu, gen_loadx, EXT_ZERO, MO_UB)
+TRANS(ldx_hu, gen_loadx, EXT_ZERO, MO_TEUW)
+TRANS(ldx_wu, gen_loadx, EXT_ZERO, MO_TEUL)
+TRANS(ldptr_w, gen_ldptr, EXT_SIGN, MO_TESL)
+TRANS(stptr_w, gen_stptr, MO_TESL)
+TRANS(ldptr_d, gen_ldptr, EXT_NONE, MO_TEQ)
+TRANS(stptr_d, gen_stptr, MO_TEQ)
+TRANS(ldgt_b, gen_load_gt, EXT_SIGN, MO_SB)
+TRANS(ldgt_h, gen_load_gt, EXT_SIGN, MO_TESW)
+TRANS(ldgt_w, gen_load_gt, EXT_SIGN, MO_TESL)
+TRANS(ldgt_d, gen_load_gt, EXT_NONE, MO_TEQ)
+TRANS(ldle_b, gen_load_le, EXT_SIGN, MO_SB)
+TRANS(ldle_h, gen_load_le, EXT_SIGN, MO_TESW)
+TRANS(ldle_w, gen_load_le, EXT_SIGN, MO_TESL)
+TRANS(ldle_d, gen_load_le, EXT_NONE, MO_TEQ)
+TRANS(stgt_b, gen_store_gt, MO_SB)
+TRANS(stgt_h, gen_store_gt, MO_TESW)
+TRANS(stgt_w, gen_store_gt, MO_TESL)
+TRANS(stgt_d, gen_store_gt, MO_TEQ)
+TRANS(stle_b, gen_store_le, MO_SB)
+TRANS(stle_h, gen_store_le, MO_TESW)
+TRANS(stle_w, gen_store_le, MO_TESL)
+TRANS(stle_d, gen_store_le, MO_TEQ)
diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode
index ec599a9..08fd232 100644
--- a/target/loongarch/insns.decode
+++ b/target/loongarch/insns.decode
@@ -24,6 +24,9 @@
%lsbw 10:5
%msbd 16:6
%lsbd 10:6
+%si14 10:s14
+%hint 0:5
+%whint 0:15
#
# Argument sets
@@ -40,6 +43,9 @@
&fmt_rdrjrksa3 rd rj rk sa3
&fmt_rdrjmsbwlsbw rd rj msbw lsbw
&fmt_rdrjmsbdlsbd rd rj msbd lsbd
+&fmt_rdrjsi14 rd rj si14
+&fmt_hintrjsi12 hint rj si12
+&fmt_whint whint
#
# Formats
@@ -56,6 +62,9 @@
@fmt_rdrjmsbwlsbw .... ....... ..... . ..... ..... ..... &fmt_rdrjmsbwlsbw %rd %rj %msbw %lsbw
@fmt_rdrjmsbdlsbd .... ...... ...... ...... ..... ..... &fmt_rdrjmsbdlsbd %rd %rj %msbd %lsbd
@fmt_rdrjrksa3 .... ........ .. ... ..... ..... ..... &fmt_rdrjrksa3 %rd %rj %rk %sa3
+@fmt_hintrjsi12 .... ...... ............ ..... ..... &fmt_hintrjsi12 %hint %rj %si12
+@fmt_whint .... ........ ..... ............... &fmt_whint %whint
+@fmt_rdrjsi14 .... .... .............. ..... ..... &fmt_rdrjsi14 %rd %rj %si14
#
# Fixed point arithmetic operation instruction
@@ -158,3 +167,52 @@ bstrins_w 0000 0000011 ..... 0 ..... ..... ..... @fmt_rdrjmsbwlsbw
bstrpick_w 0000 0000011 ..... 1 ..... ..... ..... @fmt_rdrjmsbwlsbw
bstrins_d 0000 000010 ...... ...... ..... ..... @fmt_rdrjmsbdlsbd
bstrpick_d 0000 000011 ...... ...... ..... ..... @fmt_rdrjmsbdlsbd
+
+#
+# Fixed point load/store instruction
+#
+ld_b 0010 100000 ............ ..... ..... @fmt_rdrjsi12
+ld_h 0010 100001 ............ ..... ..... @fmt_rdrjsi12
+ld_w 0010 100010 ............ ..... ..... @fmt_rdrjsi12
+ld_d 0010 100011 ............ ..... ..... @fmt_rdrjsi12
+st_b 0010 100100 ............ ..... ..... @fmt_rdrjsi12
+st_h 0010 100101 ............ ..... ..... @fmt_rdrjsi12
+st_w 0010 100110 ............ ..... ..... @fmt_rdrjsi12
+st_d 0010 100111 ............ ..... ..... @fmt_rdrjsi12
+ld_bu 0010 101000 ............ ..... ..... @fmt_rdrjsi12
+ld_hu 0010 101001 ............ ..... ..... @fmt_rdrjsi12
+ld_wu 0010 101010 ............ ..... ..... @fmt_rdrjsi12
+ldx_b 0011 10000000 00000 ..... ..... ..... @fmt_rdrjrk
+ldx_h 0011 10000000 01000 ..... ..... ..... @fmt_rdrjrk
+ldx_w 0011 10000000 10000 ..... ..... ..... @fmt_rdrjrk
+ldx_d 0011 10000000 11000 ..... ..... ..... @fmt_rdrjrk
+stx_b 0011 10000001 00000 ..... ..... ..... @fmt_rdrjrk
+stx_h 0011 10000001 01000 ..... ..... ..... @fmt_rdrjrk
+stx_w 0011 10000001 10000 ..... ..... ..... @fmt_rdrjrk
+stx_d 0011 10000001 11000 ..... ..... ..... @fmt_rdrjrk
+ldx_bu 0011 10000010 00000 ..... ..... ..... @fmt_rdrjrk
+ldx_hu 0011 10000010 01000 ..... ..... ..... @fmt_rdrjrk
+ldx_wu 0011 10000010 10000 ..... ..... ..... @fmt_rdrjrk
+preld 0010 101011 ............ ..... ..... @fmt_hintrjsi12
+dbar 0011 10000111 00100 ............... @fmt_whint
+ibar 0011 10000111 00101 ............... @fmt_whint
+ldptr_w 0010 0100 .............. ..... ..... @fmt_rdrjsi14
+stptr_w 0010 0101 .............. ..... ..... @fmt_rdrjsi14
+ldptr_d 0010 0110 .............. ..... ..... @fmt_rdrjsi14
+stptr_d 0010 0111 .............. ..... ..... @fmt_rdrjsi14
+ldgt_b 0011 10000111 10000 ..... ..... ..... @fmt_rdrjrk
+ldgt_h 0011 10000111 10001 ..... ..... ..... @fmt_rdrjrk
+ldgt_w 0011 10000111 10010 ..... ..... ..... @fmt_rdrjrk
+ldgt_d 0011 10000111 10011 ..... ..... ..... @fmt_rdrjrk
+ldle_b 0011 10000111 10100 ..... ..... ..... @fmt_rdrjrk
+ldle_h 0011 10000111 10101 ..... ..... ..... @fmt_rdrjrk
+ldle_w 0011 10000111 10110 ..... ..... ..... @fmt_rdrjrk
+ldle_d 0011 10000111 10111 ..... ..... ..... @fmt_rdrjrk
+stgt_b 0011 10000111 11000 ..... ..... ..... @fmt_rdrjrk
+stgt_h 0011 10000111 11001 ..... ..... ..... @fmt_rdrjrk
+stgt_w 0011 10000111 11010 ..... ..... ..... @fmt_rdrjrk
+stgt_d 0011 10000111 11011 ..... ..... ..... @fmt_rdrjrk
+stle_b 0011 10000111 11100 ..... ..... ..... @fmt_rdrjrk
+stle_h 0011 10000111 11101 ..... ..... ..... @fmt_rdrjrk
+stle_w 0011 10000111 11110 ..... ..... ..... @fmt_rdrjrk
+stle_d 0011 10000111 11111 ..... ..... ..... @fmt_rdrjrk
diff --git a/target/loongarch/op_helper.c b/target/loongarch/op_helper.c
index ec04369..a4ffaf9 100644
--- a/target/loongarch/op_helper.c
+++ b/target/loongarch/op_helper.c
@@ -42,3 +42,18 @@ target_ulong helper_bitswap(target_ulong v)
((v & (target_ulong)0x0F0F0F0F0F0F0F0FULL) << 4);
return v;
}
+
+/* loongarch assert op */
+void helper_asrtle_d(CPULoongArchState *env, target_ulong rj, target_ulong rk)
+{
+ if (rj > rk) {
+ do_raise_exception(env, EXCP_ADE, GETPC());
+ }
+}
+
+void helper_asrtgt_d(CPULoongArchState *env, target_ulong rj, target_ulong rk)
+{
+ if (rj <= rk) {
+ do_raise_exception(env, EXCP_ADE, GETPC());
+ }
+}
diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c
index 0f18d06..2695c0b 100644
--- a/target/loongarch/translate.c
+++ b/target/loongarch/translate.c
@@ -68,6 +68,35 @@ static void loongarch_tr_init_disas_context(DisasContextBase *dcbase,
ctx->zero = tcg_constant_tl(0);
}
+/* loongarch sync */
+static void gen_loongarch_sync(int stype)
+{
+ TCGBar tcg_mo = TCG_BAR_SC;
+
+ switch (stype) {
+ case 0x4: /* SYNC_WMB */
+ tcg_mo |= TCG_MO_ST_ST;
+ break;
+ case 0x10: /* SYNC_MB */
+ tcg_mo |= TCG_MO_ALL;
+ break;
+ case 0x11: /* SYNC_ACQUIRE */
+ tcg_mo |= TCG_MO_LD_LD | TCG_MO_LD_ST;
+ break;
+ case 0x12: /* SYNC_RELEASE */
+ tcg_mo |= TCG_MO_ST_ST | TCG_MO_LD_ST;
+ break;
+ case 0x13: /* SYNC_RMB */
+ tcg_mo |= TCG_MO_LD_LD;
+ break;
+ default:
+ tcg_mo |= TCG_MO_ALL;
+ break;
+ }
+
+ tcg_gen_mb(tcg_mo);
+}
+
static void loongarch_tr_tb_start(DisasContextBase *dcbase, CPUState *cs)
{
}
@@ -161,6 +190,7 @@ static bool gen_r3(DisasContext *ctx, arg_fmt_rdrjrk *a,
#include "insn_trans/trans_arith.c"
#include "insn_trans/trans_shift.c"
#include "insn_trans/trans_bit.c"
+#include "insn_trans/trans_memory.c"
static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
{
--
1.8.3.1
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v3 08/19] target/loongarch: Add fixed point atomic instruction translation
2021-08-27 7:14 [PATCH v3 00/19] Add LoongArch linux-user emulation support Song Gao
` (6 preceding siblings ...)
2021-08-27 7:14 ` [PATCH v3 07/19] target/loongarch: Add fixed point load/store " Song Gao
@ 2021-08-27 7:14 ` Song Gao
2021-08-27 7:14 ` [PATCH v3 09/19] target/loongarch: Add fixed point extra " Song Gao
` (10 subsequent siblings)
18 siblings, 0 replies; 22+ messages in thread
From: Song Gao @ 2021-08-27 7:14 UTC (permalink / raw)
To: qemu-devel
Cc: peter.maydell, thuth, chenhuacai, richard.henderson, f4bug,
maobibo, laurent, yangxiaojuan, alistair.francis, pbonzini,
alex.bennee
This patch implement fixed point atomic instruction translation.
This includes:
- LL.{W/D}, SC.{W/D}
- AM{SWAP/ADD/AND/OR/XOR/MAX/MIN}[_DB].{W/D}
- AM{MAX/MIN}[_DB].{WU/DU}
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
target/loongarch/insn_trans/trans_atomic.c | 132 +++++++++++++++++++++++++++++
target/loongarch/insns.decode | 44 ++++++++++
target/loongarch/translate.c | 1 +
3 files changed, 177 insertions(+)
create mode 100644 target/loongarch/insn_trans/trans_atomic.c
diff --git a/target/loongarch/insn_trans/trans_atomic.c b/target/loongarch/insn_trans/trans_atomic.c
new file mode 100644
index 0000000..fe22eb7
--- /dev/null
+++ b/target/loongarch/insn_trans/trans_atomic.c
@@ -0,0 +1,132 @@
+/*
+ * LoongArch translate functions
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+static bool gen_ll(DisasContext *ctx, arg_fmt_rdrjsi14 *a,
+ void (*func)(TCGv, TCGv, int))
+{
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+
+ tcg_gen_addi_tl(src1, src1, a->si14 << 2);
+ func(dest, src1, ctx->mem_idx);
+ tcg_gen_st_tl(src1, cpu_env, offsetof(CPULoongArchState, lladdr));
+ tcg_gen_st_tl(dest, cpu_env, offsetof(CPULoongArchState, llval));
+
+ return true;
+}
+
+static bool gen_sc(DisasContext *ctx, arg_fmt_rdrjsi14 *a, MemOp mop)
+{
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv t0 = tcg_temp_new();
+
+ TCGLabel *l1 = gen_new_label();
+ TCGLabel *done = gen_new_label();
+
+ tcg_gen_addi_tl(t0, src1, a->si14 << 2);
+ tcg_gen_brcond_tl(TCG_COND_EQ, t0, cpu_lladdr, l1);
+ tcg_gen_movi_tl(dest, 0);
+ tcg_gen_br(done);
+
+ gen_set_label(l1);
+ /* generate cmpxchg */
+ tcg_gen_atomic_cmpxchg_tl(t0, cpu_lladdr, cpu_llval,
+ dest, ctx->mem_idx, mop);
+ tcg_gen_setcond_tl(TCG_COND_EQ, dest, t0, cpu_llval);
+ gen_set_label(done);
+ tcg_temp_free(t0);
+ return true;
+}
+
+static bool gen_am(DisasContext *ctx, arg_fmt_rdrjrk *a, DisasExtend ext,
+ void (*func)(TCGv, TCGv, TCGv, TCGArg, MemOp),
+ MemOp mop)
+{
+ ctx->dst_ext = ext;
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv addr = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv val = gpr_src(ctx, a->rk, EXT_NONE);
+
+ if ((a->rd != 0) && ((a->rj == a->rd) || (a->rk == a->rd))) {
+ qemu_log("%s: waring, register equal\n", __func__);
+ return false;
+ }
+
+ func(dest, addr, val, ctx->mem_idx, mop);
+
+ if (ctx->dst_ext) {
+ gen_set_gpr(ctx, a->rd, dest);
+ }
+ return true;
+}
+
+static bool gen_am_db(DisasContext *ctx, arg_fmt_rdrjrk *a, DisasExtend ext,
+ void (*func)(TCGv, TCGv, TCGv, TCGArg, MemOp),
+ MemOp mop)
+{
+ ctx->dst_ext = ext;
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv addr = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv val = gpr_src(ctx, a->rk, EXT_NONE);
+
+ if ((a->rd != 0) && ((a->rj == a->rd) || (a->rk == a->rd))) {
+ qemu_log("%s: waring, register equal\n", __func__);
+ return false;
+ }
+
+ gen_loongarch_sync(0x10);
+
+ func(dest, addr, val, ctx->mem_idx, mop);
+
+ if (ctx->dst_ext) {
+ gen_set_gpr(ctx, a->rd, dest);
+ }
+ return true;
+}
+
+TRANS(ll_w, gen_ll, tcg_gen_qemu_ld32s)
+TRANS(sc_w, gen_sc, MO_TESL)
+TRANS(ll_d, gen_ll, tcg_gen_qemu_ld64)
+TRANS(sc_d, gen_sc, MO_TEQ)
+TRANS(amswap_w, gen_am, EXT_SIGN, tcg_gen_atomic_xchg_tl, MO_TESL)
+TRANS(amswap_d, gen_am, EXT_NONE, tcg_gen_atomic_xchg_tl, MO_TEQ)
+TRANS(amadd_w, gen_am, EXT_SIGN, tcg_gen_atomic_fetch_add_tl, MO_TESL)
+TRANS(amadd_d, gen_am, EXT_NONE, tcg_gen_atomic_fetch_add_tl, MO_TEQ)
+TRANS(amand_w, gen_am, EXT_SIGN, tcg_gen_atomic_fetch_and_tl, MO_TESL)
+TRANS(amand_d, gen_am, EXT_NONE, tcg_gen_atomic_fetch_and_tl, MO_TEQ)
+TRANS(amor_w, gen_am, EXT_SIGN, tcg_gen_atomic_fetch_or_tl, MO_TESL)
+TRANS(amor_d, gen_am, EXT_NONE, tcg_gen_atomic_fetch_or_tl, MO_TEQ)
+TRANS(amxor_w, gen_am, EXT_SIGN, tcg_gen_atomic_fetch_xor_tl, MO_TESL)
+TRANS(amxor_d, gen_am, EXT_NONE, tcg_gen_atomic_fetch_xor_tl, MO_TEQ)
+TRANS(ammax_w, gen_am, EXT_SIGN, tcg_gen_atomic_fetch_smax_tl, MO_TESL)
+TRANS(ammax_d, gen_am, EXT_NONE, tcg_gen_atomic_fetch_smax_tl, MO_TEQ)
+TRANS(ammin_w, gen_am, EXT_SIGN, tcg_gen_atomic_fetch_smin_tl, MO_TESL)
+TRANS(ammin_d, gen_am, EXT_NONE, tcg_gen_atomic_fetch_smin_tl, MO_TEQ)
+TRANS(ammax_wu, gen_am, EXT_SIGN, tcg_gen_atomic_fetch_umax_tl, MO_TESL)
+TRANS(ammax_du, gen_am, EXT_NONE, tcg_gen_atomic_fetch_umax_tl, MO_TEQ)
+TRANS(ammin_wu, gen_am, EXT_SIGN, tcg_gen_atomic_fetch_umin_tl, MO_TESL)
+TRANS(ammin_du, gen_am, EXT_NONE, tcg_gen_atomic_fetch_umin_tl, MO_TEQ)
+TRANS(amswap_db_w, gen_am_db, EXT_SIGN, tcg_gen_atomic_xchg_tl, MO_TESL)
+TRANS(amswap_db_d, gen_am_db, EXT_NONE, tcg_gen_atomic_xchg_tl, MO_TEQ)
+TRANS(amadd_db_w, gen_am_db, EXT_SIGN, tcg_gen_atomic_fetch_add_tl, MO_TESL)
+TRANS(amadd_db_d, gen_am_db, EXT_NONE, tcg_gen_atomic_fetch_add_tl, MO_TEQ)
+TRANS(amand_db_w, gen_am_db, EXT_SIGN, tcg_gen_atomic_fetch_and_tl, MO_TESL)
+TRANS(amand_db_d, gen_am_db, EXT_NONE, tcg_gen_atomic_fetch_and_tl, MO_TEQ)
+TRANS(amor_db_w, gen_am_db, EXT_SIGN, tcg_gen_atomic_fetch_or_tl, MO_TESL)
+TRANS(amor_db_d, gen_am_db, EXT_NONE, tcg_gen_atomic_fetch_or_tl, MO_TEQ)
+TRANS(amxor_db_w, gen_am_db, EXT_SIGN, tcg_gen_atomic_fetch_xor_tl, MO_TESL)
+TRANS(amxor_db_d, gen_am_db, EXT_NONE, tcg_gen_atomic_fetch_xor_tl, MO_TEQ)
+TRANS(ammax_db_w, gen_am_db, EXT_SIGN, tcg_gen_atomic_fetch_smax_tl, MO_TESL)
+TRANS(ammax_db_d, gen_am_db, EXT_NONE, tcg_gen_atomic_fetch_smax_tl, MO_TEQ)
+TRANS(ammin_db_w, gen_am_db, EXT_SIGN, tcg_gen_atomic_fetch_smin_tl, MO_TESL)
+TRANS(ammin_db_d, gen_am_db, EXT_NONE, tcg_gen_atomic_fetch_smin_tl, MO_TEQ)
+TRANS(ammax_db_wu, gen_am_db, EXT_SIGN, tcg_gen_atomic_fetch_umax_tl, MO_TESL)
+TRANS(ammax_db_du, gen_am_db, EXT_NONE, tcg_gen_atomic_fetch_umax_tl, MO_TEQ)
+TRANS(ammin_db_wu, gen_am_db, EXT_SIGN, tcg_gen_atomic_fetch_umin_tl, MO_TESL)
+TRANS(ammin_db_du, gen_am_db, EXT_NONE, tcg_gen_atomic_fetch_umin_tl, MO_TEQ)
diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode
index 08fd232..574c055 100644
--- a/target/loongarch/insns.decode
+++ b/target/loongarch/insns.decode
@@ -216,3 +216,47 @@ stle_b 0011 10000111 11100 ..... ..... ..... @fmt_rdrjrk
stle_h 0011 10000111 11101 ..... ..... ..... @fmt_rdrjrk
stle_w 0011 10000111 11110 ..... ..... ..... @fmt_rdrjrk
stle_d 0011 10000111 11111 ..... ..... ..... @fmt_rdrjrk
+
+#
+# Fixed point atomic instruction
+#
+ll_w 0010 0000 .............. ..... ..... @fmt_rdrjsi14
+sc_w 0010 0001 .............. ..... ..... @fmt_rdrjsi14
+ll_d 0010 0010 .............. ..... ..... @fmt_rdrjsi14
+sc_d 0010 0011 .............. ..... ..... @fmt_rdrjsi14
+amswap_w 0011 10000110 00000 ..... ..... ..... @fmt_rdrjrk
+amswap_d 0011 10000110 00001 ..... ..... ..... @fmt_rdrjrk
+amadd_w 0011 10000110 00010 ..... ..... ..... @fmt_rdrjrk
+amadd_d 0011 10000110 00011 ..... ..... ..... @fmt_rdrjrk
+amand_w 0011 10000110 00100 ..... ..... ..... @fmt_rdrjrk
+amand_d 0011 10000110 00101 ..... ..... ..... @fmt_rdrjrk
+amor_w 0011 10000110 00110 ..... ..... ..... @fmt_rdrjrk
+amor_d 0011 10000110 00111 ..... ..... ..... @fmt_rdrjrk
+amxor_w 0011 10000110 01000 ..... ..... ..... @fmt_rdrjrk
+amxor_d 0011 10000110 01001 ..... ..... ..... @fmt_rdrjrk
+ammax_w 0011 10000110 01010 ..... ..... ..... @fmt_rdrjrk
+ammax_d 0011 10000110 01011 ..... ..... ..... @fmt_rdrjrk
+ammin_w 0011 10000110 01100 ..... ..... ..... @fmt_rdrjrk
+ammin_d 0011 10000110 01101 ..... ..... ..... @fmt_rdrjrk
+ammax_wu 0011 10000110 01110 ..... ..... ..... @fmt_rdrjrk
+ammax_du 0011 10000110 01111 ..... ..... ..... @fmt_rdrjrk
+ammin_wu 0011 10000110 10000 ..... ..... ..... @fmt_rdrjrk
+ammin_du 0011 10000110 10001 ..... ..... ..... @fmt_rdrjrk
+amswap_db_w 0011 10000110 10010 ..... ..... ..... @fmt_rdrjrk
+amswap_db_d 0011 10000110 10011 ..... ..... ..... @fmt_rdrjrk
+amadd_db_w 0011 10000110 10100 ..... ..... ..... @fmt_rdrjrk
+amadd_db_d 0011 10000110 10101 ..... ..... ..... @fmt_rdrjrk
+amand_db_w 0011 10000110 10110 ..... ..... ..... @fmt_rdrjrk
+amand_db_d 0011 10000110 10111 ..... ..... ..... @fmt_rdrjrk
+amor_db_w 0011 10000110 11000 ..... ..... ..... @fmt_rdrjrk
+amor_db_d 0011 10000110 11001 ..... ..... ..... @fmt_rdrjrk
+amxor_db_w 0011 10000110 11010 ..... ..... ..... @fmt_rdrjrk
+amxor_db_d 0011 10000110 11011 ..... ..... ..... @fmt_rdrjrk
+ammax_db_w 0011 10000110 11100 ..... ..... ..... @fmt_rdrjrk
+ammax_db_d 0011 10000110 11101 ..... ..... ..... @fmt_rdrjrk
+ammin_db_w 0011 10000110 11110 ..... ..... ..... @fmt_rdrjrk
+ammin_db_d 0011 10000110 11111 ..... ..... ..... @fmt_rdrjrk
+ammax_db_wu 0011 10000111 00000 ..... ..... ..... @fmt_rdrjrk
+ammax_db_du 0011 10000111 00001 ..... ..... ..... @fmt_rdrjrk
+ammin_db_wu 0011 10000111 00010 ..... ..... ..... @fmt_rdrjrk
+ammin_db_du 0011 10000111 00011 ..... ..... ..... @fmt_rdrjrk
diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c
index 2695c0b..a6482c3 100644
--- a/target/loongarch/translate.c
+++ b/target/loongarch/translate.c
@@ -191,6 +191,7 @@ static bool gen_r3(DisasContext *ctx, arg_fmt_rdrjrk *a,
#include "insn_trans/trans_shift.c"
#include "insn_trans/trans_bit.c"
#include "insn_trans/trans_memory.c"
+#include "insn_trans/trans_atomic.c"
static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
{
--
1.8.3.1
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v3 09/19] target/loongarch: Add fixed point extra instruction translation
2021-08-27 7:14 [PATCH v3 00/19] Add LoongArch linux-user emulation support Song Gao
` (7 preceding siblings ...)
2021-08-27 7:14 ` [PATCH v3 08/19] target/loongarch: Add fixed point atomic " Song Gao
@ 2021-08-27 7:14 ` Song Gao
2021-08-27 7:14 ` [PATCH v3 10/19] target/loongarch: Add floating point arithmetic " Song Gao
` (9 subsequent siblings)
18 siblings, 0 replies; 22+ messages in thread
From: Song Gao @ 2021-08-27 7:14 UTC (permalink / raw)
To: qemu-devel
Cc: peter.maydell, thuth, chenhuacai, richard.henderson, f4bug,
maobibo, laurent, yangxiaojuan, alistair.francis, pbonzini,
alex.bennee
This patch implement fixed point extra instruction translation.
This includes:
- CRC[C].W.{B/H/W/D}.W
- SYSCALL
- BREAK
- ASRT{LE/GT}.D
- RDTIME{L/H}.W, RDTIME.D
- CPUCFG
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
target/loongarch/helper.h | 4 ++
| 88 +++++++++++++++++++++++++++++++
target/loongarch/insns.decode | 25 +++++++++
target/loongarch/op_helper.c | 26 +++++++++
target/loongarch/translate.c | 1 +
5 files changed, 144 insertions(+)
create mode 100644 target/loongarch/insn_trans/trans_extra.c
diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h
index 09b5a3d..e4b4595 100644
--- a/target/loongarch/helper.h
+++ b/target/loongarch/helper.h
@@ -14,3 +14,7 @@ DEF_HELPER_FLAGS_1(bitswap, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_3(asrtle_d, void, env, tl, tl)
DEF_HELPER_3(asrtgt_d, void, env, tl, tl)
+
+DEF_HELPER_3(crc32, tl, tl, tl, tl)
+DEF_HELPER_3(crc32c, tl, tl, tl, tl)
+DEF_HELPER_2(cpucfg, tl, env, tl)
--git a/target/loongarch/insn_trans/trans_extra.c b/target/loongarch/insn_trans/trans_extra.c
new file mode 100644
index 0000000..d07e791
--- /dev/null
+++ b/target/loongarch/insn_trans/trans_extra.c
@@ -0,0 +1,88 @@
+/*
+ * LoongArch translate functions
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+static bool trans_break(DisasContext *ctx, arg_break *a)
+{
+ generate_exception(ctx, EXCP_BREAK);
+ return true;
+}
+
+static bool trans_syscall(DisasContext *ctx, arg_syscall *a)
+{
+ generate_exception(ctx, EXCP_SYSCALL);
+ return true;
+}
+
+static bool trans_asrtle_d(DisasContext *ctx, arg_asrtle_d * a)
+{
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE);
+
+ gen_helper_asrtle_d(cpu_env, src1, src2);
+ return true;
+}
+
+static bool trans_asrtgt_d(DisasContext *ctx, arg_asrtgt_d * a)
+{
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE);
+
+ gen_helper_asrtgt_d(cpu_env, src1, src2);
+ return true;
+}
+
+static bool trans_rdtimel_w(DisasContext *ctx, arg_rdtimel_w *a)
+{
+ tcg_gen_movi_tl(cpu_gpr[a->rd], 0);
+ return true;
+}
+
+static bool trans_rdtimeh_w(DisasContext *ctx, arg_rdtimeh_w *a)
+{
+ tcg_gen_movi_tl(cpu_gpr[a->rd], 0);
+ return true;
+}
+
+static bool trans_rdtime_d(DisasContext *ctx, arg_rdtime_d *a)
+{
+ tcg_gen_movi_tl(cpu_gpr[a->rd], 0);
+ return true;
+}
+
+static bool trans_cpucfg(DisasContext *ctx, arg_cpucfg *a)
+{
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+
+ gen_helper_cpucfg(dest, cpu_env, src1);
+ return true;
+}
+
+static bool gen_crc(DisasContext *ctx, arg_fmt_rdrjrk *a,
+ void (*func)(TCGv, TCGv, TCGv, TCGv),
+ TCGv tsz)
+{
+ ctx->dst_ext = EXT_SIGN;
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE);
+
+ func(dest, src2, src1, tsz);
+
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+TRANS(crc_w_b_w, gen_crc, gen_helper_crc32, tcg_constant_tl(1))
+TRANS(crc_w_h_w, gen_crc, gen_helper_crc32, tcg_constant_tl(2))
+TRANS(crc_w_w_w, gen_crc, gen_helper_crc32, tcg_constant_tl(4))
+TRANS(crc_w_d_w, gen_crc, gen_helper_crc32, tcg_constant_tl(8))
+TRANS(crcc_w_b_w, gen_crc, gen_helper_crc32c, tcg_constant_tl(1))
+TRANS(crcc_w_h_w, gen_crc, gen_helper_crc32c, tcg_constant_tl(2))
+TRANS(crcc_w_w_w, gen_crc, gen_helper_crc32c, tcg_constant_tl(4))
+TRANS(crcc_w_d_w, gen_crc, gen_helper_crc32c, tcg_constant_tl(8))
diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode
index 574c055..66bc314 100644
--- a/target/loongarch/insns.decode
+++ b/target/loongarch/insns.decode
@@ -27,6 +27,7 @@
%si14 10:s14
%hint 0:5
%whint 0:15
+%code 0:15
#
# Argument sets
@@ -46,6 +47,8 @@
&fmt_rdrjsi14 rd rj si14
&fmt_hintrjsi12 hint rj si12
&fmt_whint whint
+&fmt_rjrk rj rk
+&fmt_code code
#
# Formats
@@ -65,6 +68,8 @@
@fmt_hintrjsi12 .... ...... ............ ..... ..... &fmt_hintrjsi12 %hint %rj %si12
@fmt_whint .... ........ ..... ............... &fmt_whint %whint
@fmt_rdrjsi14 .... .... .............. ..... ..... &fmt_rdrjsi14 %rd %rj %si14
+@fmt_rjrk .... ........ ..... ..... ..... ..... &fmt_rjrk %rj %rk
+@fmt_code .... ........ ..... ............... &fmt_code %code
#
# Fixed point arithmetic operation instruction
@@ -260,3 +265,23 @@ ammax_db_wu 0011 10000111 00000 ..... ..... ..... @fmt_rdrjrk
ammax_db_du 0011 10000111 00001 ..... ..... ..... @fmt_rdrjrk
ammin_db_wu 0011 10000111 00010 ..... ..... ..... @fmt_rdrjrk
ammin_db_du 0011 10000111 00011 ..... ..... ..... @fmt_rdrjrk
+
+#
+# Fixed point extra instruction
+#
+crc_w_b_w 0000 00000010 01000 ..... ..... ..... @fmt_rdrjrk
+crc_w_h_w 0000 00000010 01001 ..... ..... ..... @fmt_rdrjrk
+crc_w_w_w 0000 00000010 01010 ..... ..... ..... @fmt_rdrjrk
+crc_w_d_w 0000 00000010 01011 ..... ..... ..... @fmt_rdrjrk
+crcc_w_b_w 0000 00000010 01100 ..... ..... ..... @fmt_rdrjrk
+crcc_w_h_w 0000 00000010 01101 ..... ..... ..... @fmt_rdrjrk
+crcc_w_w_w 0000 00000010 01110 ..... ..... ..... @fmt_rdrjrk
+crcc_w_d_w 0000 00000010 01111 ..... ..... ..... @fmt_rdrjrk
+break 0000 00000010 10100 ............... @fmt_code
+syscall 0000 00000010 10110 ............... @fmt_code
+asrtle_d 0000 00000000 00010 ..... ..... 00000 @fmt_rjrk
+asrtgt_d 0000 00000000 00011 ..... ..... 00000 @fmt_rjrk
+rdtimel_w 0000 00000000 00000 11000 ..... ..... @fmt_rdrj
+rdtimeh_w 0000 00000000 00000 11001 ..... ..... @fmt_rdrj
+rdtime_d 0000 00000000 00000 11010 ..... ..... @fmt_rdrj
+cpucfg 0000 00000000 00000 11011 ..... ..... @fmt_rdrj
diff --git a/target/loongarch/op_helper.c b/target/loongarch/op_helper.c
index a4ffaf9..0a1a47b 100644
--- a/target/loongarch/op_helper.c
+++ b/target/loongarch/op_helper.c
@@ -14,6 +14,8 @@
#include "exec/exec-all.h"
#include "exec/cpu_ldst.h"
#include "internals.h"
+#include "qemu/crc32c.h"
+#include <zlib.h>
/* Exceptions helpers */
void helper_raise_exception(CPULoongArchState *env, uint32_t exception)
@@ -57,3 +59,27 @@ void helper_asrtgt_d(CPULoongArchState *env, target_ulong rj, target_ulong rk)
do_raise_exception(env, EXCP_ADE, GETPC());
}
}
+
+target_ulong helper_crc32(target_ulong val, target_ulong m, uint64_t sz)
+{
+ uint8_t buf[8];
+ target_ulong mask = ((sz * 8) == 64) ? -1ULL : ((1ULL << (sz * 8)) - 1);
+
+ m &= mask;
+ stq_le_p(buf, m);
+ return (int32_t) (crc32(val ^ 0xffffffff, buf, sz) ^ 0xffffffff);
+}
+
+target_ulong helper_crc32c(target_ulong val, target_ulong m, uint64_t sz)
+{
+ uint8_t buf[8];
+ target_ulong mask = ((sz * 8) == 64) ? -1ULL : ((1ULL << (sz * 8)) - 1);
+ m &= mask;
+ stq_le_p(buf, m);
+ return (int32_t) (crc32c(val, buf, sz) ^ 0xffffffff);
+}
+
+target_ulong helper_cpucfg(CPULoongArchState *env, target_ulong rj)
+{
+ return env->cpucfg[rj];
+}
diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c
index a6482c3..77b0180 100644
--- a/target/loongarch/translate.c
+++ b/target/loongarch/translate.c
@@ -192,6 +192,7 @@ static bool gen_r3(DisasContext *ctx, arg_fmt_rdrjrk *a,
#include "insn_trans/trans_bit.c"
#include "insn_trans/trans_memory.c"
#include "insn_trans/trans_atomic.c"
+#include "insn_trans/trans_extra.c"
static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
{
--
1.8.3.1
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v3 10/19] target/loongarch: Add floating point arithmetic instruction translation
2021-08-27 7:14 [PATCH v3 00/19] Add LoongArch linux-user emulation support Song Gao
` (8 preceding siblings ...)
2021-08-27 7:14 ` [PATCH v3 09/19] target/loongarch: Add fixed point extra " Song Gao
@ 2021-08-27 7:14 ` Song Gao
2021-08-27 7:14 ` [PATCH v3 11/19] target/loongarch: Add floating point comparison " Song Gao
` (8 subsequent siblings)
18 siblings, 0 replies; 22+ messages in thread
From: Song Gao @ 2021-08-27 7:14 UTC (permalink / raw)
To: qemu-devel
Cc: peter.maydell, thuth, chenhuacai, richard.henderson, f4bug,
maobibo, laurent, yangxiaojuan, alistair.francis, pbonzini,
alex.bennee
This patch implement floating point arithmetic instruction translation.
This includes:
- F{ADD/SUB/MUL/DIV}.{S/D}
- F{MADD/MSUB/NMADD/NMSUB}.{S/D}
- F{MAX/MIN}.{S/D}
- F{MAXA/MINA}.{S/D}
- F{ABS/NEG}.{S/D}
- F{SQRT/RECIP/RSQRT}.{S/D}
- F{SCALEB/LOGB/COPYSIGN}.{S/D}
- FCLASS.{S/D}
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
target/loongarch/cpu.c | 1 +
target/loongarch/fpu_helper.c | 438 +++++++++++++++++++++++++++++
target/loongarch/helper.h | 42 +++
target/loongarch/insn_trans/trans_farith.c | 79 ++++++
target/loongarch/insns.decode | 56 ++++
target/loongarch/internals.h | 2 +
target/loongarch/translate.c | 11 +-
target/loongarch/translate.h | 2 +
8 files changed, 630 insertions(+), 1 deletion(-)
create mode 100644 target/loongarch/fpu_helper.c
create mode 100644 target/loongarch/insn_trans/trans_farith.c
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index b89bf51..487df05 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -143,6 +143,7 @@ static void loongarch_cpu_reset(DeviceState *dev)
env->fcsr0_mask = 0x1f1f031f;
env->fcsr0 = 0x0;
+ restore_fp_status(env);
cs->exception_index = EXCP_NONE;
}
diff --git a/target/loongarch/fpu_helper.c b/target/loongarch/fpu_helper.c
new file mode 100644
index 0000000..c3bee57
--- /dev/null
+++ b/target/loongarch/fpu_helper.c
@@ -0,0 +1,438 @@
+/*
+ * LoongArch float point emulation helpers for qemu
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "exec/helper-proto.h"
+#include "exec/exec-all.h"
+#include "exec/cpu_ldst.h"
+#include "fpu/softfloat.h"
+#include "translate.h"
+#include "internals.h"
+
+#define FLOAT_TO_INT32_OVERFLOW 0x7fffffff
+#define FLOAT_TO_INT64_OVERFLOW 0x7fffffffffffffffULL
+
+static inline uint64_t nanbox_s(float32 fp)
+{
+ return fp | MAKE_64BIT_MASK(32, 32);
+}
+
+/* convert loongarch rounding mode in fcsr0 to IEEE library */
+const FloatRoundMode ieee_rm[4] = {
+ float_round_nearest_even,
+ float_round_to_zero,
+ float_round_up,
+ float_round_down
+};
+
+void restore_fp_status(CPULoongArchState *env)
+{
+ set_float_rounding_mode(ieee_rm[(env->fcsr0 >> FCSR0_RM) & 0x3],
+ &env->fp_status);
+ set_flush_to_zero(0, &env->fp_status);
+}
+
+int ieee_ex_to_loongarch(int xcpt)
+{
+ int ret = 0;
+ if (xcpt) {
+ if (xcpt & float_flag_invalid) {
+ ret |= FP_INVALID;
+ }
+ if (xcpt & float_flag_overflow) {
+ ret |= FP_OVERFLOW;
+ }
+ if (xcpt & float_flag_underflow) {
+ ret |= FP_UNDERFLOW;
+ }
+ if (xcpt & float_flag_divbyzero) {
+ ret |= FP_DIV0;
+ }
+ if (xcpt & float_flag_inexact) {
+ ret |= FP_INEXACT;
+ }
+ }
+ return ret;
+}
+
+static inline void update_fcsr0(CPULoongArchState *env, uintptr_t pc)
+{
+ int flags = ieee_ex_to_loongarch(get_float_exception_flags(
+ &env->fp_status));
+
+ SET_FP_CAUSE(env->fcsr0, flags);
+ if (flags) {
+ set_float_exception_flags(0, &env->fp_status);
+
+ if (GET_FP_ENABLE(env->fcsr0) & flags) {
+ do_raise_exception(env, EXCP_FPE, pc);
+ } else {
+ UPDATE_FP_FLAGS(env->fcsr0, flags);
+ }
+ }
+}
+
+uint64_t helper_fadd_s(CPULoongArchState *env, uint64_t fj, uint64_t fk)
+{
+ uint64_t fd;
+
+ fd = nanbox_s(float32_add((uint32_t)fj, (uint32_t)fk, &env->fp_status));
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_fadd_d(CPULoongArchState *env, uint64_t fj, uint64_t fk)
+{
+ uint64_t fd;
+
+ fd = float64_add(fj, fk, &env->fp_status);
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_fsub_s(CPULoongArchState *env, uint64_t fj, uint64_t fk)
+{
+ uint64_t fd;
+
+ fd = nanbox_s(float32_sub((uint32_t)fj, (uint32_t)fk, &env->fp_status));
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_fsub_d(CPULoongArchState *env, uint64_t fj, uint64_t fk)
+{
+ uint64_t fd;
+
+ fd = float64_sub(fj, fk, &env->fp_status);
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_fmul_s(CPULoongArchState *env, uint64_t fj, uint64_t fk)
+{
+ uint64_t fd;
+
+ fd = nanbox_s(float32_mul((uint32_t)fj, (uint32_t)fk, &env->fp_status));
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_fmul_d(CPULoongArchState *env, uint64_t fj, uint64_t fk)
+{
+ uint64_t fd;
+
+ fd = float64_mul(fj, fk, &env->fp_status);
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_fdiv_s(CPULoongArchState *env, uint64_t fj, uint64_t fk)
+{
+ uint64_t fd;
+
+ fd = nanbox_s(float32_div((uint32_t)fj, (uint32_t)fk, &env->fp_status));
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_fdiv_d(CPULoongArchState *env, uint64_t fj, uint64_t fk)
+{
+ uint64_t fd;
+
+ fd = float64_div(fj, fk, &env->fp_status);
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_fmax_s(CPULoongArchState *env, uint64_t fj, uint64_t fk)
+{
+ uint64_t fd;
+
+ fd = nanbox_s(float32_maxnum((uint32_t)fj, (uint32_t)fk, &env->fp_status));
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_fmax_d(CPULoongArchState *env, uint64_t fj, uint64_t fk)
+{
+ uint64_t fd;
+
+ fd = float64_maxnum(fj, fk, &env->fp_status);
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_fmin_s(CPULoongArchState *env, uint64_t fj, uint64_t fk)
+{
+ uint64_t fd;
+
+ fd = nanbox_s(float32_minnum((uint32_t)fj, (uint32_t)fk, &env->fp_status));
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_fmin_d(CPULoongArchState *env, uint64_t fj, uint64_t fk)
+{
+ uint64_t fd;
+
+ fd = float64_minnum(fj, fk, &env->fp_status);
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_fmaxa_s(CPULoongArchState *env, uint64_t fj, uint64_t fk)
+{
+ uint64_t fd;
+
+ fd = nanbox_s(float32_maxnummag((uint32_t)fj,
+ (uint32_t)fk, &env->fp_status));
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_fmaxa_d(CPULoongArchState *env, uint64_t fj, uint64_t fk)
+{
+ uint64_t fd;
+
+ fd = float64_maxnummag(fj, fk, &env->fp_status);
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_fmina_s(CPULoongArchState *env, uint64_t fj, uint64_t fk)
+{
+ uint64_t fd;
+
+ fd = nanbox_s(float32_minnummag((uint32_t)fj,
+ (uint32_t)fk, &env->fp_status));
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_fmina_d(CPULoongArchState *env, uint64_t fj, uint64_t fk)
+{
+ uint64_t fd;
+
+ fd = float64_minnummag(fj, fk, &env->fp_status);
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_fscaleb_s(CPULoongArchState *env, uint64_t fj, uint64_t fk)
+{
+ uint64_t fd;
+ int32_t n = (int32_t)fk;
+
+ fd = nanbox_s(float32_scalbn((uint32_t)fj,
+ n > 0x200 ? 0x200 :
+ n < -0x200 ? -0x200 : n,
+ &env->fp_status));
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_fscaleb_d(CPULoongArchState *env, uint64_t fj, uint64_t fk)
+{
+ uint64_t fd;
+ int64_t n = (int64_t)fk;
+
+ fd = float64_scalbn(fj,
+ n > 0x1000 ? 0x1000 :
+ n < -0x1000 ? -0x1000 : n,
+ &env->fp_status);
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_fabs_s(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+
+ fd = nanbox_s(float32_abs((uint32_t)fj));
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_fabs_d(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+
+ fd = float64_abs(fj);
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_fneg_s(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+
+ fd = nanbox_s(float32_chs((uint32_t)fj));
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_fneg_d(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+
+ fd = float64_chs(fj);
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_fsqrt_s(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+
+ fd = nanbox_s(float32_sqrt((uint32_t)fj, &env->fp_status));
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_fsqrt_d(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+
+ fd = float64_sqrt(fj, &env->fp_status);
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_frecip_s(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+
+ fd = nanbox_s(float32_div(float32_one, (uint32_t)fj, &env->fp_status));
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_frecip_d(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+
+ fd = float64_div(float64_one, fj, &env->fp_status);
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_frsqrt_s(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+ uint32_t fp;
+
+ fp = float32_sqrt((uint32_t)fj, &env->fp_status);
+ fd = nanbox_s(float32_div(float32_one, fp, &env->fp_status));
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_frsqrt_d(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fp, fd;
+
+ fp = float64_sqrt(fj, &env->fp_status);
+ fd = float64_div(float64_one, fp, &env->fp_status);
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_flogb_s(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+ uint32_t fp;
+ float_status *status = &env->fp_status;
+ FloatRoundMode old_mode = get_float_rounding_mode(status);
+
+ set_float_exception_flags(0, status);
+ set_float_rounding_mode(float_round_down, status);
+ fp = float32_log2((uint32_t)fj, status);
+ fd = nanbox_s(float32_round_to_int(fp, status));
+ set_float_rounding_mode(old_mode, status);
+ set_float_exception_flags(get_float_exception_flags(status) &
+ (~float_flag_inexact), status);
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_flogb_d(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+ float_status *status = &env->fp_status;
+ FloatRoundMode old_mode = get_float_rounding_mode(status);
+
+ set_float_exception_flags(0, status);
+ set_float_rounding_mode(float_round_down, status);
+ fd = float64_log2(fj, status);
+ fd = float64_round_to_int(fd, status);
+ set_float_rounding_mode(old_mode, status);
+ set_float_exception_flags(get_float_exception_flags(status) &
+ (~float_flag_inexact), status);
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_fclass_s(CPULoongArchState *env, uint64_t fj)
+{
+ float32 f = fj;
+ bool sign = float32_is_neg(f);
+
+ if (float32_is_infinity(f)) {
+ return sign ? 1 << 0 : 1 << 7;
+ } else if (float32_is_zero(f)) {
+ return sign ? 1 << 3 : 1 << 4;
+ } else if (float32_is_zero_or_denormal(f)) {
+ return sign ? 1 << 2 : 1 << 5;
+ } else if (float32_is_any_nan(f)) {
+ float_status s = { }; /* for snan_bit_is_one */
+ return float32_is_quiet_nan(f, &s) ? 1 << 9 : 1 << 8;
+ } else {
+ return sign ? 1 << 1 : 1 << 6;
+ }
+}
+
+uint64_t helper_fclass_d(CPULoongArchState *env, uint64_t fj)
+{
+ float64 f = fj;
+ bool sign = float64_is_neg(f);
+
+ if (float64_is_infinity(f)) {
+ return sign ? 1 << 0 : 1 << 7;
+ } else if (float64_is_zero(f)) {
+ return sign ? 1 << 3 : 1 << 4;
+ } else if (float64_is_zero_or_denormal(f)) {
+ return sign ? 1 << 2 : 1 << 5;
+ } else if (float64_is_any_nan(f)) {
+ float_status s = { }; /* for snan_bit_is_one */
+ return float64_is_quiet_nan(f, &s) ? 1 << 9 : 1 << 8;
+ } else {
+ return sign ? 1 << 1 : 1 << 6;
+ }
+}
+
+uint64_t helper_fmuladd_s(CPULoongArchState *env, uint64_t fj,
+ uint64_t fk, uint64_t fa, uint32_t flag)
+{
+ uint64_t fd;
+
+ fd = nanbox_s(float32_muladd((uint32_t)fj, (uint32_t)fk,
+ (uint32_t)fa, flag, &env->fp_status));
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_fmuladd_d(CPULoongArchState *env, uint64_t fj,
+ uint64_t fk, uint64_t fa, uint32_t flag)
+{
+ uint64_t fd;
+
+ fd = float64_muladd(fj, fk, fa, flag, &env->fp_status);
+ update_fcsr0(env, GETPC());
+ return fd;
+}
diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h
index e4b4595..62c262e 100644
--- a/target/loongarch/helper.h
+++ b/target/loongarch/helper.h
@@ -18,3 +18,45 @@ DEF_HELPER_3(asrtgt_d, void, env, tl, tl)
DEF_HELPER_3(crc32, tl, tl, tl, tl)
DEF_HELPER_3(crc32c, tl, tl, tl, tl)
DEF_HELPER_2(cpucfg, tl, env, tl)
+
+/* Floating-point helper */
+DEF_HELPER_3(fadd_s, i64, env, i64, i64)
+DEF_HELPER_3(fadd_d, i64, env, i64, i64)
+DEF_HELPER_3(fsub_s, i64, env, i64, i64)
+DEF_HELPER_3(fsub_d, i64, env, i64, i64)
+DEF_HELPER_3(fmul_s, i64, env, i64, i64)
+DEF_HELPER_3(fmul_d, i64, env, i64, i64)
+DEF_HELPER_3(fdiv_s, i64, env, i64, i64)
+DEF_HELPER_3(fdiv_d, i64, env, i64, i64)
+DEF_HELPER_3(fmax_s, i64, env, i64, i64)
+DEF_HELPER_3(fmax_d, i64, env, i64, i64)
+DEF_HELPER_3(fmaxa_s, i64, env, i64, i64)
+DEF_HELPER_3(fmaxa_d, i64, env, i64, i64)
+DEF_HELPER_3(fmin_s, i64, env, i64, i64)
+DEF_HELPER_3(fmin_d, i64, env, i64, i64)
+DEF_HELPER_3(fmina_s, i64, env, i64, i64)
+DEF_HELPER_3(fmina_d, i64, env, i64, i64)
+
+DEF_HELPER_5(fmuladd_s, i64, env, i64, i64, i64, i32)
+DEF_HELPER_5(fmuladd_d, i64, env, i64, i64, i64, i32)
+
+DEF_HELPER_3(fscaleb_s, i64, env, i64, i64)
+DEF_HELPER_3(fscaleb_d, i64, env, i64, i64)
+
+DEF_HELPER_2(flogb_s, i64, env, i64)
+DEF_HELPER_2(flogb_d, i64, env, i64)
+
+DEF_HELPER_2(fabs_s, i64, env, i64)
+DEF_HELPER_2(fabs_d, i64, env, i64)
+DEF_HELPER_2(fneg_s, i64, env, i64)
+DEF_HELPER_2(fneg_d, i64, env, i64)
+
+DEF_HELPER_2(fsqrt_s, i64, env, i64)
+DEF_HELPER_2(fsqrt_d, i64, env, i64)
+DEF_HELPER_2(frsqrt_s, i64, env, i64)
+DEF_HELPER_2(frsqrt_d, i64, env, i64)
+DEF_HELPER_2(frecip_s, i64, env, i64)
+DEF_HELPER_2(frecip_d, i64, env, i64)
+
+DEF_HELPER_FLAGS_2(fclass_s, TCG_CALL_NO_RWG_SE, i64, env, i64)
+DEF_HELPER_FLAGS_2(fclass_d, TCG_CALL_NO_RWG_SE, i64, env, i64)
diff --git a/target/loongarch/insn_trans/trans_farith.c b/target/loongarch/insn_trans/trans_farith.c
new file mode 100644
index 0000000..8015d3b
--- /dev/null
+++ b/target/loongarch/insn_trans/trans_farith.c
@@ -0,0 +1,79 @@
+/*
+ * LoongArch translate functions
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+static bool gen_f3(DisasContext *ctx, arg_fmt_fdfjfk *a,
+ void (*func)(TCGv, TCGv_env, TCGv, TCGv))
+{
+ func(cpu_fpr[a->fd], cpu_env, cpu_fpr[a->fj], cpu_fpr[a->fk]);
+ return true;
+}
+
+static bool gen_muladd(DisasContext *ctx, arg_fmt_fdfjfkfa *a,
+ void (*func)(TCGv, TCGv_env, TCGv, TCGv, TCGv, TCGv_i32),
+ int flag)
+{
+ TCGv_i32 tflag = tcg_constant_i32(flag);
+ func(cpu_fpr[a->fd], cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], cpu_fpr[a->fa], tflag);
+ return true;
+}
+
+static bool trans_fcopysign_s(DisasContext *ctx, arg_fmt_fdfjfk *a)
+{
+ tcg_gen_deposit_i64(cpu_fpr[a->fd], cpu_fpr[a->fk], cpu_fpr[a->fj], 0, 31);
+ return true;
+}
+
+static bool trans_fcopysign_d(DisasContext *ctx, arg_fmt_fdfjfk *a)
+{
+ tcg_gen_deposit_i64(cpu_fpr[a->fd], cpu_fpr[a->fk], cpu_fpr[a->fj], 0, 63);
+ return true;
+}
+
+TRANS(fadd_s, gen_f3, gen_helper_fadd_s)
+TRANS(fadd_d, gen_f3, gen_helper_fadd_d)
+TRANS(fsub_s, gen_f3, gen_helper_fsub_s)
+TRANS(fsub_d, gen_f3, gen_helper_fsub_d)
+TRANS(fmul_s, gen_f3, gen_helper_fmul_s)
+TRANS(fmul_d, gen_f3, gen_helper_fmul_d)
+TRANS(fdiv_s, gen_f3, gen_helper_fdiv_s)
+TRANS(fdiv_d, gen_f3, gen_helper_fdiv_d)
+TRANS(fmax_s, gen_f3, gen_helper_fmax_s)
+TRANS(fmax_d, gen_f3, gen_helper_fmax_d)
+TRANS(fmin_s, gen_f3, gen_helper_fmin_s)
+TRANS(fmin_d, gen_f3, gen_helper_fmin_d)
+TRANS(fmaxa_s, gen_f3, gen_helper_fmaxa_s)
+TRANS(fmaxa_d, gen_f3, gen_helper_fmaxa_d)
+TRANS(fmina_s, gen_f3, gen_helper_fmina_s)
+TRANS(fmina_d, gen_f3, gen_helper_fmina_d)
+TRANS(fscaleb_s, gen_f3, gen_helper_fscaleb_s)
+TRANS(fscaleb_d, gen_f3, gen_helper_fscaleb_d)
+TRANS(fabs_s, gen_f2, gen_helper_fabs_s)
+TRANS(fabs_d, gen_f2, gen_helper_fabs_d)
+TRANS(fneg_s, gen_f2, gen_helper_fneg_s)
+TRANS(fneg_d, gen_f2, gen_helper_fneg_d)
+TRANS(fsqrt_s, gen_f2, gen_helper_fsqrt_s)
+TRANS(fsqrt_d, gen_f2, gen_helper_fsqrt_d)
+TRANS(frecip_s, gen_f2, gen_helper_frecip_s)
+TRANS(frecip_d, gen_f2, gen_helper_frecip_d)
+TRANS(frsqrt_s, gen_f2, gen_helper_frsqrt_s)
+TRANS(frsqrt_d, gen_f2, gen_helper_frsqrt_d)
+TRANS(flogb_s, gen_f2, gen_helper_flogb_s)
+TRANS(flogb_d, gen_f2, gen_helper_flogb_d)
+TRANS(fclass_s, gen_f2, gen_helper_fclass_s)
+TRANS(fclass_d, gen_f2, gen_helper_fclass_d)
+TRANS(fmadd_s, gen_muladd, gen_helper_fmuladd_s, 0)
+TRANS(fmadd_d, gen_muladd, gen_helper_fmuladd_d, 0)
+TRANS(fmsub_s, gen_muladd, gen_helper_fmuladd_s, float_muladd_negate_c)
+TRANS(fmsub_d, gen_muladd, gen_helper_fmuladd_d, float_muladd_negate_c)
+TRANS(fnmadd_s, gen_muladd, gen_helper_fmuladd_s,
+ float_muladd_negate_product | float_muladd_negate_c)
+TRANS(fnmadd_d, gen_muladd, gen_helper_fmuladd_d,
+ float_muladd_negate_product | float_muladd_negate_c)
+TRANS(fnmsub_s, gen_muladd, gen_helper_fmuladd_s, float_muladd_negate_product)
+TRANS(fnmsub_d, gen_muladd, gen_helper_fmuladd_d, float_muladd_negate_product)
diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode
index 66bc314..9e6a727 100644
--- a/target/loongarch/insns.decode
+++ b/target/loongarch/insns.decode
@@ -28,6 +28,10 @@
%hint 0:5
%whint 0:15
%code 0:15
+%fd 0:5
+%fj 5:5
+%fk 10:5
+%fa 15:5
#
# Argument sets
@@ -49,6 +53,9 @@
&fmt_whint whint
&fmt_rjrk rj rk
&fmt_code code
+&fmt_fdfjfk fd fj fk
+&fmt_fdfjfkfa fd fj fk fa
+&fmt_fdfj fd fj
#
# Formats
@@ -70,6 +77,9 @@
@fmt_rdrjsi14 .... .... .............. ..... ..... &fmt_rdrjsi14 %rd %rj %si14
@fmt_rjrk .... ........ ..... ..... ..... ..... &fmt_rjrk %rj %rk
@fmt_code .... ........ ..... ............... &fmt_code %code
+@fmt_fdfjfk .... ........ ..... ..... ..... ..... &fmt_fdfjfk %fd %fj %fk
+@fmt_fdfjfkfa .... ........ ..... ..... ..... ..... &fmt_fdfjfkfa %fd %fj %fk %fa
+@fmt_fdfj .... ........ ..... ..... ..... ..... &fmt_fdfj %fd %fj
#
# Fixed point arithmetic operation instruction
@@ -285,3 +295,49 @@ rdtimel_w 0000 00000000 00000 11000 ..... ..... @fmt_rdrj
rdtimeh_w 0000 00000000 00000 11001 ..... ..... @fmt_rdrj
rdtime_d 0000 00000000 00000 11010 ..... ..... @fmt_rdrj
cpucfg 0000 00000000 00000 11011 ..... ..... @fmt_rdrj
+
+#
+# Floating point arithmetic operation instruction
+#
+fadd_s 0000 00010000 00001 ..... ..... ..... @fmt_fdfjfk
+fadd_d 0000 00010000 00010 ..... ..... ..... @fmt_fdfjfk
+fsub_s 0000 00010000 00101 ..... ..... ..... @fmt_fdfjfk
+fsub_d 0000 00010000 00110 ..... ..... ..... @fmt_fdfjfk
+fmul_s 0000 00010000 01001 ..... ..... ..... @fmt_fdfjfk
+fmul_d 0000 00010000 01010 ..... ..... ..... @fmt_fdfjfk
+fdiv_s 0000 00010000 01101 ..... ..... ..... @fmt_fdfjfk
+fdiv_d 0000 00010000 01110 ..... ..... ..... @fmt_fdfjfk
+fmadd_s 0000 10000001 ..... ..... ..... ..... @fmt_fdfjfkfa
+fmadd_d 0000 10000010 ..... ..... ..... ..... @fmt_fdfjfkfa
+fmsub_s 0000 10000101 ..... ..... ..... ..... @fmt_fdfjfkfa
+fmsub_d 0000 10000110 ..... ..... ..... ..... @fmt_fdfjfkfa
+fnmadd_s 0000 10001001 ..... ..... ..... ..... @fmt_fdfjfkfa
+fnmadd_d 0000 10001010 ..... ..... ..... ..... @fmt_fdfjfkfa
+fnmsub_s 0000 10001101 ..... ..... ..... ..... @fmt_fdfjfkfa
+fnmsub_d 0000 10001110 ..... ..... ..... ..... @fmt_fdfjfkfa
+fmax_s 0000 00010000 10001 ..... ..... ..... @fmt_fdfjfk
+fmax_d 0000 00010000 10010 ..... ..... ..... @fmt_fdfjfk
+fmin_s 0000 00010000 10101 ..... ..... ..... @fmt_fdfjfk
+fmin_d 0000 00010000 10110 ..... ..... ..... @fmt_fdfjfk
+fmaxa_s 0000 00010000 11001 ..... ..... ..... @fmt_fdfjfk
+fmaxa_d 0000 00010000 11010 ..... ..... ..... @fmt_fdfjfk
+fmina_s 0000 00010000 11101 ..... ..... ..... @fmt_fdfjfk
+fmina_d 0000 00010000 11110 ..... ..... ..... @fmt_fdfjfk
+fabs_s 0000 00010001 01000 00001 ..... ..... @fmt_fdfj
+fabs_d 0000 00010001 01000 00010 ..... ..... @fmt_fdfj
+fneg_s 0000 00010001 01000 00101 ..... ..... @fmt_fdfj
+fneg_d 0000 00010001 01000 00110 ..... ..... @fmt_fdfj
+fsqrt_s 0000 00010001 01000 10001 ..... ..... @fmt_fdfj
+fsqrt_d 0000 00010001 01000 10010 ..... ..... @fmt_fdfj
+frecip_s 0000 00010001 01000 10101 ..... ..... @fmt_fdfj
+frecip_d 0000 00010001 01000 10110 ..... ..... @fmt_fdfj
+frsqrt_s 0000 00010001 01000 11001 ..... ..... @fmt_fdfj
+frsqrt_d 0000 00010001 01000 11010 ..... ..... @fmt_fdfj
+fscaleb_s 0000 00010001 00001 ..... ..... ..... @fmt_fdfjfk
+fscaleb_d 0000 00010001 00010 ..... ..... ..... @fmt_fdfjfk
+flogb_s 0000 00010001 01000 01001 ..... ..... @fmt_fdfj
+flogb_d 0000 00010001 01000 01010 ..... ..... @fmt_fdfj
+fcopysign_s 0000 00010001 00101 ..... ..... ..... @fmt_fdfjfk
+fcopysign_d 0000 00010001 00110 ..... ..... ..... @fmt_fdfjfk
+fclass_s 0000 00010001 01000 01101 ..... ..... @fmt_fdfj
+fclass_d 0000 00010001 01000 01110 ..... ..... @fmt_fdfj
diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h
index 1052cb6..096a4a7 100644
--- a/target/loongarch/internals.h
+++ b/target/loongarch/internals.h
@@ -19,4 +19,6 @@ void QEMU_NORETURN do_raise_exception(CPULoongArchState *env,
const char *loongarch_exception_name(int32_t exception);
+void restore_fp_status(CPULoongArchState *env);
+
#endif
diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c
index 77b0180..a4a9e9a 100644
--- a/target/loongarch/translate.c
+++ b/target/loongarch/translate.c
@@ -16,7 +16,7 @@
#include "exec/translator.h"
#include "exec/log.h"
#include "qemu/qemu-print.h"
-#include "fpu_helper.h"
+#include "fpu/softfloat.h"
#include "translate.h"
#include "internals.h"
@@ -187,12 +187,21 @@ static bool gen_r3(DisasContext *ctx, arg_fmt_rdrjrk *a,
return true;
}
+/* fmt fd fj */
+static bool gen_f2(DisasContext *ctx, arg_fmt_fdfj *a,
+ void (*func)(TCGv, TCGv_env, TCGv))
+{
+ func(cpu_fpr[a->fd], cpu_env, cpu_fpr[a->fj]);
+ return true;
+}
+
#include "insn_trans/trans_arith.c"
#include "insn_trans/trans_shift.c"
#include "insn_trans/trans_bit.c"
#include "insn_trans/trans_memory.c"
#include "insn_trans/trans_atomic.c"
#include "insn_trans/trans_extra.c"
+#include "insn_trans/trans_farith.c"
static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
{
diff --git a/target/loongarch/translate.h b/target/loongarch/translate.h
index f064fdd..99ab329 100644
--- a/target/loongarch/translate.h
+++ b/target/loongarch/translate.h
@@ -44,4 +44,6 @@ extern TCGv cpu_gpr[32], cpu_pc;
extern TCGv_i32 cpu_fscr0;
extern TCGv_i64 cpu_fpr[32];
+int ieee_ex_to_loongarch(int xcpt);
+
#endif
--
1.8.3.1
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v3 11/19] target/loongarch: Add floating point comparison instruction translation
2021-08-27 7:14 [PATCH v3 00/19] Add LoongArch linux-user emulation support Song Gao
` (9 preceding siblings ...)
2021-08-27 7:14 ` [PATCH v3 10/19] target/loongarch: Add floating point arithmetic " Song Gao
@ 2021-08-27 7:14 ` Song Gao
2021-08-27 7:14 ` [PATCH v3 12/19] target/loongarch: Add floating point conversion " Song Gao
` (7 subsequent siblings)
18 siblings, 0 replies; 22+ messages in thread
From: Song Gao @ 2021-08-27 7:14 UTC (permalink / raw)
To: qemu-devel
Cc: peter.maydell, thuth, chenhuacai, richard.henderson, f4bug,
maobibo, laurent, yangxiaojuan, alistair.francis, pbonzini,
alex.bennee
This patch implement floating point comparison instruction translation.
This includes:
- FCMP.cond.{S/D}
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
target/loongarch/fpu_helper.c | 110 ++++++++++++
target/loongarch/helper.h | 9 +
target/loongarch/insn_trans/trans_fcmp.c | 279 +++++++++++++++++++++++++++++++
target/loongarch/insns.decode | 10 ++
target/loongarch/translate.c | 1 +
target/loongarch/translate.h | 5 +
6 files changed, 414 insertions(+)
create mode 100644 target/loongarch/insn_trans/trans_fcmp.c
diff --git a/target/loongarch/fpu_helper.c b/target/loongarch/fpu_helper.c
index c3bee57..bad7238 100644
--- a/target/loongarch/fpu_helper.c
+++ b/target/loongarch/fpu_helper.c
@@ -436,3 +436,113 @@ uint64_t helper_fmuladd_d(CPULoongArchState *env, uint64_t fj,
update_fcsr0(env, GETPC());
return fd;
}
+
+/* fcmp_cXXX_s */
+uint64_t helper_fcmp_c_s(CPULoongArchState *env, uint64_t fj,
+ uint64_t fk, uint32_t flags)
+{
+ uint32_t t0, t1;
+ uint64_t cmp = 0;
+ t0 = (uint32_t)fj;
+ t1 = (uint32_t)fk;
+
+ if (flags) {
+ if (flags & FCMP_LT) {
+ cmp |= float32_lt_quiet(t0, t1, &env->fp_status);
+ }
+ if (flags & FCMP_EQ) {
+ cmp |= float32_eq_quiet(t0, t1, &env->fp_status);
+ }
+ if (flags & FCMP_GT) {
+ cmp |= float32_lt_quiet(t1, t0, &env->fp_status);
+ }
+ if (flags & FCMP_UN) {
+ cmp |= float32_unordered_quiet(t1, t0, &env->fp_status);
+ }
+ } else {
+ cmp = (float32_unordered_quiet(t1, t0, &env->fp_status), 0);
+ }
+ update_fcsr0(env, GETPC());
+ return cmp;
+}
+
+/* fcmp_sXXX_s */
+uint64_t helper_fcmp_s_s(CPULoongArchState *env, uint64_t fj,
+ uint64_t fk, uint32_t flags)
+{
+ uint32_t t0, t1;
+ uint64_t cmp = 0;
+ t0 = (uint32_t)fj;
+ t1 = (uint32_t)fk;
+
+ if (flags) {
+ if (flags & FCMP_LT) {
+ cmp |= float32_lt(t0, t1, &env->fp_status);
+ }
+ if (flags & FCMP_EQ) {
+ cmp |= float32_eq(t0, t1, &env->fp_status);
+ }
+ if (flags & FCMP_GT) {
+ cmp |= float32_lt(t1, t0, &env->fp_status);
+ }
+ if (flags & FCMP_UN) {
+ cmp |= float32_unordered(t1, t0, &env->fp_status);
+ }
+ } else {
+ cmp = (float32_unordered(t1, t0, &env->fp_status), 0);
+ }
+ update_fcsr0(env, GETPC());
+ return cmp;
+}
+
+/* fcmp_cXXX_d */
+uint64_t helper_fcmp_c_d(CPULoongArchState *env, uint64_t fj,
+ uint64_t fk, uint32_t flags)
+{
+ uint64_t cmp = 0;
+
+ if (flags) {
+ if (flags & FCMP_LT) {
+ cmp |= float64_lt_quiet(fj, fk, &env->fp_status);
+ }
+ if (flags & FCMP_EQ) {
+ cmp |= float64_eq_quiet(fj, fk, &env->fp_status);
+ }
+ if (flags & FCMP_GT) {
+ cmp |= float64_lt_quiet(fk, fj, &env->fp_status);
+ }
+ if (flags & FCMP_UN) {
+ cmp |= float64_unordered_quiet(fk, fj, &env->fp_status);
+ }
+ } else {
+ cmp = (float64_unordered_quiet(fk, fj, &env->fp_status), 0);
+ }
+ update_fcsr0(env, GETPC());
+ return cmp;
+}
+
+/* fcmp_sXXX_d */
+uint64_t helper_fcmp_s_d(CPULoongArchState *env, uint64_t fj,
+ uint64_t fk, uint32_t flags)
+{
+ uint64_t cmp = 0;
+
+ if (flags) {
+ if (flags & FCMP_LT) {
+ cmp |= float64_lt(fj, fk, &env->fp_status);
+ }
+ if (flags & FCMP_EQ) {
+ cmp |= float64_eq(fj, fk, &env->fp_status);
+ }
+ if (flags & FCMP_GT) {
+ cmp |= float64_lt(fk, fj, &env->fp_status);
+ }
+ if (flags & FCMP_UN) {
+ cmp |= float64_unordered(fk, fj, &env->fp_status);
+ }
+ } else {
+ cmp = (float64_unordered(fk, fj, &env->fp_status), 0);
+ }
+ update_fcsr0(env, GETPC());
+ return cmp;
+}
diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h
index 62c262e..5f6e60d 100644
--- a/target/loongarch/helper.h
+++ b/target/loongarch/helper.h
@@ -60,3 +60,12 @@ DEF_HELPER_2(frecip_d, i64, env, i64)
DEF_HELPER_FLAGS_2(fclass_s, TCG_CALL_NO_RWG_SE, i64, env, i64)
DEF_HELPER_FLAGS_2(fclass_d, TCG_CALL_NO_RWG_SE, i64, env, i64)
+
+/* fcmp.cXXX.s */
+DEF_HELPER_4(fcmp_c_s, i64, env, i64, i64, i32)
+/* fcmp.sXXX.s */
+DEF_HELPER_4(fcmp_s_s, i64, env, i64, i64, i32)
+/* fcmp.cXXX.d */
+DEF_HELPER_4(fcmp_c_d, i64, env, i64, i64, i32)
+/* fcmp.sXXX.d */
+DEF_HELPER_4(fcmp_s_d, i64, env, i64, i64, i32)
diff --git a/target/loongarch/insn_trans/trans_fcmp.c b/target/loongarch/insn_trans/trans_fcmp.c
new file mode 100644
index 0000000..e9d7c3b
--- /dev/null
+++ b/target/loongarch/insn_trans/trans_fcmp.c
@@ -0,0 +1,279 @@
+/*
+ * LoongArch translate functions
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+static bool trans_fcmp_cond_s(DisasContext *ctx, arg_fcmp_cond_s *a)
+{
+ TCGv var = tcg_temp_new();
+ TCGv_i32 flags = NULL;
+
+ switch (a->fcond) {
+ /* caf */
+ case 0:
+ flags = tcg_constant_i32(0);
+ gen_helper_fcmp_c_s(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ /* saf */
+ case 1:
+ flags = tcg_constant_i32(0);
+ gen_helper_fcmp_s_s(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ /* clt */
+ case 2:
+ flags = tcg_constant_i32(FCMP_LT);
+ gen_helper_fcmp_c_s(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ /* slt */
+ case 3:
+ flags = tcg_constant_i32(FCMP_LT);
+ gen_helper_fcmp_s_s(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ /* ceq */
+ case 4:
+ flags = tcg_constant_i32(FCMP_EQ);
+ gen_helper_fcmp_c_s(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ /* seq */
+ case 5:
+ flags = tcg_constant_i32(FCMP_EQ);
+ gen_helper_fcmp_s_s(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ /* cle */
+ case 6:
+ flags = tcg_constant_i32(FCMP_LT | FCMP_EQ);
+ gen_helper_fcmp_c_s(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ /* sle */
+ case 7:
+ flags = tcg_constant_i32(FCMP_LT | FCMP_EQ);
+ gen_helper_fcmp_s_s(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ /* cun */
+ case 8:
+ flags = tcg_constant_i32(FCMP_UN);
+ gen_helper_fcmp_c_s(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ /* sun */
+ case 9:
+ flags = tcg_constant_i32(FCMP_UN);
+ gen_helper_fcmp_s_s(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ /* cult */
+ case 10:
+ flags = tcg_constant_i32(FCMP_UN | FCMP_LT);
+ gen_helper_fcmp_c_s(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ /* sult */
+ case 11:
+ flags = tcg_constant_i32(FCMP_UN | FCMP_LT);
+ gen_helper_fcmp_s_s(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ /* cueq */
+ case 12:
+ flags = tcg_constant_i32(FCMP_UN | FCMP_EQ);
+ gen_helper_fcmp_c_s(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ /* sueq */
+ case 13:
+ flags = tcg_constant_i32(FCMP_UN | FCMP_EQ);
+ gen_helper_fcmp_s_s(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ /* cule */
+ case 14:
+ flags = tcg_constant_i32(FCMP_UN | FCMP_LT | FCMP_EQ);
+ gen_helper_fcmp_c_s(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ /* sule */
+ case 15:
+ flags = tcg_constant_i32(FCMP_UN | FCMP_LT | FCMP_EQ);
+ gen_helper_fcmp_s_s(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ /* cne */
+ case 16:
+ flags = tcg_constant_i32(FCMP_GT | FCMP_LT);
+ gen_helper_fcmp_c_s(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ /* sne */
+ case 17:
+ flags = tcg_constant_i32(FCMP_GT | FCMP_LT);
+ gen_helper_fcmp_s_s(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ /* cor */
+ case 20:
+ flags = tcg_constant_i32(FCMP_GT | FCMP_LT | FCMP_EQ);
+ gen_helper_fcmp_c_s(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ /* sor */
+ case 21:
+ flags = tcg_constant_i32(FCMP_GT | FCMP_LT | FCMP_EQ);
+ gen_helper_fcmp_s_s(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ /* cune */
+ case 24:
+ flags = tcg_constant_i32(FCMP_UN | FCMP_GT | FCMP_LT);
+ gen_helper_fcmp_c_s(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ /* sune */
+ case 25:
+ flags = tcg_constant_i32(FCMP_UN | FCMP_GT | FCMP_LT);
+ gen_helper_fcmp_s_s(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ default:
+ abort();
+ }
+
+ tcg_gen_st8_tl(var, cpu_env, offsetof(CPULoongArchState, cf[a->cd & 0x7]));
+ tcg_temp_free(var);
+ return true;
+}
+
+static bool trans_fcmp_cond_d(DisasContext *ctx, arg_fcmp_cond_d *a)
+{
+ TCGv var = tcg_temp_new();
+ TCGv_i32 flags = NULL;
+
+ switch (a->fcond) {
+ case 0:
+ flags = tcg_constant_i32(0);
+ gen_helper_fcmp_c_d(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ case 1:
+ flags = tcg_constant_i32(0);
+ gen_helper_fcmp_s_d(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ case 2:
+ flags = tcg_constant_i32(FCMP_LT);
+ gen_helper_fcmp_c_d(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ case 3:
+ flags = tcg_constant_i32(FCMP_LT);
+ gen_helper_fcmp_s_d(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ case 4:
+ flags = tcg_constant_i32(FCMP_EQ);
+ gen_helper_fcmp_c_d(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ case 5:
+ flags = tcg_constant_i32(FCMP_EQ);
+ gen_helper_fcmp_s_d(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ case 6:
+ flags = tcg_constant_i32(FCMP_LT | FCMP_EQ);
+ gen_helper_fcmp_c_d(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ case 7:
+ flags = tcg_constant_i32(FCMP_LT | FCMP_EQ);
+ gen_helper_fcmp_s_d(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ case 8:
+ flags = tcg_constant_i32(FCMP_UN);
+ gen_helper_fcmp_c_d(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ case 9:
+ flags = tcg_constant_i32(FCMP_UN);
+ gen_helper_fcmp_s_d(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ case 10:
+ flags = tcg_constant_i32(FCMP_UN | FCMP_LT);
+ gen_helper_fcmp_c_d(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ case 11:
+ flags = tcg_constant_i32(FCMP_UN | FCMP_LT);
+ gen_helper_fcmp_s_d(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ case 12:
+ flags = tcg_constant_i32(FCMP_UN | FCMP_EQ);
+ gen_helper_fcmp_c_d(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ case 13:
+ flags = tcg_constant_i32(FCMP_UN | FCMP_EQ);
+ gen_helper_fcmp_s_d(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ case 14:
+ flags = tcg_constant_i32(FCMP_UN | FCMP_LT | FCMP_EQ);
+ gen_helper_fcmp_c_d(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ case 15:
+ flags = tcg_constant_i32(FCMP_UN | FCMP_LT | FCMP_EQ);
+ gen_helper_fcmp_s_d(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ case 16:
+ flags = tcg_constant_i32(FCMP_GT | FCMP_LT);
+ gen_helper_fcmp_c_d(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ case 17:
+ flags = tcg_constant_i32(FCMP_GT | FCMP_LT);
+ gen_helper_fcmp_s_d(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ case 20:
+ flags = tcg_constant_i32(FCMP_GT | FCMP_LT | FCMP_EQ);
+ gen_helper_fcmp_c_d(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ case 21:
+ flags = tcg_constant_i32(FCMP_GT | FCMP_LT | FCMP_EQ);
+ gen_helper_fcmp_s_d(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ case 24:
+ flags = tcg_constant_i32(FCMP_UN | FCMP_GT | FCMP_LT);
+ gen_helper_fcmp_c_d(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ case 25:
+ flags = tcg_constant_i32(FCMP_UN | FCMP_GT | FCMP_LT);
+ gen_helper_fcmp_s_d(var, cpu_env, cpu_fpr[a->fj],
+ cpu_fpr[a->fk], flags);
+ break;
+ default:
+ abort();
+ }
+
+ tcg_gen_st8_tl(var, cpu_env, offsetof(CPULoongArchState, cf[a->cd & 0x7]));
+ tcg_temp_free(var);
+ return true;
+}
diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode
index 9e6a727..8aadcfd 100644
--- a/target/loongarch/insns.decode
+++ b/target/loongarch/insns.decode
@@ -32,6 +32,8 @@
%fj 5:5
%fk 10:5
%fa 15:5
+%cd 0:3
+%fcond 15:5
#
# Argument sets
@@ -56,6 +58,7 @@
&fmt_fdfjfk fd fj fk
&fmt_fdfjfkfa fd fj fk fa
&fmt_fdfj fd fj
+&fmt_cdfjfkfcond cd fj fk fcond
#
# Formats
@@ -80,6 +83,7 @@
@fmt_fdfjfk .... ........ ..... ..... ..... ..... &fmt_fdfjfk %fd %fj %fk
@fmt_fdfjfkfa .... ........ ..... ..... ..... ..... &fmt_fdfjfkfa %fd %fj %fk %fa
@fmt_fdfj .... ........ ..... ..... ..... ..... &fmt_fdfj %fd %fj
+@fmt_cdfjfkfcond .... ........ ..... ..... ..... .. ... &fmt_cdfjfkfcond %cd %fj %fk %fcond
#
# Fixed point arithmetic operation instruction
@@ -341,3 +345,9 @@ fcopysign_s 0000 00010001 00101 ..... ..... ..... @fmt_fdfjfk
fcopysign_d 0000 00010001 00110 ..... ..... ..... @fmt_fdfjfk
fclass_s 0000 00010001 01000 01101 ..... ..... @fmt_fdfj
fclass_d 0000 00010001 01000 01110 ..... ..... @fmt_fdfj
+
+#
+# Floating point compare instruction
+#
+fcmp_cond_s 0000 11000001 ..... ..... ..... 00 ... @fmt_cdfjfkfcond
+fcmp_cond_d 0000 11000010 ..... ..... ..... 00 ... @fmt_cdfjfkfcond
diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c
index a4a9e9a..8cce6cc 100644
--- a/target/loongarch/translate.c
+++ b/target/loongarch/translate.c
@@ -202,6 +202,7 @@ static bool gen_f2(DisasContext *ctx, arg_fmt_fdfj *a,
#include "insn_trans/trans_atomic.c"
#include "insn_trans/trans_extra.c"
#include "insn_trans/trans_farith.c"
+#include "insn_trans/trans_fcmp.c"
static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
{
diff --git a/target/loongarch/translate.h b/target/loongarch/translate.h
index 99ab329..16e570c 100644
--- a/target/loongarch/translate.h
+++ b/target/loongarch/translate.h
@@ -11,6 +11,11 @@
#include "exec/translator.h"
+#define FCMP_LT 0x0001 /* fp0 < fp1 */
+#define FCMP_EQ 0x0010 /* fp0 = fp1 */
+#define FCMP_GT 0x0100 /* fp1 < fp0 */
+#define FCMP_UN 0x1000 /* unordered */
+
#define TRANS(NAME, FUNC, ...) \
static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
{ return FUNC(ctx, a, __VA_ARGS__); }
--
1.8.3.1
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v3 12/19] target/loongarch: Add floating point conversion instruction translation
2021-08-27 7:14 [PATCH v3 00/19] Add LoongArch linux-user emulation support Song Gao
` (10 preceding siblings ...)
2021-08-27 7:14 ` [PATCH v3 11/19] target/loongarch: Add floating point comparison " Song Gao
@ 2021-08-27 7:14 ` Song Gao
2021-08-27 7:14 ` [PATCH v3 13/19] target/loongarch: Add floating point move " Song Gao
` (6 subsequent siblings)
18 siblings, 0 replies; 22+ messages in thread
From: Song Gao @ 2021-08-27 7:14 UTC (permalink / raw)
To: qemu-devel
Cc: peter.maydell, thuth, chenhuacai, richard.henderson, f4bug,
maobibo, laurent, yangxiaojuan, alistair.francis, pbonzini,
alex.bennee
This patch implement floating point conversion instruction translation.
This includes:
- FCVT.S.D, FCVT.D.S
- FFINT.{S/D}.{W/L}, FTINT.{W/L}.{S/D}
- FTINT{RM/RP/RZ/RNE}.{W/L}.{S/D}
- FRINT.{S/D}
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
target/loongarch/fpu_helper.c | 393 +++++++++++++++++++++++++++++++
target/loongarch/helper.h | 29 +++
target/loongarch/insn_trans/trans_fcnv.c | 36 +++
target/loongarch/insns.decode | 32 +++
target/loongarch/translate.c | 1 +
5 files changed, 491 insertions(+)
create mode 100644 target/loongarch/insn_trans/trans_fcnv.c
diff --git a/target/loongarch/fpu_helper.c b/target/loongarch/fpu_helper.c
index bad7238..2aef1fa 100644
--- a/target/loongarch/fpu_helper.c
+++ b/target/loongarch/fpu_helper.c
@@ -546,3 +546,396 @@ uint64_t helper_fcmp_s_d(CPULoongArchState *env, uint64_t fj,
update_fcsr0(env, GETPC());
return cmp;
}
+
+/* floating point conversion */
+uint64_t helper_fcvt_s_d(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+
+ fd = nanbox_s(float64_to_float32(fj, &env->fp_status));
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_fcvt_d_s(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+
+ fd = float32_to_float64((uint32_t)fj, &env->fp_status);
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_ffint_s_w(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+
+ fd = nanbox_s(int32_to_float32((int32_t)fj, &env->fp_status));
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_ffint_s_l(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+
+ fd = nanbox_s(int64_to_float32(fj, &env->fp_status));
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_ffint_d_w(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+
+ fd = int32_to_float64((int32_t)fj, &env->fp_status);
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_ffint_d_l(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+
+ fd = int64_to_float64(fj, &env->fp_status);
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_frint_s(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+
+ fd = (uint64_t)(float32_round_to_int((uint32_t)fj, &env->fp_status));
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_frint_d(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+
+ fd = float64_round_to_int(fj, &env->fp_status);
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_ftintrm_l_d(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+ FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status);
+
+ set_float_rounding_mode(float_round_down, &env->fp_status);
+ fd = float64_to_int64(fj, &env->fp_status);
+ set_float_rounding_mode(old_mode, &env->fp_status);
+
+ if (get_float_exception_flags(&env->fp_status) &
+ (float_flag_invalid | float_flag_overflow)) {
+ fd = FLOAT_TO_INT64_OVERFLOW;
+ }
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_ftintrm_l_s(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+ FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status);
+
+ set_float_rounding_mode(float_round_down, &env->fp_status);
+ fd = float32_to_int64((uint32_t)fj, &env->fp_status);
+ set_float_rounding_mode(old_mode, &env->fp_status);
+
+ if (get_float_exception_flags(&env->fp_status) &
+ (float_flag_invalid | float_flag_overflow)) {
+ fd = FLOAT_TO_INT64_OVERFLOW;
+ }
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_ftintrm_w_d(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+ FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status);
+
+ set_float_rounding_mode(float_round_down, &env->fp_status);
+ fd = (uint64_t)float64_to_int32(fj, &env->fp_status);
+ set_float_rounding_mode(old_mode, &env->fp_status);
+
+ if (get_float_exception_flags(&env->fp_status) &
+ (float_flag_invalid | float_flag_overflow)) {
+ fd = FLOAT_TO_INT32_OVERFLOW;
+ }
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_ftintrm_w_s(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+ FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status);
+
+ set_float_rounding_mode(float_round_down, &env->fp_status);
+ fd = (uint64_t)float32_to_int32((uint32_t)fj, &env->fp_status);
+ set_float_rounding_mode(old_mode, &env->fp_status);
+
+ if (get_float_exception_flags(&env->fp_status) &
+ (float_flag_invalid | float_flag_overflow)) {
+ fd = FLOAT_TO_INT32_OVERFLOW;
+ }
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_ftintrp_l_d(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+ FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status);
+
+ set_float_rounding_mode(float_round_up, &env->fp_status);
+ fd = float64_to_int64(fj, &env->fp_status);
+ set_float_rounding_mode(old_mode, &env->fp_status);
+
+ if (get_float_exception_flags(&env->fp_status) &
+ (float_flag_invalid | float_flag_overflow)) {
+ fd = FLOAT_TO_INT64_OVERFLOW;
+ }
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_ftintrp_l_s(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+ FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status);
+
+ set_float_rounding_mode(float_round_up, &env->fp_status);
+ fd = float32_to_int64((uint32_t)fj, &env->fp_status);
+ set_float_rounding_mode(old_mode, &env->fp_status);
+
+ if (get_float_exception_flags(&env->fp_status) &
+ (float_flag_invalid | float_flag_overflow)) {
+ fd = FLOAT_TO_INT64_OVERFLOW;
+ }
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_ftintrp_w_d(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+ FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status);
+
+ set_float_rounding_mode(float_round_up, &env->fp_status);
+ fd = (uint64_t)float64_to_int32(fj, &env->fp_status);
+ set_float_rounding_mode(old_mode, &env->fp_status);
+
+ if (get_float_exception_flags(&env->fp_status) &
+ (float_flag_invalid | float_flag_overflow)) {
+ fd = FLOAT_TO_INT32_OVERFLOW;
+ }
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_ftintrp_w_s(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+ FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status);
+
+ set_float_rounding_mode(float_round_up, &env->fp_status);
+ fd = (uint64_t)float32_to_int32((uint32_t)fj, &env->fp_status);
+ set_float_rounding_mode(old_mode, &env->fp_status);
+
+ if (get_float_exception_flags(&env->fp_status) &
+ (float_flag_invalid | float_flag_overflow)) {
+ fd = FLOAT_TO_INT32_OVERFLOW;
+ }
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_ftintrz_l_d(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+ FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status);
+
+ fd = float64_to_int64_round_to_zero(fj, &env->fp_status);
+ set_float_rounding_mode(old_mode, &env->fp_status);
+
+ if (get_float_exception_flags(&env->fp_status) &
+ (float_flag_invalid | float_flag_overflow)) {
+ fd = FLOAT_TO_INT64_OVERFLOW;
+ }
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_ftintrz_l_s(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+ FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status);
+
+ fd = float32_to_int64_round_to_zero((uint32_t)fj, &env->fp_status);
+ set_float_rounding_mode(old_mode, &env->fp_status);
+
+ if (get_float_exception_flags(&env->fp_status) &
+ (float_flag_invalid | float_flag_overflow)) {
+ fd = FLOAT_TO_INT64_OVERFLOW;
+ }
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_ftintrz_w_d(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+ FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status);
+
+ fd = (uint64_t)float64_to_int32_round_to_zero(fj, &env->fp_status);
+ set_float_rounding_mode(old_mode, &env->fp_status);
+
+ if (get_float_exception_flags(&env->fp_status) &
+ (float_flag_invalid | float_flag_overflow)) {
+ fd = FLOAT_TO_INT32_OVERFLOW;
+ }
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_ftintrz_w_s(CPULoongArchState *env, uint64_t fj)
+{
+ uint32_t fd;
+ FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status);
+
+ fd = float32_to_int32_round_to_zero((uint32_t)fj, &env->fp_status);
+ set_float_rounding_mode(old_mode, &env->fp_status);
+
+ if (get_float_exception_flags(&env->fp_status) &
+ (float_flag_invalid | float_flag_overflow)) {
+ fd = FLOAT_TO_INT32_OVERFLOW;
+ }
+ update_fcsr0(env, GETPC());
+ return (uint64_t)fd;
+}
+
+uint64_t helper_ftintrne_l_d(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+ FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status);
+
+ set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
+ fd = float64_to_int64(fj, &env->fp_status);
+ set_float_rounding_mode(old_mode, &env->fp_status);
+
+ if (get_float_exception_flags(&env->fp_status) &
+ (float_flag_invalid | float_flag_overflow)) {
+ fd = FLOAT_TO_INT64_OVERFLOW;
+ }
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_ftintrne_l_s(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+ FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status);
+
+ set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
+ fd = float32_to_int64((uint32_t)fj, &env->fp_status);
+ set_float_rounding_mode(old_mode, &env->fp_status);
+
+ if (get_float_exception_flags(&env->fp_status) &
+ (float_flag_invalid | float_flag_overflow)) {
+ fd = FLOAT_TO_INT64_OVERFLOW;
+ }
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_ftintrne_w_d(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+ FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status);
+
+ set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
+ fd = (uint64_t)float64_to_int32(fj, &env->fp_status);
+ set_float_rounding_mode(old_mode, &env->fp_status);
+
+ if (get_float_exception_flags(&env->fp_status) &
+ (float_flag_invalid | float_flag_overflow)) {
+ fd = FLOAT_TO_INT32_OVERFLOW;
+ }
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_ftintrne_w_s(CPULoongArchState *env, uint64_t fj)
+{
+ uint32_t fd;
+ FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status);
+
+ set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
+ fd = float32_to_int32((uint32_t)fj, &env->fp_status);
+ set_float_rounding_mode(old_mode, &env->fp_status);
+
+ if (get_float_exception_flags(&env->fp_status) &
+ (float_flag_invalid | float_flag_overflow)) {
+ fd = FLOAT_TO_INT32_OVERFLOW;
+ }
+ update_fcsr0(env, GETPC());
+ return (uint64_t)fd;
+}
+
+uint64_t helper_ftint_l_d(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+
+ fd = float64_to_int64(fj, &env->fp_status);
+ if (get_float_exception_flags(&env->fp_status) &
+ (float_flag_invalid | float_flag_overflow)) {
+ fd = FLOAT_TO_INT64_OVERFLOW;
+ }
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_ftint_l_s(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+
+ fd = float32_to_int64((uint32_t)fj, &env->fp_status);
+ if (get_float_exception_flags(&env->fp_status) &
+ (float_flag_invalid | float_flag_overflow)) {
+ fd = FLOAT_TO_INT64_OVERFLOW;
+ }
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_ftint_w_s(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+
+ fd = (uint64_t)float32_to_int32((uint32_t)fj, &env->fp_status);
+ if (get_float_exception_flags(&env->fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ fd = FLOAT_TO_INT32_OVERFLOW;
+ }
+ update_fcsr0(env, GETPC());
+ return fd;
+}
+
+uint64_t helper_ftint_w_d(CPULoongArchState *env, uint64_t fj)
+{
+ uint64_t fd;
+
+ fd = (uint64_t)float64_to_int32(fj, &env->fp_status);
+ if (get_float_exception_flags(&env->fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ fd = FLOAT_TO_INT32_OVERFLOW;
+ }
+ update_fcsr0(env, GETPC());
+ return fd;
+}
diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h
index 5f6e60d..d90b093 100644
--- a/target/loongarch/helper.h
+++ b/target/loongarch/helper.h
@@ -69,3 +69,32 @@ DEF_HELPER_4(fcmp_s_s, i64, env, i64, i64, i32)
DEF_HELPER_4(fcmp_c_d, i64, env, i64, i64, i32)
/* fcmp.sXXX.d */
DEF_HELPER_4(fcmp_s_d, i64, env, i64, i64, i32)
+
+DEF_HELPER_2(fcvt_d_s, i64, env, i64)
+DEF_HELPER_2(fcvt_s_d, i64, env, i64)
+DEF_HELPER_2(ffint_d_w, i64, env, i64)
+DEF_HELPER_2(ffint_d_l, i64, env, i64)
+DEF_HELPER_2(ffint_s_w, i64, env, i64)
+DEF_HELPER_2(ffint_s_l, i64, env, i64)
+DEF_HELPER_2(ftintrm_l_s, i64, env, i64)
+DEF_HELPER_2(ftintrm_l_d, i64, env, i64)
+DEF_HELPER_2(ftintrm_w_s, i64, env, i64)
+DEF_HELPER_2(ftintrm_w_d, i64, env, i64)
+DEF_HELPER_2(ftintrp_l_s, i64, env, i64)
+DEF_HELPER_2(ftintrp_l_d, i64, env, i64)
+DEF_HELPER_2(ftintrp_w_s, i64, env, i64)
+DEF_HELPER_2(ftintrp_w_d, i64, env, i64)
+DEF_HELPER_2(ftintrz_l_s, i64, env, i64)
+DEF_HELPER_2(ftintrz_l_d, i64, env, i64)
+DEF_HELPER_2(ftintrz_w_s, i64, env, i64)
+DEF_HELPER_2(ftintrz_w_d, i64, env, i64)
+DEF_HELPER_2(ftintrne_l_s, i64, env, i64)
+DEF_HELPER_2(ftintrne_l_d, i64, env, i64)
+DEF_HELPER_2(ftintrne_w_s, i64, env, i64)
+DEF_HELPER_2(ftintrne_w_d, i64, env, i64)
+DEF_HELPER_2(ftint_l_s, i64, env, i64)
+DEF_HELPER_2(ftint_l_d, i64, env, i64)
+DEF_HELPER_2(ftint_w_s, i64, env, i64)
+DEF_HELPER_2(ftint_w_d, i64, env, i64)
+DEF_HELPER_2(frint_s, i64, env, i64)
+DEF_HELPER_2(frint_d, i64, env, i64)
diff --git a/target/loongarch/insn_trans/trans_fcnv.c b/target/loongarch/insn_trans/trans_fcnv.c
new file mode 100644
index 0000000..6788859
--- /dev/null
+++ b/target/loongarch/insn_trans/trans_fcnv.c
@@ -0,0 +1,36 @@
+/*
+ * LoongArch translate functions
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+TRANS(fcvt_s_d, gen_f2, gen_helper_fcvt_s_d)
+TRANS(fcvt_d_s, gen_f2, gen_helper_fcvt_d_s)
+TRANS(ftintrm_w_s, gen_f2, gen_helper_ftintrm_w_s)
+TRANS(ftintrm_w_d, gen_f2, gen_helper_ftintrm_w_d)
+TRANS(ftintrm_l_s, gen_f2, gen_helper_ftintrm_l_s)
+TRANS(ftintrm_l_d, gen_f2, gen_helper_ftintrm_l_d)
+TRANS(ftintrp_w_s, gen_f2, gen_helper_ftintrp_w_s)
+TRANS(ftintrp_w_d, gen_f2, gen_helper_ftintrp_w_d)
+TRANS(ftintrp_l_s, gen_f2, gen_helper_ftintrp_l_s)
+TRANS(ftintrp_l_d, gen_f2, gen_helper_ftintrp_l_d)
+TRANS(ftintrz_w_s, gen_f2, gen_helper_ftintrz_w_s)
+TRANS(ftintrz_w_d, gen_f2, gen_helper_ftintrz_w_d)
+TRANS(ftintrz_l_s, gen_f2, gen_helper_ftintrz_l_s)
+TRANS(ftintrz_l_d, gen_f2, gen_helper_ftintrz_l_d)
+TRANS(ftintrne_w_s, gen_f2, gen_helper_ftintrne_w_s)
+TRANS(ftintrne_w_d, gen_f2, gen_helper_ftintrne_w_d)
+TRANS(ftintrne_l_s, gen_f2, gen_helper_ftintrne_l_s)
+TRANS(ftintrne_l_d, gen_f2, gen_helper_ftintrne_l_d)
+TRANS(ftint_w_s, gen_f2, gen_helper_ftint_w_s)
+TRANS(ftint_w_d, gen_f2, gen_helper_ftint_w_d)
+TRANS(ftint_l_s, gen_f2, gen_helper_ftint_l_s)
+TRANS(ftint_l_d, gen_f2, gen_helper_ftint_l_d)
+TRANS(ffint_s_w, gen_f2, gen_helper_ffint_s_w)
+TRANS(ffint_s_l, gen_f2, gen_helper_ffint_s_l)
+TRANS(ffint_d_w, gen_f2, gen_helper_ffint_d_w)
+TRANS(ffint_d_l, gen_f2, gen_helper_ffint_d_l)
+TRANS(frint_s, gen_f2, gen_helper_frint_s)
+TRANS(frint_d, gen_f2, gen_helper_frint_d)
diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode
index 8aadcfd..c6fd762 100644
--- a/target/loongarch/insns.decode
+++ b/target/loongarch/insns.decode
@@ -351,3 +351,35 @@ fclass_d 0000 00010001 01000 01110 ..... ..... @fmt_fdfj
#
fcmp_cond_s 0000 11000001 ..... ..... ..... 00 ... @fmt_cdfjfkfcond
fcmp_cond_d 0000 11000010 ..... ..... ..... 00 ... @fmt_cdfjfkfcond
+
+#
+# Floating point conversion instruction
+#
+fcvt_s_d 0000 00010001 10010 00110 ..... ..... @fmt_fdfj
+fcvt_d_s 0000 00010001 10010 01001 ..... ..... @fmt_fdfj
+ftintrm_w_s 0000 00010001 10100 00001 ..... ..... @fmt_fdfj
+ftintrm_w_d 0000 00010001 10100 00010 ..... ..... @fmt_fdfj
+ftintrm_l_s 0000 00010001 10100 01001 ..... ..... @fmt_fdfj
+ftintrm_l_d 0000 00010001 10100 01010 ..... ..... @fmt_fdfj
+ftintrp_w_s 0000 00010001 10100 10001 ..... ..... @fmt_fdfj
+ftintrp_w_d 0000 00010001 10100 10010 ..... ..... @fmt_fdfj
+ftintrp_l_s 0000 00010001 10100 11001 ..... ..... @fmt_fdfj
+ftintrp_l_d 0000 00010001 10100 11010 ..... ..... @fmt_fdfj
+ftintrz_w_s 0000 00010001 10101 00001 ..... ..... @fmt_fdfj
+ftintrz_w_d 0000 00010001 10101 00010 ..... ..... @fmt_fdfj
+ftintrz_l_s 0000 00010001 10101 01001 ..... ..... @fmt_fdfj
+ftintrz_l_d 0000 00010001 10101 01010 ..... ..... @fmt_fdfj
+ftintrne_w_s 0000 00010001 10101 10001 ..... ..... @fmt_fdfj
+ftintrne_w_d 0000 00010001 10101 10010 ..... ..... @fmt_fdfj
+ftintrne_l_s 0000 00010001 10101 11001 ..... ..... @fmt_fdfj
+ftintrne_l_d 0000 00010001 10101 11010 ..... ..... @fmt_fdfj
+ftint_w_s 0000 00010001 10110 00001 ..... ..... @fmt_fdfj
+ftint_w_d 0000 00010001 10110 00010 ..... ..... @fmt_fdfj
+ftint_l_s 0000 00010001 10110 01001 ..... ..... @fmt_fdfj
+ftint_l_d 0000 00010001 10110 01010 ..... ..... @fmt_fdfj
+ffint_s_w 0000 00010001 11010 00100 ..... ..... @fmt_fdfj
+ffint_s_l 0000 00010001 11010 00110 ..... ..... @fmt_fdfj
+ffint_d_w 0000 00010001 11010 01000 ..... ..... @fmt_fdfj
+ffint_d_l 0000 00010001 11010 01010 ..... ..... @fmt_fdfj
+frint_s 0000 00010001 11100 10001 ..... ..... @fmt_fdfj
+frint_d 0000 00010001 11100 10010 ..... ..... @fmt_fdfj
diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c
index 8cce6cc..99e5678 100644
--- a/target/loongarch/translate.c
+++ b/target/loongarch/translate.c
@@ -203,6 +203,7 @@ static bool gen_f2(DisasContext *ctx, arg_fmt_fdfj *a,
#include "insn_trans/trans_extra.c"
#include "insn_trans/trans_farith.c"
#include "insn_trans/trans_fcmp.c"
+#include "insn_trans/trans_fcnv.c"
static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
{
--
1.8.3.1
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v3 13/19] target/loongarch: Add floating point move instruction translation
2021-08-27 7:14 [PATCH v3 00/19] Add LoongArch linux-user emulation support Song Gao
` (11 preceding siblings ...)
2021-08-27 7:14 ` [PATCH v3 12/19] target/loongarch: Add floating point conversion " Song Gao
@ 2021-08-27 7:14 ` Song Gao
2021-08-27 7:14 ` [PATCH v3 14/19] target/loongarch: Add floating point load/store " Song Gao
` (5 subsequent siblings)
18 siblings, 0 replies; 22+ messages in thread
From: Song Gao @ 2021-08-27 7:14 UTC (permalink / raw)
To: qemu-devel
Cc: peter.maydell, thuth, chenhuacai, richard.henderson, f4bug,
maobibo, laurent, yangxiaojuan, alistair.francis, pbonzini,
alex.bennee
This patch implement floationg point move instruction translation.
This includes:
- FMOV.{S/D}
- FSEL
- MOVGR2FR.{W/D}, MOVGR2FRH.W
- MOVFR2GR.{S/D}, MOVFRH2GR.S
- MOVGR2FCSR, MOVFCSR2GR
- MOVFR2CF, MOVCF2FR
- MOVGR2CF, MOVCF2GR
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
target/loongarch/fpu_helper.c | 6 ++
target/loongarch/helper.h | 2 +
target/loongarch/insn_trans/trans_fmov.c | 159 +++++++++++++++++++++++++++++++
target/loongarch/insns.decode | 41 ++++++++
target/loongarch/translate.c | 1 +
5 files changed, 209 insertions(+)
create mode 100644 target/loongarch/insn_trans/trans_fmov.c
diff --git a/target/loongarch/fpu_helper.c b/target/loongarch/fpu_helper.c
index 2aef1fa..125e102 100644
--- a/target/loongarch/fpu_helper.c
+++ b/target/loongarch/fpu_helper.c
@@ -939,3 +939,9 @@ uint64_t helper_ftint_w_d(CPULoongArchState *env, uint64_t fj)
update_fcsr0(env, GETPC());
return fd;
}
+
+void helper_set_rounding_mode(CPULoongArchState *env, uint32_t fcsr0)
+{
+ set_float_rounding_mode(ieee_rm[fcsr0 >> FCSR0_RM] & 0x3,
+ &env->fp_status);
+}
diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h
index d90b093..b397a52 100644
--- a/target/loongarch/helper.h
+++ b/target/loongarch/helper.h
@@ -98,3 +98,5 @@ DEF_HELPER_2(ftint_w_s, i64, env, i64)
DEF_HELPER_2(ftint_w_d, i64, env, i64)
DEF_HELPER_2(frint_s, i64, env, i64)
DEF_HELPER_2(frint_d, i64, env, i64)
+
+DEF_HELPER_FLAGS_2(set_rounding_mode, TCG_CALL_NO_RWG, void, env, i32)
diff --git a/target/loongarch/insn_trans/trans_fmov.c b/target/loongarch/insn_trans/trans_fmov.c
new file mode 100644
index 0000000..c417fb8
--- /dev/null
+++ b/target/loongarch/insn_trans/trans_fmov.c
@@ -0,0 +1,159 @@
+/*
+ * LoongArch translate functions
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+static const uint32_t fcsr_mask[4] = {
+ UINT32_MAX, FCSR0_M1, FCSR0_M2, FCSR0_M3
+};
+
+static bool trans_fsel(DisasContext *ctx, arg_fsel *a)
+{
+ TCGv zero = tcg_constant_tl(0);
+ TCGv cond = tcg_temp_new();
+
+ tcg_gen_ld8u_tl(cond, cpu_env, offsetof(CPULoongArchState, cf[a->ca]));
+ tcg_gen_movcond_tl(TCG_COND_EQ, cpu_fpr[a->fd], cond, zero,
+ cpu_fpr[a->fj], cpu_fpr[a->fk]);
+ tcg_temp_free(cond);
+ return true;
+}
+
+static bool gen_mov(DisasContext *ctx, arg_fmt_fdfj *a,
+ void (*func)(TCGv, TCGv))
+{
+ TCGv dest = cpu_fpr[a->fd];
+ TCGv src = cpu_fpr[a->fj];
+
+ func(dest, src);
+ return true;
+}
+
+static bool gen_r2f(DisasContext *ctx, arg_fmt_fdrj *a,
+ void (*func)(TCGv, TCGv))
+{
+ TCGv src = gpr_src(ctx, a->rj, EXT_NONE);
+
+ func(cpu_fpr[a->fd], src);
+ return true;
+}
+
+static bool gen_f2r(DisasContext *ctx, arg_fmt_rdfj *a,
+ DisasExtend dst_ext, void (*func)(TCGv, TCGv))
+{
+ ctx->dst_ext = dst_ext;
+ TCGv dest = gpr_dst(ctx, a->rd);
+
+ func(dest, cpu_fpr[a->fj]);
+
+ if (ctx->dst_ext) {
+ gen_set_gpr(ctx, a->rd, dest);
+ }
+ return true;
+}
+
+static bool trans_movgr2fcsr(DisasContext *ctx, arg_movgr2fcsr *a)
+{
+ uint32_t mask = fcsr_mask[a->fcsrd];
+ TCGv Rj = gpr_src(ctx, a->rj, EXT_NONE);
+
+ if (mask == UINT32_MAX) {
+ tcg_gen_extrl_i64_i32(cpu_fcsr0, Rj);
+ } else {
+ TCGv_i32 temp = tcg_temp_new_i32();
+
+ tcg_gen_extrl_i64_i32(temp, Rj);
+ tcg_gen_andi_i32(temp, temp, mask);
+ tcg_gen_andi_i32(cpu_fcsr0, cpu_fcsr0, ~mask);
+ tcg_gen_or_i32(cpu_fcsr0, cpu_fcsr0, temp);
+ tcg_temp_free_i32(temp);
+
+ /*
+ * Install the new rounding mode to fpu_status, if changed.
+ * Note that FCSR3 is exactly the rounding mode field.
+ */
+ if (mask != FCSR0_M3) {
+ return true;
+ }
+ }
+ gen_helper_set_rounding_mode(cpu_env, cpu_fcsr0);
+ return true;
+}
+
+static bool trans_movfcsr2gr(DisasContext *ctx, arg_movfcsr2gr *a)
+{
+ TCGv_i32 temp = tcg_temp_new_i32();
+ TCGv dest = gpr_dst(ctx, a->rd);
+
+ tcg_gen_andi_i32(temp, cpu_fcsr0, fcsr_mask[a->fcsrs]);
+ tcg_gen_ext_i32_i64(dest, temp);
+ tcg_temp_free_i32(temp);
+ return true;
+}
+
+static void gen_movgr2fr_w(TCGv dest, TCGv src)
+{
+ tcg_gen_deposit_i64(dest, dest, src, 0, 32);
+}
+
+static void gen_movgr2frh_w(TCGv dest, TCGv src)
+{
+ tcg_gen_deposit_i64(dest, dest, src, 32, 32);
+}
+
+static void gen_movfrh2gr_s(TCGv dest, TCGv src)
+{
+ TCGv t0 = tcg_temp_new();
+
+ tcg_gen_extract_tl(dest, src, 32, 32);
+
+ tcg_temp_free(t0);
+}
+
+static bool trans_movfr2cf(DisasContext *ctx, arg_movfr2cf *a)
+{
+ TCGv t0 = tcg_temp_new();
+
+ tcg_gen_andi_tl(t0, cpu_fpr[a->fj], 0x1);
+ tcg_gen_st8_tl(t0, cpu_env, offsetof(CPULoongArchState, cf[a->cd & 0x7]));
+
+ tcg_temp_free(t0);
+ return true;
+}
+
+static bool trans_movcf2fr(DisasContext *ctx, arg_movcf2fr *a)
+{
+ tcg_gen_ld8u_tl(cpu_fpr[a->fd], cpu_env,
+ offsetof(CPULoongArchState, cf[a->cj & 0x7]));
+ return true;
+}
+
+static bool trans_movgr2cf(DisasContext *ctx, arg_movgr2cf *a)
+{
+ TCGv t0 = tcg_temp_new();
+
+ tcg_gen_andi_tl(t0, gpr_src(ctx, a->rj, EXT_NONE), 0x1);
+ tcg_gen_st8_tl(t0, cpu_env, offsetof(CPULoongArchState, cf[a->cd & 0x7]));
+
+ tcg_temp_free(t0);
+ return true;
+}
+
+static bool trans_movcf2gr(DisasContext *ctx, arg_movcf2gr *a)
+{
+ tcg_gen_ld8u_tl(gpr_dst(ctx, a->rd), cpu_env,
+ offsetof(CPULoongArchState, cf[a->cj & 0x7]));
+ return true;
+}
+
+TRANS(fmov_s, gen_mov, tcg_gen_mov_tl)
+TRANS(fmov_d, gen_mov, tcg_gen_mov_tl)
+TRANS(movgr2fr_w, gen_r2f, gen_movgr2fr_w)
+TRANS(movgr2fr_d, gen_r2f, tcg_gen_mov_tl)
+TRANS(movgr2frh_w, gen_r2f, gen_movgr2frh_w)
+TRANS(movfr2gr_s, gen_f2r, EXT_NONE, tcg_gen_ext32s_tl)
+TRANS(movfr2gr_d, gen_f2r, EXT_NONE, tcg_gen_mov_tl)
+TRANS(movfrh2gr_s, gen_f2r, EXT_SIGN, gen_movfrh2gr_s)
diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode
index c6fd762..febf89a 100644
--- a/target/loongarch/insns.decode
+++ b/target/loongarch/insns.decode
@@ -34,6 +34,10 @@
%fa 15:5
%cd 0:3
%fcond 15:5
+%cj 5:3
+%ca 15:3
+%fcsrd 0:5
+%fcsrs 5:5
#
# Argument sets
@@ -59,6 +63,15 @@
&fmt_fdfjfkfa fd fj fk fa
&fmt_fdfj fd fj
&fmt_cdfjfkfcond cd fj fk fcond
+&fmt_fdfjfkca fd fj fk ca
+&fmt_fdrj fd rj
+&fmt_rdfj rd fj
+&fmt_fcsrdrj fcsrd rj
+&fmt_rdfcsrs rd fcsrs
+&fmt_cdfj cd fj
+&fmt_fdcj fd cj
+&fmt_cdrj cd rj
+&fmt_rdcj rd cj
#
# Formats
@@ -84,6 +97,15 @@
@fmt_fdfjfkfa .... ........ ..... ..... ..... ..... &fmt_fdfjfkfa %fd %fj %fk %fa
@fmt_fdfj .... ........ ..... ..... ..... ..... &fmt_fdfj %fd %fj
@fmt_cdfjfkfcond .... ........ ..... ..... ..... .. ... &fmt_cdfjfkfcond %cd %fj %fk %fcond
+@fmt_fdfjfkca .... ........ .. ... ..... ..... ..... &fmt_fdfjfkca %fd %fj %fk %ca
+@fmt_fdrj .... ........ ..... ..... ..... ..... &fmt_fdrj %fd %rj
+@fmt_rdfj .... ........ ..... ..... ..... ..... &fmt_rdfj %rd %fj
+@fmt_fcsrdrj .... ........ ..... ..... ..... ..... &fmt_fcsrdrj %fcsrd %rj
+@fmt_rdfcsrs .... ........ ..... ..... ..... ..... &fmt_rdfcsrs %rd %fcsrs
+@fmt_cdfj .... ........ ..... ..... ..... .. ... &fmt_cdfj %cd %fj
+@fmt_fdcj .... ........ ..... ..... .. ... ..... &fmt_fdcj %fd %cj
+@fmt_cdrj .... ........ ..... ..... ..... .. ... &fmt_cdrj %cd %rj
+@fmt_rdcj .... ........ ..... ..... .. ... ..... &fmt_rdcj %rd %cj
#
# Fixed point arithmetic operation instruction
@@ -383,3 +405,22 @@ ffint_d_w 0000 00010001 11010 01000 ..... ..... @fmt_fdfj
ffint_d_l 0000 00010001 11010 01010 ..... ..... @fmt_fdfj
frint_s 0000 00010001 11100 10001 ..... ..... @fmt_fdfj
frint_d 0000 00010001 11100 10010 ..... ..... @fmt_fdfj
+
+#
+# Floating point move instruction
+#
+fmov_s 0000 00010001 01001 00101 ..... ..... @fmt_fdfj
+fmov_d 0000 00010001 01001 00110 ..... ..... @fmt_fdfj
+fsel 0000 11010000 00 ... ..... ..... ..... @fmt_fdfjfkca
+movgr2fr_w 0000 00010001 01001 01001 ..... ..... @fmt_fdrj
+movgr2fr_d 0000 00010001 01001 01010 ..... ..... @fmt_fdrj
+movgr2frh_w 0000 00010001 01001 01011 ..... ..... @fmt_fdrj
+movfr2gr_s 0000 00010001 01001 01101 ..... ..... @fmt_rdfj
+movfr2gr_d 0000 00010001 01001 01110 ..... ..... @fmt_rdfj
+movfrh2gr_s 0000 00010001 01001 01111 ..... ..... @fmt_rdfj
+movgr2fcsr 0000 00010001 01001 10000 ..... ..... @fmt_fcsrdrj
+movfcsr2gr 0000 00010001 01001 10010 ..... ..... @fmt_rdfcsrs
+movfr2cf 0000 00010001 01001 10100 ..... 00 ... @fmt_cdfj
+movcf2fr 0000 00010001 01001 10101 00 ... ..... @fmt_fdcj
+movgr2cf 0000 00010001 01001 10110 ..... 00 ... @fmt_cdrj
+movcf2gr 0000 00010001 01001 10111 00 ... ..... @fmt_rdcj
diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c
index 99e5678..55185ae 100644
--- a/target/loongarch/translate.c
+++ b/target/loongarch/translate.c
@@ -204,6 +204,7 @@ static bool gen_f2(DisasContext *ctx, arg_fmt_fdfj *a,
#include "insn_trans/trans_farith.c"
#include "insn_trans/trans_fcmp.c"
#include "insn_trans/trans_fcnv.c"
+#include "insn_trans/trans_fmov.c"
static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
{
--
1.8.3.1
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v3 14/19] target/loongarch: Add floating point load/store instruction translation
2021-08-27 7:14 [PATCH v3 00/19] Add LoongArch linux-user emulation support Song Gao
` (12 preceding siblings ...)
2021-08-27 7:14 ` [PATCH v3 13/19] target/loongarch: Add floating point move " Song Gao
@ 2021-08-27 7:14 ` Song Gao
2021-08-27 7:14 ` [PATCH v3 15/19] target/loongarch: Add branch " Song Gao
` (4 subsequent siblings)
18 siblings, 0 replies; 22+ messages in thread
From: Song Gao @ 2021-08-27 7:14 UTC (permalink / raw)
To: qemu-devel
Cc: peter.maydell, thuth, chenhuacai, richard.henderson, f4bug,
maobibo, laurent, yangxiaojuan, alistair.francis, pbonzini,
alex.bennee
This patch implement floating point load/store instruction translation.
This includes:
- FLD.{S/D}, FST.{S/D}
- FLDX.{S/D}, FSTX.{S/D}
- FLD{GT/LE}.{S/D}, FST{GT/LE}.{S/D}
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
target/loongarch/insn_trans/trans_fmemory.c | 143 ++++++++++++++++++++++++++++
target/loongarch/insns.decode | 24 +++++
target/loongarch/translate.c | 1 +
3 files changed, 168 insertions(+)
create mode 100644 target/loongarch/insn_trans/trans_fmemory.c
diff --git a/target/loongarch/insn_trans/trans_fmemory.c b/target/loongarch/insn_trans/trans_fmemory.c
new file mode 100644
index 0000000..88727c3
--- /dev/null
+++ b/target/loongarch/insn_trans/trans_fmemory.c
@@ -0,0 +1,143 @@
+/*
+ * LoongArch translate functions
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+static bool gen_fload_imm(DisasContext *ctx, arg_fmt_fdrjsi12 *a, MemOp mop)
+{
+ TCGv addr = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv temp = NULL;
+
+ if (a->si12) {
+ temp = tcg_temp_new();
+ tcg_gen_addi_tl(temp, addr, a->si12);
+ addr = temp;
+ }
+ tcg_gen_qemu_ld_tl(cpu_fpr[a->fd], addr, ctx->mem_idx, mop);
+
+ if (temp) {
+ tcg_temp_free(temp);
+ }
+ return true;
+}
+
+static bool gen_fstore_imm(DisasContext *ctx, arg_fmt_fdrjsi12 *a, MemOp mop)
+{
+ TCGv addr = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv temp = NULL;
+
+ if (a->si12) {
+ temp = tcg_temp_new();
+ tcg_gen_addi_tl(temp, addr, a->si12);
+ addr = temp;
+ }
+ tcg_gen_qemu_st_tl(cpu_fpr[a->fd], addr, ctx->mem_idx, mop);
+
+ if (temp) {
+ tcg_temp_free(temp);
+ }
+ return true;
+}
+
+static bool gen_fload_tl(DisasContext *ctx, arg_fmt_fdrjrk *a, MemOp mop)
+{
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE);
+ TCGv addr = tcg_temp_new();
+
+ tcg_gen_add_tl(addr, src1, src2);
+ tcg_gen_qemu_ld_tl(cpu_fpr[a->fd], addr, ctx->mem_idx, mop);
+
+ tcg_temp_free(addr);
+ return true;
+}
+
+static bool gen_fstore_tl(DisasContext *ctx, arg_fmt_fdrjrk *a, MemOp mop)
+{
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE);
+ TCGv addr = tcg_temp_new();
+
+ tcg_gen_add_tl(addr, src1, src2);
+ tcg_gen_qemu_st_tl(cpu_fpr[a->fd], addr, ctx->mem_idx, mop);
+
+ tcg_temp_free(addr);
+ return true;
+}
+
+static bool gen_fload_gt(DisasContext *ctx, arg_fmt_fdrjrk *a, MemOp mop)
+{
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE);
+ TCGv addr = tcg_temp_new();
+
+ gen_helper_asrtgt_d(cpu_env, src1, src2);
+ tcg_gen_add_tl(addr, src1, src2);
+ tcg_gen_qemu_ld_tl(cpu_fpr[a->fd], addr, ctx->mem_idx, mop);
+
+ tcg_temp_free(addr);
+
+ return true;
+}
+
+static bool gen_fstore_gt(DisasContext *ctx, arg_fmt_fdrjrk *a, MemOp mop)
+{
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE);
+ TCGv addr = tcg_temp_new();
+
+ gen_helper_asrtgt_d(cpu_env, src1, src2);
+ tcg_gen_add_tl(addr, src1, src2);
+ tcg_gen_qemu_st_tl(cpu_fpr[a->fd], addr, ctx->mem_idx, mop);
+
+ tcg_temp_free(addr);
+ return true;
+}
+
+static bool gen_fload_le(DisasContext *ctx, arg_fmt_fdrjrk *a, MemOp mop)
+{
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE);
+ TCGv addr = tcg_temp_new();
+
+ gen_helper_asrtle_d(cpu_env, src1, src2);
+ tcg_gen_add_tl(addr, src1, src2);
+ tcg_gen_qemu_ld_tl(cpu_fpr[a->fd], addr, ctx->mem_idx, mop);
+
+ tcg_temp_free(addr);
+ return true;
+}
+
+static bool gen_fstore_le(DisasContext *ctx, arg_fmt_fdrjrk *a, MemOp mop)
+{
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE);
+ TCGv addr = tcg_temp_new();
+
+ gen_helper_asrtle_d(cpu_env, src1, src2);
+ tcg_gen_add_tl(addr, src1, src2);
+ tcg_gen_qemu_st_tl(cpu_fpr[a->fd], addr, ctx->mem_idx, mop);
+
+ tcg_temp_free(addr);
+ return true;
+}
+
+TRANS(fld_s, gen_fload_imm, MO_TESL)
+TRANS(fst_s, gen_fstore_imm, MO_TEUL)
+TRANS(fld_d, gen_fload_imm, MO_TEQ)
+TRANS(fst_d, gen_fstore_imm, MO_TEQ)
+TRANS(fldx_s, gen_fload_tl, MO_TESL)
+TRANS(fldx_d, gen_fload_tl, MO_TEQ)
+TRANS(fstx_s, gen_fstore_tl, MO_TEUL)
+TRANS(fstx_d, gen_fstore_tl, MO_TEQ)
+TRANS(fldgt_s, gen_fload_gt, MO_TESL)
+TRANS(fldgt_d, gen_fload_gt, MO_TEQ)
+TRANS(fldle_s, gen_fload_le, MO_TESL)
+TRANS(fldle_d, gen_fload_le, MO_TEQ)
+TRANS(fstgt_s, gen_fstore_gt, MO_TEUL)
+TRANS(fstgt_d, gen_fstore_gt, MO_TEQ)
+TRANS(fstle_s, gen_fstore_le, MO_TEUL)
+TRANS(fstle_d, gen_fstore_le, MO_TEQ)
diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode
index febf89a..ea776c2 100644
--- a/target/loongarch/insns.decode
+++ b/target/loongarch/insns.decode
@@ -72,6 +72,8 @@
&fmt_fdcj fd cj
&fmt_cdrj cd rj
&fmt_rdcj rd cj
+&fmt_fdrjrk fd rj rk
+&fmt_fdrjsi12 fd rj si12
#
# Formats
@@ -106,6 +108,8 @@
@fmt_fdcj .... ........ ..... ..... .. ... ..... &fmt_fdcj %fd %cj
@fmt_cdrj .... ........ ..... ..... ..... .. ... &fmt_cdrj %cd %rj
@fmt_rdcj .... ........ ..... ..... .. ... ..... &fmt_rdcj %rd %cj
+@fmt_fdrjrk .... ........ ..... ..... ..... ..... &fmt_fdrjrk %fd %rj %rk
+@fmt_fdrjsi12 .... ...... ............ ..... ..... &fmt_fdrjsi12 %fd %rj %si12
#
# Fixed point arithmetic operation instruction
@@ -424,3 +428,23 @@ movfr2cf 0000 00010001 01001 10100 ..... 00 ... @fmt_cdfj
movcf2fr 0000 00010001 01001 10101 00 ... ..... @fmt_fdcj
movgr2cf 0000 00010001 01001 10110 ..... 00 ... @fmt_cdrj
movcf2gr 0000 00010001 01001 10111 00 ... ..... @fmt_rdcj
+
+#
+# Floating point load/store instruction
+#
+fld_s 0010 101100 ............ ..... ..... @fmt_fdrjsi12
+fst_s 0010 101101 ............ ..... ..... @fmt_fdrjsi12
+fld_d 0010 101110 ............ ..... ..... @fmt_fdrjsi12
+fst_d 0010 101111 ............ ..... ..... @fmt_fdrjsi12
+fldx_s 0011 10000011 00000 ..... ..... ..... @fmt_fdrjrk
+fldx_d 0011 10000011 01000 ..... ..... ..... @fmt_fdrjrk
+fstx_s 0011 10000011 10000 ..... ..... ..... @fmt_fdrjrk
+fstx_d 0011 10000011 11000 ..... ..... ..... @fmt_fdrjrk
+fldgt_s 0011 10000111 01000 ..... ..... ..... @fmt_fdrjrk
+fldgt_d 0011 10000111 01001 ..... ..... ..... @fmt_fdrjrk
+fldle_s 0011 10000111 01010 ..... ..... ..... @fmt_fdrjrk
+fldle_d 0011 10000111 01011 ..... ..... ..... @fmt_fdrjrk
+fstgt_s 0011 10000111 01100 ..... ..... ..... @fmt_fdrjrk
+fstgt_d 0011 10000111 01101 ..... ..... ..... @fmt_fdrjrk
+fstle_s 0011 10000111 01110 ..... ..... ..... @fmt_fdrjrk
+fstle_d 0011 10000111 01111 ..... ..... ..... @fmt_fdrjrk
diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c
index 55185ae..d4a622f 100644
--- a/target/loongarch/translate.c
+++ b/target/loongarch/translate.c
@@ -205,6 +205,7 @@ static bool gen_f2(DisasContext *ctx, arg_fmt_fdfj *a,
#include "insn_trans/trans_fcmp.c"
#include "insn_trans/trans_fcnv.c"
#include "insn_trans/trans_fmov.c"
+#include "insn_trans/trans_fmemory.c"
static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
{
--
1.8.3.1
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v3 15/19] target/loongarch: Add branch instruction translation
2021-08-27 7:14 [PATCH v3 00/19] Add LoongArch linux-user emulation support Song Gao
` (13 preceding siblings ...)
2021-08-27 7:14 ` [PATCH v3 14/19] target/loongarch: Add floating point load/store " Song Gao
@ 2021-08-27 7:14 ` Song Gao
2021-08-27 7:14 ` [PATCH v3 16/19] target/loongarch: Add disassembler Song Gao
` (3 subsequent siblings)
18 siblings, 0 replies; 22+ messages in thread
From: Song Gao @ 2021-08-27 7:14 UTC (permalink / raw)
To: qemu-devel
Cc: peter.maydell, thuth, chenhuacai, richard.henderson, f4bug,
maobibo, laurent, yangxiaojuan, alistair.francis, pbonzini,
alex.bennee
This patch implement branch instruction translation.
This includes:
- BEQ, BNE, BLT[U], BGE[U]
- BEQZ, BNEZ
- B
- BL
- JIRL
- BCEQZ, BCNEZ
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
target/loongarch/insn_trans/trans_branch.c | 84 ++++++++++++++++++++++++++++++
target/loongarch/insns.decode | 30 +++++++++++
target/loongarch/translate.c | 1 +
3 files changed, 115 insertions(+)
create mode 100644 target/loongarch/insn_trans/trans_branch.c
diff --git a/target/loongarch/insn_trans/trans_branch.c b/target/loongarch/insn_trans/trans_branch.c
new file mode 100644
index 0000000..acf1966
--- /dev/null
+++ b/target/loongarch/insn_trans/trans_branch.c
@@ -0,0 +1,84 @@
+/*
+ * LoongArch translate functions
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+static bool trans_b(DisasContext *ctx, arg_b *a)
+{
+ gen_goto_tb(ctx, 0, ctx->base.pc_next + (a->offs << 2));
+ ctx->base.is_jmp = DISAS_NORETURN;
+ return true;
+}
+
+static bool trans_bl(DisasContext *ctx, arg_bl *a)
+{
+ tcg_gen_movi_tl(cpu_gpr[1], ctx->base.pc_next + 4);
+ gen_goto_tb(ctx, 0, ctx->base.pc_next + (a->offs << 2));
+ ctx->base.is_jmp = DISAS_NORETURN;
+ return true;
+}
+
+static bool trans_jirl(DisasContext *ctx, arg_jirl *a)
+{
+ TCGv dest = gpr_dst(ctx, a->rd);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+
+ tcg_gen_addi_tl(cpu_pc, src1, (a->offs16) << 2);
+ tcg_gen_movi_tl(dest, ctx->base.pc_next + 4);
+ tcg_gen_lookup_and_goto_ptr();
+ ctx->base.is_jmp = DISAS_NORETURN;
+ return true;
+}
+
+static void gen_bc(DisasContext *ctx, TCGv src1, TCGv src2,
+ target_long offs, TCGCond cond)
+{
+ TCGLabel *l = gen_new_label();
+ tcg_gen_brcond_tl(cond, src1, src2, l);
+ gen_goto_tb(ctx, 1, ctx->base.pc_next + 4);
+ gen_set_label(l);
+ gen_goto_tb(ctx, 0, ctx->base.pc_next + offs);
+ ctx->base.is_jmp = DISAS_NORETURN;
+}
+
+static bool gen_r2_bc(DisasContext *ctx, arg_fmt_rjrdoffs16 *a, TCGCond cond)
+{
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv src2 = gpr_src(ctx, a->rd, EXT_NONE);
+
+ gen_bc(ctx, src1, src2, (a->offs16 << 2), cond);
+ return true;
+}
+
+static bool gen_rz_bc(DisasContext *ctx, arg_fmt_rjoffs21 *a, TCGCond cond)
+{
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv src2 = tcg_constant_tl(0);
+
+ gen_bc(ctx, src1, src2, (a->offs21 << 2), cond);
+ return true;
+}
+static bool gen_cz_bc(DisasContext *ctx, arg_fmt_cjoffs21 *a, TCGCond cond)
+{
+ TCGv src1 = tcg_temp_new();
+ TCGv src2 = tcg_constant_tl(0);
+
+ tcg_gen_ld8u_tl(src1, cpu_env,
+ offsetof(CPULoongArchState, cf[a->cj & 0x7]));
+ gen_bc(ctx, src1, src2, (a->offs21 << 2), cond);
+ return true;
+}
+
+TRANS(beq, gen_r2_bc, TCG_COND_EQ)
+TRANS(bne, gen_r2_bc, TCG_COND_NE)
+TRANS(blt, gen_r2_bc, TCG_COND_LT)
+TRANS(bge, gen_r2_bc, TCG_COND_GE)
+TRANS(bltu, gen_r2_bc, TCG_COND_LTU)
+TRANS(bgeu, gen_r2_bc, TCG_COND_GEU)
+TRANS(beqz, gen_rz_bc, TCG_COND_EQ)
+TRANS(bnez, gen_rz_bc, TCG_COND_NE)
+TRANS(bceqz, gen_cz_bc, TCG_COND_EQ)
+TRANS(bcnez, gen_cz_bc, TCG_COND_NE)
diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode
index ea776c2..077063e 100644
--- a/target/loongarch/insns.decode
+++ b/target/loongarch/insns.decode
@@ -38,6 +38,9 @@
%ca 15:3
%fcsrd 0:5
%fcsrs 5:5
+%offs21 0:s5 10:16
+%offs16 10:s16
+%offs 0:s10 10:16
#
# Argument sets
@@ -74,6 +77,11 @@
&fmt_rdcj rd cj
&fmt_fdrjrk fd rj rk
&fmt_fdrjsi12 fd rj si12
+&fmt_rjoffs21 rj offs21
+&fmt_cjoffs21 cj offs21
+&fmt_rdrjoffs16 rd rj offs16
+&fmt_offs offs
+&fmt_rjrdoffs16 rj rd offs16
#
# Formats
@@ -110,6 +118,11 @@
@fmt_rdcj .... ........ ..... ..... .. ... ..... &fmt_rdcj %rd %cj
@fmt_fdrjrk .... ........ ..... ..... ..... ..... &fmt_fdrjrk %fd %rj %rk
@fmt_fdrjsi12 .... ...... ............ ..... ..... &fmt_fdrjsi12 %fd %rj %si12
+@fmt_rjoffs21 .... .. ................ ..... ..... &fmt_rjoffs21 %rj %offs21
+@fmt_cjoffs21 .... .. ................ .. ... ..... &fmt_cjoffs21 %cj %offs21
+@fmt_rdrjoffs16 .... .. ................ ..... ..... &fmt_rdrjoffs16 %rd %rj %offs16
+@fmt_offs .... .. .......................... &fmt_offs %offs
+@fmt_rjrdoffs16 .... .. ................ ..... ..... &fmt_rjrdoffs16 %rj %rd %offs16
#
# Fixed point arithmetic operation instruction
@@ -448,3 +461,20 @@ fstgt_s 0011 10000111 01100 ..... ..... ..... @fmt_fdrjrk
fstgt_d 0011 10000111 01101 ..... ..... ..... @fmt_fdrjrk
fstle_s 0011 10000111 01110 ..... ..... ..... @fmt_fdrjrk
fstle_d 0011 10000111 01111 ..... ..... ..... @fmt_fdrjrk
+
+#
+# Branch instructions
+#
+beqz 0100 00 ................ ..... ..... @fmt_rjoffs21
+bnez 0100 01 ................ ..... ..... @fmt_rjoffs21
+bceqz 0100 10 ................ 00 ... ..... @fmt_cjoffs21
+bcnez 0100 10 ................ 01 ... ..... @fmt_cjoffs21
+jirl 0100 11 ................ ..... ..... @fmt_rdrjoffs16
+b 0101 00 .......................... @fmt_offs
+bl 0101 01 .......................... @fmt_offs
+beq 0101 10 ................ ..... ..... @fmt_rjrdoffs16
+bne 0101 11 ................ ..... ..... @fmt_rjrdoffs16
+blt 0110 00 ................ ..... ..... @fmt_rjrdoffs16
+bge 0110 01 ................ ..... ..... @fmt_rjrdoffs16
+bltu 0110 10 ................ ..... ..... @fmt_rjrdoffs16
+bgeu 0110 11 ................ ..... ..... @fmt_rjrdoffs16
diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c
index d4a622f..db90399 100644
--- a/target/loongarch/translate.c
+++ b/target/loongarch/translate.c
@@ -206,6 +206,7 @@ static bool gen_f2(DisasContext *ctx, arg_fmt_fdfj *a,
#include "insn_trans/trans_fcnv.c"
#include "insn_trans/trans_fmov.c"
#include "insn_trans/trans_fmemory.c"
+#include "insn_trans/trans_branch.c"
static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
{
--
1.8.3.1
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v3 16/19] target/loongarch: Add disassembler
2021-08-27 7:14 [PATCH v3 00/19] Add LoongArch linux-user emulation support Song Gao
` (14 preceding siblings ...)
2021-08-27 7:14 ` [PATCH v3 15/19] target/loongarch: Add branch " Song Gao
@ 2021-08-27 7:14 ` Song Gao
2021-08-27 7:14 ` [PATCH v3 17/19] LoongArch Linux User Emulation Song Gao
` (2 subsequent siblings)
18 siblings, 0 replies; 22+ messages in thread
From: Song Gao @ 2021-08-27 7:14 UTC (permalink / raw)
To: qemu-devel
Cc: peter.maydell, thuth, chenhuacai, richard.henderson, f4bug,
maobibo, laurent, yangxiaojuan, alistair.francis, pbonzini,
alex.bennee
This patch add support for disassembling via option '-d in_asm'.
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
MAINTAINERS | 1 +
disas/loongarch.c | 2511 +++++++++++++++++++++++++++++++++++++++++++++++
disas/meson.build | 1 +
include/disas/dis-asm.h | 2 +
meson.build | 1 +
5 files changed, 2516 insertions(+)
create mode 100644 disas/loongarch.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 396f970..073cda2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -214,6 +214,7 @@ LoongArch TCG CPUS
M: Song Gao <gaosong@loongson.cn>
S: Maintained
F: target/loongarch/
+F: disas/loongarch.c
M68K TCG CPUs
M: Laurent Vivier <laurent@vivier.eu>
diff --git a/disas/loongarch.c b/disas/loongarch.c
new file mode 100644
index 0000000..eb7475b
--- /dev/null
+++ b/disas/loongarch.c
@@ -0,0 +1,2511 @@
+/*
+ * QEMU LoongArch Disassembler
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited.
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "qemu/osdep.h"
+#include "disas/dis-asm.h"
+
+#define INSNLEN 4
+
+/* enums */
+typedef enum {
+ la_op_illegal = 0,
+ la_op_clo_w = 1,
+ la_op_clz_w = 2,
+ la_op_cto_w = 3,
+ la_op_ctz_w = 4,
+ la_op_clo_d = 5,
+ la_op_clz_d = 6,
+ la_op_cto_d = 7,
+ la_op_ctz_d = 8,
+ la_op_revb_2h = 9,
+ la_op_revb_4h = 10,
+ la_op_revb_2w = 11,
+ la_op_revb_d = 12,
+ la_op_revh_2w = 13,
+ la_op_revh_d = 14,
+ la_op_bitrev_4b = 15,
+ la_op_bitrev_8b = 16,
+ la_op_bitrev_w = 17,
+ la_op_bitrev_d = 18,
+ la_op_ext_w_h = 19,
+ la_op_ext_w_b = 20,
+ la_op_rdtime_d = 21,
+ la_op_cpucfg = 22,
+ la_op_asrtle_d = 23,
+ la_op_asrtgt_d = 24,
+ la_op_alsl_w = 25,
+ la_op_alsl_wu = 26,
+ la_op_bytepick_w = 27,
+ la_op_bytepick_d = 28,
+ la_op_add_w = 29,
+ la_op_add_d = 30,
+ la_op_sub_w = 31,
+ la_op_sub_d = 32,
+ la_op_slt = 33,
+ la_op_sltu = 34,
+ la_op_maskeqz = 35,
+ la_op_masknez = 36,
+ la_op_nor = 37,
+ la_op_and = 38,
+ la_op_or = 39,
+ la_op_xor = 40,
+ la_op_orn = 41,
+ la_op_andn = 42,
+ la_op_sll_w = 43,
+ la_op_srl_w = 44,
+ la_op_sra_w = 45,
+ la_op_sll_d = 46,
+ la_op_srl_d = 47,
+ la_op_sra_d = 48,
+ la_op_rotr_w = 49,
+ la_op_rotr_d = 50,
+ la_op_mul_w = 51,
+ la_op_mulh_w = 52,
+ la_op_mulh_wu = 53,
+ la_op_mul_d = 54,
+ la_op_mulh_d = 55,
+ la_op_mulh_du = 56,
+ la_op_mulw_d_w = 57,
+ la_op_mulw_d_wu = 58,
+ la_op_div_w = 59,
+ la_op_mod_w = 60,
+ la_op_div_wu = 61,
+ la_op_mod_wu = 62,
+ la_op_div_d = 63,
+ la_op_mod_d = 64,
+ la_op_div_du = 65,
+ la_op_mod_du = 66,
+ la_op_crc_w_b_w = 67,
+ la_op_crc_w_h_w = 68,
+ la_op_crc_w_w_w = 69,
+ la_op_crc_w_d_w = 70,
+ la_op_crcc_w_b_w = 71,
+ la_op_crcc_w_h_w = 72,
+ la_op_crcc_w_w_w = 73,
+ la_op_crcc_w_d_w = 74,
+ la_op_break = 75,
+ la_op_syscall = 76,
+ la_op_alsl_d = 77,
+ la_op_slli_w = 78,
+ la_op_slli_d = 79,
+ la_op_srli_w = 80,
+ la_op_srli_d = 81,
+ la_op_srai_w = 82,
+ la_op_srai_d = 83,
+ la_op_rotri_w = 84,
+ la_op_rotri_d = 85,
+ la_op_bstrins_w = 86,
+ la_op_bstrpick_w = 87,
+ la_op_bstrins_d = 88,
+ la_op_bstrpick_d = 89,
+ la_op_fadd_s = 90,
+ la_op_fadd_d = 91,
+ la_op_fsub_s = 92,
+ la_op_fsub_d = 93,
+ la_op_fmul_s = 94,
+ la_op_fmul_d = 95,
+ la_op_fdiv_s = 96,
+ la_op_fdiv_d = 97,
+ la_op_fmax_s = 98,
+ la_op_fmax_d = 99,
+ la_op_fmin_s = 100,
+ la_op_fmin_d = 101,
+ la_op_fmaxa_s = 102,
+ la_op_fmaxa_d = 103,
+ la_op_fmina_s = 104,
+ la_op_fmina_d = 105,
+ la_op_fscaleb_s = 106,
+ la_op_fscaleb_d = 107,
+ la_op_fcopysign_s = 108,
+ la_op_fcopysign_d = 109,
+ la_op_fabs_s = 110,
+ la_op_fabs_d = 111,
+ la_op_fneg_s = 112,
+ la_op_fneg_d = 113,
+ la_op_flogb_s = 114,
+ la_op_flogb_d = 115,
+ la_op_fclass_s = 116,
+ la_op_fclass_d = 117,
+ la_op_fsqrt_s = 118,
+ la_op_fsqrt_d = 119,
+ la_op_frecip_s = 120,
+ la_op_frecip_d = 121,
+ la_op_frsqrt_s = 122,
+ la_op_frsqrt_d = 123,
+ la_op_fmov_s = 124,
+ la_op_fmov_d = 125,
+ la_op_movgr2fr_w = 126,
+ la_op_movgr2fr_d = 127,
+ la_op_movgr2frh_w = 128,
+ la_op_movfr2gr_s = 129,
+ la_op_movfr2gr_d = 130,
+ la_op_movfrh2gr_s = 131,
+ la_op_movgr2fcsr = 132,
+ la_op_movfcsr2gr = 133,
+ la_op_movfr2cf = 134,
+ la_op_movcf2fr = 135,
+ la_op_movgr2cf = 136,
+ la_op_movcf2gr = 137,
+ la_op_fcvt_s_d = 138,
+ la_op_fcvt_d_s = 139,
+ la_op_ftintrm_w_s = 140,
+ la_op_ftintrm_w_d = 141,
+ la_op_ftintrm_l_s = 142,
+ la_op_ftintrm_l_d = 143,
+ la_op_ftintrp_w_s = 144,
+ la_op_ftintrp_w_d = 145,
+ la_op_ftintrp_l_s = 146,
+ la_op_ftintrp_l_d = 147,
+ la_op_ftintrz_w_s = 148,
+ la_op_ftintrz_w_d = 149,
+ la_op_ftintrz_l_s = 150,
+ la_op_ftintrz_l_d = 151,
+ la_op_ftintrne_w_s = 152,
+ la_op_ftintrne_w_d = 153,
+ la_op_ftintrne_l_s = 154,
+ la_op_ftintrne_l_d = 155,
+ la_op_ftint_w_s = 156,
+ la_op_ftint_w_d = 157,
+ la_op_ftint_l_s = 158,
+ la_op_ftint_l_d = 159,
+ la_op_ffint_s_w = 160,
+ la_op_ffint_s_l = 161,
+ la_op_ffint_d_w = 162,
+ la_op_ffint_d_l = 163,
+ la_op_frint_s = 164,
+ la_op_frint_d = 165,
+ la_op_slti = 166,
+ la_op_sltui = 167,
+ la_op_addi_w = 168,
+ la_op_addi_d = 169,
+ la_op_lu52i_d = 170,
+ la_op_addi = 171,
+ la_op_ori = 172,
+ la_op_xori = 173,
+ la_op_rdtimel_w = 174,
+ la_op_rdtimeh_w = 175,
+ la_op_fmadd_s = 176,
+ la_op_fmadd_d = 177,
+ la_op_fmsub_s = 178,
+ la_op_fmsub_d = 179,
+ la_op_fnmadd_s = 180,
+ la_op_fnmadd_d = 181,
+ la_op_fnmsub_s = 182,
+ la_op_fnmsub_d = 183,
+ la_op_fcmp_cond_s = 184,
+ la_op_fcmp_cond_d = 185,
+ la_op_fsel = 186,
+ la_op_addu16i_d = 187,
+ la_op_lu12i_w = 188,
+ la_op_lu32i_d = 189,
+ la_op_pcaddi = 190,
+ la_op_pcalau12i = 191,
+ la_op_pcaddu12i = 192,
+ la_op_pcaddu18i = 193,
+ la_op_ll_w = 194,
+ la_op_sc_w = 195,
+ la_op_ll_d = 196,
+ la_op_sc_d = 197,
+ la_op_ldptr_w = 198,
+ la_op_stptr_w = 199,
+ la_op_ldptr_d = 200,
+ la_op_stptr_d = 201,
+ la_op_ld_b = 202,
+ la_op_ld_h = 203,
+ la_op_ld_w = 204,
+ la_op_ld_d = 205,
+ la_op_st_b = 206,
+ la_op_st_h = 207,
+ la_op_st_w = 208,
+ la_op_st_d = 209,
+ la_op_ld_bu = 210,
+ la_op_ld_hu = 211,
+ la_op_ld_wu = 212,
+ la_op_preld = 213,
+ la_op_fld_s = 214,
+ la_op_fst_s = 215,
+ la_op_fld_d = 216,
+ la_op_fst_d = 217,
+ la_op_ldx_b = 218,
+ la_op_ldx_h = 219,
+ la_op_ldx_w = 220,
+ la_op_ldx_d = 221,
+ la_op_stx_b = 222,
+ la_op_stx_h = 223,
+ la_op_stx_w = 224,
+ la_op_stx_d = 225,
+ la_op_ldx_bu = 226,
+ la_op_ldx_hu = 227,
+ la_op_ldx_wu = 228,
+ la_op_fldx_s = 229,
+ la_op_fldx_d = 230,
+ la_op_fstx_s = 231,
+ la_op_fstx_d = 232,
+ la_op_amswap_w = 233,
+ la_op_amswap_d = 234,
+ la_op_amadd_w = 235,
+ la_op_amadd_d = 236,
+ la_op_amand_w = 237,
+ la_op_amand_d = 238,
+ la_op_amor_w = 239,
+ la_op_amor_d = 240,
+ la_op_amxor_w = 241,
+ la_op_amxor_d = 242,
+ la_op_ammax_w = 243,
+ la_op_ammax_d = 244,
+ la_op_ammin_w = 245,
+ la_op_ammin_d = 246,
+ la_op_ammax_wu = 247,
+ la_op_ammax_du = 248,
+ la_op_ammin_wu = 249,
+ la_op_ammin_du = 250,
+ la_op_amswap_db_w = 251,
+ la_op_amswap_db_d = 252,
+ la_op_amadd_db_w = 253,
+ la_op_amadd_db_d = 254,
+ la_op_amand_db_w = 255,
+ la_op_amand_db_d = 256,
+ la_op_amor_db_w = 257,
+ la_op_amor_db_d = 258,
+ la_op_amxor_db_w = 259,
+ la_op_amxor_db_d = 260,
+ la_op_ammax_db_w = 261,
+ la_op_ammax_db_d = 262,
+ la_op_ammin_db_w = 263,
+ la_op_ammin_db_d = 264,
+ la_op_ammax_db_wu = 265,
+ la_op_ammax_db_du = 266,
+ la_op_ammin_db_wu = 267,
+ la_op_ammin_db_du = 268,
+ la_op_dbar = 269,
+ la_op_ibar = 270,
+ la_op_fldgt_s = 271,
+ la_op_fldgt_d = 272,
+ la_op_fldle_s = 273,
+ la_op_fldle_d = 274,
+ la_op_fstgt_s = 275,
+ la_op_fstgt_d = 276,
+ ls_op_fstle_s = 277,
+ la_op_fstle_d = 278,
+ la_op_ldgt_b = 279,
+ la_op_ldgt_h = 280,
+ la_op_ldgt_w = 281,
+ la_op_ldgt_d = 282,
+ la_op_ldle_b = 283,
+ la_op_ldle_h = 284,
+ la_op_ldle_w = 285,
+ la_op_ldle_d = 286,
+ la_op_stgt_b = 287,
+ la_op_stgt_h = 288,
+ la_op_stgt_w = 289,
+ la_op_stgt_d = 290,
+ la_op_stle_b = 291,
+ la_op_stle_h = 292,
+ la_op_stle_w = 293,
+ la_op_stle_d = 294,
+ la_op_beqz = 295,
+ la_op_bnez = 296,
+ la_op_bceqz = 297,
+ la_op_bcnez = 298,
+ la_op_jirl = 299,
+ la_op_b = 300,
+ la_op_bl = 301,
+ la_op_beq = 302,
+ la_op_bne = 303,
+ la_op_blt = 304,
+ la_op_bge = 305,
+ la_op_bltu = 306,
+ la_op_bgeu = 307,
+
+} la_op;
+
+typedef enum {
+ la_codec_illegal,
+ la_codec_empty,
+ la_codec_2r,
+ la_codec_2r_u5,
+ la_codec_2r_u6,
+ la_codec_2r_2bw,
+ la_codec_2r_2bd,
+ la_codec_3r,
+ la_codec_3r_rd0,
+ la_codec_3r_sa2,
+ la_codec_3r_sa3,
+ la_codec_4r,
+ la_codec_r_im20,
+ la_codec_2r_im16,
+ la_codec_2r_im14,
+ la_codec_r_im14,
+ la_codec_2r_im12,
+ la_codec_im5_r_im12,
+ la_codec_2r_im8,
+ la_codec_r_sd,
+ la_codec_r_sj,
+ la_codec_r_cd,
+ la_codec_r_cj,
+ la_codec_r_seq,
+ la_codec_code,
+ la_codec_whint,
+ la_codec_invtlb,
+ la_codec_r_ofs21,
+ la_codec_cj_ofs21,
+ la_codec_ofs26,
+ la_codec_cond,
+ la_codec_sel,
+
+} la_codec;
+
+#define la_fmt_illegal "nte"
+#define la_fmt_empty "nt"
+#define la_fmt_sd_rj "ntA,1"
+#define la_fmt_rd_sj "nt0,B"
+#define la_fmt_rd_rj "nt0,1"
+#define la_fmt_rj_rk "nt1,2"
+#define la_fmt_rj_seq "nt1,x"
+#define la_fmt_rd_si20 "nt0,i(x)"
+#define la_fmt_rd_rj_ui5 "nt0,1,C"
+#define la_fmt_rd_rj_ui6 "nt0,1.C"
+#define la_fmt_rd_rj_level "nt0,1,x"
+#define la_fmt_rd_rj_msbw_lsbw "nt0,1,C,D"
+#define la_fmt_rd_rj_msbd_lsbd "nt0,1,C,D"
+#define la_fmt_rd_rj_si12 "nt0,1,i(x)"
+#define la_fmt_hint_rj_si12 "ntE,1,i(x)"
+#define la_fmt_rd_rj_csr "nt0,1,x"
+#define la_fmt_rd_csr "nt0,x"
+#define la_fmt_rd_rj_si14 "nt0,1,i(x)"
+#define la_fmt_rd_rj_si16 "nt0,1,i(x)"
+#define la_fmt_rd_rj_rk "nt0,1,2"
+#define la_fmt_fd_rj_rk "nt3,1,2"
+#define la_fmt_rd_rj_rk_sa2 "nt0,1,2,D"
+#define la_fmt_rd_rj_rk_sa3 "nt0,1,2,D"
+#define la_fmt_fd_rj "nt3,1"
+#define la_fmt_rd_fj "nt0,4"
+#define la_fmt_fd_fj "nt3,4"
+#define la_fmt_fd_fj_si12 "nt3,4,i(x)"
+#define la_fmt_fcsrd_rj "ntF,1"
+#define la_fmt_rd_fcsrs "nt0,G"
+#define la_fmt_cd_fj "ntH,4"
+#define la_fmt_fd_cj "nt3,I"
+#define la_fmt_fd_fj_fk "nt3,4,5"
+#define la_fmt_code "ntJ"
+#define la_fmt_whint "ntx"
+#define la_fmt_invtlb "ntx,1,2"
+#define la_fmt_offs26 "nto(X)p"
+#define la_fmt_rj_offs21 "nt1,o(X)p"
+#define la_fmt_cj_offs21 "ntQ,o(X)p"
+#define la_fmt_rd_rj_offs16 "nt0,1,o(X)"
+#define la_fmt_rj_rd_offs16 "nt1,0,o(X)p"
+#define la_fmt_s_cd_fj_fk "K.stH,4,5"
+#define la_fmt_d_cd_fj_fk "K.dtH,4,5"
+#define la_fmt_fd_fj_fk_fa "nt3,4,5,6"
+#define la_fmt_fd_fj_fk_ca "nt3,4,5,L"
+#define la_fmt_cop_rj_si12 "ntM,1,i(x)"
+
+/* structures */
+typedef struct {
+ uint32_t pc;
+ uint32_t insn;
+ int32_t imm;
+ int32_t imm2;
+ uint16_t op;
+ uint16_t code;
+ uint8_t codec;
+ uint8_t r1;
+ uint8_t r2;
+ uint8_t r3;
+ uint8_t r4;
+ uint8_t bit;
+} la_decode;
+
+typedef struct {
+ const char * const name;
+ const la_codec codec;
+ const char * const format;
+} la_opcode_data;
+
+/* reg names */
+const char * const loongarch_r_normal_name[32] = {
+ "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7",
+ "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15",
+ "$r16", "$r17", "$r18", "$r19", "$r20", "$r21", "$r22", "$r23",
+ "$r24", "$r25", "$r26", "$r27", "$r28", "$r29", "$r30", "$r31",
+};
+
+const char * const loongarch_f_normal_name[32] = {
+ "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7",
+ "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
+ "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
+ "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31",
+};
+
+const char * const loongarch_cr_normal_name[4] = {
+ "$scr0", "$scr1", "$scr2", "$scr3",
+};
+
+const char * const loongarch_c_normal_name[8] = {
+ "$fcc0", "$fcc1", "$fcc2", "$fcc3", "$fcc4", "$fcc5", "$fcc6", "$fcc7",
+};
+
+/* instruction data */
+const la_opcode_data opcode_data[] = {
+ { "illegal", la_codec_illegal, la_fmt_illegal },
+ { "clo.w", la_codec_2r, la_fmt_rd_rj },
+ { "clz.w", la_codec_2r, la_fmt_rd_rj },
+ { "cto.w", la_codec_2r, la_fmt_rd_rj },
+ { "ctz.w", la_codec_2r, la_fmt_rd_rj },
+ { "clo.d", la_codec_2r, la_fmt_rd_rj },
+ { "clz.d", la_codec_2r, la_fmt_rd_rj },
+ { "cto.d", la_codec_2r, la_fmt_rd_rj },
+ { "ctz_d", la_codec_2r, la_fmt_rd_rj },
+ { "revb.2h", la_codec_2r, la_fmt_rd_rj },
+ { "revb.4h", la_codec_2r, la_fmt_rd_rj },
+ { "revb.2w", la_codec_2r, la_fmt_rd_rj },
+ { "revb.d", la_codec_2r, la_fmt_rd_rj },
+ { "revh.2w", la_codec_2r, la_fmt_rd_rj },
+ { "revh.d", la_codec_2r, la_fmt_rd_rj },
+ { "bitrev.4b", la_codec_2r, la_fmt_rd_rj },
+ { "bitrev.8b", la_codec_2r, la_fmt_rd_rj },
+ { "bitrev.w", la_codec_2r, la_fmt_rd_rj },
+ { "bitrev.d", la_codec_2r, la_fmt_rd_rj },
+ { "ext.w.h", la_codec_2r, la_fmt_rd_rj },
+ { "ext.w.b", la_codec_2r, la_fmt_rd_rj },
+ { "rdtime.d", la_codec_2r, la_fmt_rd_rj },
+ { "cpucfg", la_codec_2r, la_fmt_rd_rj },
+ { "asrtle.d", la_codec_3r_rd0, la_fmt_rj_rk },
+ { "asrtgt.d", la_codec_3r_rd0, la_fmt_rj_rk },
+ { "alsl.w", la_codec_3r_sa2, la_fmt_rd_rj_rk_sa2 },
+ { "alsl.wu", la_codec_3r_sa2, la_fmt_rd_rj_rk_sa2 },
+ { "bytepick.w", la_codec_3r_sa2, la_fmt_rd_rj_rk_sa2 },
+ { "bytepick.d", la_codec_3r_sa3, la_fmt_rd_rj_rk_sa3 },
+ { "add.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "add.d", la_codec_3r, la_fmt_rd_rj_rk },
+ { "sub.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "sub.d", la_codec_3r, la_fmt_rd_rj_rk },
+ { "slt", la_codec_3r, la_fmt_rd_rj_rk },
+ { "sltu", la_codec_3r, la_fmt_rd_rj_rk },
+ { "maskeqz", la_codec_3r, la_fmt_rd_rj_rk },
+ { "masknez", la_codec_3r, la_fmt_rd_rj_rk },
+ { "nor", la_codec_3r, la_fmt_rd_rj_rk },
+ { "and", la_codec_3r, la_fmt_rd_rj_rk },
+ { "or", la_codec_3r, la_fmt_rd_rj_rk },
+ { "xor", la_codec_3r, la_fmt_rd_rj_rk },
+ { "orn", la_codec_3r, la_fmt_rd_rj_rk },
+ { "andn", la_codec_3r, la_fmt_rd_rj_rk },
+ { "sll.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "srl.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "sra.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "sll.d", la_codec_3r, la_fmt_rd_rj_rk },
+ { "srl.d", la_codec_3r, la_fmt_rd_rj_rk },
+ { "sra.d", la_codec_3r, la_fmt_rd_rj_rk },
+ { "rotr.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "rotr.d", la_codec_3r, la_fmt_rd_rj_rk },
+ { "mul.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "mulh.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "mulh.wu", la_codec_3r, la_fmt_rd_rj_rk },
+ { "mul.d", la_codec_3r, la_fmt_rd_rj_rk },
+ { "mulh.d", la_codec_3r, la_fmt_rd_rj_rk },
+ { "mulh.du", la_codec_3r, la_fmt_rd_rj_rk },
+ { "mulw.d.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "mulw.d.wu", la_codec_3r, la_fmt_rd_rj_rk },
+ { "div.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "mod.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "div.wu", la_codec_3r, la_fmt_rd_rj_rk },
+ { "mod.wu", la_codec_3r, la_fmt_rd_rj_rk },
+ { "div.d", la_codec_3r, la_fmt_rd_rj_rk },
+ { "mod.d", la_codec_3r, la_fmt_rd_rj_rk },
+ { "div.du", la_codec_3r, la_fmt_rd_rj_rk },
+ { "mod.du", la_codec_3r, la_fmt_rd_rj_rk },
+ { "crc.w.b.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "crc.w.h.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "crc.w.w.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "crc.w.d.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "crcc.w.b.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "crcc.w.h.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "crcc.w.w.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "crcc.w.d.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "break", la_codec_code, la_fmt_code },
+ { "syscall", la_codec_code, la_fmt_code },
+ { "alsl.d", la_codec_3r_sa2, la_fmt_rd_rj_rk_sa2 },
+ { "slli.w", la_codec_2r_u5, la_fmt_rd_rj_ui5 },
+ { "slli.d", la_codec_2r_u6, la_fmt_rd_rj_ui6 },
+ { "srli.w", la_codec_2r_u5, la_fmt_rd_rj_ui5 },
+ { "srli.d", la_codec_2r_u6, la_fmt_rd_rj_ui6 },
+ { "srai.w", la_codec_2r_u5, la_fmt_rd_rj_ui5 },
+ { "srai.d", la_codec_2r_u6, la_fmt_rd_rj_ui6 },
+ { "rotri.w", la_codec_2r_u5, la_fmt_rd_rj_ui5 },
+ { "rotri.d", la_codec_2r_u6, la_fmt_rd_rj_ui6 },
+ { "bstrins.w", la_codec_2r_2bw, la_fmt_rd_rj_msbw_lsbw },
+ { "bstrpick.w", la_codec_2r_2bw, la_fmt_rd_rj_msbw_lsbw },
+ { "bstrins.d", la_codec_2r_2bd, la_fmt_rd_rj_msbd_lsbd },
+ { "bstrpick.d", la_codec_2r_2bd, la_fmt_rd_rj_msbd_lsbd },
+ { "fadd.s", la_codec_3r, la_fmt_fd_fj_fk },
+ { "fadd.d", la_codec_3r, la_fmt_fd_fj_fk },
+ { "fsub.s", la_codec_3r, la_fmt_fd_fj_fk },
+ { "fsub.d", la_codec_3r, la_fmt_fd_fj_fk },
+ { "fmul.s", la_codec_3r, la_fmt_fd_fj_fk },
+ { "fmul.d", la_codec_3r, la_fmt_fd_fj_fk },
+ { "fdiv.s", la_codec_3r, la_fmt_fd_fj_fk },
+ { "fdiv.d", la_codec_3r, la_fmt_fd_fj_fk },
+ { "fmax.s", la_codec_3r, la_fmt_fd_fj_fk },
+ { "fmax.d", la_codec_3r, la_fmt_fd_fj_fk },
+ { "fmin.s", la_codec_3r, la_fmt_fd_fj_fk },
+ { "fmin.d", la_codec_3r, la_fmt_fd_fj_fk },
+ { "fmaxa.s", la_codec_3r, la_fmt_fd_fj_fk },
+ { "fmaxa.d", la_codec_3r, la_fmt_fd_fj_fk },
+ { "fmina.s", la_codec_3r, la_fmt_fd_fj_fk },
+ { "fmina.d", la_codec_3r, la_fmt_fd_fj_fk },
+ { "fscaleb.s", la_codec_3r, la_fmt_fd_fj_fk },
+ { "fscaleb.d", la_codec_3r, la_fmt_fd_fj_fk },
+ { "fcopysign.s", la_codec_3r, la_fmt_fd_fj_fk },
+ { "fcopysign.d", la_codec_3r, la_fmt_fd_fj_fk },
+ { "fabs.s", la_codec_2r, la_fmt_fd_fj },
+ { "fabs.d", la_codec_2r, la_fmt_fd_fj },
+ { "fneg.s", la_codec_2r, la_fmt_fd_fj },
+ { "fneg.d", la_codec_2r, la_fmt_fd_fj },
+ { "flogb.s", la_codec_2r, la_fmt_fd_fj },
+ { "flogb.d", la_codec_2r, la_fmt_fd_fj },
+ { "fclass.s", la_codec_2r, la_fmt_fd_fj },
+ { "fclass.d", la_codec_2r, la_fmt_fd_fj },
+ { "fsqrt.s", la_codec_2r, la_fmt_fd_fj },
+ { "fsqrt.d", la_codec_2r, la_fmt_fd_fj },
+ { "frecip.s", la_codec_2r, la_fmt_fd_fj },
+ { "frecip.d", la_codec_2r, la_fmt_fd_fj },
+ { "frsqrt.s", la_codec_2r, la_fmt_fd_fj },
+ { "frsqrt.d", la_codec_2r, la_fmt_fd_fj },
+ { "fmov.s", la_codec_2r, la_fmt_fd_fj },
+ { "fmov.d", la_codec_2r, la_fmt_fd_fj },
+ { "movgr2fr.w", la_codec_2r, la_fmt_fd_rj },
+ { "movgr2fr.d", la_codec_2r, la_fmt_fd_rj },
+ { "movgr2frh.w", la_codec_2r, la_fmt_fd_rj },
+ { "movfr2gr.s", la_codec_2r, la_fmt_rd_fj },
+ { "movfr2gr.d", la_codec_2r, la_fmt_rd_fj },
+ { "movfrh2gr.s", la_codec_2r, la_fmt_rd_fj },
+ { "movgr2fcsr", la_codec_2r, la_fmt_fcsrd_rj },
+ { "movfcsr2gr", la_codec_2r, la_fmt_rd_fcsrs },
+ { "movfr2cf", la_codec_r_cd, la_fmt_cd_fj },
+ { "movcf2fr", la_codec_r_cj, la_fmt_fd_cj },
+ { "movgr2cf", la_codec_r_cd, la_fmt_cd_fj },
+ { "movcf2gr", la_codec_r_cj, la_fmt_fd_cj },
+ { "fcvt.s.d", la_codec_2r, la_fmt_fd_fj },
+ { "fcvt.d.s", la_codec_2r, la_fmt_fd_fj },
+ { "ftintrm.w.s", la_codec_2r, la_fmt_fd_fj },
+ { "ftintrm.w.d", la_codec_2r, la_fmt_fd_fj },
+ { "ftintrm.l.s", la_codec_2r, la_fmt_fd_fj },
+ { "ftintrm.l.d", la_codec_2r, la_fmt_fd_fj },
+ { "ftintrp.w.s", la_codec_2r, la_fmt_fd_fj },
+ { "ftintrp.w.d", la_codec_2r, la_fmt_fd_fj },
+ { "ftintrp.l.s", la_codec_2r, la_fmt_fd_fj },
+ { "ftintrp.l.d", la_codec_2r, la_fmt_fd_fj },
+ { "ftintrz.w.s", la_codec_2r, la_fmt_fd_fj },
+ { "ftintrz.w.d", la_codec_2r, la_fmt_fd_fj },
+ { "ftintrz.l.s", la_codec_2r, la_fmt_fd_fj },
+ { "ftintrz.l.d", la_codec_2r, la_fmt_fd_fj },
+ { "ftintrne.w.s", la_codec_2r, la_fmt_fd_fj },
+ { "ftintrne.w.d", la_codec_2r, la_fmt_fd_fj },
+ { "ftintrne.l.s", la_codec_2r, la_fmt_fd_fj },
+ { "ftintrne.l.d", la_codec_2r, la_fmt_fd_fj },
+ { "ftint.w.s", la_codec_2r, la_fmt_fd_fj },
+ { "ftint.w.d", la_codec_2r, la_fmt_fd_fj },
+ { "ftint.l.s", la_codec_2r, la_fmt_fd_fj },
+ { "ftint.l.d", la_codec_2r, la_fmt_fd_fj },
+ { "ffint.s.w", la_codec_2r, la_fmt_fd_fj },
+ { "ffint.s.l", la_codec_2r, la_fmt_fd_fj },
+ { "ffint.d.w", la_codec_2r, la_fmt_fd_fj },
+ { "ffint.d.l", la_codec_2r, la_fmt_fd_fj },
+ { "frint.s", la_codec_2r, la_fmt_fd_fj },
+ { "frint.d", la_codec_2r, la_fmt_fd_fj },
+ { "slti", la_codec_2r_im12, la_fmt_rd_rj_si12 },
+ { "sltui", la_codec_2r_im12, la_fmt_rd_rj_si12 },
+ { "addi.w", la_codec_2r_im12, la_fmt_rd_rj_si12 },
+ { "addi.d", la_codec_2r_im12, la_fmt_rd_rj_si12 },
+ { "lu52i.d", la_codec_2r_im12, la_fmt_rd_rj_si12 },
+ { "addi", la_codec_2r_im12, la_fmt_rd_rj_si12 },
+ { "ori", la_codec_2r_im12, la_fmt_rd_rj_si12 },
+ { "xori", la_codec_2r_im12, la_fmt_rd_rj_si12 },
+ { "rdtimel.w", la_codec_2r, la_fmt_rd_rj },
+ { "rdtimeh.w", la_codec_2r, la_fmt_rd_rj },
+ { "fmadd.s", la_codec_4r, la_fmt_fd_fj_fk_fa },
+ { "fmadd.d", la_codec_4r, la_fmt_fd_fj_fk_fa },
+ { "fmsub.s", la_codec_4r, la_fmt_fd_fj_fk_fa },
+ { "fmsub.d", la_codec_4r, la_fmt_fd_fj_fk_fa },
+ { "fnmadd.s", la_codec_4r, la_fmt_fd_fj_fk_fa },
+ { "fnmadd.d", la_codec_4r, la_fmt_fd_fj_fk_fa },
+ { "fnmsub.s", la_codec_4r, la_fmt_fd_fj_fk_fa },
+ { "fnmsub.d", la_codec_4r, la_fmt_fd_fj_fk_fa },
+ { "fcmp.cond.s", la_codec_cond, la_fmt_s_cd_fj_fk },
+ { "fcmp.cond.d", la_codec_cond, la_fmt_d_cd_fj_fk },
+ { "fsel", la_codec_sel, la_fmt_fd_fj_fk_ca },
+ { "addu16i.d", la_codec_2r_im16, la_fmt_rd_rj_si16 },
+ { "lu12i.w", la_codec_r_im20, la_fmt_rd_si20 },
+ { "lu32i.d", la_codec_r_im20, la_fmt_rd_si20 },
+ { "pcaddi", la_codec_r_im20, la_fmt_rd_si20 },
+ { "pcalau12i", la_codec_r_im20, la_fmt_rd_si20 },
+ { "pcaddu12i", la_codec_r_im20, la_fmt_rd_si20 },
+ { "pcaddu18i", la_codec_r_im20, la_fmt_rd_si20 },
+ { "ll.w", la_codec_2r_im14, la_fmt_rd_rj_si14 },
+ { "sc.w", la_codec_2r_im14, la_fmt_rd_rj_si14 },
+ { "ll.d", la_codec_2r_im14, la_fmt_rd_rj_si14 },
+ { "sc.d", la_codec_2r_im14, la_fmt_rd_rj_si14 },
+ { "ldptr.w", la_codec_2r_im14, la_fmt_rd_rj_si14 },
+ { "stptr.w", la_codec_2r_im14, la_fmt_rd_rj_si14 },
+ { "ldptr.d", la_codec_2r_im14, la_fmt_rd_rj_si14 },
+ { "stptr.d", la_codec_2r_im14, la_fmt_rd_rj_si14 },
+ { "ld.b", la_codec_2r_im12, la_fmt_rd_rj_si12 },
+ { "ld.h", la_codec_2r_im12, la_fmt_rd_rj_si12 },
+ { "ld.w", la_codec_2r_im12, la_fmt_rd_rj_si12 },
+ { "ld.d", la_codec_2r_im12, la_fmt_rd_rj_si12 },
+ { "st.b", la_codec_2r_im12, la_fmt_rd_rj_si12 },
+ { "st.h", la_codec_2r_im12, la_fmt_rd_rj_si12 },
+ { "st.w", la_codec_2r_im12, la_fmt_rd_rj_si12 },
+ { "st.d", la_codec_2r_im12, la_fmt_rd_rj_si12 },
+ { "ld.bu", la_codec_2r_im12, la_fmt_rd_rj_si12 },
+ { "ld.hu", la_codec_2r_im12, la_fmt_rd_rj_si12 },
+ { "ld.wu", la_codec_2r_im12, la_fmt_rd_rj_si12 },
+ { "preld", la_codec_2r_im12, la_fmt_hint_rj_si12 },
+ { "fld.s", la_codec_2r_im12, la_fmt_fd_fj_si12 },
+ { "fst.s", la_codec_2r_im12, la_fmt_fd_fj_si12 },
+ { "fld.d", la_codec_2r_im12, la_fmt_fd_fj_si12 },
+ { "fst.d", la_codec_2r_im12, la_fmt_fd_fj_si12 },
+ { "ldx.b", la_codec_3r, la_fmt_rd_rj_rk },
+ { "ldx.h", la_codec_3r, la_fmt_rd_rj_rk },
+ { "ldx.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "ldx.d", la_codec_3r, la_fmt_rd_rj_rk },
+ { "stx.b", la_codec_3r, la_fmt_rd_rj_rk },
+ { "stx.h", la_codec_3r, la_fmt_rd_rj_rk },
+ { "stx.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "stx.d", la_codec_3r, la_fmt_rd_rj_rk },
+ { "ldx.bu", la_codec_3r, la_fmt_rd_rj_rk },
+ { "ldx.hu", la_codec_3r, la_fmt_rd_rj_rk },
+ { "ldx.wu", la_codec_3r, la_fmt_rd_rj_rk },
+ { "fldx.s", la_codec_3r, la_fmt_fd_rj_rk },
+ { "fldx.d", la_codec_3r, la_fmt_fd_rj_rk },
+ { "fstx.s", la_codec_3r, la_fmt_fd_rj_rk },
+ { "fstx.d", la_codec_3r, la_fmt_fd_rj_rk },
+ { "amswap.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "amswap.d", la_codec_3r, la_fmt_rd_rj_rk },
+ { "amadd.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "amadd.d", la_codec_3r, la_fmt_rd_rj_rk },
+ { "amand.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "amand.d", la_codec_3r, la_fmt_rd_rj_rk },
+ { "amor.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "amor.d", la_codec_3r, la_fmt_rd_rj_rk },
+ { "amxor.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "amxor.d", la_codec_3r, la_fmt_rd_rj_rk },
+ { "ammax.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "ammax.d", la_codec_3r, la_fmt_rd_rj_rk },
+ { "ammin.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "ammin.d", la_codec_3r, la_fmt_rd_rj_rk },
+ { "ammax.wu", la_codec_3r, la_fmt_rd_rj_rk },
+ { "ammax.du", la_codec_3r, la_fmt_rd_rj_rk },
+ { "ammin.wu", la_codec_3r, la_fmt_rd_rj_rk },
+ { "ammin.du", la_codec_3r, la_fmt_rd_rj_rk },
+ { "amswap.db.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "amswap.db.d", la_codec_3r, la_fmt_rd_rj_rk },
+ { "amadd.db.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "amadd.db.d", la_codec_3r, la_fmt_rd_rj_rk },
+ { "amand.db.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "amand.db.d", la_codec_3r, la_fmt_rd_rj_rk },
+ { "amor.db.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "amor.db.d", la_codec_3r, la_fmt_rd_rj_rk },
+ { "amxor.db.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "amxor.db.d", la_codec_3r, la_fmt_rd_rj_rk },
+ { "ammax.db.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "ammax.db.d", la_codec_3r, la_fmt_rd_rj_rk },
+ { "ammin.db.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "ammin.db.d", la_codec_3r, la_fmt_rd_rj_rk },
+ { "ammax.db.wu", la_codec_3r, la_fmt_rd_rj_rk },
+ { "ammax.db.du", la_codec_3r, la_fmt_rd_rj_rk },
+ { "ammin.db.wu", la_codec_3r, la_fmt_rd_rj_rk },
+ { "ammin.db.du", la_codec_3r, la_fmt_rd_rj_rk },
+ { "dbar", la_codec_whint, la_fmt_whint },
+ { "ibar", la_codec_whint, la_fmt_whint },
+ { "fldgt.s", la_codec_3r, la_fmt_fd_rj_rk },
+ { "fldgt.d", la_codec_3r, la_fmt_fd_rj_rk },
+ { "fldle.s", la_codec_3r, la_fmt_fd_rj_rk },
+ { "fldle.d", la_codec_3r, la_fmt_fd_rj_rk },
+ { "fstgt.s", la_codec_3r, la_fmt_fd_rj_rk },
+ { "fstgt.d", la_codec_3r, la_fmt_fd_rj_rk },
+ { "fstle.s", la_codec_3r, la_fmt_fd_rj_rk },
+ { "fstle.d", la_codec_3r, la_fmt_fd_rj_rk },
+ { "ldgt.b", la_codec_3r, la_fmt_rd_rj_rk },
+ { "ldgt.h", la_codec_3r, la_fmt_rd_rj_rk },
+ { "ldgt.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "ldgt.d", la_codec_3r, la_fmt_rd_rj_rk },
+ { "ldle.b", la_codec_3r, la_fmt_rd_rj_rk },
+ { "ldle.h", la_codec_3r, la_fmt_rd_rj_rk },
+ { "ldle.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "ldle.d", la_codec_3r, la_fmt_rd_rj_rk },
+ { "stgt.b", la_codec_3r, la_fmt_rd_rj_rk },
+ { "stgt.h", la_codec_3r, la_fmt_rd_rj_rk },
+ { "stgt.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "stgt.d", la_codec_3r, la_fmt_rd_rj_rk },
+ { "stle.b", la_codec_3r, la_fmt_rd_rj_rk },
+ { "stle.h", la_codec_3r, la_fmt_rd_rj_rk },
+ { "stle.w", la_codec_3r, la_fmt_rd_rj_rk },
+ { "stle.d", la_codec_3r, la_fmt_rd_rj_rk },
+ { "beqz", la_codec_r_ofs21, la_fmt_rj_offs21 },
+ { "bnez", la_codec_r_ofs21, la_fmt_rj_offs21 },
+ { "bceqz", la_codec_cj_ofs21, la_fmt_cj_offs21 },
+ { "bcnez", la_codec_cj_ofs21, la_fmt_cj_offs21 },
+ { "jirl", la_codec_2r_im16, la_fmt_rd_rj_offs16 },
+ { "b", la_codec_ofs26, la_fmt_offs26 },
+ { "bl", la_codec_ofs26, la_fmt_offs26 },
+ { "beq", la_codec_2r_im16, la_fmt_rj_rd_offs16 },
+ { "bne", la_codec_2r_im16, la_fmt_rj_rd_offs16 },
+ { "blt", la_codec_2r_im16, la_fmt_rj_rd_offs16 },
+ { "bge", la_codec_2r_im16, la_fmt_rj_rd_offs16 },
+ { "bltu", la_codec_2r_im16, la_fmt_rj_rd_offs16 },
+ { "bgeu", la_codec_2r_im16, la_fmt_rj_rd_offs16 },
+
+};
+
+
+/* decode opcode */
+static void decode_insn_opcode(la_decode *dec)
+{
+ uint32_t insn = dec->insn;
+ uint16_t op = la_op_illegal;
+ switch ((insn >> 26) & 0x3f) {
+ case 0x0:
+ switch ((insn >> 22) & 0xf) {
+ case 0x0:
+ switch ((insn >> 18) & 0xf) {
+ case 0x0:
+ switch ((insn >> 15) & 0x7) {
+ case 0x0:
+ switch ((insn >> 10) & 0x1f) {
+ case 0x4:
+ op = la_op_clo_w;
+ break;
+ case 0x5:
+ op = la_op_clz_w;
+ break;
+ case 0x6:
+ op = la_op_cto_w;
+ break;
+ case 0x7:
+ op = la_op_ctz_w;
+ break;
+ case 0x8:
+ op = la_op_clo_d;
+ break;
+ case 0x9:
+ op = la_op_clz_d;
+ break;
+ case 0xa:
+ op = la_op_cto_d;
+ break;
+ case 0xb:
+ op = la_op_ctz_d;
+ break;
+ case 0xc:
+ op = la_op_revb_2h;
+ break;
+ case 0xd:
+ op = la_op_revb_4h;
+ break;
+ case 0xe:
+ op = la_op_revb_2w;
+ break;
+ case 0xf:
+ op = la_op_revb_d;
+ break;
+ case 0x10:
+ op = la_op_revh_2w;
+ break;
+ case 0x11:
+ op = la_op_revh_d;
+ break;
+ case 0x12:
+ op = la_op_bitrev_4b;
+ break;
+ case 0x13:
+ op = la_op_bitrev_8b;
+ break;
+ case 0x14:
+ op = la_op_bitrev_w;
+ break;
+ case 0x15:
+ op = la_op_bitrev_d;
+ break;
+ case 0x16:
+ op = la_op_ext_w_h;
+ break;
+ case 0x17:
+ op = la_op_ext_w_b;
+ break;
+ case 0x18:
+ op = la_op_rdtimel_w;
+ break;
+ case 0x19:
+ op = la_op_rdtimeh_w;
+ break;
+ case 0x1a:
+ op = la_op_rdtime_d;
+ break;
+ case 0x1b:
+ op = la_op_cpucfg;
+ break;
+ }
+ break;
+ case 0x2:
+ switch (insn & 0x0000001f) {
+ case 0x00000000:
+ op = la_op_asrtle_d;
+ break;
+ }
+ break;
+ case 0x3:
+ switch (insn & 0x0000001f) {
+ case 0x00000000:
+ op = la_op_asrtgt_d;
+ break;
+ }
+ break;
+ }
+ break;
+ case 0x1:
+ switch ((insn >> 17) & 0x1) {
+ case 0x0:
+ op = la_op_alsl_w;
+ break;
+ case 0x1:
+ op = la_op_alsl_wu;
+ break;
+ }
+ break;
+ case 0x2:
+ switch ((insn >> 17) & 0x1) {
+ case 0x0:
+ op = la_op_bytepick_w;
+ break;
+ }
+ break;
+ case 0x3:
+ op = la_op_bytepick_d;
+ break;
+ case 0x4:
+ switch ((insn >> 15) & 0x7) {
+ case 0x0:
+ op = la_op_add_w;
+ break;
+ case 0x1:
+ op = la_op_add_d;
+ break;
+ case 0x2:
+ op = la_op_sub_w;
+ break;
+ case 0x3:
+ op = la_op_sub_d;
+ break;
+ case 0x4:
+ op = la_op_slt;
+ break;
+ case 0x5:
+ op = la_op_sltu;
+ break;
+ case 0x6:
+ op = la_op_maskeqz;
+ break;
+ case 0x7:
+ op = la_op_masknez;
+ break;
+ }
+ break;
+ case 0x5:
+ switch ((insn >> 15) & 0x7) {
+ case 0x0:
+ op = la_op_nor;
+ break;
+ case 0x1:
+ op = la_op_and;
+ break;
+ case 0x2:
+ op = la_op_or;
+ break;
+ case 0x3:
+ op = la_op_xor;
+ break;
+ case 0x4:
+ op = la_op_orn;
+ break;
+ case 0x5:
+ op = la_op_andn;
+ break;
+ case 0x6:
+ op = la_op_sll_w;
+ break;
+ case 0x7:
+ op = la_op_srl_w;
+ break;
+ }
+ break;
+ case 0x6:
+ switch ((insn >> 15) & 0x7) {
+ case 0x0:
+ op = la_op_sra_w;
+ break;
+ case 0x1:
+ op = la_op_sll_d;
+ break;
+ case 0x2:
+ op = la_op_srl_d;
+ break;
+ case 0x3:
+ op = la_op_sra_d;
+ break;
+ case 0x6:
+ op = la_op_rotr_w;
+ break;
+ case 0x7:
+ op = la_op_rotr_d;
+ break;
+ }
+ break;
+ case 0x7:
+ switch ((insn >> 15) & 0x7) {
+ case 0x0:
+ op = la_op_mul_w;
+ break;
+ case 0x1:
+ op = la_op_mulh_w;
+ break;
+ case 0x2:
+ op = la_op_mulh_wu;
+ break;
+ case 0x3:
+ op = la_op_mul_d;
+ break;
+ case 0x4:
+ op = la_op_mulh_d;
+ break;
+ case 0x5:
+ op = la_op_mulh_du;
+ break;
+ case 0x6:
+ op = la_op_mulw_d_w;
+ break;
+ case 0x7:
+ op = la_op_mulw_d_wu;
+ break;
+ }
+ break;
+ case 0x8:
+ switch ((insn >> 15) & 0x7) {
+ case 0x0:
+ op = la_op_div_w;
+ break;
+ case 0x1:
+ op = la_op_mod_w;
+ break;
+ case 0x2:
+ op = la_op_div_wu;
+ break;
+ case 0x3:
+ op = la_op_mod_wu;
+ break;
+ case 0x4:
+ op = la_op_div_d;
+ break;
+ case 0x5:
+ op = la_op_mod_d;
+ break;
+ case 0x6:
+ op = la_op_div_du;
+ break;
+ case 0x7:
+ op = la_op_mod_du;
+ break;
+ }
+ break;
+ case 0x9:
+ switch ((insn >> 15) & 0x7) {
+ case 0x0:
+ op = la_op_crc_w_b_w;
+ break;
+ case 0x1:
+ op = la_op_crc_w_h_w;
+ break;
+ case 0x2:
+ op = la_op_crc_w_w_w;
+ break;
+ case 0x3:
+ op = la_op_crc_w_d_w;
+ break;
+ case 0x4:
+ op = la_op_crcc_w_b_w;
+ break;
+ case 0x5:
+ op = la_op_crcc_w_h_w;
+ break;
+ case 0x6:
+ op = la_op_crcc_w_w_w;
+ break;
+ case 0x7:
+ op = la_op_crcc_w_d_w;
+ break;
+ }
+ break;
+ case 0xa:
+ switch ((insn >> 15) & 0x7) {
+ case 0x4:
+ op = la_op_break;
+ break;
+ case 0x6:
+ op = la_op_syscall;
+ break;
+ }
+ break;
+ case 0xb:
+ switch ((insn >> 17) & 0x1) {
+ case 0x0:
+ op = la_op_alsl_d;
+ break;
+ }
+ break;
+ }
+ break;
+ case 0x1:
+ switch ((insn >> 21) & 0x1) {
+ case 0x0:
+ switch ((insn >> 16) & 0x1f) {
+ case 0x0:
+ switch ((insn >> 15) & 0x1) {
+ case 0x1:
+ op = la_op_slli_w;
+ break;
+ }
+ break;
+ case 0x1:
+ op = la_op_slli_d;
+ break;
+ case 0x4:
+ switch ((insn >> 15) & 0x1) {
+ case 0x1:
+ op = la_op_srli_w;
+ break;
+ }
+ break;
+ case 0x5:
+ op = la_op_srli_d;
+ break;
+ case 0x8:
+ switch ((insn >> 15) & 0x1) {
+ case 0x1:
+ op = la_op_srai_w;
+ break;
+ }
+ break;
+ case 0x9:
+ op = la_op_srai_d;
+ break;
+ case 0xc:
+ switch ((insn >> 15) & 0x1) {
+ case 0x1:
+ op = la_op_rotri_w;
+ break;
+ }
+ break;
+ case 0xd:
+ op = la_op_rotri_d;
+ break;
+ }
+ break;
+ case 0x1:
+ switch ((insn >> 15) & 0x1) {
+ case 0x0:
+ op = la_op_bstrins_w;
+ break;
+ case 0x1:
+ op = la_op_bstrpick_w;
+ break;
+ }
+ break;
+ }
+ break;
+ case 0x2:
+ op = la_op_bstrins_d;
+ break;
+ case 0x3:
+ op = la_op_bstrpick_d;
+ break;
+ case 0x4:
+ switch ((insn >> 15) & 0x7f) {
+ case 0x1:
+ op = la_op_fadd_s;
+ break;
+ case 0x2:
+ op = la_op_fadd_d;
+ break;
+ case 0x5:
+ op = la_op_fsub_s;
+ break;
+ case 0x6:
+ op = la_op_fsub_d;
+ break;
+ case 0x9:
+ op = la_op_fmul_s;
+ break;
+ case 0xa:
+ op = la_op_fmul_d;
+ break;
+ case 0xd:
+ op = la_op_fdiv_s;
+ break;
+ case 0xe:
+ op = la_op_fdiv_d;
+ break;
+ case 0x11:
+ op = la_op_fmax_s;
+ break;
+ case 0x12:
+ op = la_op_fmax_d;
+ break;
+ case 0x15:
+ op = la_op_fmin_s;
+ break;
+ case 0x16:
+ op = la_op_fmin_d;
+ break;
+ case 0x19:
+ op = la_op_fmaxa_s;
+ break;
+ case 0x1a:
+ op = la_op_fmaxa_d;
+ break;
+ case 0x1d:
+ op = la_op_fmina_s;
+ break;
+ case 0x1e:
+ op = la_op_fmina_d;
+ break;
+ case 0x21:
+ op = la_op_fscaleb_s;
+ break;
+ case 0x22:
+ op = la_op_fscaleb_d;
+ break;
+ case 0x25:
+ op = la_op_fcopysign_s;
+ break;
+ case 0x26:
+ op = la_op_fcopysign_d;
+ break;
+ case 0x28:
+ switch ((insn >> 10) & 0x1f) {
+ case 0x1:
+ op = la_op_fabs_s;
+ break;
+ case 0x2:
+ op = la_op_fabs_d;
+ break;
+ case 0x5:
+ op = la_op_fneg_s;
+ break;
+ case 0x6:
+ op = la_op_fneg_d;
+ break;
+ case 0x9:
+ op = la_op_flogb_s;
+ break;
+ case 0xa:
+ op = la_op_flogb_d;
+ break;
+ case 0xd:
+ op = la_op_fclass_s;
+ break;
+ case 0xe:
+ op = la_op_fclass_d;
+ break;
+ case 0x11:
+ op = la_op_fsqrt_s;
+ break;
+ case 0x12:
+ op = la_op_fsqrt_d;
+ break;
+ case 0x15:
+ op = la_op_frecip_s;
+ break;
+ case 0x16:
+ op = la_op_frecip_d;
+ break;
+ case 0x19:
+ op = la_op_frsqrt_s;
+ break;
+ case 0x1a:
+ op = la_op_frsqrt_d;
+ break;
+ }
+ break;
+ case 0x29:
+ switch ((insn >> 10) & 0x1f) {
+ case 0x5:
+ op = la_op_fmov_s;
+ break;
+ case 0x6:
+ op = la_op_fmov_d;
+ break;
+ case 0x9:
+ op = la_op_movgr2fr_w;
+ break;
+ case 0xa:
+ op = la_op_movgr2fr_d;
+ break;
+ case 0xb:
+ op = la_op_movgr2frh_w;
+ break;
+ case 0xd:
+ op = la_op_movfr2gr_s;
+ break;
+ case 0xe:
+ op = la_op_movfr2gr_d;
+ break;
+ case 0xf:
+ op = la_op_movfrh2gr_s;
+ break;
+ case 0x10:
+ op = la_op_movgr2fcsr;
+ break;
+ case 0x12:
+ op = la_op_movfcsr2gr;
+ break;
+ case 0x14:
+ switch ((insn >> 3) & 0x3) {
+ case 0x0:
+ op = la_op_movfr2cf;
+ break;
+ }
+ break;
+ case 0x15:
+ switch ((insn >> 8) & 0x3) {
+ case 0x0:
+ op = la_op_movcf2fr;
+ break;
+ }
+ break;
+ case 0x16:
+ switch ((insn >> 3) & 0x3) {
+ case 0x0:
+ op = la_op_movgr2cf;
+ break;
+ }
+ break;
+ case 0x17:
+ switch ((insn >> 8) & 0x3) {
+ case 0x0:
+ op = la_op_movcf2gr;
+ break;
+ }
+ break;
+ }
+ break;
+ case 0x32:
+ switch ((insn >> 10) & 0x1f) {
+ case 0x6:
+ op = la_op_fcvt_s_d;
+ break;
+ case 0x9:
+ op = la_op_fcvt_d_s;
+ break;
+ }
+ break;
+ case 0x34:
+ switch ((insn >> 10) & 0x1f) {
+ case 0x1:
+ op = la_op_ftintrm_w_s;
+ break;
+ case 0x2:
+ op = la_op_ftintrm_w_d;
+ break;
+ case 0x9:
+ op = la_op_ftintrm_l_s;
+ break;
+ case 0xa:
+ op = la_op_ftintrm_l_d;
+ break;
+ case 0x11:
+ op = la_op_ftintrp_w_s;
+ break;
+ case 0x12:
+ op = la_op_ftintrp_w_d;
+ break;
+ case 0x19:
+ op = la_op_ftintrp_l_s;
+ break;
+ case 0x1a:
+ op = la_op_ftintrp_l_d;
+ break;
+ }
+ break;
+ case 0x35:
+ switch ((insn >> 10) & 0x1f) {
+ case 0x1:
+ op = la_op_ftintrz_w_s;
+ break;
+ case 0x2:
+ op = la_op_ftintrz_w_d;
+ break;
+ case 0x9:
+ op = la_op_ftintrz_l_s;
+ break;
+ case 0xa:
+ op = la_op_ftintrz_l_d;
+ break;
+ case 0x11:
+ op = la_op_ftintrne_w_s;
+ break;
+ case 0x12:
+ op = la_op_ftintrne_w_d;
+ break;
+ case 0x19:
+ op = la_op_ftintrne_l_s;
+ break;
+ case 0x1a:
+ op = la_op_ftintrne_l_d;
+ break;
+ }
+ break;
+ case 0x36:
+ switch ((insn >> 10) & 0x1f) {
+ case 0x1:
+ op = la_op_ftint_w_s;
+ break;
+ case 0x2:
+ op = la_op_ftint_w_d;
+ break;
+ case 0x9:
+ op = la_op_ftint_l_s;
+ break;
+ case 0xa:
+ op = la_op_ftint_l_d;
+ break;
+ }
+ break;
+ case 0x3a:
+ switch ((insn >> 10) & 0x1f) {
+ case 0x4:
+ op = la_op_ffint_s_w;
+ break;
+ case 0x6:
+ op = la_op_ffint_s_l;
+ break;
+ case 0x8:
+ op = la_op_ffint_d_w;
+ break;
+ case 0xa:
+ op = la_op_ffint_d_l;
+ break;
+ }
+ break;
+ case 0x3c:
+ switch ((insn >> 10) & 0x1f) {
+ case 0x11:
+ op = la_op_frint_s;
+ break;
+ case 0x12:
+ op = la_op_frint_d;
+ break;
+ }
+ break;
+ }
+ break;
+ case 0x8:
+ op = la_op_slti;
+ break;
+ case 0x9:
+ op = la_op_sltui;
+ break;
+ case 0xa:
+ op = la_op_addi_w;
+ break;
+ case 0xb:
+ op = la_op_addi_d;
+ break;
+ case 0xc:
+ op = la_op_lu52i_d;
+ break;
+ case 0xd:
+ op = la_op_addi;
+ break;
+ case 0xe:
+ op = la_op_ori;
+ break;
+ case 0xf:
+ op = la_op_xori;
+ break;
+ }
+ break;
+ case 0x2:
+ switch ((insn >> 20) & 0x3f) {
+ case 0x1:
+ op = la_op_fmadd_s;
+ break;
+ case 0x2:
+ op = la_op_fmadd_d;
+ break;
+ case 0x5:
+ op = la_op_fmsub_s;
+ break;
+ case 0x6:
+ op = la_op_fmsub_d;
+ break;
+ case 0x9:
+ op = la_op_fnmadd_s;
+ break;
+ case 0xa:
+ op = la_op_fnmadd_d;
+ break;
+ case 0xd:
+ op = la_op_fnmsub_s;
+ break;
+ case 0xe:
+ op = la_op_fnmsub_d;
+ break;
+ }
+ break;
+ case 0x3:
+ switch ((insn >> 20) & 0x3f) {
+ case 0x1:
+ switch ((insn >> 3) & 0x3) {
+ case 0x0:
+ op = la_op_fcmp_cond_s;
+ break;
+ }
+ break;
+ case 0x2:
+ switch ((insn >> 3) & 0x3) {
+ case 0x0:
+ op = la_op_fcmp_cond_d;
+ break;
+ }
+ break;
+ case 0x10:
+ switch ((insn >> 18) & 0x3) {
+ case 0x0:
+ op = la_op_fsel;
+ break;
+ }
+ break;
+ }
+ break;
+ case 0x4:
+ op = la_op_addu16i_d;
+ break;
+ case 0x5:
+ switch ((insn >> 25) & 0x1) {
+ case 0x0:
+ op = la_op_lu12i_w;
+ break;
+ case 0x1:
+ op = la_op_lu32i_d;
+ break;
+ }
+ break;
+ case 0x6:
+ switch ((insn >> 25) & 0x1) {
+ case 0x0:
+ op = la_op_pcaddi;
+ break;
+ case 0x1:
+ op = la_op_pcalau12i;
+ break;
+ }
+ break;
+ case 0x7:
+ switch ((insn >> 25) & 0x1) {
+ case 0x0:
+ op = la_op_pcaddu12i;
+ break;
+ case 0x1:
+ op = la_op_pcaddu18i;
+ break;
+ }
+ break;
+ case 0x8:
+ switch ((insn >> 24) & 0x3) {
+ case 0x0:
+ op = la_op_ll_w;
+ break;
+ case 0x1:
+ op = la_op_sc_w;
+ break;
+ case 0x2:
+ op = la_op_ll_d;
+ break;
+ case 0x3:
+ op = la_op_sc_d;
+ break;
+ }
+ break;
+ case 0x9:
+ switch ((insn >> 24) & 0x3) {
+ case 0x0:
+ op = la_op_ldptr_w;
+ break;
+ case 0x1:
+ op = la_op_stptr_w;
+ break;
+ case 0x2:
+ op = la_op_ldptr_d;
+ break;
+ case 0x3:
+ op = la_op_stptr_d;
+ break;
+ }
+ break;
+ case 0xa:
+ switch ((insn >> 22) & 0xf) {
+ case 0x0:
+ op = la_op_ld_b;
+ break;
+ case 0x1:
+ op = la_op_ld_h;
+ break;
+ case 0x2:
+ op = la_op_ld_w;
+ break;
+ case 0x3:
+ op = la_op_ld_d;
+ break;
+ case 0x4:
+ op = la_op_st_b;
+ break;
+ case 0x5:
+ op = la_op_st_h;
+ break;
+ case 0x6:
+ op = la_op_st_w;
+ break;
+ case 0x7:
+ op = la_op_st_d;
+ break;
+ case 0x8:
+ op = la_op_ld_bu;
+ break;
+ case 0x9:
+ op = la_op_ld_hu;
+ break;
+ case 0xa:
+ op = la_op_ld_wu;
+ break;
+ case 0xb:
+ op = la_op_preld;
+ break;
+ case 0xc:
+ op = la_op_fld_s;
+ break;
+ case 0xd:
+ op = la_op_fst_s;
+ break;
+ case 0xe:
+ op = la_op_fld_d;
+ break;
+ case 0xf:
+ op = la_op_fst_d;
+ break;
+ }
+ break;
+ case 0xe:
+ switch ((insn >> 15) & 0x7ff) {
+ case 0x0:
+ op = la_op_ldx_b;
+ break;
+ case 0x8:
+ op = la_op_ldx_h;
+ break;
+ case 0x10:
+ op = la_op_ldx_w;
+ break;
+ case 0x18:
+ op = la_op_ldx_d;
+ break;
+ case 0x20:
+ op = la_op_stx_b;
+ break;
+ case 0x28:
+ op = la_op_stx_h;
+ break;
+ case 0x30:
+ op = la_op_stx_w;
+ break;
+ case 0x38:
+ op = la_op_stx_d;
+ break;
+ case 0x40:
+ op = la_op_ldx_bu;
+ break;
+ case 0x48:
+ op = la_op_ldx_hu;
+ break;
+ case 0x50:
+ op = la_op_ldx_wu;
+ break;
+ case 0x60:
+ op = la_op_fldx_s;
+ break;
+ case 0x68:
+ op = la_op_fldx_d;
+ break;
+ case 0x70:
+ op = la_op_fstx_s;
+ break;
+ case 0x78:
+ op = la_op_fstx_d;
+ break;
+ case 0xc0:
+ op = la_op_amswap_w;
+ break;
+ case 0xc1:
+ op = la_op_amswap_d;
+ break;
+ case 0xc2:
+ op = la_op_amadd_w;
+ break;
+ case 0xc3:
+ op = la_op_amadd_d;
+ break;
+ case 0xc4:
+ op = la_op_amand_w;
+ break;
+ case 0xc5:
+ op = la_op_amand_d;
+ break;
+ case 0xc6:
+ op = la_op_amor_w;
+ break;
+ case 0xc7:
+ op = la_op_amor_d;
+ break;
+ case 0xc8:
+ op = la_op_amxor_w;
+ break;
+ case 0xc9:
+ op = la_op_amxor_d;
+ break;
+ case 0xca:
+ op = la_op_ammax_w;
+ break;
+ case 0xcb:
+ op = la_op_ammax_d;
+ break;
+ case 0xcc:
+ op = la_op_ammin_w;
+ break;
+ case 0xcd:
+ op = la_op_ammin_d;
+ break;
+ case 0xce:
+ op = la_op_ammax_wu;
+ break;
+ case 0xcf:
+ op = la_op_ammax_du;
+ break;
+ case 0xd0:
+ op = la_op_ammin_wu;
+ break;
+ case 0xd1:
+ op = la_op_ammin_du;
+ break;
+ case 0xd2:
+ op = la_op_amswap_db_w;
+ break;
+ case 0xd3:
+ op = la_op_amswap_db_d;
+ break;
+ case 0xd4:
+ op = la_op_amadd_db_w;
+ break;
+ case 0xd5:
+ op = la_op_amadd_db_d;
+ break;
+ case 0xd6:
+ op = la_op_amand_db_w;
+ break;
+ case 0xd7:
+ op = la_op_amand_db_d;
+ break;
+ case 0xd8:
+ op = la_op_amor_db_w;
+ break;
+ case 0xd9:
+ op = la_op_amor_db_d;
+ break;
+ case 0xda:
+ op = la_op_amxor_db_w;
+ break;
+ case 0xdb:
+ op = la_op_amxor_db_d;
+ break;
+ case 0xdc:
+ op = la_op_ammax_db_w;
+ break;
+ case 0xdd:
+ op = la_op_ammax_db_d;
+ break;
+ case 0xde:
+ op = la_op_ammin_db_w;
+ break;
+ case 0xdf:
+ op = la_op_ammin_db_d;
+ break;
+ case 0xe0:
+ op = la_op_ammax_db_wu;
+ break;
+ case 0xe1:
+ op = la_op_ammax_db_du;
+ break;
+ case 0xe2:
+ op = la_op_ammin_db_wu;
+ break;
+ case 0xe3:
+ op = la_op_ammin_db_du;
+ break;
+ case 0xe4:
+ op = la_op_dbar;
+ break;
+ case 0xe5:
+ op = la_op_ibar;
+ break;
+ case 0xe8:
+ op = la_op_fldgt_s;
+ break;
+ case 0xe9:
+ op = la_op_fldgt_d;
+ break;
+ case 0xea:
+ op = la_op_fldle_s;
+ break;
+ case 0xeb:
+ op = la_op_fldle_d;
+ break;
+ case 0xec:
+ op = la_op_fstgt_s;
+ break;
+ case 0xed:
+ op = la_op_fstgt_d;
+ break;
+ case 0xee:
+ op = ls_op_fstle_s;
+ break;
+ case 0xef:
+ op = la_op_fstle_d;
+ break;
+ case 0xf0:
+ op = la_op_ldgt_b;
+ break;
+ case 0xf1:
+ op = la_op_ldgt_h;
+ break;
+ case 0xf2:
+ op = la_op_ldgt_w;
+ break;
+ case 0xf3:
+ op = la_op_ldgt_d;
+ break;
+ case 0xf4:
+ op = la_op_ldle_b;
+ break;
+ case 0xf5:
+ op = la_op_ldle_h;
+ break;
+ case 0xf6:
+ op = la_op_ldle_w;
+ break;
+ case 0xf7:
+ op = la_op_ldle_d;
+ break;
+ case 0xf8:
+ op = la_op_stgt_b;
+ break;
+ case 0xf9:
+ op = la_op_stgt_h;
+ break;
+ case 0xfa:
+ op = la_op_stgt_w;
+ break;
+ case 0xfb:
+ op = la_op_stgt_d;
+ break;
+ case 0xfc:
+ op = la_op_stle_b;
+ break;
+ case 0xfd:
+ op = la_op_stle_h;
+ break;
+ case 0xfe:
+ op = la_op_stle_w;
+ break;
+ case 0xff:
+ op = la_op_stle_d;
+ break;
+ }
+ break;
+ case 0x10:
+ op = la_op_beqz;
+ break;
+ case 0x11:
+ op = la_op_bnez;
+ break;
+ case 0x12:
+ switch ((insn >> 8) & 0x3) {
+ case 0x0:
+ op = la_op_bceqz;
+ break;
+ case 0x1:
+ op = la_op_bcnez;
+ break;
+ }
+ break;
+ case 0x13:
+ op = la_op_jirl;
+ break;
+ case 0x14:
+ op = la_op_b;
+ break;
+ case 0x15:
+ op = la_op_bl;
+ break;
+ case 0x16:
+ op = la_op_beq;
+ break;
+ case 0x17:
+ op = la_op_bne;
+ break;
+ case 0x18:
+ op = la_op_blt;
+ break;
+ case 0x19:
+ op = la_op_bge;
+ break;
+ case 0x1a:
+ op = la_op_bltu;
+ break;
+ case 0x1b:
+ op = la_op_bgeu;
+ break;
+ default:
+ op = la_op_illegal;
+ break;
+ }
+ dec->op = op;
+}
+
+/* operand extractors */
+#define IM_5 5
+#define IM_8 8
+#define IM_12 12
+#define IM_14 14
+#define IM_15 15
+#define IM_16 16
+#define IM_20 20
+#define IM_21 21
+#define IM_26 26
+
+static uint32_t operand_r1(uint32_t insn)
+{
+ return insn & 0x1f;
+}
+
+static uint32_t operand_r2(uint32_t insn)
+{
+ return (insn >> 5) & 0x1f;
+}
+
+static uint32_t operand_r3(uint32_t insn)
+{
+ return (insn >> 10) & 0x1f;
+}
+
+static uint32_t operand_r4(uint32_t insn)
+{
+ return (insn >> 15) & 0x1f;
+}
+
+static uint32_t operand_u6(uint32_t insn)
+{
+ return (insn >> 10) & 0x3f;
+}
+
+static uint32_t operand_bw1(uint32_t insn)
+{
+ return (insn >> 10) & 0x1f;
+}
+
+static uint32_t operand_bw2(uint32_t insn)
+{
+ return (insn >> 16) & 0x1f;
+}
+
+static uint32_t operand_bd1(uint32_t insn)
+{
+ return (insn >> 10) & 0x3f;
+}
+
+static uint32_t operand_bd2(uint32_t insn)
+{
+ return (insn >> 16) & 0x3f;
+}
+
+static uint32_t operand_sa2(uint32_t insn)
+{
+ return (insn >> 15) & 0x3;
+}
+
+static uint32_t operand_sa3(uint32_t insn)
+{
+ return (insn >> 15) & 0x3;
+}
+
+static int32_t operand_im20(uint32_t insn)
+{
+ int32_t imm = (int32_t)((insn >> 5) & 0xfffff);
+ return imm > (1 << 19) ? imm - (1 << 20) : imm;
+}
+
+static int32_t operand_im16(uint32_t insn)
+{
+ int32_t imm = (int32_t)((insn >> 10) & 0xffff);
+ return imm > (1 << 15) ? imm - (1 << 16) : imm;
+}
+
+static int32_t operand_im14(uint32_t insn)
+{
+ int32_t imm = (int32_t)((insn >> 10) & 0x3fff);
+ return imm > (1 << 13) ? imm - (1 << 14) : imm;
+}
+
+static int32_t operand_im12(uint32_t insn)
+{
+ int32_t imm = (int32_t)((insn >> 10) & 0xfff);
+ return imm > (1 << 11) ? imm - (1 << 12) : imm;
+}
+
+static int32_t operand_im8(uint32_t insn)
+{
+ int32_t imm = (int32_t)((insn >> 10) & 0xff);
+ return imm > (1 << 7) ? imm - (1 << 8) : imm;
+}
+
+static uint32_t operand_sd(uint32_t insn)
+{
+ return insn & 0x3;
+}
+
+static uint32_t operand_sj(uint32_t insn)
+{
+ return (insn >> 5) & 0x3;
+}
+
+static uint32_t operand_cd(uint32_t insn)
+{
+ return insn & 0x7;
+}
+
+static uint32_t operand_cj(uint32_t insn)
+{
+ return (insn >> 5) & 0x7;
+}
+
+static uint32_t operand_code(uint32_t insn)
+{
+ return insn & 0x7fff;
+}
+
+static int32_t operand_whint(uint32_t insn)
+{
+ int32_t imm = (int32_t)(insn & 0x7fff);
+ return imm > (1 << 14) ? imm - (1 << 15) : imm;
+}
+
+static int32_t operand_invop(uint32_t insn)
+{
+ int32_t imm = (int32_t)(insn & 0x1f);
+ return imm > (1 << 4) ? imm - (1 << 5) : imm;
+}
+
+static int32_t operand_ofs21(uint32_t insn)
+{
+ int32_t imm = (((int32_t)insn & 0x1f) << 16) |
+ ((insn >> 10) & 0xffff);
+ return imm > (1 << 20) ? imm - (1 << 21) : imm;
+}
+
+static int32_t operand_ofs26(uint32_t insn)
+{
+ int32_t imm = (((int32_t)insn & 0x3ff) << 16) |
+ ((insn >> 10) & 0xffff);
+ return imm > (1 << 25) ? imm - (1 << 26) : imm;
+}
+
+static uint32_t operand_fcond(uint32_t insn)
+{
+ return (insn >> 15) & 0x1f;
+}
+
+static uint32_t operand_sel(uint32_t insn)
+{
+ return (insn >> 15) & 0x7;
+}
+
+/* decode operands */
+static void decode_insn_operands(la_decode *dec)
+{
+ uint32_t insn = dec->insn;
+ dec->codec = opcode_data[dec->op].codec;
+ switch (dec->codec) {
+ case la_codec_illegal:
+ case la_codec_empty:
+ break;
+ case la_codec_2r:
+ dec->r1 = operand_r1(insn);
+ dec->r2 = operand_r2(insn);
+ break;
+ case la_codec_2r_u5:
+ dec->r1 = operand_r1(insn);
+ dec->r2 = operand_r2(insn);
+ dec->r3 = operand_r3(insn);
+ break;
+ case la_codec_2r_u6:
+ dec->r1 = operand_r1(insn);
+ dec->r2 = operand_r2(insn);
+ dec->r3 = operand_u6(insn);
+ break;
+ case la_codec_2r_2bw:
+ dec->r1 = operand_r1(insn);
+ dec->r2 = operand_r2(insn);
+ dec->r3 = operand_bw1(insn);
+ dec->r4 = operand_bw2(insn);
+ break;
+ case la_codec_2r_2bd:
+ dec->r1 = operand_r1(insn);
+ dec->r2 = operand_r2(insn);
+ dec->r3 = operand_bd1(insn);
+ dec->r4 = operand_bd2(insn);
+ break;
+ case la_codec_3r:
+ dec->r1 = operand_r1(insn);
+ dec->r2 = operand_r2(insn);
+ dec->r3 = operand_r3(insn);
+ break;
+ case la_codec_3r_rd0:
+ dec->r1 = 0;
+ dec->r2 = operand_r2(insn);
+ dec->r3 = operand_r3(insn);
+ break;
+ case la_codec_3r_sa2:
+ dec->r1 = operand_r1(insn);
+ dec->r2 = operand_r2(insn);
+ dec->r3 = operand_r3(insn);
+ dec->r4 = operand_sa2(insn);
+ break;
+ case la_codec_3r_sa3:
+ dec->r1 = operand_r1(insn);
+ dec->r2 = operand_r2(insn);
+ dec->r3 = operand_r3(insn);
+ dec->r4 = operand_sa3(insn);
+ break;
+ case la_codec_4r:
+ dec->r1 = operand_r1(insn);
+ dec->r2 = operand_r2(insn);
+ dec->r3 = operand_r3(insn);
+ dec->r4 = operand_r4(insn);
+ break;
+ case la_codec_r_im20:
+ dec->r1 = operand_r1(insn);
+ dec->imm = operand_im20(insn);
+ dec->bit = IM_20;
+ break;
+ case la_codec_2r_im16:
+ dec->r1 = operand_r1(insn);
+ dec->r2 = operand_r2(insn);
+ dec->imm = operand_im16(insn);
+ dec->bit = IM_16;
+ break;
+ case la_codec_2r_im14:
+ dec->r1 = operand_r1(insn);
+ dec->r2 = operand_r2(insn);
+ dec->imm = operand_im14(insn);
+ dec->bit = IM_14;
+ break;
+ case la_codec_r_im14:
+ dec->r1 = operand_r1(insn);
+ dec->imm = operand_im14(insn);
+ dec->bit = IM_14;
+ break;
+ case la_codec_im5_r_im12:
+ dec->imm2 = operand_r1(insn);
+ dec->r2 = operand_r2(insn);
+ dec->imm = operand_im12(insn);
+ dec->bit = IM_12;
+ break;
+ case la_codec_2r_im12:
+ dec->r1 = operand_r1(insn);
+ dec->r2 = operand_r2(insn);
+ dec->imm = operand_im12(insn);
+ dec->bit = IM_12;
+ break;
+ case la_codec_2r_im8:
+ dec->r1 = operand_r1(insn);
+ dec->r2 = operand_r2(insn);
+ dec->imm = operand_im8(insn);
+ dec->bit = IM_8;
+ break;
+ case la_codec_r_sd:
+ dec->r1 = operand_sd(insn);
+ dec->r2 = operand_r2(insn);
+ break;
+ case la_codec_r_sj:
+ dec->r1 = operand_r1(insn);
+ dec->r2 = operand_sj(insn);
+ break;
+ case la_codec_r_cd:
+ dec->r1 = operand_cd(insn);
+ dec->r2 = operand_r2(insn);
+ break;
+ case la_codec_r_cj:
+ dec->r1 = operand_r1(insn);
+ dec->r2 = operand_cj(insn);
+ break;
+ case la_codec_r_seq:
+ dec->r1 = 0;
+ dec->r2 = operand_r1(insn);
+ dec->imm = operand_im8(insn);
+ dec->bit = IM_8;
+ break;
+ case la_codec_code:
+ dec->code = operand_code(insn);
+ break;
+ case la_codec_whint:
+ dec->imm = operand_whint(insn);
+ dec->bit = IM_15;
+ break;
+ case la_codec_invtlb:
+ dec->imm = operand_invop(insn);
+ dec->bit = IM_5;
+ dec->r2 = operand_r2(insn);
+ dec->r3 = operand_r3(insn);
+ break;
+ case la_codec_r_ofs21:
+ dec->imm = operand_ofs21(insn);
+ dec->bit = IM_21;
+ dec->r2 = operand_r2(insn);
+ break;
+ case la_codec_cj_ofs21:
+ dec->imm = operand_ofs21(insn);
+ dec->bit = IM_21;
+ dec->r2 = operand_cj(insn);
+ break;
+ case la_codec_ofs26:
+ dec->imm = operand_ofs26(insn);
+ dec->bit = IM_26;
+ break;
+ case la_codec_cond:
+ dec->r1 = operand_cd(insn);
+ dec->r2 = operand_r2(insn);
+ dec->r3 = operand_r3(insn);
+ dec->r4 = operand_fcond(insn);
+ break;
+ case la_codec_sel:
+ dec->r1 = operand_r1(insn);
+ dec->r2 = operand_r2(insn);
+ dec->r3 = operand_r3(insn);
+ dec->r4 = operand_sel(insn);
+ break;
+ }
+}
+
+/* format instruction */
+static void append(char *s1, const char *s2, size_t n)
+{
+ size_t l1 = strlen(s1);
+ if (n - l1 - 1 > 0) {
+ strncat(s1, s2, n - l1);
+ }
+}
+
+static void format_insn(char *buf, size_t buflen, size_t tab, la_decode *dec)
+{
+ char tmp[16];
+ const char *fmt;
+
+ fmt = opcode_data[dec->op].format;
+ while (*fmt) {
+ switch (*fmt) {
+ case 'n': /* name */
+ append(buf, opcode_data[dec->op].name, buflen);
+ break;
+ case 's':
+ append(buf, "s", buflen);
+ break;
+ case 'd':
+ append(buf, "d", buflen);
+ break;
+ case 'e': /* illegal */
+ snprintf(tmp, sizeof(tmp), "%x", dec->insn);
+ append(buf, tmp, buflen);
+ break;
+ case 't':
+ while (strlen(buf) < tab) {
+ append(buf, " ", buflen);
+ }
+ break;
+ case '(':
+ append(buf, "(", buflen);
+ break;
+ case ',':
+ append(buf, ",", buflen);
+ break;
+ case '.':
+ append(buf, ".", buflen);
+ break;
+ case ')':
+ append(buf, ")", buflen);
+ break;
+ case '0': /* rd */
+ append(buf, loongarch_r_normal_name[dec->r1], buflen);
+ break;
+ case '1': /* rj */
+ append(buf, loongarch_r_normal_name[dec->r2], buflen);
+ break;
+ case '2': /* rk */
+ append(buf, loongarch_r_normal_name[dec->r3], buflen);
+ break;
+ case '3': /* fd */
+ append(buf, loongarch_f_normal_name[dec->r1], buflen);
+ break;
+ case '4': /* fj */
+ append(buf, loongarch_f_normal_name[dec->r2], buflen);
+ break;
+ case '5': /* fk */
+ append(buf, loongarch_f_normal_name[dec->r3], buflen);
+ break;
+ case '6': /* fa */
+ append(buf, loongarch_f_normal_name[dec->r4], buflen);
+ break;
+ case 'A': /* sd */
+ append(buf, loongarch_cr_normal_name[dec->r1], buflen);
+ break;
+ case 'B': /* sj */
+ append(buf, loongarch_cr_normal_name[dec->r2], buflen);
+ break;
+ case 'C': /* r3 */
+ snprintf(tmp, sizeof(tmp), "%x", dec->r3);
+ append(buf, tmp, buflen);
+ break;
+ case 'D': /* r4 */
+ snprintf(tmp, sizeof(tmp), "%x", dec->r4);
+ append(buf, tmp, buflen);
+ break;
+ case 'E': /* r1 */
+ snprintf(tmp, sizeof(tmp), "%x", dec->r1);
+ append(buf, tmp, buflen);
+ break;
+ case 'F': /* fcsrd */
+ append(buf, loongarch_r_normal_name[dec->r1], buflen);
+ break;
+ case 'G': /* fcsrs */
+ append(buf, loongarch_r_normal_name[dec->r2], buflen);
+ break;
+ case 'H': /* cd */
+ append(buf, loongarch_c_normal_name[dec->r1], buflen);
+ break;
+ case 'I': /* cj */
+ append(buf, loongarch_c_normal_name[dec->r2], buflen);
+ break;
+ case 'J': /* code */
+ snprintf(tmp, sizeof(tmp), "0x%x", dec->code);
+ append(buf, tmp, buflen);
+ break;
+ case 'K': /* cond */
+ switch (dec->r4) {
+ case 0x0:
+ append(buf, "caf", buflen);
+ break;
+ case 0x1:
+ append(buf, "saf", buflen);
+ break;
+ case 0x2:
+ append(buf, "clt", buflen);
+ break;
+ case 0x3:
+ append(buf, "slt", buflen);
+ break;
+ case 0x4:
+ append(buf, "ceq", buflen);
+ break;
+ case 0x5:
+ append(buf, "seq", buflen);
+ break;
+ case 0x6:
+ append(buf, "cle", buflen);
+ break;
+ case 0x7:
+ append(buf, "sle", buflen);
+ break;
+ case 0x8:
+ append(buf, "cun", buflen);
+ break;
+ case 0x9:
+ append(buf, "sun", buflen);
+ break;
+ case 0xA:
+ append(buf, "cult", buflen);
+ break;
+ case 0xB:
+ append(buf, "sult", buflen);
+ break;
+ case 0xC:
+ append(buf, "cueq", buflen);
+ break;
+ case 0xD:
+ append(buf, "sueq", buflen);
+ break;
+ case 0xE:
+ append(buf, "cule", buflen);
+ break;
+ case 0xF:
+ append(buf, "sule", buflen);
+ break;
+ case 0x10:
+ append(buf, "cne", buflen);
+ break;
+ case 0x11:
+ append(buf, "sne", buflen);
+ break;
+ case 0x14:
+ append(buf, "cor", buflen);
+ break;
+ case 0x15:
+ append(buf, "sor", buflen);
+ break;
+ case 0x18:
+ append(buf, "cune", buflen);
+ break;
+ case 0x19:
+ append(buf, "sune", buflen);
+ break;
+ }
+ break;
+ case 'L': /* ca */
+ append(buf, loongarch_c_normal_name[dec->r4], buflen);
+ break;
+ case 'M': /* cop */
+ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm2) & 0x1f);
+ append(buf, tmp, buflen);
+ break;
+ case 'i': /* sixx d */
+ snprintf(tmp, sizeof(tmp), "%d", dec->imm);
+ append(buf, tmp, buflen);
+ break;
+ case 'o': /* offset */
+ snprintf(tmp, sizeof(tmp), "%d", (dec->imm) << 2);
+ append(buf, tmp, buflen);
+ break;
+ case 'x': /* sixx x */
+ switch (dec->bit) {
+ case IM_5:
+ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0x1f);
+ append(buf, tmp, buflen);
+ break;
+ case IM_8:
+ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0xff);
+ append(buf, tmp, buflen);
+ break;
+ case IM_12:
+ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0xfff);
+ append(buf, tmp, buflen);
+ break;
+ case IM_14:
+ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0x3fff);
+ append(buf, tmp, buflen);
+ break;
+ case IM_15:
+ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0x7fff);
+ append(buf, tmp, buflen);
+ break;
+ case IM_16:
+ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0xffff);
+ append(buf, tmp, buflen);
+ break;
+ case IM_20:
+ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0xfffff);
+ append(buf, tmp, buflen);
+ break;
+ default:
+ snprintf(tmp, sizeof(tmp), "0x%x", dec->imm);
+ append(buf, tmp, buflen);
+ break;
+ }
+ break;
+ case 'X': /* offset x*/
+ switch (dec->bit) {
+ case IM_16:
+ snprintf(tmp, sizeof(tmp), "0x%x",
+ ((dec->imm) << 2) & 0xffff);
+ append(buf, tmp, buflen);
+ break;
+ case IM_21:
+ snprintf(tmp, sizeof(tmp), "0x%x",
+ ((dec->imm) << 2) & 0x1fffff);
+ append(buf, tmp, buflen);
+ break;
+ case IM_26:
+ snprintf(tmp, sizeof(tmp), "0x%x",
+ ((dec->imm) << 2) & 0x3ffffff);
+ append(buf, tmp, buflen);
+ break;
+ default:
+ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) << 2);
+ append(buf, tmp, buflen);
+ break;
+ }
+ break;
+ case 'p': /* pc */
+ snprintf(tmp, sizeof(tmp), " # 0x%"PRIx32"",
+ dec->pc + ((dec->imm) << 2));
+ append(buf, tmp, buflen);
+ break;
+ default:
+ break;
+ }
+ fmt++;
+ }
+}
+
+/* disassemble instruction */
+static void
+disasm_insn(char *buf, size_t buflen, bfd_vma pc, unsigned long int insn)
+{
+ la_decode dec = { 0 };
+ dec.pc = pc;
+ dec.insn = insn;
+ decode_insn_opcode(&dec);
+ decode_insn_operands(&dec);
+ format_insn(buf, buflen, 16, &dec);
+}
+
+int
+print_insn_loongarch(bfd_vma memaddr, struct disassemble_info *info)
+{
+ char buf[128] = { 0 };
+ bfd_byte buffer[INSNLEN];
+ unsigned long insn;
+ int status;
+
+ status = (*info->read_memory_func)(memaddr, buffer, INSNLEN, info);
+ if (status == 0) {
+ insn = (uint32_t) bfd_getl32(buffer);
+ (*info->fprintf_func)(info->stream, "%08" PRIx64 " ", insn);
+ } else {
+ (*info->memory_error_func)(status, memaddr, info);
+ return -1;
+ }
+ disasm_insn(buf, sizeof(buf), memaddr, insn);
+ (*info->fprintf_func)(info->stream, "\t%s", buf);
+ return INSNLEN;
+}
diff --git a/disas/meson.build b/disas/meson.build
index 449f99e..a1bd8b8 100644
--- a/disas/meson.build
+++ b/disas/meson.build
@@ -9,6 +9,7 @@ common_ss.add(when: 'CONFIG_CRIS_DIS', if_true: files('cris.c'))
common_ss.add(when: 'CONFIG_HEXAGON_DIS', if_true: files('hexagon.c'))
common_ss.add(when: 'CONFIG_HPPA_DIS', if_true: files('hppa.c'))
common_ss.add(when: 'CONFIG_I386_DIS', if_true: files('i386.c'))
+common_ss.add(when: 'CONFIG_LOONGARCH_DIS', if_true: files('loongarch.c'))
common_ss.add(when: 'CONFIG_M68K_DIS', if_true: files('m68k.c'))
common_ss.add(when: 'CONFIG_MICROBLAZE_DIS', if_true: files('microblaze.c'))
common_ss.add(when: 'CONFIG_MIPS_DIS', if_true: files('mips.c'))
diff --git a/include/disas/dis-asm.h b/include/disas/dis-asm.h
index 524f291..009a03a 100644
--- a/include/disas/dis-asm.h
+++ b/include/disas/dis-asm.h
@@ -253,6 +253,7 @@ enum bfd_architecture
#define bfd_mach_rx 0x75
#define bfd_mach_rx_v2 0x76
#define bfd_mach_rx_v3 0x77
+ bfd_arch_loongarch,
bfd_arch_last
};
#define bfd_mach_s390_31 31
@@ -462,6 +463,7 @@ int print_insn_riscv32 (bfd_vma, disassemble_info*);
int print_insn_riscv64 (bfd_vma, disassemble_info*);
int print_insn_rx(bfd_vma, disassemble_info *);
int print_insn_hexagon(bfd_vma, disassemble_info *);
+int print_insn_loongarch(bfd_vma, disassemble_info *);
#ifdef CONFIG_CAPSTONE
bool cap_disas_target(disassemble_info *info, uint64_t pc, size_t size);
diff --git a/meson.build b/meson.build
index bf63784..08131fc 100644
--- a/meson.build
+++ b/meson.build
@@ -1499,6 +1499,7 @@ disassemblers = {
'sh4' : ['CONFIG_SH4_DIS'],
'sparc' : ['CONFIG_SPARC_DIS'],
'xtensa' : ['CONFIG_XTENSA_DIS'],
+ 'loongarch' : ['CONFIG_LOONGARCH_DIS'],
}
if link_language == 'cpp'
disassemblers += {
--
1.8.3.1
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v3 17/19] LoongArch Linux User Emulation
2021-08-27 7:14 [PATCH v3 00/19] Add LoongArch linux-user emulation support Song Gao
` (15 preceding siblings ...)
2021-08-27 7:14 ` [PATCH v3 16/19] target/loongarch: Add disassembler Song Gao
@ 2021-08-27 7:14 ` Song Gao
2021-08-27 7:14 ` [PATCH v3 18/19] default-configs: Add loongarch linux-user support Song Gao
2021-08-27 7:14 ` [PATCH v3 19/19] target/loongarch: Add target build suport Song Gao
18 siblings, 0 replies; 22+ messages in thread
From: Song Gao @ 2021-08-27 7:14 UTC (permalink / raw)
To: qemu-devel
Cc: peter.maydell, thuth, chenhuacai, richard.henderson, f4bug,
maobibo, laurent, yangxiaojuan, alistair.francis, pbonzini,
alex.bennee
Implementation of linux user emulation for LoongArch.
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
include/elf.h | 2 +
linux-user/elfload.c | 58 ++++++
linux-user/loongarch64/cpu_loop.c | 108 ++++++++++
linux-user/loongarch64/signal.c | 178 +++++++++++++++++
linux-user/loongarch64/sockbits.h | 1 +
linux-user/loongarch64/syscall_nr.h | 307 +++++++++++++++++++++++++++++
linux-user/loongarch64/target_cpu.h | 36 ++++
linux-user/loongarch64/target_elf.h | 14 ++
linux-user/loongarch64/target_errno_defs.h | 7 +
linux-user/loongarch64/target_fcntl.h | 12 ++
linux-user/loongarch64/target_signal.h | 28 +++
linux-user/loongarch64/target_structs.h | 49 +++++
linux-user/loongarch64/target_syscall.h | 46 +++++
linux-user/loongarch64/termbits.h | 229 +++++++++++++++++++++
linux-user/syscall_defs.h | 10 +-
15 files changed, 1081 insertions(+), 4 deletions(-)
create mode 100644 linux-user/loongarch64/cpu_loop.c
create mode 100644 linux-user/loongarch64/signal.c
create mode 100644 linux-user/loongarch64/sockbits.h
create mode 100644 linux-user/loongarch64/syscall_nr.h
create mode 100644 linux-user/loongarch64/target_cpu.h
create mode 100644 linux-user/loongarch64/target_elf.h
create mode 100644 linux-user/loongarch64/target_errno_defs.h
create mode 100644 linux-user/loongarch64/target_fcntl.h
create mode 100644 linux-user/loongarch64/target_signal.h
create mode 100644 linux-user/loongarch64/target_structs.h
create mode 100644 linux-user/loongarch64/target_syscall.h
create mode 100644 linux-user/loongarch64/termbits.h
diff --git a/include/elf.h b/include/elf.h
index 811bf4a..3a4bcb6 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -182,6 +182,8 @@ typedef struct mips_elf_abiflags_v0 {
#define EM_NANOMIPS 249 /* Wave Computing nanoMIPS */
+#define EM_LOONGARCH 258 /* LoongArch */
+
/*
* This is an interim value that we will use until the committee comes
* up with a final number.
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 01e9a83..cf47ccd 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -909,6 +909,64 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUPPCState *en
#endif
+#ifdef TARGET_LOONGARCH64
+
+#define ELF_START_MMAP 0x80000000
+
+#define ELF_CLASS ELFCLASS64
+#define ELF_ARCH EM_LOONGARCH
+
+#define elf_check_arch(x) ((x) == EM_LOONGARCH)
+static inline void init_thread(struct target_pt_regs *regs,
+ struct image_info *infop)
+{
+ regs->csr_crmd = 2 << 3;
+ regs->csr_era = infop->entry;
+ regs->regs[3] = infop->start_stack;
+}
+
+/* See linux kernel: arch/loongarch/include/asm/elf.h. */
+#define ELF_NREG 45
+typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
+
+/* See linux kernel: arch/loongarch/include/asm/reg.h. */
+enum {
+ TARGET_EF_R0 = 0,
+ TARGET_EF_CSR_ERA = TARGET_EF_R0 + 32,
+ TARGET_EF_CSR_BADVADDR = TARGET_EF_R0 + 33,
+};
+
+/* See linux kernel: arch/loongarch/kernel/process.c:loongarch_dump_regs64. */
+static void elf_core_copy_regs(target_elf_gregset_t *regs,
+ const CPULoongArchState *env)
+{
+ int i;
+
+ for (i = 0; i < TARGET_EF_R0; i++) {
+ (*regs)[i] = 0;
+ }
+ (*regs)[TARGET_EF_R0] = 0;
+
+ for (i = 1; i < ARRAY_SIZE(env->gpr); i++) {
+ (*regs)[TARGET_EF_R0 + i] = tswapreg(env->gpr[i]);
+ }
+
+ (*regs)[TARGET_EF_CSR_ERA] = tswapreg(env->pc);
+ (*regs)[TARGET_EF_CSR_BADVADDR] = tswapreg(env->badaddr);
+}
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE 4096
+
+#define ELF_HWCAP get_elf_hwcap()
+
+static uint32_t get_elf_hwcap(void)
+{
+ return 0;
+}
+
+#endif /* TARGET_LOONGARCH64 */
+
#ifdef TARGET_MIPS
#define ELF_START_MMAP 0x80000000
diff --git a/linux-user/loongarch64/cpu_loop.c b/linux-user/loongarch64/cpu_loop.c
new file mode 100644
index 0000000..bc81d22
--- /dev/null
+++ b/linux-user/loongarch64/cpu_loop.c
@@ -0,0 +1,108 @@
+/*
+ * QEMU LoongArch user cpu loop.
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "qemu-common.h"
+#include "cpu_loop-common.h"
+#include "elf.h"
+
+void cpu_loop(CPULoongArchState *env)
+{
+ CPUState *cs = env_cpu(env);
+ target_siginfo_t info;
+ int trapnr;
+ abi_long ret;
+
+ for (;;) {
+ cpu_exec_start(cs);
+ trapnr = cpu_exec(cs);
+ cpu_exec_end(cs);
+ process_queued_cpu_work(cs);
+
+ switch (trapnr) {
+ case EXCP_INTERRUPT:
+ /* just indicate that signals should be handled asap */
+ break;
+ case EXCP_SYSCALL:
+ env->pc += 4;
+ ret = do_syscall(env, env->gpr[11],
+ env->gpr[4], env->gpr[5],
+ env->gpr[6], env->gpr[7],
+ env->gpr[8], env->gpr[9],
+ -1, -1);
+ if (ret == -TARGET_ERESTARTSYS) {
+ env->pc -= 4;
+ break;
+ }
+ if (ret == -TARGET_QEMU_ESIGRETURN) {
+ /*
+ * Returning from a successful sigreturn syscall.
+ * Avoid clobbering register state.
+ */
+ break;
+ }
+ env->gpr[4] = ret;
+ break;
+ case EXCP_ADE:
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SEGV_MAPERR;
+ info._sifields._sigfault._addr = env->badaddr;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP_INE:
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ info.si_code = 0;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP_FPE:
+ info.si_signo = TARGET_SIGFPE;
+ info.si_errno = 0;
+ info.si_code = TARGET_FPE_FLTUNK;
+ if (GET_FP_CAUSE(env->fcsr0) & FP_INVALID) {
+ info.si_code = TARGET_FPE_FLTINV;
+ } else if (GET_FP_CAUSE(env->fcsr0) & FP_DIV0) {
+ info.si_code = TARGET_FPE_FLTDIV;
+ } else if (GET_FP_CAUSE(env->fcsr0) & FP_OVERFLOW) {
+ info.si_code = TARGET_FPE_FLTOVF;
+ } else if (GET_FP_CAUSE(env->fcsr0) & FP_UNDERFLOW) {
+ info.si_code = TARGET_FPE_FLTUND;
+ } else if (GET_FP_CAUSE(env->fcsr0) & FP_INEXACT) {
+ info.si_code = TARGET_FPE_FLTRES;
+ }
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP_BREAK:
+ info.si_signo = TARGET_SIGTRAP;
+ info.si_code = TARGET_TRAP_BRKPT;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP_ATOMIC:
+ cpu_exec_step_atomic(cs);
+ break;
+ default:
+ EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n",
+ trapnr);
+ exit(EXIT_FAILURE);
+ }
+ process_pending_signals(env);
+ }
+}
+
+void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
+{
+ int i;
+
+ for (i = 0; i < 32; i++) {
+ env->gpr[i] = regs->regs[i];
+ }
+ env->pc = regs->csr_era & ~(target_ulong)1;
+
+}
diff --git a/linux-user/loongarch64/signal.c b/linux-user/loongarch64/signal.c
new file mode 100644
index 0000000..2da8317
--- /dev/null
+++ b/linux-user/loongarch64/signal.c
@@ -0,0 +1,178 @@
+/*
+ * LoongArch emulation of Linux signals
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "signal-common.h"
+#include "linux-user/trace.h"
+
+struct target_sigcontext {
+ uint64_t sc_pc;
+ uint64_t sc_gpr[32];
+ uint64_t sc_fpr[32];
+ uint64_t sc_fcc;
+ uint32_t sc_fcsr;
+ uint32_t sc_flags;
+};
+
+struct sigframe {
+ uint32_t sf_ass[4]; /* argument save space for o32 */
+ uint32_t sf_code[2]; /* signal trampoline */
+ struct target_sigcontext sf_sc;
+ target_sigset_t sf_mask;
+};
+
+struct target_ucontext {
+ target_ulong tuc_flags;
+ target_ulong tuc_link;
+ target_stack_t tuc_stack;
+ target_ulong pad0;
+ struct target_sigcontext tuc_mcontext;
+ target_sigset_t tuc_sigmask;
+};
+
+struct target_rt_sigframe {
+ uint32_t rs_ass[4]; /* argument save space for o32 */
+ uint32_t rs_code[2]; /* signal trampoline */
+ struct target_siginfo rs_info;
+ struct target_ucontext rs_uc;
+};
+
+/* Install trampoline to jump back from signal handler */
+static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
+{
+ int err = 0;
+
+ /*
+ * Set up the return code ...
+ *
+ * li a7, 139
+ * syscall
+ */
+
+ __put_user(0x03822c0b, tramp + 0); /* ori a7, a7, 0x8b */
+ __put_user(0x002b0000, tramp + 1); /* syscall 0 */
+ return err;
+}
+
+static inline void setup_sigcontext(CPULoongArchState *env,
+ struct target_sigcontext *sc)
+{
+ int i;
+
+ __put_user(env->pc, &sc->sc_pc);
+
+ __put_user(0, &sc->sc_gpr[0]);
+ for (i = 1; i < 32; ++i) {
+ __put_user(env->gpr[i], &sc->sc_gpr[i]);
+ }
+
+ for (i = 0; i < 32; ++i) {
+ __put_user(env->fpr[i], &sc->sc_fpr[i]);
+ }
+}
+
+static inline void
+restore_sigcontext(CPULoongArchState *env, struct target_sigcontext *sc)
+{
+ int i;
+
+ __get_user(env->pc, &sc->sc_pc);
+
+ for (i = 1; i < 32; ++i) {
+ __get_user(env->gpr[i], &sc->sc_gpr[i]);
+ }
+
+ for (i = 0; i < 32; ++i) {
+ __get_user(env->fpr[i], &sc->sc_fpr[i]);
+ }
+}
+
+/*
+ * Determine which stack to use..
+ */
+static inline abi_ulong
+get_sigframe(struct target_sigaction *ka, CPULoongArchState *env,
+ size_t frame_size)
+{
+ unsigned long sp;
+
+ sp = target_sigsp(get_sp_from_cpustate(env) - 32, ka);
+
+ return (sp - frame_size) & ~7;
+}
+
+void setup_rt_frame(int sig, struct target_sigaction *ka,
+ target_siginfo_t *info,
+ target_sigset_t *set, CPULoongArchState *env)
+{
+ struct target_rt_sigframe *frame;
+ abi_ulong frame_addr;
+ int i;
+
+ frame_addr = get_sigframe(ka, env, sizeof(*frame));
+ trace_user_setup_rt_frame(env, frame_addr);
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+ goto give_sigsegv;
+ }
+
+ install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn);
+
+ tswap_siginfo(&frame->rs_info, info);
+
+ __put_user(0, &frame->rs_uc.tuc_flags);
+ __put_user(0, &frame->rs_uc.tuc_link);
+ target_save_altstack(&frame->rs_uc.tuc_stack, env);
+
+ setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
+
+ for (i = 0; i < TARGET_NSIG_WORDS; i++) {
+ __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
+ }
+
+ env->gpr[4] = sig;
+ env->gpr[5] = frame_addr + offsetof(struct target_rt_sigframe, rs_info);
+ env->gpr[6] = frame_addr + offsetof(struct target_rt_sigframe, rs_uc);
+ env->gpr[3] = frame_addr;
+ env->gpr[1] = frame_addr + offsetof(struct target_rt_sigframe, rs_code);
+
+ env->pc = env->gpr[20] = ka->_sa_handler;
+ unlock_user_struct(frame, frame_addr, 1);
+ return;
+
+give_sigsegv:
+ unlock_user_struct(frame, frame_addr, 1);
+ force_sigsegv(sig);
+}
+
+long do_rt_sigreturn(CPULoongArchState *env)
+{
+ struct target_rt_sigframe *frame;
+ abi_ulong frame_addr;
+ sigset_t blocked;
+
+ frame_addr = env->gpr[3];
+ trace_user_do_rt_sigreturn(env, frame_addr);
+ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
+ goto badframe;
+ }
+
+ target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
+ set_sigmask(&blocked);
+
+ restore_sigcontext(env, &frame->rs_uc.tuc_mcontext);
+ target_restore_altstack(&frame->rs_uc.tuc_stack, env);
+
+ unlock_user_struct(frame, frame_addr, 0);
+ return -TARGET_QEMU_ESIGRETURN;
+
+badframe:
+ unlock_user_struct(frame, frame_addr, 0);
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
+}
diff --git a/linux-user/loongarch64/sockbits.h b/linux-user/loongarch64/sockbits.h
new file mode 100644
index 0000000..0e4c8f0
--- /dev/null
+++ b/linux-user/loongarch64/sockbits.h
@@ -0,0 +1 @@
+#include "../generic/sockbits.h"
diff --git a/linux-user/loongarch64/syscall_nr.h b/linux-user/loongarch64/syscall_nr.h
new file mode 100644
index 0000000..64cb17d
--- /dev/null
+++ b/linux-user/loongarch64/syscall_nr.h
@@ -0,0 +1,307 @@
+#ifndef LINUX_USER_LOONGARCH_SYSCALL_NR_H
+#define LINUX_USER_LOONGARCH_SYSCALL_NR_H
+
+/* copy from kernel: include/uapi/asm-generic/unistd.h */
+#define TARGET_NR_io_setup 0
+#define TARGET_NR_io_destroy 1
+#define TARGET_NR_io_submit 2
+#define TARGET_NR_io_cancel 3
+#define TARGET_NR_io_getevents 4
+#define TARGET_NR_setxattr 5
+#define TARGET_NR_lsetxattr 6
+#define TARGET_NR_fsetxattr 7
+#define TARGET_NR_getxattr 8
+#define TARGET_NR_lgetxattr 9
+#define TARGET_NR_fgetxattr 10
+#define TARGET_NR_listxattr 11
+#define TARGET_NR_llistxattr 12
+#define TARGET_NR_flistxattr 13
+#define TARGET_NR_removexattr 14
+#define TARGET_NR_lremovexattr 15
+#define TARGET_NR_fremovexattr 16
+#define TARGET_NR_getcwd 17
+#define TARGET_NR_lookup_dcookie 18
+#define TARGET_NR_eventfd2 19
+#define TARGET_NR_epoll_create1 20
+#define TARGET_NR_epoll_ctl 21
+#define TARGET_NR_epoll_pwait 22
+#define TARGET_NR_dup 23
+#define TARGET_NR_dup3 24
+#define TARGET_NR_fcntl 25
+#define TARGET_NR_inotify_init1 26
+#define TARGET_NR_inotify_add_watch 27
+#define TARGET_NR_inotify_rm_watch 28
+#define TARGET_NR_ioctl 29
+#define TARGET_NR_ioprio_set 30
+#define TARGET_NR_ioprio_get 31
+#define TARGET_NR_flock 32
+#define TARGET_NR_mknodat 33
+#define TARGET_NR_mkdirat 34
+#define TARGET_NR_unlinkat 35
+#define TARGET_NR_symlinkat 36
+#define TARGET_NR_linkat 37
+#define TARGET_NR_renameat 38
+#define TARGET_NR_umount2 39
+#define TARGET_NR_mount 40
+#define TARGET_NR_pivot_root 41
+#define TARGET_NR_nfsservctl 42
+#define TARGET_NR_statfs 43
+#define TARGET_NR_fstatfs 44
+#define TARGET_NR_truncate 45
+#define TARGET_NR_ftruncate 46
+#define TARGET_NR_fallocate 47
+#define TARGET_NR_faccessat 48
+#define TARGET_NR_chdir 49
+#define TARGET_NR_fchdir 50
+#define TARGET_NR_chroot 51
+#define TARGET_NR_fchmod 52
+#define TARGET_NR_fchmodat 53
+#define TARGET_NR_fchownat 54
+#define TARGET_NR_fchown 55
+#define TARGET_NR_openat 56
+#define TARGET_NR_close 57
+#define TARGET_NR_vhangup 58
+#define TARGET_NR_pipe2 59
+#define TARGET_NR_quotactl 60
+#define TARGET_NR_getdents64 61
+#define TARGET_NR_lseek 62
+#define TARGET_NR_read 63
+#define TARGET_NR_write 64
+#define TARGET_NR_readv 65
+#define TARGET_NR_writev 66
+#define TARGET_NR_pread64 67
+#define TARGET_NR_pwrite64 68
+#define TARGET_NR_preadv 69
+#define TARGET_NR_pwritev 70
+#define TARGET_NR_sendfile 71
+#define TARGET_NR_pselect6 72
+#define TARGET_NR_ppoll 73
+#define TARGET_NR_signalfd4 74
+#define TARGET_NR_vmsplice 75
+#define TARGET_NR_splice 76
+#define TARGET_NR_tee 77
+#define TARGET_NR_readlinkat 78
+#define TARGET_NR_newfstatat 79
+#define TARGET_NR_fstat 80
+#define TARGET_NR_sync 81
+#define TARGET_NR_fsync 82
+#define TARGET_NR_fdatasync 83
+#define TARGET_NR_sync_file_range 84
+#define TARGET_NR_timerfd_create 85
+#define TARGET_NR_timerfd_settime 86
+#define TARGET_NR_timerfd_gettime 87
+#define TARGET_NR_utimensat 88
+#define TARGET_NR_acct 89
+#define TARGET_NR_capget 90
+#define TARGET_NR_capset 91
+#define TARGET_NR_personality 92
+#define TARGET_NR_exit 93
+#define TARGET_NR_exit_group 94
+#define TARGET_NR_waitid 95
+#define TARGET_NR_set_tid_address 96
+#define TARGET_NR_unshare 97
+#define TARGET_NR_futex 98
+#define TARGET_NR_set_robust_list 99
+#define TARGET_NR_get_robust_list 100
+#define TARGET_NR_nanosleep 101
+#define TARGET_NR_getitimer 102
+#define TARGET_NR_setitimer 103
+#define TARGET_NR_kexec_load 104
+#define TARGET_NR_init_module 105
+#define TARGET_NR_delete_module 106
+#define TARGET_NR_timer_create 107
+#define TARGET_NR_timer_gettime 108
+#define TARGET_NR_timer_getoverrun 109
+#define TARGET_NR_timer_settime 110
+#define TARGET_NR_timer_delete 111
+#define TARGET_NR_clock_settime 112
+#define TARGET_NR_clock_gettime 113
+#define TARGET_NR_clock_getres 114
+#define TARGET_NR_clock_nanosleep 115
+#define TARGET_NR_syslog 116
+#define TARGET_NR_ptrace 117
+#define TARGET_NR_sched_setparam 118
+#define TARGET_NR_sched_setscheduler 119
+#define TARGET_NR_sched_getscheduler 120
+#define TARGET_NR_sched_getparam 121
+#define TARGET_NR_sched_setaffinity 122
+#define TARGET_NR_sched_getaffinity 123
+#define TARGET_NR_sched_yield 124
+#define TARGET_NR_sched_get_priority_max 125
+#define TARGET_NR_sched_get_priority_min 126
+#define TARGET_NR_sched_rr_get_interval 127
+#define TARGET_NR_restart_syscall 128
+#define TARGET_NR_kill 129
+#define TARGET_NR_tkill 130
+#define TARGET_NR_tgkill 131
+#define TARGET_NR_sigaltstack 132
+#define TARGET_NR_rt_sigsuspend 133
+#define TARGET_NR_rt_sigaction 134
+#define TARGET_NR_rt_sigprocmask 135
+#define TARGET_NR_rt_sigpending 136
+#define TARGET_NR_rt_sigtimedwait 137
+#define TARGET_NR_rt_sigqueueinfo 138
+#define TARGET_NR_rt_sigreturn 139
+#define TARGET_NR_setpriority 140
+#define TARGET_NR_getpriority 141
+#define TARGET_NR_reboot 142
+#define TARGET_NR_setregid 143
+#define TARGET_NR_setgid 144
+#define TARGET_NR_setreuid 145
+#define TARGET_NR_setuid 146
+#define TARGET_NR_setresuid 147
+#define TARGET_NR_getresuid 148
+#define TARGET_NR_setresgid 149
+#define TARGET_NR_getresgid 150
+#define TARGET_NR_setfsuid 151
+#define TARGET_NR_setfsgid 152
+#define TARGET_NR_times 153
+#define TARGET_NR_setpgid 154
+#define TARGET_NR_getpgid 155
+#define TARGET_NR_getsid 156
+#define TARGET_NR_setsid 157
+#define TARGET_NR_getgroups 158
+#define TARGET_NR_setgroups 159
+#define TARGET_NR_uname 160
+#define TARGET_NR_sethostname 161
+#define TARGET_NR_setdomainname 162
+#define TARGET_NR_getrlimit 163
+#define TARGET_NR_setrlimit 164
+#define TARGET_NR_getrusage 165
+#define TARGET_NR_umask 166
+#define TARGET_NR_prctl 167
+#define TARGET_NR_getcpu 168
+#define TARGET_NR_gettimeofday 169
+#define TARGET_NR_settimeofday 170
+#define TARGET_NR_adjtimex 171
+#define TARGET_NR_getpid 172
+#define TARGET_NR_getppid 173
+#define TARGET_NR_getuid 174
+#define TARGET_NR_geteuid 175
+#define TARGET_NR_getgid 176
+#define TARGET_NR_getegid 177
+#define TARGET_NR_gettid 178
+#define TARGET_NR_sysinfo 179
+#define TARGET_NR_mq_open 180
+#define TARGET_NR_mq_unlink 181
+#define TARGET_NR_mq_timedsend 182
+#define TARGET_NR_mq_timedreceive 183
+#define TARGET_NR_mq_notify 184
+#define TARGET_NR_mq_getsetattr 185
+#define TARGET_NR_msgget 186
+#define TARGET_NR_msgctl 187
+#define TARGET_NR_msgrcv 188
+#define TARGET_NR_msgsnd 189
+#define TARGET_NR_semget 190
+#define TARGET_NR_semctl 191
+#define TARGET_NR_semtimedop 192
+#define TARGET_NR_semop 193
+#define TARGET_NR_shmget 194
+#define TARGET_NR_shmctl 195
+#define TARGET_NR_shmat 196
+#define TARGET_NR_shmdt 197
+#define TARGET_NR_socket 198
+#define TARGET_NR_socketpair 199
+#define TARGET_NR_bind 200
+#define TARGET_NR_listen 201
+#define TARGET_NR_accept 202
+#define TARGET_NR_connect 203
+#define TARGET_NR_getsockname 204
+#define TARGET_NR_getpeername 205
+#define TARGET_NR_sendto 206
+#define TARGET_NR_recvfrom 207
+#define TARGET_NR_setsockopt 208
+#define TARGET_NR_getsockopt 209
+#define TARGET_NR_shutdown 210
+#define TARGET_NR_sendmsg 211
+#define TARGET_NR_recvmsg 212
+#define TARGET_NR_readahead 213
+#define TARGET_NR_brk 214
+#define TARGET_NR_munmap 215
+#define TARGET_NR_mremap 216
+#define TARGET_NR_add_key 217
+#define TARGET_NR_request_key 218
+#define TARGET_NR_keyctl 219
+#define TARGET_NR_clone 220
+#define TARGET_NR_execve 221
+#define TARGET_NR_mmap 222
+#define TARGET_NR_fadvise64 223
+#define TARGET_NR_swapon 224
+#define TARGET_NR_swapoff 225
+#define TARGET_NR_mprotect 226
+#define TARGET_NR_msync 227
+#define TARGET_NR_mlock 228
+#define TARGET_NR_munlock 229
+#define TARGET_NR_mlockall 230
+#define TARGET_NR_munlockall 231
+#define TARGET_NR_mincore 232
+#define TARGET_NR_madvise 233
+#define TARGET_NR_remap_file_pages 234
+#define TARGET_NR_mbind 235
+#define TARGET_NR_get_mempolicy 236
+#define TARGET_NR_set_mempolicy 237
+#define TARGET_NR_migrate_pages 238
+#define TARGET_NR_move_pages 239
+#define TARGET_NR_rt_tgsigqueueinfo 240
+#define TARGET_NR_perf_event_open 241
+#define TARGET_NR_accept4 242
+#define TARGET_NR_recvmmsg 243
+#define TARGET_NR_arch_specific_syscall 244
+#define TARGET_NR_wait4 260
+#define TARGET_NR_prlimit64 261
+#define TARGET_NR_fanotify_init 262
+#define TARGET_NR_fanotify_mark 263
+#define TARGET_NR_name_to_handle_at 264
+#define TARGET_NR_open_by_handle_at 265
+#define TARGET_NR_clock_adjtime 266
+#define TARGET_NR_syncfs 267
+#define TARGET_NR_setns 268
+#define TARGET_NR_sendmmsg 269
+#define TARGET_NR_process_vm_readv 270
+#define TARGET_NR_process_vm_writev 271
+#define TARGET_NR_kcmp 272
+#define TARGET_NR_finit_module 273
+#define TARGET_NR_sched_setattr 274
+#define TARGET_NR_sched_getattr 275
+#define TARGET_NR_renameat2 276
+#define TARGET_NR_seccomp 277
+#define TARGET_NR_getrandom 278
+#define TARGET_NR_memfd_create 279
+#define TARGET_NR_bpf 280
+#define TARGET_NR_execveat 281
+#define TARGET_NR_userfaultfd 282
+#define TARGET_NR_membarrier 283
+#define TARGET_NR_mlock2 284
+#define TARGET_NR_copy_file_range 285
+#define TARGET_NR_preadv2 286
+#define TARGET_NR_pwritev2 287
+#define TARGET_NR_pkey_mprotect 288
+#define TARGET_NR_pkey_alloc 289
+#define TARGET_NR_pkey_free 290
+#define TARGET_NR_statx 291
+#define TARGET_NR_io_pgetevents 292
+#define TARGET_NR_rseq 293
+#define TARGET_NR_kexec_file_load 294
+#define TARGET_NR_pidfd_send_signal 424
+#define TARGET_NR_io_uring_setup 425
+#define TARGET_NR_io_uring_enter 426
+#define TARGET_NR_io_uring_register 427
+#define TARGET_NR_open_tree 428
+#define TARGET_NR_move_mount 429
+#define TARGET_NR_fsopen 430
+#define TARGET_NR_fsconfig 431
+#define TARGET_NR_fsmount 432
+#define TARGET_NR_fspick 433
+#define TARGET_NR_pidfd_open 434
+#define TARGET_NR_clone3 435
+#define TARGET_NR_close_range 436
+#define TARGET_NR_openat2 437
+#define TARGET_NR_pidfd_getfd 438
+#define TARGET_NR_faccessat2 439
+#define TARGET_NR_process_madvise 440
+#define TARGET_NR_epoll_pwait2 441
+#define TARGET_NR_mount_setattr 442
+
+#define TARGET_NR_syscalls 443
+
+#endif
diff --git a/linux-user/loongarch64/target_cpu.h b/linux-user/loongarch64/target_cpu.h
new file mode 100644
index 0000000..9896271
--- /dev/null
+++ b/linux-user/loongarch64/target_cpu.h
@@ -0,0 +1,36 @@
+/*
+ * LoongArch specific CPU ABI and functions for linux-user
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#ifndef LOONGARCH_TARGET_CPU_H
+#define LOONGARCH_TARGET_CPU_H
+
+static inline void cpu_clone_regs_child(CPULoongArchState *env,
+ target_ulong newsp, unsigned flags)
+{
+ if (newsp) {
+ env->gpr[3] = newsp;
+ }
+ env->gpr[7] = 0;
+ env->gpr[4] = 0;
+}
+
+static inline void cpu_clone_regs_parent(CPULoongArchState *env,
+ unsigned flags)
+{
+}
+
+static inline void cpu_set_tls(CPULoongArchState *env, target_ulong newtls)
+{
+ env->gpr[2] = newtls;
+}
+
+static inline abi_ulong get_sp_from_cpustate(CPULoongArchState *state)
+{
+ return state->gpr[3];
+}
+#endif
diff --git a/linux-user/loongarch64/target_elf.h b/linux-user/loongarch64/target_elf.h
new file mode 100644
index 0000000..7c88394
--- /dev/null
+++ b/linux-user/loongarch64/target_elf.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+
+#ifndef LOONGARCH_TARGET_ELF_H
+#define LOONGARCH_TARGET_ELF_H
+static inline const char *cpu_get_model(uint32_t eflags)
+{
+ return "Loongson-3A5000";
+}
+#endif
diff --git a/linux-user/loongarch64/target_errno_defs.h b/linux-user/loongarch64/target_errno_defs.h
new file mode 100644
index 0000000..17165c1
--- /dev/null
+++ b/linux-user/loongarch64/target_errno_defs.h
@@ -0,0 +1,7 @@
+#ifndef LOONGARCH_TARGET_ERRNO_DEFS_H
+#define LOONGARCH_TARGET_ERRNO_DEFS_H
+
+/* Target uses generic errno */
+#include "../generic/target_errno_defs.h"
+
+#endif
diff --git a/linux-user/loongarch64/target_fcntl.h b/linux-user/loongarch64/target_fcntl.h
new file mode 100644
index 0000000..b810293
--- /dev/null
+++ b/linux-user/loongarch64/target_fcntl.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#ifndef LOONGARCH_TARGET_FCNTL_H
+#define LOONGARCH_TARGET_FCNTL_H
+
+#include "../generic/fcntl.h"
+
+#endif /* LOONGARCH_TARGET_FCNTL_H */
diff --git a/linux-user/loongarch64/target_signal.h b/linux-user/loongarch64/target_signal.h
new file mode 100644
index 0000000..713c26a
--- /dev/null
+++ b/linux-user/loongarch64/target_signal.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#ifndef LOONGARCH_TARGET_SIGNAL_H
+#define LOONGARCH_TARGET_SIGNAL_H
+
+/* this struct defines a stack used during syscall handling */
+typedef struct target_sigaltstack {
+ abi_long ss_sp;
+ abi_int ss_flags;
+ abi_ulong ss_size;
+} target_stack_t;
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK 1
+#define TARGET_SS_DISABLE 2
+
+#define TARGET_MINSIGSTKSZ 2048
+#define TARGET_SIGSTKSZ 8192
+
+#include "../generic/signal.h"
+
+#endif /* LOONGARCH_TARGET_SIGNAL_H */
diff --git a/linux-user/loongarch64/target_structs.h b/linux-user/loongarch64/target_structs.h
new file mode 100644
index 0000000..818e8d6
--- /dev/null
+++ b/linux-user/loongarch64/target_structs.h
@@ -0,0 +1,49 @@
+/*
+ * LoongArch specific structures for linux-user
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#ifndef LOONGARCH_TARGET_STRUCTS_H
+#define LOONGARCH_TARGET_STRUCTS_H
+
+struct target_ipc_perm {
+ abi_int __key; /* Key. */
+ abi_uint uid; /* Owner's user ID. */
+ abi_uint gid; /* Owner's group ID. */
+ abi_uint cuid; /* Creator's user ID. */
+ abi_uint cgid; /* Creator's group ID. */
+ abi_uint mode; /* Read/write permission. */
+ abi_ushort __seq; /* Sequence number. */
+ abi_ushort __pad1;
+ abi_ulong __unused1;
+ abi_ulong __unused2;
+};
+
+struct target_shmid_ds {
+ struct target_ipc_perm shm_perm; /* operation permission struct */
+ abi_long shm_segsz; /* size of segment in bytes */
+ abi_ulong shm_atime; /* time of last shmat() */
+ abi_ulong shm_dtime; /* time of last shmdt() */
+ abi_ulong shm_ctime; /* time of last change by shmctl() */
+ abi_int shm_cpid; /* pid of creator */
+ abi_int shm_lpid; /* pid of last shmop */
+ abi_ulong shm_nattch; /* number of current attaches */
+ abi_ulong __unused1;
+ abi_ulong __unused2;
+};
+
+#define TARGET_SEMID64_DS
+
+struct target_semid64_ds {
+ struct target_ipc_perm sem_perm;
+ abi_ulong sem_otime;
+ abi_ulong sem_ctime;
+ abi_ulong sem_nsems;
+ abi_ulong __unused1;
+ abi_ulong __unused2;
+};
+
+#endif
diff --git a/linux-user/loongarch64/target_syscall.h b/linux-user/loongarch64/target_syscall.h
new file mode 100644
index 0000000..b98ac12
--- /dev/null
+++ b/linux-user/loongarch64/target_syscall.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#ifndef LOONGARCH_TARGET_SYSCALL_H
+#define LOONGARCH_TARGET_SYSCALL_H
+
+/*
+ * this struct defines the way the registers are stored on the
+ * stack during a system call.
+ */
+
+struct target_pt_regs {
+ /* Saved main processor registers. */
+ target_ulong regs[32];
+
+ /* Saved special registers. */
+ target_ulong csr_crmd;
+ target_ulong csr_prmd;
+ target_ulong csr_euen;
+ target_ulong csr_ecfg;
+ target_ulong csr_estat;
+ target_ulong csr_era;
+ target_ulong csr_badvaddr;
+ target_ulong orig_a0;
+ target_ulong __last[0];
+};
+
+#define UNAME_MACHINE "loongarch"
+#define UNAME_MINIMUM_RELEASE "4.19.0"
+
+#define TARGET_MINSIGSTKSZ 2048
+#define TARGET_MCL_CURRENT 1
+#define TARGET_MCL_FUTURE 2
+#define TARGET_MCL_ONFAULT 4
+
+#define TARGET_FORCE_SHMLBA
+
+static inline abi_ulong target_shmlba(CPULoongArchState *env)
+{
+ return 0x40000;
+}
+
+#endif
diff --git a/linux-user/loongarch64/termbits.h b/linux-user/loongarch64/termbits.h
new file mode 100644
index 0000000..33e74ed
--- /dev/null
+++ b/linux-user/loongarch64/termbits.h
@@ -0,0 +1,229 @@
+#ifndef LINUX_USER_LOONGARCH_TERMBITS_H
+#define LINUX_USER_LOONGARCH_TERMBITS_H
+
+#define TARGET_NCCS 19
+
+typedef unsigned char target_cc_t; /* cc_t */
+typedef unsigned int target_speed_t; /* speed_t */
+typedef unsigned int target_tcflag_t; /* tcflag_t */
+
+struct target_termios {
+ target_tcflag_t c_iflag; /* input mode flags */
+ target_tcflag_t c_oflag; /* output mode flags */
+ target_tcflag_t c_cflag; /* control mode flags */
+ target_tcflag_t c_lflag; /* local mode flags */
+ target_cc_t c_line; /* line discipline */
+ target_cc_t c_cc[TARGET_NCCS]; /* control characters */
+};
+
+/* c_iflag bits */
+#define TARGET_IGNBRK 0000001
+#define TARGET_BRKINT 0000002
+#define TARGET_IGNPAR 0000004
+#define TARGET_PARMRK 0000010
+#define TARGET_INPCK 0000020
+#define TARGET_ISTRIP 0000040
+#define TARGET_INLCR 0000100
+#define TARGET_IGNCR 0000200
+#define TARGET_ICRNL 0000400
+#define TARGET_IUCLC 0001000
+#define TARGET_IXON 0002000
+#define TARGET_IXANY 0004000
+#define TARGET_IXOFF 0010000
+#define TARGET_IMAXBEL 0020000
+#define TARGET_IUTF8 0040000
+
+/* c_oflag bits */
+#define TARGET_OPOST 0000001
+#define TARGET_OLCUC 0000002
+#define TARGET_ONLCR 0000004
+#define TARGET_OCRNL 0000010
+#define TARGET_ONOCR 0000020
+#define TARGET_ONLRET 0000040
+#define TARGET_OFILL 0000100
+#define TARGET_OFDEL 0000200
+#define TARGET_NLDLY 0000400
+#define TARGET_NL0 0000000
+#define TARGET_NL1 0000400
+#define TARGET_CRDLY 0003000
+#define TARGET_CR0 0000000
+#define TARGET_CR1 0001000
+#define TARGET_CR2 0002000
+#define TARGET_CR3 0003000
+#define TARGET_TABDLY 0014000
+#define TARGET_TAB0 0000000
+#define TARGET_TAB1 0004000
+#define TARGET_TAB2 0010000
+#define TARGET_TAB3 0014000
+#define TARGET_XTABS 0014000
+#define TARGET_BSDLY 0020000
+#define TARGET_BS0 0000000
+#define TARGET_BS1 0020000
+#define TARGET_VTDLY 0040000
+#define TARGET_VT0 0000000
+#define TARGET_VT1 0040000
+#define TARGET_FFDLY 0100000
+#define TARGET_FF0 0000000
+#define TARGET_FF1 0100000
+
+/* c_cflag bit meaning */
+#define TARGET_CBAUD 0010017
+#define TARGET_B0 0000000 /* hang up */
+#define TARGET_B50 0000001
+#define TARGET_B75 0000002
+#define TARGET_B110 0000003
+#define TARGET_B134 0000004
+#define TARGET_B150 0000005
+#define TARGET_B200 0000006
+#define TARGET_B300 0000007
+#define TARGET_B600 0000010
+#define TARGET_B1200 0000011
+#define TARGET_B1800 0000012
+#define TARGET_B2400 0000013
+#define TARGET_B4800 0000014
+#define TARGET_B9600 0000015
+#define TARGET_B19200 0000016
+#define TARGET_B38400 0000017
+#define TARGET_EXTA B19200
+#define TARGET_EXTB B38400
+#define TARGET_CSIZE 0000060
+#define TARGET_CS5 0000000
+#define TARGET_CS6 0000020
+#define TARGET_CS7 0000040
+#define TARGET_CS8 0000060
+#define TARGET_CSTOPB 0000100
+#define TARGET_CREAD 0000200
+#define TARGET_PARENB 0000400
+#define TARGET_PARODD 0001000
+#define TARGET_HUPCL 0002000
+#define TARGET_CLOCAL 0004000
+#define TARGET_CBAUDEX 0010000
+#define TARGET_B57600 0010001
+#define TARGET_B115200 0010002
+#define TARGET_B230400 0010003
+#define TARGET_B460800 0010004
+#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */
+#define TARGET_CMSPAR 010000000000 /* mark or space (stick) parity */
+#define TARGET_CRTSCTS 020000000000 /* flow control */
+
+/* c_lflag bits */
+#define TARGET_ISIG 0000001
+#define TARGET_ICANON 0000002
+#define TARGET_XCASE 0000004
+#define TARGET_ECHO 0000010
+#define TARGET_ECHOE 0000020
+#define TARGET_ECHOK 0000040
+#define TARGET_ECHONL 0000100
+#define TARGET_NOFLSH 0000200
+#define TARGET_TOSTOP 0000400
+#define TARGET_ECHOCTL 0001000
+#define TARGET_ECHOPRT 0002000
+#define TARGET_ECHOKE 0004000
+#define TARGET_FLUSHO 0010000
+#define TARGET_PENDIN 0040000
+#define TARGET_IEXTEN 0100000
+#define TARGET_EXTPROC 0200000
+
+/* c_cc character offsets */
+#define TARGET_VINTR 0
+#define TARGET_VQUIT 1
+#define TARGET_VERASE 2
+#define TARGET_VKILL 3
+#define TARGET_VEOF 4
+#define TARGET_VTIME 5
+#define TARGET_VMIN 6
+#define TARGET_VSWTC 7
+#define TARGET_VSTART 8
+#define TARGET_VSTOP 9
+#define TARGET_VSUSP 10
+#define TARGET_VEOL 11
+#define TARGET_VREPRINT 12
+#define TARGET_VDISCARD 13
+#define TARGET_VWERASE 14
+#define TARGET_VLNEXT 15
+#define TARGET_VEOL2 16
+
+/* ioctls */
+
+#define TARGET_TCGETS 0x5401
+#define TARGET_TCSETS 0x5402
+#define TARGET_TCSETSW 0x5403
+#define TARGET_TCSETSF 0x5404
+#define TARGET_TCGETA 0x5405
+#define TARGET_TCSETA 0x5406
+#define TARGET_TCSETAW 0x5407
+#define TARGET_TCSETAF 0x5408
+#define TARGET_TCSBRK 0x5409
+#define TARGET_TCXONC 0x540A
+#define TARGET_TCFLSH 0x540B
+
+#define TARGET_TIOCEXCL 0x540C
+#define TARGET_TIOCNXCL 0x540D
+#define TARGET_TIOCSCTTY 0x540E
+#define TARGET_TIOCGPGRP 0x540F
+#define TARGET_TIOCSPGRP 0x5410
+#define TARGET_TIOCOUTQ 0x5411
+#define TARGET_TIOCSTI 0x5412
+#define TARGET_TIOCGWINSZ 0x5413
+#define TARGET_TIOCSWINSZ 0x5414
+#define TARGET_TIOCMGET 0x5415
+#define TARGET_TIOCMBIS 0x5416
+#define TARGET_TIOCMBIC 0x5417
+#define TARGET_TIOCMSET 0x5418
+#define TARGET_TIOCGSOFTCAR 0x5419
+#define TARGET_TIOCSSOFTCAR 0x541A
+#define TARGET_FIONREAD 0x541B
+#define TARGET_TIOCINQ TARGET_FIONREAD
+#define TARGET_TIOCLINUX 0x541C
+#define TARGET_TIOCCONS 0x541D
+#define TARGET_TIOCGSERIAL 0x541E
+#define TARGET_TIOCSSERIAL 0x541F
+#define TARGET_TIOCPKT 0x5420
+#define TARGET_FIONBIO 0x5421
+#define TARGET_TIOCNOTTY 0x5422
+#define TARGET_TIOCSETD 0x5423
+#define TARGET_TIOCGETD 0x5424
+#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */
+#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */
+#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */
+#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */
+#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */
+#define TARGET_TIOCGPTN TARGET_IOR('T', 0x30, unsigned int)
+ /* Get Pty Number (of pty-mux device) */
+#define TARGET_TIOCSPTLCK TARGET_IOW('T', 0x31, int)
+ /* Lock/unlock Pty */
+#define TARGET_TIOCGPTPEER TARGET_IO('T', 0x41)
+ /* Safely open the slave */
+
+#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */
+#define TARGET_FIOCLEX 0x5451
+#define TARGET_FIOASYNC 0x5452
+#define TARGET_TIOCSERCONFIG 0x5453
+#define TARGET_TIOCSERGWILD 0x5454
+#define TARGET_TIOCSERSWILD 0x5455
+#define TARGET_TIOCGLCKTRMIOS 0x5456
+#define TARGET_TIOCSLCKTRMIOS 0x5457
+#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */
+#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */
+#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */
+#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
+
+#define TARGET_TIOCMIWAIT 0x545C
+ /* wait for a change on serial input line(s) */
+#define TARGET_TIOCGICOUNT 0x545D
+ /* read serial port inline interrupt counts */
+#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */
+#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */
+
+/* Used for packet mode */
+#define TARGET_TIOCPKT_DATA 0
+#define TARGET_TIOCPKT_FLUSHREAD 1
+#define TARGET_TIOCPKT_FLUSHWRITE 2
+#define TARGET_TIOCPKT_STOP 4
+#define TARGET_TIOCPKT_START 8
+#define TARGET_TIOCPKT_NOSTOP 16
+#define TARGET_TIOCPKT_DOSTOP 32
+
+#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */
+
+#endif
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index a5ce487..92e1a35 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -74,7 +74,7 @@
|| defined(TARGET_M68K) || defined(TARGET_CRIS) \
|| defined(TARGET_S390X) || defined(TARGET_OPENRISC) \
|| defined(TARGET_NIOS2) || defined(TARGET_RISCV) \
- || defined(TARGET_XTENSA)
+ || defined(TARGET_XTENSA) || defined(TARGET_LOONGARCH64)
#define TARGET_IOC_SIZEBITS 14
#define TARGET_IOC_DIRBITS 2
@@ -450,7 +450,7 @@ struct target_dirent64 {
#define TARGET_SIG_IGN ((abi_long)1) /* ignore signal */
#define TARGET_SIG_ERR ((abi_long)-1) /* error return from signal */
-#ifdef TARGET_MIPS
+#if defined(TARGET_MIPS) || defined(TARGET_LOONGARCH64)
#define TARGET_NSIG 128
#else
#define TARGET_NSIG 64
@@ -2129,7 +2129,8 @@ struct target_stat64 {
abi_ulong __unused5;
};
-#elif defined(TARGET_OPENRISC) || defined(TARGET_NIOS2) || defined(TARGET_RISCV)
+#elif defined(TARGET_OPENRISC) || defined(TARGET_NIOS2) || \
+ defined(TARGET_RISCV) || defined(TARGET_LOONGARCH64)
/* These are the asm-generic versions of the stat and stat64 structures */
@@ -2327,7 +2328,8 @@ struct target_statfs64 {
};
#elif (defined(TARGET_PPC64) || defined(TARGET_X86_64) || \
defined(TARGET_SPARC64) || defined(TARGET_AARCH64) || \
- defined(TARGET_RISCV)) && !defined(TARGET_ABI32)
+ defined(TARGET_RISCV) || defined(TARGET_LOONGARCH64)) && \
+ !defined(TARGET_ABI32)
struct target_statfs {
abi_long f_type;
abi_long f_bsize;
--
1.8.3.1
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v3 18/19] default-configs: Add loongarch linux-user support
2021-08-27 7:14 [PATCH v3 00/19] Add LoongArch linux-user emulation support Song Gao
` (16 preceding siblings ...)
2021-08-27 7:14 ` [PATCH v3 17/19] LoongArch Linux User Emulation Song Gao
@ 2021-08-27 7:14 ` Song Gao
2021-08-27 7:14 ` [PATCH v3 19/19] target/loongarch: Add target build suport Song Gao
18 siblings, 0 replies; 22+ messages in thread
From: Song Gao @ 2021-08-27 7:14 UTC (permalink / raw)
To: qemu-devel
Cc: peter.maydell, thuth, chenhuacai, richard.henderson, f4bug,
maobibo, laurent, yangxiaojuan, alistair.francis, pbonzini,
alex.bennee
Add loongarch64 linux-user default configs file.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
configs/targets/loongarch64-linux-user.mak | 3 +++
1 file changed, 3 insertions(+)
create mode 100644 configs/targets/loongarch64-linux-user.mak
diff --git a/configs/targets/loongarch64-linux-user.mak b/configs/targets/loongarch64-linux-user.mak
new file mode 100644
index 0000000..5b0acfa
--- /dev/null
+++ b/configs/targets/loongarch64-linux-user.mak
@@ -0,0 +1,3 @@
+# Default configuration for loongson64-linux-user
+TARGET_ARCH=loongarch64
+TARGET_BASE_ARCH=loongarch
--
1.8.3.1
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v3 19/19] target/loongarch: Add target build suport
2021-08-27 7:14 [PATCH v3 00/19] Add LoongArch linux-user emulation support Song Gao
` (17 preceding siblings ...)
2021-08-27 7:14 ` [PATCH v3 18/19] default-configs: Add loongarch linux-user support Song Gao
@ 2021-08-27 7:14 ` Song Gao
18 siblings, 0 replies; 22+ messages in thread
From: Song Gao @ 2021-08-27 7:14 UTC (permalink / raw)
To: qemu-devel
Cc: peter.maydell, thuth, chenhuacai, richard.henderson, f4bug,
maobibo, laurent, yangxiaojuan, alistair.francis, pbonzini,
alex.bennee
This patch add build loongarch-linux-user target support.
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
target/loongarch/meson.build | 18 ++++++++++++++++++
target/meson.build | 1 +
2 files changed, 19 insertions(+)
create mode 100644 target/loongarch/meson.build
diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build
new file mode 100644
index 0000000..31f9e9f
--- /dev/null
+++ b/target/loongarch/meson.build
@@ -0,0 +1,18 @@
+gen = decodetree.process('insns.decode')
+
+loongarch_ss = ss.source_set()
+loongarch_ss.add(files(
+ 'cpu.c',
+))
+loongarch_tcg_ss = ss.source_set()
+loongarch_tcg_ss.add(gen)
+loongarch_tcg_ss.add(files(
+ 'fpu_helper.c',
+ 'op_helper.c',
+ 'translate.c',
+))
+loongarch_tcg_ss.add(zlib)
+
+loongarch_ss.add_all(when: 'CONFIG_TCG', if_true: [loongarch_tcg_ss])
+
+target_arch += {'loongarch': loongarch_ss}
diff --git a/target/meson.build b/target/meson.build
index 2f69402..a53a604 100644
--- a/target/meson.build
+++ b/target/meson.build
@@ -5,6 +5,7 @@ subdir('cris')
subdir('hexagon')
subdir('hppa')
subdir('i386')
+subdir('loongarch')
subdir('m68k')
subdir('microblaze')
subdir('mips')
--
1.8.3.1
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH v3 01/19] target/loongarch: Add README
2021-08-27 7:14 ` [PATCH v3 01/19] target/loongarch: Add README Song Gao
@ 2021-08-27 15:06 ` Peter Xu
2021-08-30 1:06 ` Song Gao
0 siblings, 1 reply; 22+ messages in thread
From: Peter Xu @ 2021-08-27 15:06 UTC (permalink / raw)
To: Song Gao
Cc: peter.maydell, thuth, chenhuacai, richard.henderson, qemu-devel,
maobibo, f4bug, yangxiaojuan, alistair.francis, pbonzini,
alex.bennee, laurent
On Fri, Aug 27, 2021 at 03:14:36PM +0800, Song Gao wrote:
> +The following versions of the LoongArch core are supported
> + core: 3A5000
> + https://github.com/loongson/LoongArch-Documentation/releases/download/LoongArch-Vol1-v3/LoongArch-Vol1-v1.00-EN.pdf
This link seems invalid now.
--
Peter Xu
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v3 01/19] target/loongarch: Add README
2021-08-27 15:06 ` Peter Xu
@ 2021-08-30 1:06 ` Song Gao
0 siblings, 0 replies; 22+ messages in thread
From: Song Gao @ 2021-08-30 1:06 UTC (permalink / raw)
To: Peter Xu
Cc: peter.maydell, thuth, chenhuacai, richard.henderson, qemu-devel,
maobibo, f4bug, yangxiaojuan, alistair.francis, pbonzini,
alex.bennee, laurent
Hi, Peter.
On 08/27/2021 11:06 PM, Peter Xu wrote:
> On Fri, Aug 27, 2021 at 03:14:36PM +0800, Song Gao wrote:
>> +The following versions of the LoongArch core are supported
>> + core: 3A5000
>> + https://github.com/loongson/LoongArch-Documentation/releases/download/LoongArch-Vol1-v3/LoongArch-Vol1-v1.00-EN.pdf
>
> This link seems invalid now
Sorry. The path has been updated.
https://github.com/loongson/LoongArch-Documentation/releases/download/2021.08.17/LoongArch-Vol1-v1.00-EN.pdf
thanks
Song Gao
^ permalink raw reply [flat|nested] 22+ messages in thread
end of thread, other threads:[~2021-08-30 1:07 UTC | newest]
Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-27 7:14 [PATCH v3 00/19] Add LoongArch linux-user emulation support Song Gao
2021-08-27 7:14 ` [PATCH v3 01/19] target/loongarch: Add README Song Gao
2021-08-27 15:06 ` Peter Xu
2021-08-30 1:06 ` Song Gao
2021-08-27 7:14 ` [PATCH v3 02/19] target/loongarch: Add core definition Song Gao
2021-08-27 7:14 ` [PATCH v3 03/19] target/loongarch: Add main translation routines Song Gao
2021-08-27 7:14 ` [PATCH v3 04/19] target/loongarch: Add fixed point arithmetic instruction translation Song Gao
2021-08-27 7:14 ` [PATCH v3 05/19] target/loongarch: Add fixed point shift " Song Gao
2021-08-27 7:14 ` [PATCH v3 06/19] target/loongarch: Add fixed point bit " Song Gao
2021-08-27 7:14 ` [PATCH v3 07/19] target/loongarch: Add fixed point load/store " Song Gao
2021-08-27 7:14 ` [PATCH v3 08/19] target/loongarch: Add fixed point atomic " Song Gao
2021-08-27 7:14 ` [PATCH v3 09/19] target/loongarch: Add fixed point extra " Song Gao
2021-08-27 7:14 ` [PATCH v3 10/19] target/loongarch: Add floating point arithmetic " Song Gao
2021-08-27 7:14 ` [PATCH v3 11/19] target/loongarch: Add floating point comparison " Song Gao
2021-08-27 7:14 ` [PATCH v3 12/19] target/loongarch: Add floating point conversion " Song Gao
2021-08-27 7:14 ` [PATCH v3 13/19] target/loongarch: Add floating point move " Song Gao
2021-08-27 7:14 ` [PATCH v3 14/19] target/loongarch: Add floating point load/store " Song Gao
2021-08-27 7:14 ` [PATCH v3 15/19] target/loongarch: Add branch " Song Gao
2021-08-27 7:14 ` [PATCH v3 16/19] target/loongarch: Add disassembler Song Gao
2021-08-27 7:14 ` [PATCH v3 17/19] LoongArch Linux User Emulation Song Gao
2021-08-27 7:14 ` [PATCH v3 18/19] default-configs: Add loongarch linux-user support Song Gao
2021-08-27 7:14 ` [PATCH v3 19/19] target/loongarch: Add target build suport Song Gao
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).