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 = &reg->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 = &reg->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


Reply via email to