|
| 1 | +from typing import List, Dict |
| 2 | +import os |
| 3 | +import yaml |
| 4 | +import json |
| 5 | + |
| 6 | + |
| 7 | +def range_size(range_str: str) -> int: |
| 8 | + try: |
| 9 | + end, start = map(int, range_str.split('-')) |
| 10 | + return abs(end - start) + 1 |
| 11 | + except ValueError: |
| 12 | + return 0; |
| 13 | + |
| 14 | +reg_names = {'qs1', 'qs2', 'qd', |
| 15 | + 'fs1', 'fs2', 'fd'} |
| 16 | + |
| 17 | +def GetVariables(vars: List[Dict[str, str]]): |
| 18 | + var_names = [] |
| 19 | + for var in vars: |
| 20 | + var_name = var['name'] |
| 21 | + if var_name in reg_names: |
| 22 | + # Since strings are immutable. |
| 23 | + lst_var_name = list(var_name) |
| 24 | + lst_var_name[0] = 'r' |
| 25 | + var_name = "".join(lst_var_name) |
| 26 | + elif var_name == "shamt": |
| 27 | + size = range_size(var['location']) |
| 28 | + if size == 5: |
| 29 | + var_name = "shamtw" |
| 30 | + elif size == 6: |
| 31 | + var_name = "shamtd" |
| 32 | + var_names.append(var_name) |
| 33 | + var_names.reverse() |
| 34 | + |
| 35 | + return var_names |
| 36 | + |
| 37 | +def BitStringToHex(bit_str: str) -> str: |
| 38 | + new_bit_str = "" |
| 39 | + for bit in bit_str: |
| 40 | + if bit == '-': |
| 41 | + new_bit_str += '0' |
| 42 | + else: |
| 43 | + new_bit_str += bit |
| 44 | + return hex(int(new_bit_str, 2)) |
| 45 | + |
| 46 | +def GetMask(bit_str: str) -> str: |
| 47 | + mask_str = "" |
| 48 | + for bit in bit_str: |
| 49 | + if bit == '-': |
| 50 | + mask_str += '0' |
| 51 | + else: |
| 52 | + mask_str += '1' |
| 53 | + return hex(int(mask_str, 2)) |
| 54 | + |
| 55 | +def GetExtension(ext, base): |
| 56 | + prefix = f'rv{base}_' |
| 57 | + final_extensions = [] |
| 58 | + |
| 59 | + if isinstance(ext, str): |
| 60 | + final_extensions.append(prefix + ext.lower()) |
| 61 | + elif isinstance(ext, dict): |
| 62 | + for _, extensions in ext.items(): |
| 63 | + for extension in extensions: |
| 64 | + final_extensions.append(prefix + extension.lower()) |
| 65 | + final_extensions.reverse() |
| 66 | + |
| 67 | + return final_extensions |
| 68 | + |
| 69 | +def find_first_match(data): |
| 70 | + if isinstance(data, dict): |
| 71 | + for key, value in data.items(): |
| 72 | + if key == "match": |
| 73 | + return value |
| 74 | + elif isinstance(value, (dict, list)): |
| 75 | + result = find_first_match(value) |
| 76 | + if result is not None: |
| 77 | + return result |
| 78 | + elif isinstance(data, list): |
| 79 | + for item in data: |
| 80 | + result = find_first_match(item) |
| 81 | + if result is not None: |
| 82 | + return result |
| 83 | + return "" |
| 84 | + |
| 85 | +def GetEncodings(enc: str): |
| 86 | + n = len(enc) |
| 87 | + if n < 32: |
| 88 | + return '-' * (32-n) + enc |
| 89 | + return enc |
| 90 | + |
| 91 | +def convert(file_dir: str, json_out): |
| 92 | + with open(file_dir, 'r') as file: |
| 93 | + data = yaml.safe_load(file) |
| 94 | + instr_name = data['name'].replace('.', '_') |
| 95 | + |
| 96 | + print(instr_name) |
| 97 | + encodings = data['encoding'] |
| 98 | + |
| 99 | + # USE RV_64 |
| 100 | + rv64_flag = False |
| 101 | + if 'RV64' in encodings: |
| 102 | + encodings = encodings['RV64'] |
| 103 | + rv64_flag = True |
| 104 | + enc_match = GetEncodings(encodings['match']) |
| 105 | + |
| 106 | + var_names = [] |
| 107 | + if 'variables' in encodings: |
| 108 | + var_names = GetVariables(encodings['variables']) |
| 109 | + |
| 110 | + extension = [] |
| 111 | + prefix = "" |
| 112 | + if rv64_flag: |
| 113 | + prefix = "64" |
| 114 | + if "base" in data: |
| 115 | + extension = GetExtension(data["definedBy"], data["base"]) |
| 116 | + else: |
| 117 | + extension = GetExtension(data["definedBy"], prefix) |
| 118 | + |
| 119 | + match_hex = BitStringToHex(enc_match) |
| 120 | + match_mask = GetMask(enc_match) |
| 121 | + |
| 122 | + json_out[instr_name] = { |
| 123 | + "encoding": enc_match, |
| 124 | + "variable_fields": var_names, |
| 125 | + "extension": extension, |
| 126 | + "match": match_hex, |
| 127 | + "mask": match_mask |
| 128 | + } |
| 129 | + |
| 130 | +def read_yaml_insts(path: str): |
| 131 | + yaml_files = [] |
| 132 | + for root, _, files in os.walk(path): |
| 133 | + for file in files: |
| 134 | + if file.endswith('.yaml') or file.endswith('.yml'): |
| 135 | + yaml_files.append(os.path.join(root, file)) |
| 136 | + return yaml_files |
| 137 | + |
| 138 | +def main(): |
| 139 | + directory = "../arch/inst/" |
| 140 | + insts = read_yaml_insts(directory) |
| 141 | + |
| 142 | + inst_dict = {} |
| 143 | + with open('data.json', 'w') as outfile: |
| 144 | + for inst_dir in insts: |
| 145 | + convert(inst_dir, inst_dict) |
| 146 | + json.dump(inst_dict, outfile, indent=4) |
| 147 | +main() |
| 148 | + |
0 commit comments