This includes:
- IOCSR{RD/WR}.{B/H/W/D}
Signed-off-by: Xiaojuan Yang <yangxiaoj...@loongson.cn>
Signed-off-by: Song Gao <gaos...@loongson.cn>
---
target/loongarch/cpu.c | 52 ++++++
target/loongarch/cpu.h | 25 +++
target/loongarch/disas.c | 8 +
target/loongarch/helper.h | 8 +
.../insn_trans/trans_privileged.c.inc | 35 ++++
target/loongarch/insns.decode | 9 +
target/loongarch/iocsr_helper.c | 174 ++++++++++++++++++
target/loongarch/meson.build | 1 +
8 files changed, 312 insertions(+)
create mode 100644 target/loongarch/iocsr_helper.c
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index 6d6216a846..3167323821 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -17,6 +17,8 @@
#include "internals.h"
#include "fpu/softfloat-helpers.h"
#include "cpu-csr.h"
+#include "sysemu/reset.h"
+#include "hw/loader.h"
const char * const regnames[32] = {
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
@@ -483,14 +485,64 @@ static void loongarch_cpu_realizefn(DeviceState *dev,
Error **errp)
lacc->parent_realize(dev, errp);
}
+static void loongarch_qemu_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+}
+
+static uint64_t loongarch_qemu_read(void *opaque, hwaddr addr, unsigned size)
+{
+ switch (addr) {
+ case FEATURE_REG:
+ return 1UL << IOCSRF_MSI | 1UL << IOCSRF_EXTIOI |
+ 1UL << IOCSRF_CSRIPI;
+ case VENDOR_REG:
+ return 0x6e6f73676e6f6f4c; /* "Loongson" */
+ case CPUNAME_REG:
+ return 0x303030354133; /* "3A5000" */
+ case MISC_FUNC_REG:
+ return 1UL << IOCSRM_EXTIOI_EN;
+ }
+ return 0;
+}
+
+static const MemoryRegionOps loongarch_qemu_ops = {
+ .read = loongarch_qemu_read,
+ .write = loongarch_qemu_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 8,
+ },
+ .impl = {
+ .min_access_size = 8,
+ .max_access_size = 8,
+ },
+};
+
+static void do_cpu_reset(void *opaque)
+{
+ LoongArchCPU *cpu = opaque;
+
+ cpu_reset(CPU(cpu));
+}
+
static void loongarch_cpu_init(Object *obj)
{
LoongArchCPU *cpu = LOONGARCH_CPU(obj);
+ CPULoongArchState *env = &cpu->env;
cpu_set_cpustate_pointers(cpu);
qdev_init_gpio_in(DEVICE(cpu), loongarch_cpu_set_irq, N_IRQS);
timer_init_ns(&cpu->timer, QEMU_CLOCK_VIRTUAL,
&loongarch_constant_timer_cb, cpu);
+ memory_region_init_io(&env->system_iocsr, OBJECT(cpu), NULL,
+ env, "iocsr", UINT64_MAX);
+ address_space_init(&env->address_space_iocsr, &env->system_iocsr, "IOCSR");
+ qemu_register_reset(do_cpu_reset, cpu);
+ memory_region_init_io(&env->iocsr_mem, OBJECT(cpu), &loongarch_qemu_ops,
+ NULL, "iocsr_misc", 0x428);
+ memory_region_add_subregion(&env->system_iocsr, 0, &env->iocsr_mem);
}
static ObjectClass *loongarch_cpu_class_by_name(const char *cpu_model)
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index e907fe3c51..734f90168e 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -12,6 +12,27 @@
#include "fpu/softfloat-types.h"
#include "hw/registerfields.h"
#include "qemu/timer.h"
+#include "exec/memory.h"
+#include "hw/sysbus.h"
+
+#define IOCSRF_TEMP 0
+#define IOCSRF_NODECNT 1
+#define IOCSRF_MSI 2
+#define IOCSRF_EXTIOI 3
+#define IOCSRF_CSRIPI 4
+#define IOCSRF_FREQCSR 5
+#define IOCSRF_FREQSCALE 6
+#define IOCSRF_DVFSV1 7
+#define IOCSRF_GMOD 9
+#define IOCSRF_VM 11
+
+#define FEATURE_REG 0x8
+#define VENDOR_REG 0x10
+#define CPUNAME_REG 0x20
+#define MISC_FUNC_REG 0x420
+#define IOCSRM_EXTIOI_EN 48
+
+#define IOCSR_MEM_SIZE 0x428
#define TCG_GUEST_DEFAULT_MO (0)
@@ -284,6 +305,10 @@ typedef struct CPUArchState {
uint64_t CSR_DSAVE;
LoongArchTLB tlb[LOONGARCH_TLB_MAX];
+
+ AddressSpace address_space_iocsr;
+ MemoryRegion system_iocsr;
+ MemoryRegion iocsr_mem;
} CPULoongArchState;
/**
diff --git a/target/loongarch/disas.c b/target/loongarch/disas.c
index c76b82dfdf..fcc06abc6b 100644
--- a/target/loongarch/disas.c
+++ b/target/loongarch/disas.c
@@ -609,6 +609,14 @@ INSN(bgeu, rr_offs)
INSN(csrrd, r_csr)
INSN(csrwr, r_csr)
INSN(csrxchg, rr_csr)
+INSN(iocsrrd_b, rr)
+INSN(iocsrrd_h, rr)
+INSN(iocsrrd_w, rr)
+INSN(iocsrrd_d, rr)
+INSN(iocsrwr_b, rr)
+INSN(iocsrwr_h, rr)
+INSN(iocsrwr_w, rr)
+INSN(iocsrwr_d, rr)
#define output_fcmp(C, PREFIX, SUFFIX) \
{
\
diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h
index 5a6754eb65..4664a02dcf 100644
--- a/target/loongarch/helper.h
+++ b/target/loongarch/helper.h
@@ -100,3 +100,11 @@ DEF_HELPER_2(csrwr_estat, i64, env, tl)
DEF_HELPER_2(csrwr_asid, i64, env, tl)
DEF_HELPER_2(csrwr_tcfg, i64, env, tl)
DEF_HELPER_2(csrwr_ticlr, i64, env, tl)
+DEF_HELPER_2(iocsrrd_b, i64, env, tl)
+DEF_HELPER_2(iocsrrd_h, i64, env, tl)
+DEF_HELPER_2(iocsrrd_w, i64, env, tl)
+DEF_HELPER_2(iocsrrd_d, i64, env, tl)
+DEF_HELPER_3(iocsrwr_b, void, env, tl, tl)
+DEF_HELPER_3(iocsrwr_h, void, env, tl, tl)
+DEF_HELPER_3(iocsrwr_w, void, env, tl, tl)
+DEF_HELPER_3(iocsrwr_d, void, env, tl, tl)
diff --git a/target/loongarch/insn_trans/trans_privileged.c.inc
b/target/loongarch/insn_trans/trans_privileged.c.inc
index 0fc5d7935c..8a1c5b8511 100644
--- a/target/loongarch/insn_trans/trans_privileged.c.inc
+++ b/target/loongarch/insn_trans/trans_privileged.c.inc
@@ -256,3 +256,38 @@ static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg
*a)
tcg_temp_free(oldv);
return true;
}
+
+static bool gen_iocsrrd(DisasContext *ctx, arg_rr *a,
+ void (*func)(TCGv, TCGv_ptr, TCGv))
+{
+ TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+
+ if (check_plv(ctx)) {
+ return false;
+ }
+ func(dest, cpu_env, src1);
+ return true;
+}
+
+static bool gen_iocsrwr(DisasContext *ctx, arg_rr *a,
+ void (*func)(TCGv_ptr, TCGv, TCGv))
+{
+ TCGv val = gpr_src(ctx, a->rd, EXT_NONE);
+ TCGv addr = gpr_src(ctx, a->rj, EXT_NONE);
+
+ if (check_plv(ctx)) {
+ return false;
+ }
+ func(cpu_env, addr, val);
+ return true;
+}
+
+TRANS(iocsrrd_b, gen_iocsrrd, gen_helper_iocsrrd_b)
+TRANS(iocsrrd_h, gen_iocsrrd, gen_helper_iocsrrd_h)
+TRANS(iocsrrd_w, gen_iocsrrd, gen_helper_iocsrrd_w)
+TRANS(iocsrrd_d, gen_iocsrrd, gen_helper_iocsrrd_d)
+TRANS(iocsrwr_b, gen_iocsrwr, gen_helper_iocsrwr_b)
+TRANS(iocsrwr_h, gen_iocsrwr, gen_helper_iocsrwr_h)
+TRANS(iocsrwr_w, gen_iocsrwr, gen_helper_iocsrwr_w)
+TRANS(iocsrwr_d, gen_iocsrwr, gen_helper_iocsrwr_d)
diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode
index 43005ca283..2b436d3cd6 100644
--- a/target/loongarch/insns.decode
+++ b/target/loongarch/insns.decode
@@ -450,3 +450,12 @@ bgeu 0110 11 ................ ..... .....
@rr_offs16
csrwr 0000 0100 .............. 00001 ..... @r_csr
csrxchg 0000 0100 .............. ..... ..... @rr_csr
}
+
+iocsrrd_b 0000 01100100 10000 00000 ..... ..... @rr
+iocsrrd_h 0000 01100100 10000 00001 ..... ..... @rr
+iocsrrd_w 0000 01100100 10000 00010 ..... ..... @rr
+iocsrrd_d 0000 01100100 10000 00011 ..... ..... @rr
+iocsrwr_b 0000 01100100 10000 00100 ..... ..... @rr
+iocsrwr_h 0000 01100100 10000 00101 ..... ..... @rr
+iocsrwr_w 0000 01100100 10000 00110 ..... ..... @rr
+iocsrwr_d 0000 01100100 10000 00111 ..... ..... @rr
diff --git a/target/loongarch/iocsr_helper.c b/target/loongarch/iocsr_helper.c
new file mode 100644
index 0000000000..ce8e17fb12
--- /dev/null
+++ b/target/loongarch/iocsr_helper.c
@@ -0,0 +1,174 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * Helpers for IOCSR reads/writes
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/main-loop.h"
+#include "cpu.h"
+#include "internals.h"
+#include "qemu/host-utils.h"
+#include "exec/helper-proto.h"
+#include "exec/exec-all.h"
+#include "exec/cpu_ldst.h"
+#include "tcg/tcg-ldst.h"
+
+uint64_t helper_iocsrrd_b(CPULoongArchState *env, target_ulong r_addr)
+{
+ return address_space_ldub(&env->address_space_iocsr, r_addr,
+ MEMTXATTRS_UNSPECIFIED, NULL);
+}
+
+uint64_t helper_iocsrrd_h(CPULoongArchState *env, target_ulong r_addr)
+{
+ return address_space_lduw(&env->address_space_iocsr, r_addr,
+ MEMTXATTRS_UNSPECIFIED, NULL);
+}
+
+uint64_t helper_iocsrrd_w(CPULoongArchState *env, target_ulong r_addr)
+{
+ return address_space_ldl(&env->address_space_iocsr, r_addr,
+ MEMTXATTRS_UNSPECIFIED, NULL);
+}
+
+uint64_t helper_iocsrrd_d(CPULoongArchState *env, target_ulong r_addr)
+{
+ return address_space_ldq(&env->address_space_iocsr, r_addr,
+ MEMTXATTRS_UNSPECIFIED, NULL);
+}
+
+static int get_ipi_data(target_ulong val)
+{
+ int i, mask, data;
+
+ data = val >> 32;
+ mask = (val >> 27) & 0xf;
+
+ for (i = 0; i < 4; i++) {
+ if ((mask >> i) & 1) {
+ data &= ~(0xff << (i * 8));
+ }
+ }
+ return data;
+}
+
+static void check_ipi_send(CPULoongArchState *env, target_ulong val)