Hi Khushit, On 5/27/26 4:35 PM, Khushit Shah wrote: > >> On 19 May 2026, at 6:57 PM, Eric Auger <[email protected]> wrote: >> >> !-------------------------------------------------------------------| >> CAUTION: External Email >> >> |-------------------------------------------------------------------! >> >> Introduce a script that takes as input the Registers.json file >> delivered in the AARCHMRS Features Model downloadable from the >> Arm Developer A-Profile Architecture Exploration Tools page: >> https://urldefense.proofpoint.com/v2/url?u=https-3A__developer.arm.com_Architectures_A-2DProfile-2520Architecture-23Downloads&d=DwIDAg&c=s883GpUCOChKOHiocYtGcg&r=PGWMyignA0NiDmTlyP7vOTHozBws_VN86yrVmSMkBp0&m=lifWLuAPiWiPtZHA1AnNwE36XKErpJppnuqSRce8eEXbd2seIXgOyghkIcv1h_tk&s=HRujmTCQGTPR11d90Orv_1iwKOLX_k3RFbkK_mx7A1s&e= >> >> and automates the generation of system register properties definitions. >> >> generates target/arm/cpu-idregs.h.inc containing definitions for >> feature ID registers. >> >> We only care about IDregs with opcodes satisfying: >> op0 = 3, op1 = {0,1,3}, crn = 0, crm within [0, 7], op2 within [0, 7] >> >> Signed-off-by: Eric Auger <[email protected]> >> --- >> .../update-aarch64-cpu-sysreg-properties.py | 168 ++++++++++++++++++ >> 1 file changed, 168 insertions(+) >> create mode 100644 scripts/update-aarch64-cpu-sysreg-properties.py >> >> diff --git a/scripts/update-aarch64-cpu-sysreg-properties.py >> b/scripts/update-aarch64-cpu-sysreg-properties.py >> new file mode 100644 >> index 0000000000..3571e228ee >> --- /dev/null >> +++ b/scripts/update-aarch64-cpu-sysreg-properties.py >> @@ -0,0 +1,168 @@ >> +#!/usr/bin/env python3 >> + >> +# This script takes as input the Registers.json file delivered in >> +# the AARCHMRS Features Model downloadable from the Arm Developer >> +# A-Profile Architecture Exploration Tools page: >> +# >> https://urldefense.proofpoint.com/v2/url?u=https-3A__developer.arm.com_Architectures_A-2DProfile-2520Architecture-23Downloads&d=DwIDAg&c=s883GpUCOChKOHiocYtGcg&r=PGWMyignA0NiDmTlyP7vOTHozBws_VN86yrVmSMkBp0&m=lifWLuAPiWiPtZHA1AnNwE36XKErpJppnuqSRce8eEXbd2seIXgOyghkIcv1h_tk&s=HRujmTCQGTPR11d90Orv_1iwKOLX_k3RFbkK_mx7A1s&e= >> >> +# and outputs target/arm/cpu-sysreg-properties.c content. >> +# There, initialize_cpu_sysreg_properties() populates arm64_id_regs array >> +# with the name of each ID register and definition of all its fields >> +# including their name and min/max bit under the form of the below pattern: >> +# >> +# /* CCSIDR2_EL1 */ >> +# ARM64SysReg *CCSIDR2_EL1 = arm64_sysreg_get(CCSIDR2_EL1_IDX); >> +# CCSIDR2_EL1->name = "CCSIDR2_EL1"; >> +# arm64_sysreg_add_field(CCSIDR2_EL1, "NumSets", 0, 23); >> +# >> +# Copyright (C) 2026 Red Hat, Inc. >> +# >> +# Authors: Eric Auger <[email protected]> >> +# >> +# SPDX-License-Identifier: GPL-2.0-or-later >> + >> + >> +import json >> +import os >> +import sys >> +from aarch64_sysreg_helpers import extract_idregs_from_registers_json >> + >> +def collect_fields(item, bit_offset=0): >> + """ >> + Recursively finds all field-like objects, handling Fields.Array, >> + Fields.ArrayField, and ConditionalField structures. >> + Applies bit_offset from containers to child fields. >> + """ >> + fields = [] >> + if not isinstance(item, dict): >> + return fields >> + >> + _type = item.get('_type', '') >> + >> + # Array types (for example CLIDR_EL1 Ctype<n>, Ttype<n>) >> + if _type == 'Fields.Array': >> + name_template = item.get('name') or item.get('label', '') >> + index_info = item.get('indexes', [{}])[0] >> + start_idx = index_info.get('start', 0) >> + count = index_info.get('width', 0) >> + >> + full_range = item.get('rangeset', [{}])[0] >> + bit_start = full_range.get('start', 0) + bit_offset >> + elem_width = full_range.get('width', 0) // count if count else 0 >> + >> + for i in range(count): >> + idx = start_idx + i >> + # Correctly handle indexed names like Ctype1, Ctype2 >> + field_name = name_template.replace('<n>', str(idx)) >> + fields.append({ >> + 'name': field_name, >> + 'rangeset': [{ >> + 'start': bit_start + (i * elem_width), >> + 'width': elem_width >> + }], >> + '_type': 'Fields.Field' >> + }) >> + return fields >> + >> + # ConditionalFields >> + elif _type == 'Fields.ConditionalField': >> + inner_offset = bit_offset >> + if item.get('rangeset'): >> + # Parent container defines the absolute start bit >> + inner_offset = item['rangeset'][0].get('start', bit_offset) >> + >> + for entry in item.get('fields', []): >> + inner = entry.get('field') >> + if inner: >> + fields.extend(collect_fields(inner, inner_offset)) >> + return fields >> + >> + # Normal Field Types >> + leaf_types = ['Fields.Field', 'Fields.ConstantField', >> + 'Fields.EnumeratedField', 'Fields.Bitfield'] >> + if _type in leaf_types: >> + field_copy = item.copy() >> + if field_copy.get('rangeset'): >> + new_ranges = [] >> + for r in field_copy['rangeset']: >> + nr = r.copy() >> + # Apply the cumulative offset to the field's start bit >> + nr['start'] = r.get('start', 0) + bit_offset >> + new_ranges.append(nr) >> + field_copy['rangeset'] = new_ranges >> + fields.append(field_copy) >> + return fields >> + >> + # Traverse the hierarchy for other cases >> + for key in ['fields', 'values', 'fieldsets']: >> + for nested in item.get(key, []): >> + fields.extend(collect_fields(nested, bit_offset)) >> + >> + return fields >> + >> + >> +def generate_sysreg_properties_from_registers_json(id_reg_names, >> raw_json_path): >> + with open(raw_json_path, 'r') as f: >> + register_data = json.load(f) >> + >> + regs = {r.get('name'): r for r in register_data if r.get('_type') == >> 'Register'} >> + >> + final_output = "" >> + >> + for reg_name in id_reg_names: >> + register = regs.get(reg_name) >> + if not register: >> + continue >> + >> + final_output += f" IDREG_START({reg_name})\n" >> + >> + unique_fields = {} >> + for fieldset in register.get('fieldsets', []): >> + candidates = collect_fields(fieldset) >> + for val in candidates: >> + name = (val.get('name') or val.get('label', '')).strip() >> + if not name or "RESERVED" in name.upper(): >> + continue >> + for r in val.get('rangeset', []): >> + lsb = int(r.get('start')) >> + width = r.get('width') >> + msb = lsb + int(width) - 1 >> + >> + # Only keep the fields with the highest MSB >> + # needed fir CCSIDR_EL1 >> + if name not in unique_fields or msb > >> unique_fields[name]['msb']: >> + unique_fields[name] = {'lsb': lsb, 'msb': msb, >> 'width': width} >> + >> + # Sort decreasing lsbs >> + sorted_fields = sorted(unique_fields.items(), >> + key=lambda x: x[1]['lsb'], reverse=True) >> + >> + for name, bits in sorted_fields: >> + line = (f" IDREG_FIELD({reg_name}, " >> + f"{name}, {bits['lsb']}, {bits['width']})\n") >> + final_output += line >> + final_output += f" IDREG_END({reg_name})\n" >> + final_output += "\n" >> + >> + os.makedirs("target/arm", exist_ok=True) >> + with open("target/arm/cpu-idregs.h.inc", 'w') as f: >> + f.write("/* AUTOMATICALLY GENERATED, DO NOT MODIFY */\n\n") >> + f.write("/* SPDX-License-Identifier: GPL-2.0-or-later */\n\n") >> + f.write("/* IDREG_START(REG) */\n") >> + f.write("/* IDREG_FIELD(REG, FIELD, SHIFT, LENGTH) */\n") >> + f.write("/* ... */\n") >> + f.write("/* IDREG_END(REG) */\n\n") >> + f.write(final_output) >> + >> +if __name__ == "__main__": >> + if len(sys.argv) < 2: >> + print("Usage: python >> scripts/update-aarch64-cpu-sysreg-properties.py " >> + "<path_to_registers_json>") >> + else: >> + json_path = sys.argv[1] >> + >> + id_regs_dict = extract_idregs_from_registers_json(json_path) >> + sorted_names = sorted(id_regs_dict.keys()) >> + >> + if sorted_names: >> + generate_sysreg_properties_from_registers_json(sorted_names, >> json_path) >> + print("Generated target/arm/cpu-idregs.h.inc") >> -- >> 2.53.0 >> > Hi Eric, > > Can we also have the arch-defined values in here? It is already available in > Registers.json easily, would be great if we can validate at-least the user > set values are architecturally valid.
Yes valid values should be easily extractable Thanks Eric > > Warm Regards, > Khushit >
