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 #3 from riscv/Crypto-Extension
Browse files Browse the repository at this point in the history
K-scalar crypto extension support
  • Loading branch information
neelgala authored May 27, 2021
2 parents 4013385 + 4923666 commit 65773a2
Show file tree
Hide file tree
Showing 10 changed files with 689 additions and 80 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

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

## [0.6.0] - 2021-05-27
- added support in parsers for K-scalar crypto instructions
- added support for abstract functions: uniform random, byte-count, leading-ones, leading-zeros,
trailing-ones, trailing-zeros
- now maintain a separate list of instructions which require unsigned interpretation of rs1 and rs2.
- restructured coverage report handling to preserve comments throughout processing and merging.
- switched yaml to a round-trip parser for preserving comments

## [0.5.2] - 2021-02-23
- Moved ci to github actions
- fixed links in docs
Expand Down
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.5.2'
__version__ = '0.6.0'
277 changes: 266 additions & 11 deletions riscv_isac/cgf_normalize.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
from math import *
import riscv_isac.utils as utils
import itertools
import random
import pprint
import copy

def twos(val,bits):
'''
Expand Down Expand Up @@ -56,7 +59,7 @@ def sp_dataset(bit_width,var_lst=["rs1_val","rs2_val"],signed=True):
dataset = itertools.product(*datasets)
for entry in dataset:
coverpoints.append(' and '.join([var_names[i]+"=="+str(entry[i]) for i in range(len(var_names))]))
return coverpoints
return [(coverpoint,"Special Dataset") for coverpoint in coverpoints]

def walking_ones(var, size, signed=True, fltr_func=None, scale_func=None):
'''
Expand Down Expand Up @@ -87,7 +90,9 @@ def walking_ones(var, size, signed=True, fltr_func=None, scale_func=None):
dataset = [scale_func(x) for x in dataset]
if fltr_func:
dataset = filter(fltr_func,dataset)
coverpoints = [var + ' == ' + str(d) for d in dataset]
coverpoints =[]
for d in dataset:
coverpoints.append((var + ' == ' + str(d),'Walking Ones: '+str(hex(d))))
return coverpoints

def walking_zeros(var, size,signed=True, fltr_func=None, scale_func=None):
Expand Down Expand Up @@ -120,9 +125,255 @@ def walking_zeros(var, size,signed=True, fltr_func=None, scale_func=None):
dataset = [scale_func(x) for x in dataset]
if fltr_func:
dataset = filter(fltr_func,dataset)
coverpoints = [var + ' == ' + str(d) for d in dataset]
coverpoints =[]
for d in dataset:
coverpoints.append((var + ' == ' + str(d),'Walking Zeros: '+str(hex(d))))
return coverpoints

def byte_count(xlen, variables=['rs1_val','rs2_val','imm_val'], overlap = "N"):
'''
Test pattern 1: SBox Testing
This uses the byte-count pattern described above.
Generate a 256-byte sequence 0..255 and pack the sequence into 32-bit words.
Each word in the sequence is the rs2 input. The rs1 input is set to zero so we do not alter the SBox output value.
For each input word, generate 4 instructions, with bs=0..3.
This will mean that every possible SBox input pattern is tested.
:param xlen: size of the bit-vector to generate byte-count pattern
:param variables: list of string variables indicating the operands
:param overlap: Set "Y" to test byte-count pattern on lower word of the xlen-bit vector, else set "N".
:type xlen: int
:type variables: List[str]
:type overlap: str
'''
rs1 = 0
rs2 = []
coverpoints = []
hex_str = ""
i=0
cvpt = ""

while(i<=256):
hex_str = "{:02x}".format(i) + hex_str
if((len(hex_str)/2)%(xlen/8) == 0):
rs2.append('0x'+hex_str)
hex_str = ""
if(overlap == "Y"):
i=int(i-(xlen/16))
i=i+1

if xlen == 32:
for i in range(len(rs2)):
for j in range(4):
coverpoints.append(variables[0] +' == '+ str(rs1) +' and '+ variables[1] +' == '+ rs2[i] + ' and '+ variables[2] +' == '+ str(j) + ' #nosat')
else:
if variables[1] == "rs2_val":
for i in range(len(rs2)):
if((i+1)%2==0):
y = rs2[i-1]
x = rs2[i]
else:
x = rs2[i]
y = rs2[i+1]
cvpt = variables[0] +' == '+ x +' and '+ variables[1] +' == '+ y
if len(variables)==3:
if variables[2] == "imm_val":
for j in range(4):
coverpoints.append(cvpt+' and imm_val == '+ str(j) + ' #nosat')
else:
coverpoints.append(cvpt + ' #nosat')
cvpt = ""
elif variables[1] == "rcon":
for i in range(len(rs2)):
coverpoints.append(variables[0] +' == '+ rs2[i] +' and '+ variables[1] +' == 0xA' + ' #nosat')
return [(coverpoint,"Byte Count") for coverpoint in coverpoints]

def uniform_random(N=10, seed=9, variables=['rs1_val','rs2_val','imm_val'], size=[32,32,2]):
'''
Test pattern 2: Uniform Random
Generate uniform random values for rs1, rs2 and bs.
Let register values be un-constrained: 0..31.
Repeat N times for each instruction until sufficient coverage is reached.
:param N: Number of random combinations to be generated
:param seed: intial seed value of the random library
:param variables: list of string variables indicating the operands
:param size: list of bit-sizes of each variable defined in variables.
:type N: int
:type seed: int
:type variables: List[str]
:type size: List[int]
'''
random.seed(seed)

coverpoints = []
while N!= 0:
random_vals = []
for v in range(len(variables)):
val = random.randint(0,2**int(size[v])-1)
random_vals.append(variables[v] + \
' == {0:#0{1}x}'.format(val,int(size[v]/4)+2))
coverpoints.append((" and ".join(random_vals) + " #nosat",\
"Uniform Random "+str(N)))
N = N-1

return coverpoints

def leading_ones(xlen, var = ['rs1_val','rs2_val'], sizes = [32,32], seed = 10):
'''
For each variable in var, generate a random input value, and set the most-significant i bits.
See the other rs input and set a random value.
:param xlen: size of the bit-vector to generate leading-1s
:param var: list of string variables indicating the operands
:param sizes: list of sizes of the variables in var
:param seed: intial seed value of the random library
:type xlen: int
:type var: List[str]
:type sizes: List[int]
:type seed: int
'''
random.seed(seed)
coverpoints = []
for i in range(0,len(var)):
curr_var = var[i]
curr_sz = sizes[i]
default = 2**curr_sz-1
for sz in range(0,curr_sz+1):
cvpt = ''
val = (default << sz) & default
setval = (1 << sz-1) ^ default if sz!=0 else default
val = (val | random.randrange(1,2**curr_sz)) & default & setval
cvpt += curr_var + ' == 0x{0:0{1}X}'.format(val,int(ceil(curr_sz/4)))
cmnt = '{1} Leading ones for {0}. Other operands are random'.\
format(curr_var, curr_sz-sz)
for othervars in range(0,len(var)):
if othervars != i:
otherval = random.randrange(0,2**sizes[othervars])
cvpt += ' and ' + var[othervars] + ' == 0x{0:0{1}X}'.format(otherval,int(ceil(sizes[othervars]/4)))
coverpoints.append((cvpt+ " #nosat", cmnt))
return coverpoints

def leading_zeros(xlen, var = ['rs1_val','rs2_val'], sizes = [32,32], seed = 11):
'''
For each rs register input, generate a random XLEN input value, and clear the most-significant i bits.
See the other rs input, pick a random value.
:param xlen: size of the bit-vector to generate leading-0s
:param var: list of string variables indicating the operands
:param sizes: list of sizes of the variables in var
:param seed: intial seed value of the random library
:type xlen: int
:type var: List[str]
:type sizes: List[int]
:type seed: int
'''
random.seed(seed)
coverpoints = []
for i in range(0,len(var)):
curr_var = var[i]
curr_sz = sizes[i]
default = 2**curr_sz-1
for sz in range(0,curr_sz+1):
cvpt = ''
val = (1 << sz)-1 & default
setval = 1 << (sz-1) if sz!=0 else 0
val = (val & random.randrange(1,2**curr_sz)) & default | setval
cvpt += curr_var + ' == 0x{0:0{1}X}'.format(val,int(ceil(curr_sz/4)))
cmnt = '{1} Leading zeros for {0}. Other operands are random'.\
format(curr_var, curr_sz-sz)
for othervars in range(0,len(var)):
if othervars != i:
otherval = random.randrange(0,2**sizes[othervars])
cvpt += ' and ' + var[othervars] + ' == 0x{0:0{1}X}'.format(otherval,int(ceil(sizes[othervars]/4)))
coverpoints.append((cvpt+ " #nosat",cmnt))
return coverpoints


def trailing_zeros(xlen, var = ['rs1_val','rs2_val'], sizes = [32,32], seed = 12):
'''
For each rs register input, generate a random XLEN input value, and clear the least-significant i bits.
See the other rs input, pick a random value.
:param xlen: size of the bit-vector to generate trailing-0s
:param var: list of string variables indicating the operands
:param sizes: list of sizes of the variables in var
:param seed: intial seed value of the random library
:type xlen: int
:type var: List[str]
:type sizes: List[int]
:type seed: int
'''
random.seed(seed)
coverpoints = []
for i in range(0,len(var)):
curr_var = var[i]
curr_sz = sizes[i]
default = 2**curr_sz-1
for sz in range(0,curr_sz+1):
cvpt = ''
val = (default << sz) & default
setval = (1 << sz) & default
val = (val & (random.randrange(1,2**curr_sz)<<sz)) & default
val = val | setval
cvpt += curr_var + ' == 0x{0:0{1}X}'.format(val,int(ceil(curr_sz/4)))
cmnt = '{1} Trailing zeros for {0}. Other operands are random'.\
format(curr_var, sz)
for othervars in range(0,len(var)):
if othervars != i:
otherval = random.randrange(0,2**sizes[othervars])
cvpt += ' and ' + var[othervars] + ' == 0x{0:0{1}X}'.format(otherval,int(ceil(sizes[othervars]/4)))
coverpoints.append((cvpt+ " #nosat",cmnt))
return coverpoints

def trailing_ones(xlen, var = ['rs1_val','rs2_val'], sizes = [32,32], seed = 13):
'''
For each rs register input, generate a random XLEN input value, and set the least-significant i bits.
See the other rs input, pick a random value.
:param xlen: size of the bit-vector to generate trailing-1s
:param var: list of string variables indicating the operands
:param sizes: list of sizes of the variables in var
:param seed: intial seed value of the random library
:type xlen: int
:type var: List[str]
:type sizes: List[int]
:type seed: int
'''
random.seed(seed)
coverpoints = []
for i in range(0,len(var)):
curr_var = var[i]
curr_sz = sizes[i]
default = (2**curr_sz)-1
for sz in range(0,curr_sz+1):
cvpt = ''
val = random.randrange(1,(2**curr_sz))
setval = (1<<(curr_sz-sz)) ^ (default)
val = val | (default>> sz)
val = val & setval
cvpt += curr_var + ' == 0x{0:0{1}X}'.format(val,int(ceil(curr_sz/4)))
cmnt = '{1} Trailing ones for {0}. Other operands are random'.\
format(curr_var, curr_sz-sz)
for othervars in range(0,len(var)):
if othervars != i:
otherval = random.randrange(0,2**sizes[othervars])
cvpt += ' and ' + var[othervars] + ' == 0x{0:0{1}X}'.format(otherval,int(ceil(sizes[othervars]/4)))
coverpoints.append((cvpt+ " #nosat",cmnt))
return coverpoints


def alternate(var, size, signed=True, fltr_func=None,scale_func=None):
'''
This function converts an abstract alternate function into individual
Expand Down Expand Up @@ -155,8 +406,13 @@ def alternate(var, size, signed=True, fltr_func=None,scale_func=None):
dataset = [scale_func(x) for x in dataset]
if fltr_func:
dataset = filter(fltr_func,dataset)
coverpoints = [var + ' == ' + str(d) for d in dataset]
coverpoints =[]
for d in dataset:
coverpoints.append((var + ' == ' + str(d),'Alternate: '+str(hex(d))))
return coverpoints
#coverpoints = [var + ' == ' + str(d) for d in dataset]
#return [(coverpoint,"Alternate") for coverpoint in coverpoints]


def expand_cgf(cgf_files, xlen):
'''
Expand All @@ -175,13 +431,12 @@ def expand_cgf(cgf_files, xlen):
for label,node in cats.items():
if isinstance(node,dict):
if 'abstract_comb' in node:
temp = cgf[labels][label]['abstract_comb']
del cgf[labels][label]['abstract_comb']
temp = node['abstract_comb']
del node['abstract_comb']
for coverpoints, coverage in temp.items():
if 'walking' in coverpoints or 'alternate' in coverpoints or 'sp_dataset' in coverpoints:
if 'walking' in coverpoints or 'alternate' in coverpoints or 'sp_dataset' in coverpoints or 'byte_count' in coverpoints or 'uniform_random' in coverpoints or 'leading' in coverpoints or 'trailing' in coverpoints:
exp_cp = eval(coverpoints)
for e in exp_cp:
cgf[labels][label][e] = coverage
return cgf

for cp,comment in exp_cp:
cgf[labels][label].insert(1,cp,coverage,comment=comment)
return dict(cgf)

Loading

0 comments on commit 65773a2

Please sign in to comment.