From b91ed4e58227d0afbd7f5bf531d34f2c2328781a Mon Sep 17 00:00:00 2001 From: MuhammadHammad001 Date: Tue, 21 Jan 2025 19:58:19 +0500 Subject: [PATCH 1/2] Update translator to support multiple macro lists --- .../riscv_isac/plugins/translator_cgf.py | 86 +++++++++++-------- 1 file changed, 48 insertions(+), 38 deletions(-) diff --git a/riscv-isac/riscv_isac/plugins/translator_cgf.py b/riscv-isac/riscv_isac/plugins/translator_cgf.py index b70e91a09..da1dbef70 100644 --- a/riscv-isac/riscv_isac/plugins/translator_cgf.py +++ b/riscv-isac/riscv_isac/plugins/translator_cgf.py @@ -24,9 +24,9 @@ def __init__(self): self.multi_brace_finder = re.compile(r'({\s*{.*?}.*?})') self.macro_def_finder = re.compile(r'(\${.*?})') # ${variable}To ignore any such definition self.number_brace_finder = re.compile(r'(\$\d+)') # $1 - self.macro_brace_resolver = re.compile(r'(\%\d+)') # + self.macro_brace_resolver = re.compile(r'(\%\d+)') # self.repeat_brace_index = re.compile(r'(\*\d+)') - self.list_brace_finder = re.compile(r'\{([^}]*)\}\{(\[[^\]]+\])\}') + self.list_brace_finder = re.compile(r'\{((?:\s*\$\{[\w\d_]+\}\s*,?)*|[^}]*)\}\{(\[[^\]]+\])\}') self.list_with_index_finder = re.compile(r'\{(?:\s*\$\{[\w\d]+\}\s*,?)*\}\{\[\$[\w\d]+\]\}') self.list_index_brace_finder = re.compile(r'(\{\[.*?\]\})') self.list_index_number_finder = re.compile(r'(\<\<[^>]*\>\>\{\[[^\]]+\]\})') @@ -36,7 +36,7 @@ def __init__(self): def translate_using_path(self, input_path, output_path): """Translate YAML data from the input file and dump it into the output file. - + Args: input_path (str): Path to the input YAML file. output_path (str): Path to save the translated YAML data. @@ -47,7 +47,7 @@ def translate_using_path(self, input_path, output_path): def translate(self, loaded_cgf): """Translate YAML data from the input cgf and return the translated_cgf. - + Args: input_path (str): Loaded cgf. """ @@ -145,7 +145,7 @@ def finder(self, curr_cov, label): # Resolve the comma separated self.resolve_comma_brace(self.replacement_dict) - # Resolve list-braces + # Resolve list-braces self.resolve_list_braces(self.replacement_dict) # Substitute the values in the coverpoint @@ -181,14 +181,14 @@ def replace_macros(self, instr): if len(list_with_index) != 0: for index, values in enumerate(list_with_index): instr = instr.replace(values, f'<>') - + #Find the other macros inside the instr macros = self.macro_def_finder.findall(instr) macro_dict = {macro: f'<>' for index, macro in enumerate(macros)} instr, replacements = self.replace_using_dict(instr, macro_dict) self.replacement_dict.update(replacements) - #replace the Temp replacement back with the actual list + #replace the Temp replacement back with the actual list temp_replacement_finds = self.temp_replacement_finder.findall(instr) if len(temp_replacement_finds) != 0: @@ -196,7 +196,7 @@ def replace_macros(self, instr): instr = instr.replace(f'<>', values) return instr - + def replace_multibraces(self, instr): """ Replace multibraces in the instruction with placeholders. @@ -247,7 +247,7 @@ def replace_braces_commas(self, instr): instr, replacements = self.replace_using_dict(instr, {**comma_dict, **single_dict}) self.replacement_dict.update(replacements) return instr - + def replace_number_placeholders(self, instr): """ Replace $number placeholders in the instruction string with unique placeholders. @@ -283,21 +283,18 @@ def replace_list_braces(self, instr): """ #This pattern includes all the normal pattern inside the list list_braces_pattern_anything = self.list_brace_finder.findall(instr) - #This pattern checks the all macros pattern inside the list - list_macros_braces_pattern = re.compile(r'\{((?:\s*\$\{[\w\d]+\}\s*,?)*)\}\{(\[\$[\w\d]+\])\}') - list_braces_pattern_macros = list_macros_braces_pattern.findall(instr) + list_braces = [] + #This pattern checks the all macros pattern inside the list if len(list_braces_pattern_anything) != 0: - list_braces = list_braces_pattern_anything - else: - list_braces = list_braces_pattern_macros + list_braces= list_braces_pattern_anything replacements = {} for index, brace in enumerate(list_braces): - brace_content, brace_index = brace[0], brace[1] placeholder_brace = f'<>' + instr = instr.replace(f'{{{brace_content}}}', placeholder_brace) # Check if the placeholders already exist in replacements @@ -306,7 +303,7 @@ def replace_list_braces(self, instr): # Update the replacement dictionary self.replacement_dict.update(replacements) - # print("instr after list", instr) + return instr @@ -407,10 +404,10 @@ def resolve_multibraces(self, replacement_dict): raise ValueError(f"No operation found for key {val}!") else: raise ValueError(f"Range pattern not found in the value for key {val}.") - + self.replacement_dict = replacement_dict - + def resolve_comma_brace(self, replacement_dict): """ Resolve comma-separated values in the replacement dictionary. @@ -436,6 +433,14 @@ def resolve_comma_brace(self, replacement_dict): self.replacement_dict = replacement_dict + ''' + Resolve Lists {val1, val2, ..., valn} or in the format {val1, val2, ..., valn}{[$m]} + -> replaces back the values using the replacement dict. + Logic: Get a instr. then resolve the above format and generate new instrs. depending upon the format. + + Returns: + resolved expanded list. + ''' def resolve_lists(self, instr_lst, replacement_dict, place_holder_pattern): number_pattern = re.compile(r'\d+') return_instr_lst = [] @@ -443,22 +448,27 @@ def resolve_lists(self, instr_lst, replacement_dict, place_holder_pattern): for instr in instr_lst: req_element_list = [] list_index_matches = self.list_index_brace_finder.findall(instr) - resolved_list_index = self.list_index_resolver(list_index_matches) + resolved_list_index = self.list_index_resolver(list_index_matches) + i = 0 for index, (key, val) in enumerate(replacement_dict.items()): if "LIST" in key: - req_element_list.append(val[resolved_list_index[0]]) - #Replace the list index with No space + req_element_list.append(val[resolved_list_index[i]]) + i +=1 + + #Replace the position where list index -> {[$]} is located with empty string. for index, val in enumerate(req_element_list): if list_index_matches[index] in instr: instr = instr.replace(list_index_matches[index], "") temp_element_dict = {} + i = 0 for index, (key, val) in enumerate(replacement_dict.items()): if "LIST" in key: - temp_element_dict[key] = req_element_list[0] - instr = instr.replace(key, req_element_list[0]) - + temp_element_dict[key] = req_element_list[i] + instr = instr.replace(key, req_element_list[i]) + i +=1 + for (key, val) in replacement_dict.items(): if "NUMBER" in key: result = number_pattern.findall(val) @@ -466,7 +476,7 @@ def resolve_lists(self, instr_lst, replacement_dict, place_holder_pattern): var = place_holder_pattern[result] if "LIST" in var: instr = instr.replace(key, temp_element_dict[var]) - + return_instr_lst.append(instr) return return_instr_lst @@ -478,7 +488,7 @@ def loop_controller(self, instr, replacement_dict, place_holder_pattern): req_fn_list = [] gen_cov_list.append(instr) - + #In case of only macro is present if len(placeholders) == 0: track_dict = {} @@ -488,7 +498,7 @@ def loop_controller(self, instr, replacement_dict, place_holder_pattern): for curr_resolve in placeholders: #create a req_fn_list which will help in resolving the Number placeholder req_fn_list = [placeholders[current_cov_track]] - #always include MULTI_INTER as it is not explicitly present in the instr + #always include MULTI_INTER as it is not explicitly present in the instr for value in place_holder_pattern: if "MULTI_INTER" in value: req_fn_list.append(value) @@ -505,16 +515,16 @@ def loop_controller(self, instr, replacement_dict, place_holder_pattern): #Append the completed generated coverpoint list to the final_cov_list final_cov_list.extend(gen_cov_list) - + #Resolve the lists when everything is solved - final_cov_list = self.resolve_lists(final_cov_list, replacement_dict, place_holder_pattern) + final_cov_list = self.resolve_lists(final_cov_list, replacement_dict, place_holder_pattern) #Call the generator function after creating all the coverpoints for coverpoint in final_cov_list: self.generator(self.curr_cov, self.label, f"{coverpoint}", 1) - + @@ -533,7 +543,7 @@ def calculate_coverpoints(self, instr, replacement_dict, place_holder_pattern, r # Create a Track Dictionary of the current variables track_dict = {} # Populate the dictionary with the proper indexes | only the req_fn_list - track_dict = self.initialize_track_dict(track_dict, replacement_dict) + track_dict = self.initialize_track_dict(track_dict, replacement_dict) #required length of the coverpoints -> defined by the req_fn_list max_len = len(replacement_dict[req_fn_list[0]]) @@ -541,7 +551,7 @@ def calculate_coverpoints(self, instr, replacement_dict, place_holder_pattern, r gen_cov_list = [] for _ in range(max_len): - + # Generate coverpoint for current track out_cov = self.generate_current_cov(instr, track_dict, replacement_dict, place_holder_pattern, req_fn_list) @@ -549,7 +559,7 @@ def calculate_coverpoints(self, instr, replacement_dict, place_holder_pattern, r track_dict = self.update_replacement_dict(track_dict) gen_cov_list.append(out_cov) - + return gen_cov_list def generate_current_cov(self, instr, track_dict, replacement_dict, place_holder_pattern, req_fn_list): @@ -625,7 +635,7 @@ def generate_current_cov(self, instr, track_dict, replacement_dict, place_holder for key, val in replacement_dict.items(): if "MACRO" in key: instr = instr.replace(key, val) - + return instr def generator(self, curr_cov, label, line, rule): @@ -666,7 +676,7 @@ def replace_using_dict(self, instr, replace_dict): """ if not replace_dict: return instr, {} - + replacements = {} def replace(match): replacement = replace_dict[match.group(0)] @@ -687,7 +697,7 @@ def replace_order_pattern(self, instr): """ placeholders = self.placeholder_pattern.findall(instr) sorted_placeholders = sorted(placeholders, key=lambda x: instr.index(x)) - + # Create a new list to store the modified order of placeholders modified_placeholders = [] @@ -716,7 +726,7 @@ def initialize_track_dict(self, track_dict, replacement_dict): for key, val in replacement_dict.items(): if isinstance(val, list): start_index, end_index, curr_index = 0, len(val), 0 - track_dict[key] = [start_index, end_index, curr_index] + track_dict[key] = [start_index, end_index, curr_index] return track_dict From 26629956d406120fc5b14424a0232989159b8b19 Mon Sep 17 00:00:00 2001 From: MuhammadHammad001 Date: Tue, 21 Jan 2025 20:04:38 +0500 Subject: [PATCH 2/2] pmp_rgn_check function added --- riscv-isac/riscv_isac/coverage.py | 49 +++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/riscv-isac/riscv_isac/coverage.py b/riscv-isac/riscv_isac/coverage.py index 76866d9e1..7b4bbf3e3 100644 --- a/riscv-isac/riscv_isac/coverage.py +++ b/riscv-isac/riscv_isac/coverage.py @@ -643,7 +643,7 @@ def __init__ (self, xlen, flen,inxFlg): self.fcsr = 0 elif flen == 32: self.f_rf = ['00000000']*32 - + else: self.f_rf = ['0000000000000000']*32 self.pc = 0 @@ -1049,11 +1049,11 @@ def get_pte_prop(prop_name, pte_addr): :return: 1 or 0 depending whether the specific (or combination of) permission/s is set or not respectively. ''' bitmask_dict = {'v': 0x01, 'r': 0x02, 'w': 0x04, 'x': 0x08, 'u': 0x10, 'g': 0x20, 'a': 0x40, 'd': 0x80} - + if pte_addr is not None: # Get the permissions bit out of the pte_addr pte_per = pte_addr & 0x3FF - + # Check each character in prop_name for char in prop_name.lower(): if char in bitmask_dict and (pte_per & bitmask_dict[char] == 0): @@ -1062,10 +1062,53 @@ def get_pte_prop(prop_name, pte_addr): else: return 0 + def pmp_rgn_chk(req_addr, access_len, pmp_config, pmp_addr, prev_pmp_addr = None): + """ + Function to check whether the requested address is inside the required setup pmpaddr entry. + + :param req_addr: value for the requested addrress (int or hex). + :param access_len: For instance, 1 for lb, 2 for lh and ... + :param pmp_config: Selected PMP Configuration for that region. i.e., TOR, NA4, NAPOT + :param pmp_addr: pmpaddr csr value to examine (int or hex). + :param prev_pmp_addr: prev pmpaddr csr value to examine required in case of TOR (int or hex). + + :return: True if conditions are met, False otherwise. + """ + + #Skip the not required cases. + if pmp_addr is None or access_len is None: + return False + + #Implementation credits: Sail RISC-V Golden Reference Model. + if pmp_config == "NAPOT": + mask = pmp_addr ^ (pmp_addr + 1) + lo = pmp_addr & (~(mask)) + length = mask + 1 + #requested address is above the minimum and below the maximum + access_len. + #Here, we are giving relaxation of access_len + max because we have to verify cases + #in which we are crossing the boundary as well upto the access len (for instance, 8 Bytes in case of ld). + return (req_addr) >= (lo*4) and (req_addr + access_len) < (((lo + length)*4) + access_len) + + elif pmp_config == "TOR": + if prev_pmp_addr is None: + raise ValueError("The 'prev_pmp_addr' argument is required when 'TOR' is selected.") + else: + return (req_addr) >= prev_pmp_addr*4 and (req_addr + access_len) < (pmp_addr*4 + access_len) + + elif pmp_config == "NA4": + return (req_addr) >= pmp_addr and (req_addr + access_len) < (pmp_addr*4 + 4) + access_len + + elif pmp_config == "OFF": + return False + else: + raise ValueError("PMP Config is not selected properly. Select b/w NA4, NAPOT, TOR only") + globals()['get_addr'] = check_label_address + globals()['old_csr_val'] = old_fn_csr_comb_covpt globals()['get_mem_val'] = get_mem_val globals()['get_pte'] = get_pte globals()['get_pte_prop'] = get_pte_prop + globals()['pmp_rgn_chk'] = pmp_rgn_chk if enable : ucovpt = []