#ifndef LOONGARCH_CPU_H
#define LOONGARCH_CPU_H
+#include "qemu/int128.h"
#include "exec/cpu-defs.h"
#include "fpu/softfloat-types.h"
#include "hw/registerfields.h"
FIELD(TLB_MISC, VPPN, 13, 35)
FIELD(TLB_MISC, PS, 48, 6)
+#define LSX_LEN (128)
+typedef union VReg {
+ int8_t B[LSX_LEN / 8];
+ int16_t H[LSX_LEN / 16];
+ int32_t W[LSX_LEN / 32];
+ int64_t D[LSX_LEN / 64];
+ uint8_t UB[LSX_LEN / 8];
+ uint16_t UH[LSX_LEN / 16];
+ uint32_t UW[LSX_LEN / 32];
+ uint64_t UD[LSX_LEN / 64];
+ Int128 Q[LSX_LEN / 128];
+}VReg;
+
+typedef union fpr_t fpr_t;
+union fpr_t {
+ VReg vreg;
+};
+
struct LoongArchTLB {
uint64_t tlb_misc;
/* Fields corresponding to CSR_TLBELO0/1 */
uint64_t gpr[32];
uint64_t pc;
- uint64_t fpr[32];
+ fpr_t fpr[32];
float_status fp_status;
bool cf[8];
#include "migration/cpu.h"
#include "internals.h"
+static const VMStateDescription vmstate_fpu_reg = {
+ .name = "fpu_reg",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT64(UD(0), VReg),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+#define VMSTATE_FPU_REGS(_field, _state, _start) \
+ VMSTATE_STRUCT_SUB_ARRAY(_field, _state, _start, 32, 0, \
+ vmstate_fpu_reg, fpr_t)
+
+static bool fpu_needed(void *opaque)
+{
+ LoongArchCPU *cpu = opaque;
+
+ return FIELD_EX64(cpu->env.cpucfg[2], CPUCFG2, FP);
+}
+
+static const VMStateDescription vmstate_fpu = {
+ .name = "cpu/fpu",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = fpu_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_FPU_REGS(env.fpr, LoongArchCPU, 0),
+ VMSTATE_UINT32(env.fcsr0, LoongArchCPU),
+ VMSTATE_BOOL_ARRAY(env.cf, LoongArchCPU, 8),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static const VMStateDescription vmstate_lsxh_reg = {
+ .name = "lsxh_reg",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT64(UD(1), VReg),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+#define VMSTATE_LSXH_REGS(_field, _state, _start) \
+ VMSTATE_STRUCT_SUB_ARRAY(_field, _state, _start, 32, 0, \
+ vmstate_lsxh_reg, fpr_t)
+
+static bool lsx_needed(void *opaque)
+{
+ LoongArchCPU *cpu = opaque;
+
+ return FIELD_EX64(cpu->env.cpucfg[2], CPUCFG2, LSX);
+}
+
+static const VMStateDescription vmstate_lsx = {
+ .name = "cpu/lsx",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = lsx_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_LSXH_REGS(env.fpr, LoongArchCPU, 0),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
/* TLB state */
const VMStateDescription vmstate_tlb = {
.name = "cpu/tlb",
};
/* LoongArch CPU state */
-
const VMStateDescription vmstate_loongarch_cpu = {
.name = "cpu",
- .version_id = 0,
- .minimum_version_id = 0,
+ .version_id = 1,
+ .minimum_version_id = 1,
.fields = (VMStateField[]) {
-
VMSTATE_UINTTL_ARRAY(env.gpr, LoongArchCPU, 32),
VMSTATE_UINTTL(env.pc, LoongArchCPU),
- VMSTATE_UINT64_ARRAY(env.fpr, LoongArchCPU, 32),
- VMSTATE_UINT32(env.fcsr0, LoongArchCPU),
- VMSTATE_BOOL_ARRAY(env.cf, LoongArchCPU, 8),
/* Remaining CSRs */
VMSTATE_UINT64(env.CSR_CRMD, LoongArchCPU),
VMSTATE_END_OF_LIST()
},
+ .subsections = (const VMStateDescription*[]) {
+ &vmstate_fpu,
+ &vmstate_lsx,
+ }
};