Add helper functions to extract and set fields from the ID registers. These include reading/writing individual fields, looking up architectural value names, and resetting ID registers to their default values.
Co-authored-by: Khushit Shah <[email protected]> Signed-off-by: Shaju Abraham <[email protected]> --- target/arm/cpu-idregs.c | 107 ++++++++++++++++++++++++++++++++++++++++ target/arm/cpu-idregs.h | 9 ++++ 2 files changed, 116 insertions(+) diff --git a/target/arm/cpu-idregs.c b/target/arm/cpu-idregs.c index 8fced7d8d7..5ffdeb5f21 100644 --- a/target/arm/cpu-idregs.c +++ b/target/arm/cpu-idregs.c @@ -122,3 +122,110 @@ const ArmIdRegFieldLoc arm_field_locs[ARM_FIELD__MAX] = { #undef IDREG_FIELD_START #undef IDREG_END #undef IDREG_START + +void arm_idreg_field_read(ARMCPU *cpu, ArmFieldIdx field, uint64_t *value) +{ + ARMIDRegisterIdx reg_idx = ARM_FIELD_REG(field); + uint64_t reg_value = cpu->isar.idregs[reg_idx]; + uint32_t shift = ARM_FIELD_SHIFT(field); + uint32_t length = ARM_FIELD_LENGTH(field); + + *value = extract64(reg_value, shift, length); +} + +bool arm_idreg_field_write(ARMCPU *cpu, ArmFieldIdx field, uint64_t value, + Error **errp) +{ + ARMIDRegisterIdx reg_idx = ARM_FIELD_REG(field); + uint64_t reg_value = cpu->isar.idregs[reg_idx]; + uint32_t shift = ARM_FIELD_SHIFT(field); + uint32_t length = ARM_FIELD_LENGTH(field); + ArmIdReg *reg; + ArmIdRegField *fdesc; + + if (length < 64 && value > ((1ULL << length) - 1)) { + reg = &arm_idregs[reg_idx]; + fdesc = ®->fields[ARM_FIELD_REG_FIELD(field)]; + + error_setg(errp, "value %" PRIu64 " is too large for field %s.%s", + value, reg->name, fdesc->name); + return false; + } + + cpu->isar.idregs[reg_idx] = deposit64(reg_value, shift, length, value); + return true; +} + +static const ArmIdRegField *arm_get_field_desc(ArmFieldIdx field) +{ + ARMIDRegisterIdx reg_idx = ARM_FIELD_REG(field); + uint16_t field_idx = ARM_FIELD_REG_FIELD(field); + return &arm_idregs[reg_idx].fields[field_idx]; +} + +const char *arm_arch_val_name(ArmFieldIdx field, uint64_t val) +{ + uint32_t i; + const ArmIdRegField *f = arm_get_field_desc(field); + + for (i = 0; i < f->arch_vals_count; i++) { + if (f->arch_vals[i].value == val && f->arch_vals[i].name) { + return f->arch_vals[i].name; + } + } + return NULL; +} + +bool arm_arch_val_from_name(ArmFieldIdx field, const char *name, + uint64_t *val) +{ + uint32_t i; + ArmIdRegArchVal *av; + const ArmIdRegField *f = arm_get_field_desc(field); + + for (i = 0; i < f->arch_vals_count; i++) { + av = &f->arch_vals[i]; + + if (av->name && g_ascii_strcasecmp(av->name, name) == 0) { + *val = av->value; + return true; + } + } + return false; +} + +bool arm_field_is_idreg_any(ArmFieldIdx field) +{ + const ArmIdRegField *f = arm_get_field_desc(field); + + return f->arch_vals_count == 1 && + f->arch_vals[0].value == 0xffffffffUL && + f->arch_vals[0].name == NULL; +} + +void arm_idregs_reset_to_defaults(ARMCPU *cpu) +{ + int i; + uint32_t j; + ArmIdReg *reg; + ArmIdRegField *f; + uint64_t val = 0; + + for (i = 0; i < NUM_ID_IDX; i++) { + reg = &arm_idregs[i]; + + if (!reg->name) { + warn_report("target/arm: no field table for ID register slot " + "%d; cpu->isar.idregs[%d] left at 0x%016" + PRIx64, i, + i, cpu->isar.idregs[i]); + continue; + } + + for (j = 0; j < reg->fields_count; j++) { + f = ®->fields[j]; + val = deposit64(val, f->shift, f->length, f->default_val); + } + cpu->isar.idregs[i] = val; + } +} diff --git a/target/arm/cpu-idregs.h b/target/arm/cpu-idregs.h index 4e568e877d..0127bc0a95 100644 --- a/target/arm/cpu-idregs.h +++ b/target/arm/cpu-idregs.h @@ -119,4 +119,13 @@ extern const ArmIdRegFieldLoc arm_field_locs[ARM_FIELD__MAX]; #define ARM_FIELD_IDX(reg, field) ARM_FIELD_##reg##_##field extern ArmIdReg arm_idregs[NUM_ID_IDX]; + +void arm_idreg_field_read(ARMCPU *cpu, ArmFieldIdx field, uint64_t *value); +bool arm_idreg_field_write(ARMCPU *cpu, ArmFieldIdx field, + uint64_t value, Error **errp); +const char *arm_arch_val_name(ArmFieldIdx field, uint64_t val); +bool arm_arch_val_from_name(ArmFieldIdx field, const char *name, + uint64_t *val); +bool arm_field_is_idreg_any(ArmFieldIdx field); +void arm_idregs_reset_to_defaults(ARMCPU *cpu); #endif /* CPU_IDREGS_H */ -- 2.52.0
