Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ISAC] Translator Update and PMP Region Check Function Support #604

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 46 additions & 3 deletions riscv-isac/riscv_isac/coverage.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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):
Expand All @@ -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 = []
Expand Down
86 changes: 48 additions & 38 deletions riscv-isac/riscv_isac/plugins/translator_cgf.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'(\<\<[^>]*\>\>\{\[[^\]]+\]\})')
Expand All @@ -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.
Expand All @@ -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.
"""
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -181,22 +181,22 @@ def replace_macros(self, instr):
if len(list_with_index) != 0:
for index, values in enumerate(list_with_index):
instr = instr.replace(values, f'<<TEMP_REPLACEMENT{index}>>')

#Find the other macros inside the instr
macros = self.macro_def_finder.findall(instr)
macro_dict = {macro: f'<<MACRO{index}>>' 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:
for index, values in enumerate(list_with_index):
instr = instr.replace(f'<<TEMP_REPLACEMENT{index}>>', values)

return instr

def replace_multibraces(self, instr):
"""
Replace multibraces in the instruction with placeholders.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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'<<LIST{index}>>'

instr = instr.replace(f'{{{brace_content}}}', placeholder_brace)

# Check if the placeholders already exist in replacements
Expand All @@ -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


Expand Down Expand Up @@ -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.
Expand All @@ -436,37 +433,50 @@ 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 = []

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)
result = int(result[0]) -1
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

Expand All @@ -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 = {}
Expand All @@ -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)
Expand All @@ -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)





Expand All @@ -533,23 +543,23 @@ 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]])

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)

# Update the state of the track_dict
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):
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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)]
Expand All @@ -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 = []

Expand Down Expand Up @@ -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

Expand Down