Skip to content

Commit

Permalink
Enhance error handling and support for non-default extensions, such a…
Browse files Browse the repository at this point in the history
…s qc_iu

Signed-off-by: Afonso Oliveira <[email protected]>
  • Loading branch information
AFOliveira committed Jan 30, 2025
1 parent 62e0711 commit 2c7c616
Showing 1 changed file with 110 additions and 80 deletions.
190 changes: 110 additions & 80 deletions ext/opcodes_maker/yaml_to_json.py
Original file line number Diff line number Diff line change
@@ -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:
Expand All @@ -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"]
Expand All @@ -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


Expand All @@ -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:
Expand Down Expand Up @@ -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__":
Expand Down

0 comments on commit 2c7c616

Please sign in to comment.