From 2c7c61615868b1e6abf82b42555f8b8eaaf54377 Mon Sep 17 00:00:00 2001 From: Afonso Oliveira Date: Thu, 30 Jan 2025 13:23:18 +0000 Subject: [PATCH] Enhance error handling and support for non-default extensions, such as qc_iu Signed-off-by: Afonso Oliveira --- ext/opcodes_maker/yaml_to_json.py | 190 +++++++++++++++++------------- 1 file changed, 110 insertions(+), 80 deletions(-) diff --git a/ext/opcodes_maker/yaml_to_json.py b/ext/opcodes_maker/yaml_to_json.py index 2d9c9fbba..93c55182e 100644 --- a/ext/opcodes_maker/yaml_to_json.py +++ b/ext/opcodes_maker/yaml_to_json.py @@ -1,8 +1,11 @@ -from typing import List, Dict +#!/usr/bin/env python3 + +from typing import List, Dict, Union, Any import os import yaml import json import argparse +import sys def range_size(range_str: str) -> int: @@ -16,7 +19,7 @@ def range_size(range_str: str) -> int: reg_names = {"qs1", "qs2", "qd", "fs1", "fs2", "fd"} -def GetVariables(vars: List[Dict[str, str]]): +def GetVariables(vars: List[Dict[str, str]]) -> List[str]: var_names = [] for var in vars: var_name = var["name"] @@ -33,7 +36,6 @@ def GetVariables(vars: List[Dict[str, str]]): var_name = "shamtd" var_names.append(var_name) var_names.reverse() - return var_names @@ -57,86 +59,105 @@ def GetMask(bit_str: str) -> str: return hex(int(mask_str, 2)) -def GetExtension(ext, base): +def process_extension(ext: Union[str, dict]) -> List[str]: + """Process an extension definition into a list of strings.""" + if isinstance(ext, str): + return [ext.lower()] + elif isinstance(ext, dict): + result = [] + for item in ext.values(): + if isinstance(item, list): + result.extend( + [ + x.lower() if isinstance(x, str) else x["name"].lower() + for x in item + ] + ) + elif isinstance(item, (str, dict)): + if isinstance(item, str): + result.append(item.lower()) + else: + result.append(item["name"].lower()) + return result + return [] + + +def GetExtension(ext: Union[str, dict, list], base: str) -> List[str]: + """Get a list of extensions with proper prefix.""" prefix = f"rv{base}_" final_extensions = [] - if isinstance(ext, str): - final_extensions.append(prefix + ext.lower()) - elif isinstance(ext, dict): - for _, extensions in ext.items(): - for extension in extensions: - final_extensions.append(prefix + extension.lower()) - final_extensions.reverse() - - return final_extensions - - -def find_first_match(data): - if isinstance(data, dict): - for key, value in data.items(): - if key == "match": - return value - elif isinstance(value, (dict, list)): - result = find_first_match(value) - if result is not None: - return result - elif isinstance(data, list): - for item in data: - result = find_first_match(item) - if result is not None: - return result - return "" - - -def GetEncodings(enc: str): + if isinstance(ext, (str, dict)): + extensions = process_extension(ext) + final_extensions.extend(prefix + x for x in extensions) + elif isinstance(ext, list): + for item in ext: + extensions = process_extension(item) + final_extensions.extend(prefix + x for x in extensions) + + # Remove duplicates while preserving order + seen = set() + return [x for x in final_extensions if not (x in seen or seen.add(x))] + + +def GetEncodings(enc: str) -> str: n = len(enc) if n < 32: return "-" * (32 - n) + enc return enc -def convert(file_dir: str, json_out): - with open(file_dir) as file: - data = yaml.safe_load(file) - instr_name = data["name"].replace(".", "_") - - print(instr_name) - encodings = data["encoding"] - - # USE RV_64 - rv64_flag = False - if "RV64" in encodings: - encodings = encodings["RV64"] - rv64_flag = True - enc_match = GetEncodings(encodings["match"]) - - var_names = [] - if "variables" in encodings: - var_names = GetVariables(encodings["variables"]) - - extension = [] - prefix = "" - if rv64_flag: - prefix = "64" - if "base" in data: - extension = GetExtension(data["definedBy"], data["base"]) - else: - extension = GetExtension(data["definedBy"], prefix) - - match_hex = BitStringToHex(enc_match) - match_mask = GetMask(enc_match) - - json_out[instr_name] = { - "encoding": enc_match, - "variable_fields": var_names, - "extension": extension, - "match": match_hex, - "mask": match_mask, - } - - -def read_yaml_insts(path: str): +def convert(file_dir: str, json_out: Dict[str, Any]) -> None: + try: + with open(file_dir) as file: + data = yaml.safe_load(file) + instr_name = data["name"].replace(".", "_") + + print(instr_name) + encodings = data["encoding"] + + # USE RV_64 + rv64_flag = False + if "RV64" in encodings: + encodings = encodings["RV64"] + rv64_flag = True + enc_match = GetEncodings(encodings["match"]) + + var_names = [] + if "variables" in encodings: + var_names = GetVariables(encodings["variables"]) + + extension = [] + prefix = "" + if rv64_flag: + prefix = "64" + try: + if "base" in data: + extension = GetExtension(data["definedBy"], data["base"]) + else: + extension = GetExtension(data["definedBy"], prefix) + except Exception as e: + print( + f"Warning: Error processing extensions for {instr_name}: {str(e)}" + ) + extension = [] + + match_hex = BitStringToHex(enc_match) + match_mask = GetMask(enc_match) + + json_out[instr_name] = { + "encoding": enc_match, + "variable_fields": var_names, + "extension": extension, + "match": match_hex, + "mask": match_mask, + } + except Exception as e: + print(f"Error processing file {file_dir}: {str(e)}") + raise + + +def read_yaml_insts(path: str) -> List[str]: yaml_files = [] for root, _, files in os.walk(path): for file in files: @@ -165,13 +186,22 @@ def main(): inst_dict = {} output_file = os.path.join(args.output_dir, "instr_dict.json") - with open(output_file, "w") as outfile: + try: for inst_dir in insts: - convert(inst_dir, inst_dict) - json.dump(inst_dict, outfile, indent=4) - - print(f"Successfully processed {len(insts)} YAML files") - print(f"Output written to: {output_file}") + try: + convert(inst_dir, inst_dict) + except Exception as e: + print(f"Warning: Failed to process {inst_dir}: {str(e)}") + continue + + with open(output_file, "w") as outfile: + json.dump(inst_dict, outfile, indent=4) + + print(f"Successfully processed {len(insts)} YAML files") + print(f"Output written to: {output_file}") + except Exception as e: + print(f"Error: Failed to process YAML files: {str(e)}") + sys.exit(1) if __name__ == "__main__":