Skip to content
This repository has been archived by the owner on Nov 4, 2024. It is now read-only.

Commit

Permalink
Merge pull request #2 from xueliangh/P-Extension
Browse files Browse the repository at this point in the history
P-extension PR RISCV-ISAC
  • Loading branch information
neelgala authored Jan 8, 2022
2 parents 94e62c9 + 130d7bc commit 8abfa33
Show file tree
Hide file tree
Showing 8 changed files with 758 additions and 36 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.9.0] - 2022-01-07
- Added support for P extension cover point generation and instruction decoding.
- Allowed an instruction to generate results in multiple registers.

## [0.8.0] - 2021-10-30
- Added cross combination coverage support.

Expand Down
8 changes: 7 additions & 1 deletion riscv_isac/InstructionObject.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ def __init__(
self.reg_commit = reg_commit
self.csr_commit = csr_commit
self.mnemonic = mnemonic
self.is_rvp = False
self.rs1_nregs = 1
self.rs2_nregs = 1
self.rs3_nregs = 1
self.rd_nregs = 1


def __str__(self):
line = 'instr: '+ str(self.instr)+ ' addr: '+ str(hex(self.instr_addr)) +' instr_name: '+ str(self.instr_name)
Expand Down Expand Up @@ -92,4 +98,4 @@ def __str__(self):
line+= ' csr_commit: '+ str(self.csr_commit)
if self.mnemonic:
line+= ' mnemonic: '+ str(self.mnemonic)
return line
return line
2 changes: 1 addition & 1 deletion riscv_isac/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@

__author__ = """InCore Semiconductors Pvt Ltd"""
__email__ = '[email protected]'
__version__ = '0.8.0'
__version__ = '0.9.0'
68 changes: 67 additions & 1 deletion riscv_isac/cgf_normalize.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,72 @@ def twos(val,bits):
val = val - (1 << bits)
return val

def simd_val_comb(xlen, bit_width, signed=True):
if type(bit_width)==tuple:
bit_width1, bit_width2 = bit_width
else:
bit_width1, bit_width2 = bit_width, bit_width

fmt = {8: 'b', 16: 'h', 32: 'w', 64: 'd'}
sz1 = fmt[bit_width1]
sz2 = fmt[bit_width2]
var_num = xlen//bit_width1
coverpoints = []
for i in range(var_num):
var1 = f'rs1_{sz1}{i}_val'
var2 = f'rs2_{sz2}{i}_val'
if (signed):
coverpoints += [(f'{var1} > 0 and {var2} > 0','simd_val_comb')]
coverpoints += [(f'{var1} > 0 and {var2} < 0','simd_val_comb')]
coverpoints += [(f'{var1} < 0 and {var2} < 0','simd_val_comb')]
coverpoints += [(f'{var1} < 0 and {var2} > 0','simd_val_comb')]
coverpoints += [(f'{var1} == {var2}','simd_val_comb')]
coverpoints += [(f'{var1} != {var2}','simd_val_comb')]
else:
coverpoints += [(f'{var1} == {var2} and {var1} > 0 and {var2} > 0','simd_val_comb')]
coverpoints += [(f'{var1} != {var2} and {var1} > 0 and {var2} > 0','simd_val_comb')]

return coverpoints

def simd_base_val(rs, xlen, _bit_width, signed=True):
fmt = {8: 'b', 16: 'h', 32: 'w', 64: 'd'}

if type(_bit_width)==tuple:
if (rs=="rs1"):
bit_width, not_used = _bit_width
else:
not_used, bit_width = _bit_width
else:
bit_width, not_used = _bit_width, _bit_width

sz = fmt[bit_width]
var_num = xlen//bit_width
sign_val = [(-2**(bit_width-1)), -1, 0, 1, int((2**(bit_width-1)-1))]
usign_val = [0, 1, 2**bit_width-2, 2**bit_width-1]
coverpoints = []
for i in range(var_num):
var = f'{rs}_{sz}{i}_val'
if (signed):
for val in sign_val:
coverpoints += [(f'{var} == {val}', 'signed_min_max_middle')]
coverpoints += walking_ones(var, bit_width, True)
coverpoints += walking_zeros(var, bit_width, True)
coverpoints += alternate(var, bit_width, True)
else:
for val in usign_val:
coverpoints += [(f'{var} == {val}','unsigned_min_max_middle')]
coverpoints += walking_ones(var, bit_width, False)
coverpoints += walking_zeros(var, bit_width, False)
coverpoints += alternate(var, bit_width, False)
return coverpoints

def simd_imm_val(imm, bit_width):
usign_val = (2**(bit_width))
coverpoints = []
for i in range(usign_val):
coverpoints += [(f'{imm} == {i}','simd_imm_val')]
return coverpoints

def sp_vals(bit_width,signed):
if signed:
conv_func = lambda x: twos(x,bit_width)
Expand All @@ -36,7 +102,6 @@ def sp_vals(bit_width,signed):
sqrt_min = 0
sqrt_max = int(sqrt((2**bit_width)-1))
conv_func = lambda x: (int(x,16) if '0x' in x else int(x,2)) if isinstance(x,str) else x

dataset = [3, "0x"+"".join(["5"]*int(bit_width/4)), "0x"+"".join(["a"]*int(bit_width/4)), 5, "0x"+"".join(["3"]*int(bit_width/4)), "0x"+"".join(["6"]*int(bit_width/4))]
dataset = list(map(conv_func,dataset)) + [int(sqrt(abs(conv_func("0x8"+"".join(["0"]*int((bit_width/4)-1)))))*(-1 if signed else 1))] + [sqrt_min,sqrt_max]
return dataset + [x - 1 if x>0 else 0 for x in dataset] + [x+1 for x in dataset]
Expand Down Expand Up @@ -436,6 +501,7 @@ def expand_cgf(cgf_files, xlen):
if 'abstract_comb' in node:
temp = node['abstract_comb']
del node['abstract_comb']

for coverpoints, coverage in temp.items():
i = 0
try:
Expand Down
136 changes: 106 additions & 30 deletions riscv_isac/coverage.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ def __init__ (self, xlen, flen):
else:
self.f_rf = ['0000000000000000']*32
self.fcsr = 0
self.vxsat = 0
self.pc = 0

class statistics:
Expand Down Expand Up @@ -465,6 +466,46 @@ def twos_complement(val,bits):
val = val - (1 << bits)
return val

def simd_val_unpack(val_comb, op_width, op_name, val, local_dict):
'''
This function unpacks `val` into its simd elements.
:param val_comb: val_comb from the cgf dictionary
:param op_name: name of the operand (rs1/rs2)
:param val: operand value
:param local_dict: locals() of the calling context
'''
simd_size = op_width
simd_sgn = False
for coverpoints in val_comb:
if f"{op_name}_b0_val" in coverpoints:
simd_size = 8
if f"{op_name}_h0_val" in coverpoints:
simd_size = 16
if f"{op_name}_w0_val" in coverpoints:
simd_size = 32
if op_name in coverpoints:
if any([s in coverpoints for s in ["<", "== -", "== (-"]]):
simd_sgn = True

fmt = {8: 'b', 16: 'h', 32: 'w', 64: 'd'}
sz = fmt[simd_size]

if simd_size > op_width:
return

elm_urange = 1<<simd_size
elm_mask = elm_urange-1
elm_msb_mask = (1<<(simd_size-1))
for i in range(op_width//simd_size):
elm_val = (val >> (i*simd_size)) & elm_mask
if simd_sgn and (elm_val & elm_msb_mask) != 0:
elm_val = elm_val - elm_urange
local_dict[f"{op_name}_{sz}{i}_val"]=elm_val
if simd_size == op_width:
local_dict[f"{op_name}_val"]=elm_val

def compute_per_line(instr, cgf, xlen, addr_pairs, sig_addrs):
'''
This function checks if the current instruction under scrutiny matches a
Expand All @@ -484,6 +525,7 @@ def compute_per_line(instr, cgf, xlen, addr_pairs, sig_addrs):
global arch_state
global csr_regfile
global stats
global result_count

mnemonic = instr.mnemonic
commitvalue = instr.reg_commit
Expand Down Expand Up @@ -547,6 +589,11 @@ def compute_per_line(instr, cgf, xlen, addr_pairs, sig_addrs):
# special value conversion based on signed/unsigned operations
if instr.instr_name in unsgn_rs1:
rs1_val = struct.unpack(unsgn_sz, bytes.fromhex(arch_state.x_rf[rs1]))[0]
elif instr.is_rvp:
rs1_val = struct.unpack(unsgn_sz, bytes.fromhex(arch_state.x_rf[rs1]))[0]
if instr.rs1_nregs == 2:
rs1_hi_val = struct.unpack(unsgn_sz, bytes.fromhex(arch_state.x_rf[rs1+1]))[0]
rs1_val = (rs1_hi_val << 32) | rs1_val
elif rs1_type == 'x':
rs1_val = struct.unpack(sgn_sz, bytes.fromhex(arch_state.x_rf[rs1]))[0]
if instr.instr_name in ["fmv.w.x"]:
Expand All @@ -558,13 +605,31 @@ def compute_per_line(instr, cgf, xlen, addr_pairs, sig_addrs):

if instr.instr_name in unsgn_rs2:
rs2_val = struct.unpack(unsgn_sz, bytes.fromhex(arch_state.x_rf[rs2]))[0]
elif instr.is_rvp:
rs2_val = struct.unpack(unsgn_sz, bytes.fromhex(arch_state.x_rf[rs2]))[0]
if instr.rs2_nregs == 2:
rs2_hi_val = struct.unpack(unsgn_sz, bytes.fromhex(arch_state.x_rf[rs2+1]))[0]
rs2_val = (rs2_hi_val << 32) | rs2_val
elif rs2_type == 'x':
rs2_val = struct.unpack(sgn_sz, bytes.fromhex(arch_state.x_rf[rs2]))[0]
elif rs2_type == 'f':
rs2_val = struct.unpack(sgn_sz, bytes.fromhex(arch_state.f_rf[rs2]))[0]
if instr.instr_name in ["fadd.s","fsub.s","fmul.s","fdiv.s","fmadd.s","fmsub.s","fnmadd.s","fnmsub.s","fmax.s","fmin.s","feq.s","flt.s","fle.s","fsgnj.s","fsgnjn.s","fsgnjx.s"]:
rs2_val = '0x' + (arch_state.f_rf[rs2]).lower()

sig_update = False
if instr.instr_name in ['sh','sb','sw','sd','c.sw','c.sd','c.swsp','c.sdsp'] and sig_addrs:
store_address = rs1_val + imm_val
for start, end in sig_addrs:
if store_address >= start and store_address <= end:
sig_update = True
break

if sig_update: # writing result operands of last non-store instruction to the signature region
result_count = result_count - 1
else:
result_count = instr.rd_nregs

if instr.instr_name in ["fmadd.s","fmsub.s","fnmadd.s","fnmsub.s"]:
rs3_val = '0x' + (arch_state.f_rf[rs3]).lower()

Expand Down Expand Up @@ -704,8 +769,15 @@ def compute_per_line(instr, cgf, xlen, addr_pairs, sig_addrs):
stats.covpt.append(str(val_key[0]))
cgf[cov_labels]['val_comb'][val_key[0]] += 1
else:
lcls=locals().copy()
if instr.is_rvp and "rs1" in value:
op_width = 64 if instr.rs1_nregs == 2 else xlen
simd_val_unpack(value['val_comb'], op_width, "rs1", rs1_val, lcls)
if instr.is_rvp and "rs2" in value:
op_width = 64 if instr.rs2_nregs == 2 else xlen
simd_val_unpack(value['val_comb'], op_width, "rs2", rs2_val, lcls)
for coverpoints in value['val_comb']:
if eval(coverpoints):
if eval(coverpoints, globals(), lcls):
if cgf[cov_labels]['val_comb'][coverpoints] == 0:
stats.ucovpt.append(str(coverpoints))
stats.covpt.append(str(coverpoints))
Expand Down Expand Up @@ -753,35 +825,37 @@ def compute_per_line(instr, cgf, xlen, addr_pairs, sig_addrs):
logger.debug('Signature update : ' + str(hex(store_address)))
stats.stat5.append((store_address, store_val, stats.ucovpt, stats.code_seq))
stats.cov_pt_sig += stats.covpt
if stats.ucovpt:
stats.stat1.append((store_address, store_val, stats.ucovpt, stats.ucode_seq))
stats.last_meta = [store_address, store_val, stats.ucovpt, stats.ucode_seq]
stats.ucovpt = []
elif stats.covpt:
_log = 'Op without unique coverpoint updates Signature\n'
_log += ' -- Code Sequence:\n'
for op in stats.code_seq:
_log += ' ' + op + '\n'
_log += ' -- Signature Address: {0} Data: {1}\n'.format(
str(hex(store_address)), store_val)
_log += ' -- Redundant Coverpoints hit by the op\n'
for c in stats.covpt:
_log += ' - ' + str(c) + '\n'
logger.warn(_log)
stats.stat2.append(_log + '\n\n')
stats.last_meta = [store_address, store_val, stats.covpt, stats.code_seq]
else:
_log = 'Last Coverpoint : ' + str(stats.last_meta[2]) + '\n'
_log += 'Last Code Sequence : \n\t-' + '\n\t-'.join(stats.last_meta[3]) + '\n'
_log +='Current Store : [{0}] : {1} -- Store: [{2}]:{3}\n'.format(\
str(hex(instr.instr_addr)), mnemonic,
str(hex(store_address)),
store_val)
logger.error(_log)
stats.stat4.append(_log + '\n\n')
stats.covpt = []
stats.code_seq = []
stats.ucode_seq = []
if result_count <= 0:
if stats.ucovpt:
stats.stat1.append((store_address, store_val, stats.ucovpt, stats.ucode_seq))
stats.last_meta = [store_address, store_val, stats.ucovpt, stats.ucode_seq]
stats.ucovpt = []
elif stats.covpt:
_log = 'Op without unique coverpoint updates Signature\n'
_log += ' -- Code Sequence:\n'
for op in stats.code_seq:
_log += ' ' + op + '\n'
_log += ' -- Signature Address: {0} Data: {1}\n'.format(
str(hex(store_address)), store_val)
_log += ' -- Redundant Coverpoints hit by the op\n'
for c in stats.covpt:
_log += ' - ' + str(c) + '\n'
logger.warn(_log)
stats.stat2.append(_log + '\n\n')
stats.last_meta = [store_address, store_val, stats.covpt, stats.code_seq]
else:
_log = 'Last Coverpoint : ' + str(stats.last_meta[2]) + '\n'
_log += 'Last Code Sequence : \n\t-' + '\n\t-'.join(stats.last_meta[3]) + '\n'
_log +='Current Store : [{0}] : {1} -- Store: [{2}]:{3}\n'.format(\
str(hex(instr.instr_addr)), mnemonic,
str(hex(store_address)),
store_val)
logger.error(_log)
stats.stat4.append(_log + '\n\n')

stats.covpt = []
stats.code_seq = []
stats.ucode_seq = []



Expand All @@ -808,6 +882,7 @@ def compute(trace_file, test_name, cgf, parser_name, decoder_name, detailed, xle
global csr_regfile
global stats
global cross_cover_queue
global result_count

temp = cgf.copy()
if cov_labels:
Expand All @@ -826,6 +901,7 @@ def compute(trace_file, test_name, cgf, parser_name, decoder_name, detailed, xle
csr_regfile = csr_registers(xlen)
stats = statistics(xlen, 32)
cross_cover_queue = []
result_count = 0

## Get coverpoints from cgf
obj_dict = {} ## (label,coverpoint): object
Expand Down
Loading

0 comments on commit 8abfa33

Please sign in to comment.