qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [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 ++
 target/loongarch/insn_trans/trans_extra.c | 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)
diff --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).