mirror of
https://github.com/qemu/qemu.git
synced 2025-08-16 06:43:21 +00:00
target-arm: A64: Implement minimal set of EL0-visible sysregs
Implement an initial minimal set of EL0-visible system registers: * NZCV * FPCR * FPSR * CTR_EL0 * DCZID_EL0 Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <rth@twiddle.net> Reviewed-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
This commit is contained in:
parent
fea505221e
commit
b0d2b7d0f0
@ -660,7 +660,8 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
|
|||||||
#define ARM_CP_IO 64
|
#define ARM_CP_IO 64
|
||||||
#define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 8))
|
#define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 8))
|
||||||
#define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 8))
|
#define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 8))
|
||||||
#define ARM_LAST_SPECIAL ARM_CP_WFI
|
#define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 8))
|
||||||
|
#define ARM_LAST_SPECIAL ARM_CP_NZCV
|
||||||
/* Used only as a terminator for ARMCPRegInfo lists */
|
/* Used only as a terminator for ARMCPRegInfo lists */
|
||||||
#define ARM_CP_SENTINEL 0xffff
|
#define ARM_CP_SENTINEL 0xffff
|
||||||
/* Mask of only the flag bits in a type field */
|
/* Mask of only the flag bits in a type field */
|
||||||
|
@ -1560,6 +1560,64 @@ static const ARMCPRegInfo lpae_cp_reginfo[] = {
|
|||||||
REGINFO_SENTINEL
|
REGINFO_SENTINEL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int aa64_fpcr_read(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
|
uint64_t *value)
|
||||||
|
{
|
||||||
|
*value = vfp_get_fpcr(env);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int aa64_fpcr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
|
uint64_t value)
|
||||||
|
{
|
||||||
|
vfp_set_fpcr(env, value);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int aa64_fpsr_read(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
|
uint64_t *value)
|
||||||
|
{
|
||||||
|
*value = vfp_get_fpsr(env);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int aa64_fpsr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
|
uint64_t value)
|
||||||
|
{
|
||||||
|
vfp_set_fpsr(env, value);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const ARMCPRegInfo v8_cp_reginfo[] = {
|
||||||
|
/* Minimal set of EL0-visible registers. This will need to be expanded
|
||||||
|
* significantly for system emulation of AArch64 CPUs.
|
||||||
|
*/
|
||||||
|
{ .name = "NZCV", .state = ARM_CP_STATE_AA64,
|
||||||
|
.opc0 = 3, .opc1 = 3, .opc2 = 0, .crn = 4, .crm = 2,
|
||||||
|
.access = PL0_RW, .type = ARM_CP_NZCV },
|
||||||
|
{ .name = "FPCR", .state = ARM_CP_STATE_AA64,
|
||||||
|
.opc0 = 3, .opc1 = 3, .opc2 = 0, .crn = 4, .crm = 4,
|
||||||
|
.access = PL0_RW, .readfn = aa64_fpcr_read, .writefn = aa64_fpcr_write },
|
||||||
|
{ .name = "FPSR", .state = ARM_CP_STATE_AA64,
|
||||||
|
.opc0 = 3, .opc1 = 3, .opc2 = 1, .crn = 4, .crm = 4,
|
||||||
|
.access = PL0_RW, .readfn = aa64_fpsr_read, .writefn = aa64_fpsr_write },
|
||||||
|
/* This claims a 32 byte cacheline size for icache and dcache, VIPT icache.
|
||||||
|
* It will eventually need to have a CPU-specified reset value.
|
||||||
|
*/
|
||||||
|
{ .name = "CTR_EL0", .state = ARM_CP_STATE_AA64,
|
||||||
|
.opc0 = 3, .opc1 = 3, .opc2 = 1, .crn = 0, .crm = 0,
|
||||||
|
.access = PL0_R, .type = ARM_CP_CONST,
|
||||||
|
.resetvalue = 0x80030003 },
|
||||||
|
/* Prohibit use of DC ZVA. OPTME: implement DC ZVA and allow its use.
|
||||||
|
* For system mode the DZP bit here will need to be computed, not constant.
|
||||||
|
*/
|
||||||
|
{ .name = "DCZID_EL0", .state = ARM_CP_STATE_AA64,
|
||||||
|
.opc0 = 3, .opc1 = 3, .opc2 = 7, .crn = 0, .crm = 0,
|
||||||
|
.access = PL0_R, .type = ARM_CP_CONST,
|
||||||
|
.resetvalue = 0x10 },
|
||||||
|
REGINFO_SENTINEL
|
||||||
|
};
|
||||||
|
|
||||||
static int sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
|
static int sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
|
||||||
{
|
{
|
||||||
env->cp15.c1_sys = value;
|
env->cp15.c1_sys = value;
|
||||||
@ -1662,6 +1720,9 @@ void register_cp_regs_for_features(ARMCPU *cpu)
|
|||||||
} else {
|
} else {
|
||||||
define_arm_cp_regs(cpu, not_v7_cp_reginfo);
|
define_arm_cp_regs(cpu, not_v7_cp_reginfo);
|
||||||
}
|
}
|
||||||
|
if (arm_feature(env, ARM_FEATURE_V8)) {
|
||||||
|
define_arm_cp_regs(cpu, v8_cp_reginfo);
|
||||||
|
}
|
||||||
if (arm_feature(env, ARM_FEATURE_MPU)) {
|
if (arm_feature(env, ARM_FEATURE_MPU)) {
|
||||||
/* These are the MPU registers prior to PMSAv6. Any new
|
/* These are the MPU registers prior to PMSAv6. Any new
|
||||||
* PMSA core later than the ARM946 will require that we
|
* PMSA core later than the ARM946 will require that we
|
||||||
|
@ -733,6 +733,50 @@ static void handle_msr_i(DisasContext *s, uint32_t insn,
|
|||||||
unsupported_encoding(s, insn);
|
unsupported_encoding(s, insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void gen_get_nzcv(TCGv_i64 tcg_rt)
|
||||||
|
{
|
||||||
|
TCGv_i32 tmp = tcg_temp_new_i32();
|
||||||
|
TCGv_i32 nzcv = tcg_temp_new_i32();
|
||||||
|
|
||||||
|
/* build bit 31, N */
|
||||||
|
tcg_gen_andi_i32(nzcv, cpu_NF, (1 << 31));
|
||||||
|
/* build bit 30, Z */
|
||||||
|
tcg_gen_setcondi_i32(TCG_COND_EQ, tmp, cpu_ZF, 0);
|
||||||
|
tcg_gen_deposit_i32(nzcv, nzcv, tmp, 30, 1);
|
||||||
|
/* build bit 29, C */
|
||||||
|
tcg_gen_deposit_i32(nzcv, nzcv, cpu_CF, 29, 1);
|
||||||
|
/* build bit 28, V */
|
||||||
|
tcg_gen_shri_i32(tmp, cpu_VF, 31);
|
||||||
|
tcg_gen_deposit_i32(nzcv, nzcv, tmp, 28, 1);
|
||||||
|
/* generate result */
|
||||||
|
tcg_gen_extu_i32_i64(tcg_rt, nzcv);
|
||||||
|
|
||||||
|
tcg_temp_free_i32(nzcv);
|
||||||
|
tcg_temp_free_i32(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gen_set_nzcv(TCGv_i64 tcg_rt)
|
||||||
|
|
||||||
|
{
|
||||||
|
TCGv_i32 nzcv = tcg_temp_new_i32();
|
||||||
|
|
||||||
|
/* take NZCV from R[t] */
|
||||||
|
tcg_gen_trunc_i64_i32(nzcv, tcg_rt);
|
||||||
|
|
||||||
|
/* bit 31, N */
|
||||||
|
tcg_gen_andi_i32(cpu_NF, nzcv, (1 << 31));
|
||||||
|
/* bit 30, Z */
|
||||||
|
tcg_gen_andi_i32(cpu_ZF, nzcv, (1 << 30));
|
||||||
|
tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_ZF, cpu_ZF, 0);
|
||||||
|
/* bit 29, C */
|
||||||
|
tcg_gen_andi_i32(cpu_CF, nzcv, (1 << 29));
|
||||||
|
tcg_gen_shri_i32(cpu_CF, cpu_CF, 29);
|
||||||
|
/* bit 28, V */
|
||||||
|
tcg_gen_andi_i32(cpu_VF, nzcv, (1 << 28));
|
||||||
|
tcg_gen_shli_i32(cpu_VF, cpu_VF, 3);
|
||||||
|
tcg_temp_free_i32(nzcv);
|
||||||
|
}
|
||||||
|
|
||||||
/* C5.6.129 MRS - move from system register
|
/* C5.6.129 MRS - move from system register
|
||||||
* C5.6.131 MSR (register) - move to system register
|
* C5.6.131 MSR (register) - move to system register
|
||||||
* C5.6.204 SYS
|
* C5.6.204 SYS
|
||||||
@ -767,6 +811,14 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
|
|||||||
switch (ri->type & ~(ARM_CP_FLAG_MASK & ~ARM_CP_SPECIAL)) {
|
switch (ri->type & ~(ARM_CP_FLAG_MASK & ~ARM_CP_SPECIAL)) {
|
||||||
case ARM_CP_NOP:
|
case ARM_CP_NOP:
|
||||||
return;
|
return;
|
||||||
|
case ARM_CP_NZCV:
|
||||||
|
tcg_rt = cpu_reg(s, rt);
|
||||||
|
if (isread) {
|
||||||
|
gen_get_nzcv(tcg_rt);
|
||||||
|
} else {
|
||||||
|
gen_set_nzcv(tcg_rt);
|
||||||
|
}
|
||||||
|
return;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user