Skip to content

Commit

Permalink
Updates for Virtual Memory coverage functionality and Translator (#551)
Browse files Browse the repository at this point in the history
* add a tip for the translator use

* ignore the venv folder if created here for RISC_V ISAC

* VM functions update, translator minor bugs removed for list expansion and load instructions added in the exception list

* Revert the change for unsigned rs1 to add the previous instructions

---------

Co-authored-by: Umer Shahid <[email protected]>
  • Loading branch information
MuhammadHammad001 and UmerShahidengr authored Nov 7, 2024
1 parent 9c66e51 commit ca8f7a9
Show file tree
Hide file tree
Showing 6 changed files with 168 additions and 79 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@
*.DS_Store

riscv-target/

#ignore venv
riscv-isac/riscv-env
2 changes: 2 additions & 0 deletions riscv-isac/docs/source/cgf.rst
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,8 @@ syntax for the Translator:

Operations can be performed on the *number_placeholder_index* to get the required value. Consider another example:

.. tip:: Use the modulus operator represented by % in python if you want to traverse over the length of the list !!!

.. code-block:: python
csr_comb:
Expand Down
31 changes: 23 additions & 8 deletions riscv-isac/riscv_isac/InstructionObject.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,18 @@ def evaluate_instr_vars(self, xlen, flen, arch_state, csr_regfile, instr_vars):

imm_val = instr_vars.get('imm_val', None)

#update the variable for the length of the load or store:
if self.instr_name in ['ld','lw','lb','lh','sd','sw','sb','sh']:
if self.instr_name in ['ld','sd']:
instr_vars['access_len'] = 8
if self.instr_name in ['lw','sw']:
instr_vars['access_len'] = 4
if self.instr_name in ['lh','sh']:
instr_vars['access_len'] = 2
if self.instr_name in ['lb','sb']:
instr_vars['access_len'] = 1
else:
instr_vars['access_len'] = None
#Update the values for the trap registers
self.trap_registers_update(instr_vars,self.trap_dict)

Expand Down Expand Up @@ -487,21 +499,24 @@ def trap_registers_update(self, instr_vars, trap_dict):
instr_vars['mtval'] = trap_dict['tval']
#only update on the initialization
if "scause" not in instr_vars:
instr_vars['scause'] = '0'
instr_vars['stval'] = '0'
instr_vars['scause'] = None
instr_vars['stval'] = None

elif trap_dict["mode_change"].split()[2] == "S":
instr_vars['scause'] = trap_dict['exc_num']
instr_vars['stval'] = trap_dict['tval']
#only update on the initialization
if "mcause" not in instr_vars:
instr_vars['mcause'] = '0'
instr_vars['mtval'] = '0'
instr_vars['mcause'] = None
instr_vars['mtval'] = None

else:
instr_vars['mcause'] = '0'
instr_vars['mtval'] = '0'
instr_vars['scause'] = '0'
instr_vars['stval'] = '0'
#initialize them to None for the first time in the instr_vars
#reset them to None in case the mode change is ret
instr_vars['mcause'] = None
instr_vars['mtval'] = None
instr_vars['scause'] = None
instr_vars['stval'] = None

return None

Expand Down
81 changes: 44 additions & 37 deletions riscv-isac/riscv_isac/coverage.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,10 @@
940: 'pmpcfg12',
941: 'pmpcfg13',
942: 'pmpcfg14',
943: 'pmpcfg15'
943: 'pmpcfg15',
266: 'senvcfg',
778: 'menvcfg',
1863: 'mseccfg'
}

class cross():
Expand Down Expand Up @@ -571,7 +574,10 @@ def __init__ (self, xlen):
"vxsat": int('009',16),
"fflags":int('1',16),
"frm":int('2',16),
"fcsr":int('3',16)
"fcsr":int('3',16),
"menvcfg":int('30A', 16),
"senvcfg":int('10A', 16),
"mseccfg":int('747', 16)
}
for i in range(16):
self.csr_regs["pmpaddr"+str(i)] = int('3B0',16)+i
Expand Down Expand Up @@ -951,7 +957,10 @@ def compute_per_line(queue, event, cgf_queue, stats_queue, cgf, xlen, flen, addr
#csr regfile track for the previous instruction(old_csr_regfile)
old_csr_regfile = {}
for i in csr_regfile.csr_regs:
old_csr_regfile[i] = int(csr_regfile[i],16)
if isinstance(csr_regfile[i], str):
old_csr_regfile[i] = int(csr_regfile[i],16)
else:
old_csr_regfile[i] = csr_regfile[i]
def old_fn_csr_comb_covpt(csr_reg):
return old_csr_regfile[csr_reg]

Expand All @@ -961,11 +970,11 @@ def old_fn_csr_comb_covpt(csr_reg):
instr.evaluate_instr_vars(xlen, flen, arch_state, csr_regfile, instr_vars)

#update the state of trap registers in csr_reg file using instr_vars
if instr_vars["mode_change"] is not None: #change the state only on the instruction
csr_regfile["mcause"] = instr_vars["mcause"]
csr_regfile["scause"] = instr_vars["scause"]
csr_regfile["mtval"] = instr_vars["mtval"]
csr_regfile["stval"] = instr_vars["stval"]
# if instr_vars["mode_change"] is not None: #change the state only on the instruction
csr_regfile["mcause"] = instr_vars["mcause"]
csr_regfile["scause"] = instr_vars["scause"]
csr_regfile["mtval"] = instr_vars["mtval"]
csr_regfile["stval"] = instr_vars["stval"]

if 'rs1' in instr_vars:
rs1 = instr_vars['rs1']
Expand All @@ -980,8 +989,10 @@ def old_fn_csr_comb_covpt(csr_reg):
is_rd_valid = False

for i in csr_regfile.csr_regs:
instr_vars[i] = int(csr_regfile[i],16)

if isinstance(csr_regfile[i], str):
instr_vars[i] = int(csr_regfile[i],16)
else:
instr_vars[i] = csr_regfile[i]
instr.iptw_update(instr_vars, iptw_dict)
instr.ptw_update(instr_vars)

Expand Down Expand Up @@ -1026,40 +1037,37 @@ def get_pte(pa, pte_addr, pgtb_addr):
else:
return None

def get_pte_prop(prop_name,pa, pte_addr, pgtb_addr):
pte_per = get_pte(pa, pte_addr, pgtb_addr)
if pte_per is not None:
pte_per = get_pte(pa, pte_addr, pgtb_addr) & 0x3FF
prop_name_lower = prop_name.lower()
if prop_name_lower == 'v' and (pte_per & 0x01 != 0):
return 1
elif prop_name_lower == 'r' and (pte_per & 0x02 != 0):
return 1
elif prop_name_lower == 'w' and (pte_per & 0x04 != 0):
return 1
elif prop_name_lower == 'x' and (pte_per & 0x08 != 0):
return 1
elif prop_name_lower == 'u' and (pte_per & 0x10 != 0):
return 1
elif prop_name_lower == 'g' and (pte_per & 0x20 != 0):
return 1
elif prop_name_lower == 'a' and (pte_per & 0x40 != 0):
return 1
elif prop_name_lower == 'd' and (pte_per & 0x80 != 0):
return 1
else:
return 0

def get_pte_prop(prop_name, pte_addr):
'''
Function to return whether a specific Permission is given to the PTE or not
:param prop_name: an input property ., example: 'U' for U bit or 'RWX' for a combination of bits
:param pte_addr: PTE address for which we want to get the information
:type prop_name: str
:type pte_addr: hex/int
: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):
return 0
return 1
else:
return None
return 0

globals()['get_addr'] = check_label_address
globals()['get_mem_val'] = get_mem_val
globals()['get_pte'] = get_pte
globals()['get_pte_prop'] = get_pte_prop

if enable :
print(instr_vars)
ucovpt = []
covpt = []
csr_covpt = []
Expand Down Expand Up @@ -1136,7 +1144,6 @@ def get_pte_prop(prop_name,pa, pte_addr, pgtb_addr):
value['rs3'][rs3] += 1

if 'op_comb' in value and len(value['op_comb']) != 0 :

for coverpoints in value['op_comb']:
if eval(coverpoints, globals(), instr_vars):
if cgf[cov_labels]['op_comb'][coverpoints] == 0:
Expand Down
36 changes: 28 additions & 8 deletions riscv-isac/riscv_isac/plugins/c_sail.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ def setup(self, trace, arch):
instr_pattern_c_sail_csr_reg_val = re.compile('(?P<CSR>CSR|clint::tick)\s(?P<reg>[a-z0-9]+)\s<-\s(?P<val>[0-9xABCDEF]+)(?:\s\(input:\s(?P<input_val>[0-9xABCDEF]+)\))?')
instr_pattern_c_sail_mem_val = re.compile('mem\[(?P<addr>[0-9xABCDEF]+)\]\s<-\s(?P<val>[0-9xABCDEF]+)')
instr_pattern_c_sail_trap = re.compile(r'trapping\sfrom\s(?P<mode_change>\w+\sto\s\w+)\sto\shandle\s(?P<call_type>\w+.*)\shandling\sexc#(?P<exc_num>0x[0-9a-fA-F]+)\sat\spriv\s\w\swith\stval\s(?P<tval>0x[0-9a-fA-F]+)')
instr_pattern_c_sail_ret = re.compile(r'ret-ing\sfrom\s(?P<mode_change>\w+\sto\s\w+)')
def extractInstruction(self, line):
instr_pattern = self.instr_pattern_c_sail
re_search = instr_pattern.search(line)
Expand Down Expand Up @@ -60,6 +61,13 @@ def extractVirtualMemory(self, line):
mem_r_pattern = re.compile(r'mem\[R,([0-9xABCDEF]+)\] -> 0x([0-9xABCDEF]+)')
mem_x_pattern = re.compile(r'mem\[X,([0-9xABCDEF]+)\] -> 0x([0-9xABCDEF]+)')
mem_depa_pattern = re.compile(r'mem\[([0-9xABCDEF]+)\]')
instr_trap_pattern = self.instr_pattern_c_sail_trap.search(line)

#in case of a trap
if instr_trap_pattern:
trap = 1
else:
trap = 0

match_search_mnemonic = self.instr_pattern_c_sail.search(line)
depa, ieva, ieva_align, depa_align, iepa, iepa_align = None, None, None, None, None, None
Expand All @@ -78,14 +86,19 @@ def extractVirtualMemory(self, line):
iptw_list=(mem_r_pattern.findall(line_upper_part))
dptw_list=(mem_r_pattern.findall(line_lower_part))

#Update the data physical address only when there is no trap else it will not be present in the log.
if dptw_list is not None:
if "lw" in match_search_mnemonic.group('mnemonic') and dptw_list:
depa_list=dptw_list.pop()
depa=int(depa_list[0],16)
else:
depa_list=mem_depa_pattern.findall(line_lower_part)
if len(depa_list) != 0:
if trap == 0:
#Since, the load has the same pattern as the page table walk, skip the last one as it is a false positive.
loads_exception_list = {"lw", "ld", "lh", "lb", "lr.w", "lr.d", "lbu", "lhu", "lwu", "c.lw", "c.ld", "c.lwsp", "c.ldsp", "flw", "fld"}
if match_search_mnemonic.group('mnemonic').split()[0] in loads_exception_list and dptw_list:
depa_list=dptw_list.pop()
depa=int(depa_list[0],16)
#Stores and other page table walks are normal
else:
depa_list=mem_depa_pattern.findall(line_lower_part)
if len(depa_list) != 0:
depa=int(depa_list[0],16)

ieva_align = 1 if ieva is not None and ieva & 0b11 == 0 else 0
iepa_align = 1 if iepa is not None and iepa & 0b11 == 0 else 0
Expand Down Expand Up @@ -114,15 +127,22 @@ def extracttrapvals(self, line):
instr_trap_pattern = self.instr_pattern_c_sail_trap.search(line)
trap_dict = {"mode_change": None, "call_type": None, "exc_num": None, "tval": None}

#ret will tell us to delete the previous state of the cause registers
instr_ret_pattern = self.instr_pattern_c_sail_ret.search(line)
if instr_trap_pattern:
trap_dict["mode_change"] = instr_trap_pattern.group("mode_change")
trap_dict["call_type"] = instr_trap_pattern.group("call_type")
trap_dict["exc_num"] = instr_trap_pattern.group("exc_num")
trap_dict["tval"] = instr_trap_pattern.group("tval")
self.old_trap_dict = trap_dict

#maintain the value if None
if instr_trap_pattern is None:
elif instr_ret_pattern:
#if ret_signal is 1 then clear the values of the mode_change, call_type, exc_num, tval
trap_dict = {"mode_change": None, "call_type": None, "exc_num": None, "tval": None}
self.old_trap_dict = trap_dict

#maintain the values if None unit the new trap appears
if instr_trap_pattern is None or instr_ret_pattern is None:
trap_dict = self.old_trap_dict
return trap_dict

Expand Down
Loading

0 comments on commit ca8f7a9

Please sign in to comment.