Update google_riscv-dv to google/riscv-dv@2e52518

Update code from upstream repository https://github.com/google/riscv-
dv to revision 2e5251846efb5fa42882a2b6b571ef8693e8cd60

* Remove f strings for Python 3.5-compatibility (Philipp Wagner)
* Fix start-end pair mismatch in asm file (aneels3)
* Fix AMO instruction constraint issue (google/riscv-dv#682) (taoliug)
* - Adds support for the coverage report visualization (pyucis-viewer)
  - Adds CSR, opcode, rv32i_misc, and mepc_alignment covergroups
  (Hodjat Asghari Esfeden)
* fix Todo of directed_lib (aneels3)
* Added avail_regs_c constraint (ShraddhaDevaiya)
* Fix factory method implementation (aneels3)
* Add directed instr (aneels3)
* fix label issue (aneels3)
* fix randomization issue (aneels3)
* Fix typo (aneels3)
* add riscv_pseudo_instr (aneels3)
* add value_plusargs functionality (pvipsyash)
* add riscv_utils and fix minor issues (aneels3)
* modify for directed scenario (pvipsyash)
* Fix a minor issue with the instruction PC (Hodjat Asghari Esfeden)

Signed-off-by: Philipp Wagner <phw@lowrisc.org>
This commit is contained in:
Philipp Wagner 2020-08-20 17:02:05 +01:00 committed by Philipp Wagner
parent 4c3f1e8a3b
commit f53ee9b09f
17 changed files with 442 additions and 112 deletions

View file

@ -9,6 +9,6 @@
upstream:
{
url: https://github.com/google/riscv-dv
rev: 17d79847e376a591cb3dcaae7601c98b0e70e8ac
rev: 2e5251846efb5fa42882a2b6b571ef8693e8cd60
}
}

View file

@ -63,7 +63,6 @@ class riscv_cov_instr:
def __init__(self):
# Program counter (PC) of the instruction
self.pc = vsc.bit_t(rcs.XLEN)
rcs.XLEN) # Program counter (PC) of the instruction
self.instr = None
# self.gpr = None # destination operand of the instruction
self.binary = vsc.bit_t(32) # Instruction binary

View file

@ -172,16 +172,15 @@ class riscv_instr:
# allowed_categories = []
for items in include_category:
allowed_instr.append(self.instr_category[items])
allowed_instr.extend(self.instr_category[items])
for items in exclude_category:
if(items in self.instr_category):
disallowed_instr.append(self.instr_category[items])
disallowed_instr.extend(self.instr_category[items])
for items in include_group:
allowed_instr.append(self.instr_group[items])
allowed_instr.extend(self.instr_group[items])
for items in exclude_group:
if(items in self.instr_group):
disallowed_instr.append(self.instr_group[items])
disallowed_instr.extend(self.instr_group[items])
disallowed_instr.extend(exclude_instr)

View file

@ -15,11 +15,15 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import subprocess
import logging
import random
import copy
import sys
from bitstring import BitArray
from pygen_src.riscv_instr_sequence import riscv_instr_sequence
from pygen_src.riscv_instr_pkg import pkg_ins, privileged_reg_t, privileged_mode_t, mtvec_mode_t
from pygen_src.riscv_instr_gen_config import cfg
from pygen_src.riscv_instr_gen_config import cfg, args, args_dict
from pygen_src.target.rv32i import riscv_core_setting as rcs
from pygen_src.riscv_instr_stream import riscv_rand_instr_stream
from pygen_src.riscv_utils import factory
'''
RISC-V assembly program generator
@ -33,7 +37,7 @@ class riscv_asm_program_gen:
def __init__(self):
self.instr_stream = []
self.directed_instr_stream_ratio = []
self.directed_instr_stream_ratio = {}
self.hart = 0
self.page_table_list = []
self.main_program = []
@ -77,12 +81,18 @@ class riscv_asm_program_gen:
# Generate main program
gt_lbl_str = pkg_ins.get_label("main", hart)
label_name = gt_lbl_str
gt_lbl_str = riscv_instr_sequence()
self.main_program.append(gt_lbl_str)
self.main_program[hart].instr_cnt = cfg.main_program_instr_cnt
self.main_program[hart].is_debug_program = 0
self.main_program[hart].label_name = "main"
self.main_program[hart].gen_instr(is_main_program = 1, no_branch = cfg.no_branch_jump)
self.main_program[hart].label_name = label_name
self.generate_directed_instr_stream(hart=hart,
label=self.main_program[hart].label_name,
original_instr_cnt=self.main_program[hart].instr_cnt,
min_insert_cnt=1,
instr_stream=self.main_program[hart].directed_instr)
self.main_program[hart].gen_instr(is_main_program=1, no_branch=cfg.no_branch_jump)
self.main_program[hart].post_process_instr()
self.main_program[hart].generate_instr_stream()
@ -577,14 +587,60 @@ class riscv_asm_program_gen:
pass
def add_directed_instr_stream(self, name, ratio):
pass
self.directed_instr_stream_ratio[name] = ratio
logging.info("Adding directed instruction stream:%0s ratio:%0d/1000", name, ratio)
def get_directed_instr_stream(self):
pass
opts = []
for i in range(cfg.max_directed_instr_stream_seq):
arg = "directed_instr_{}".format(i)
stream_name_opts = "stream_name_{}".format(i)
stream_freq_opts = "stream_freq_{}".format(i)
if(arg in args):
val = args_dict[arg]
opts = val.split(",")
if(len(opts) != 2):
logging.critical(
"Incorrect directed instruction format : %0s, expect: name,ratio", val)
else:
self.add_directed_instr_stream(opts[0], int(opts[1]))
elif(stream_name_opts in args and stream_freq_opts in args):
stream_name = args_dict[stream_name_opts]
stream_freq = args_dict[stream_freq_opts]
self.add_directed_instr_stream(stream_name, stream_freq)
def generate_directed_instr_stream(self, hart = 0, label = "", original_instr_cnt = None,
def generate_directed_instr_stream(self, hart = 0, label = "", original_instr_cnt = 0,
min_insert_cnt = 0, kernel_mode = 0, instr_stream = []):
pass
instr_insert_cnt = 0
idx = 0
if(cfg.no_directed_instr):
return
for instr_stream_name in self.directed_instr_stream_ratio:
instr_insert_cnt = int(original_instr_cnt *
self.directed_instr_stream_ratio[instr_stream_name] // 1000)
if(instr_insert_cnt <= min_insert_cnt):
instr_insert_cnt = min_insert_cnt
logging.info("Insert directed instr stream %0s %0d/%0d times",
instr_stream_name, instr_insert_cnt, original_instr_cnt)
for i in range(instr_insert_cnt):
name = "{}_{}".format(instr_stream_name, i)
object_h = factory(instr_stream_name)
object_h.name = name
if(object_h is None):
logging.critical("Cannot create instr stream %0s", name)
sys.exit(1)
new_instr_stream = copy.copy(object_h)
if(new_instr_stream):
new_instr_stream.hart = hart
new_instr_stream.label = "{}_{}".format(label, idx)
new_instr_stream.kernel_mode = kernel_mode
new_instr_stream.randomize()
instr_stream.append(new_instr_stream)
else:
logging.critical("Cannot Create instr stream %0s", name)
sys.exit(1)
idx += 1
random.shuffle(instr_stream)
def gen_debug_rom(self, hart):
pass

View file

@ -34,3 +34,14 @@ def DEFINE_INSTR(instr_n, instr_format, instr_category, instr_group, imm_tp=imm_
"valid": riscv_instr.register(instr_n)
})
g[class_name] = NewClass
'''
TODO
@vsc.constraint
def add_pseudo_instr(self, instr_n, instr_format, instr_category, instr_group):
with vsc.if_then(self.pseudo_instr_name == instr_n):
self.format == instr_format.name
self.category == instr_category.name
self.group == instr_group.name
'''

View file

@ -0,0 +1,98 @@
"""
Copyright 2020 Google LLC
Copyright 2020 PerfectVIPs Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
import vsc
from enum import IntEnum, auto
from pygen_src.riscv_instr_stream import riscv_rand_instr_stream
from pygen_src.isa.riscv_instr import riscv_instr_ins
from pygen_src.riscv_instr_gen_config import cfg
from pygen_src.riscv_instr_pkg import riscv_reg_t, riscv_pseudo_instr_name_t
from pygen_src.target.rv32i import riscv_core_setting as rcs
from pygen_src.riscv_pseudo_instr import riscv_pseudo_instr
class riscv_directed_instr_stream(riscv_rand_instr_stream):
def __init__(self):
super().__init__()
self.name = ""
self.label = ""
def post_randomize(self):
for i in range(len(self.instr_list)):
self.instr_list[i].has_label = 0
self.instr_list[i].atomic = 1
self.instr_list[0].comment = "Start %0s" % (self.name)
self.instr_list[-1].comment = "End %0s" % (self.name)
if self.label != "":
self.instr_list[0].label = self.label
self.instr_list[0].has_label = 1
class int_numeric_e(IntEnum):
NormalValue = auto()
Zero = auto()
AllOne = auto()
NegativeMax = auto()
@vsc.randobj
class riscv_int_numeric_corner_stream(riscv_directed_instr_stream):
def __init__(self):
super().__init__()
self.num_of_avail_regs = 10
self.num_of_instr = vsc.rand_uint8_t()
self.init_val = vsc.rand_list_t(vsc.rand_bit_t(rcs.XLEN - 1), sz = 10)
self.init_val_type = vsc.rand_list_t(vsc.enum_t(int_numeric_e), sz =10)
self.init_instr = []
@vsc.constraint
def init_val_c(self):
# TO DO
# solve init_val_type before init_val;
self.init_val_type.size == self.num_of_avail_regs
self.init_val.size == self.num_of_avail_regs
self.num_of_instr in vsc.rangelist(vsc.rng(15, 30))
@vsc.constraint
def avail_regs_c(self):
self.avail_regs.size == self.num_of_avail_regs
vsc.unique(self.avail_regs)
with vsc.foreach(self.avail_regs, idx = True) as i:
self.avail_regs[i].not_inside(cfg.reserved_regs)
self.avail_regs[i] != riscv_reg_t.ZERO
def pre_randomize(self):
pass
def post_randomize(self):
self.init_instr = [None] * self.num_of_avail_regs
for i in range(len(self.init_val_type)):
if self.init_val_type[i] == int_numeric_e.Zero:
self.init_val[i] = 0
elif self.init_val_type[i] == int_numeric_e.AllOne:
self.init_val[i] = 1
elif self.init_val_type[i] == int_numeric_e.NegativeMax:
self.init_val[i] = 1 << (rcs.XLEN - 1)
self.init_instr[i] = riscv_pseudo_instr()
self.init_instr[i].rd = self.avail_regs[i]
self.init_instr[i].pseudo_instr_name = riscv_pseudo_instr_name_t.LI
self.init_instr[i].imm_str = "0x%0x" % (self.init_val[i])
self.instr_list.append(self.init_instr[i])
for i in range(self.num_of_instr):
instr = riscv_instr_ins.get_rand_instr(
include_category = ['ARITHMETIC'],
exclude_group = ['RV32C', 'RV64C', 'RV32F', 'RV64F', 'RV32D', 'RV64D'])
instr = self.randomize_gpr(instr)
self.instr_list.append(instr)
super().post_randomize()

View file

@ -178,6 +178,7 @@ class riscv_instr_cover_group:
'''TODO: covergroup inheritance is broken at the moment. The workaround
will be switched back to the inheritance approach once it gets fixed'''
# @vsc.covergroup
# class lb_cg(load_instr_cg):
# def __init__(self, instr):
@ -1049,8 +1050,8 @@ class riscv_instr_cover_group:
cp_t=vsc.enum_t(operand_sign_e))
self.cp_branch_hit = vsc.coverpoint(lambda: instr.branch_hit,
bins={
"Non-taken": vsc.bin(0),
"Taken" : vsc.bin(1),
"Non-taken": vsc.bin(0)
}
)
self.cp_sign_cross = vsc.cross([self.cp_rs1_sign,
@ -1334,17 +1335,73 @@ class riscv_instr_cover_group:
self.cp_align = vsc.cross([self.cp_imm_align, self.cp_rs1_align])
self.cp_ras = vsc.cross([self.cp_rs1_link, self.cp_rd_link])
'''CSR instructions'''
@vsc.covergroup
class csrrw_cg(object):
def __init__(self, instr):
super().__init__()
self.cp_rd = vsc.coverpoint(lambda: instr.rd,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1,
cp_t=vsc.enum_t(riscv_reg_t))
@vsc.covergroup
class opcode_cg(object):
def __init__(self, instr):
super().__init__()
self.cp_opcode = vsc.coverpoint(lambda: instr.binary[7:2],
bins={
"a": vsc.bin_array([], [0, 31])
}
)
@vsc.covergroup
class rv32i_misc_cg(object):
def __init__(self, instr):
super().__init__()
self.cp_misc = vsc.coverpoint(lambda: instr.instr,
cp_t=vsc.enum_t(rv32i_misc_instrs))
@vsc.covergroup
class mepc_alignment_cg(object):
def __init__(self, instr):
super().__init__()
self.cp_align = vsc.coverpoint(lambda: instr.rd_value[2:0],
bins={
"Zero": vsc.bin(0),
"Two" : vsc.bin(2)
}
)
def sample(self, instr):
self.instr_cnt += 1
if self.instr_cnt > 1:
instr.check_hazard_condition(self.pre_instr)
# TODO: sampling based on the instruction binary
# TODO: sampling for hint, compressed, and illegal_compressed insts
if instr.binary[2:0] == 3:
opcode_cg = self.opcode_cg(instr)
opcode_cg.sample()
try:
cg = eval("self." + instr.instr.name.lower() + "_cg")(instr)
cg.sample()
except Exception:
logging.info("Covergroup for instr {} is not supported yet".format(
instr.instr.name))
if instr.group.name == "RV32I":
rv32i_misc_cg = self.rv32i_misc_cg(instr)
rv32i_misc_cg.sample()
if instr.category.name == "CSR":
# MEPC
if instr.csr == 833:
mepc_alignment_cg = self.mepc_alignment_cg(instr)
mepc_alignment_cg.sample()
self.pre_instr = instr
def reset(self):

View file

@ -111,10 +111,22 @@ class riscv_instr_gen_config:
self.num_of_harts = argv.num_of_harts
self.fix_sp = argv.fix_sp
self.use_push_data_section = argv.use_push_data_section
self.boot_mode_opts = ""
self.boot_mode_opts = argv.boot_mode_opts
if(self.boot_mode_opts):
logging.info("Got boot mode option - %0s", self.boot_mode_opts)
if(self.boot_mode_opts == "m"):
self.init_privileged_mode = privileged_mode_t.MACHINE_MODE.name
elif(self.boot_mode_opts == "s"):
self.init_privileged_mode = privileged_mode_t.SUPERVISOR_MODE.name
elif(self.boot_mode_opts == "u"):
self.init_privileged_mode = privileged_mode_t.USER_MODE.name
else:
logging.error("Illegal boot mode option - %0s", self.boot_mode_opts)
self.enable_page_table_exception = argv.enable_page_table_exception
self.no_directed_instr = argv.no_directed_instr
self.asm_test_suffix = ""
self.asm_test_suffix = argv.asm_test_suffix
self.enable_interrupt = argv.enable_interrupt
self.enable_nested_interrupt = argv.enable_nested_interrupt
self.enable_timer_irq = argv.enable_timer_irq
@ -153,11 +165,16 @@ class riscv_instr_gen_config:
self.enable_floating_point = argv.enable_floating_point
self.enable_vector_extension = argv.enable_vector_extension
self.enable_b_extension = argv.enable_b_extension
# Commenting out for now
# self.enable_bitmanip_groups = ['ZBB', 'ZBS', 'ZBP', 'ZBE', 'ZBF',
# 'ZBC', 'ZBR', 'ZBM', 'ZBT', 'ZB_TMP']
self.enable_bitmanip_groups = argv.enable_bitmanip_groups
self.dist_control_mode = 0
self.category_dist = {}
self.march_isa = argv.march_isa
if(len(self.march_isa) != 0):
rcs.supported_isa = self.march_isa
if(rcs.supported_isa != 'RV32C'):
self.disable_compressed_instr = 1
@vsc.constraint
def gpr_c(self):
@ -386,35 +403,35 @@ def parse_args():
choices = [0, 1], type = int, default = 0)
parse.add_argument('--enable_b_extension', help = 'enable_b_extension',
choices = [0, 1], type = int, default = 0)
parse.add_argument('--enable_bitmanip_groups', help = 'enable_bitmanip_groups',
default = ['ZBB', 'ZBS', 'ZBP', 'ZBE', 'ZBF',
'ZBC', 'ZBR', 'ZBM', 'ZBT', 'ZB_TMP'], nargs = '*')
parse.add_argument('--boot_mode_opts', help = 'boot_mode_opts', default = "")
parse.add_argument('--asm_test_suffix', help = 'asm_test_suffix', default = "")
parse.add_argument('--march_isa', help = 'march_isa', default = [],
choices = [i.name for i in riscv_instr_group_t], nargs = '*')
parse.add_argument('--directed_instr_0', help = 'directed_instr_0',
default = "riscv_int_numeric_corner_stream,4")
parse.add_argument('--stream_name_opts', help = 'stream_name_0',
default = "riscv_load_store_rand_instr_stream")
parse.add_argument('--stream_freq_opts', help = 'stream_freq_0', default = 4)
# TODO
'''
cmdline_enum_processor #(b_ext_group_t)::get_array_values("+enable_bitmanip_groups=",
enable_bitmanip_groups);
if(inst.get_arg_value("+boot_mode=", boot_mode_opts)) begin
`uvm_info(get_full_name(), $sformatf(
"Got boot mode option - %0s", boot_mode_opts), UVM_LOW)
case(boot_mode_opts)
"m" : init_privileged_mode = MACHINE_MODE;
"s" : init_privileged_mode = SUPERVISOR_MODE;
"u" : init_privileged_mode = USER_MODE;
default: `uvm_fatal(get_full_name(),
$sformatf("Illegal boot mode option - %0s", boot_mode_opts))
endcase
init_privileged_mode.rand_mode(0);
addr_translaction_rnd_order_c.constraint_mode(0);
if ($value$plusargs("tvec_alignment=%0d", tvec_alignment)) begin
tvec_alignment.rand_mode(0);
end
`uvm_info(`gfn, $sformatf("riscv_instr_pkg::supported_privileged_mode = %0d",
riscv_instr_pkg::supported_privileged_mode.size()), UVM_LOW)
void'(inst.get_arg_value("+asm_test_suffix=", asm_test_suffix));
// Directed march list from the runtime options, ex. RV32I, RV32M etc.
cmdline_enum_processor #(riscv_instr_group_t)::get_array_values("+march=", march_isa);
if (march_isa.size != 0) riscv_instr_pkg::supported_isa = march_isa;
'''
vector_cfg = riscv_vector_cfg::type_id::create("vector_cfg");
pmp_cfg = riscv_pmp_cfg::type_id::create("pmp_cfg");
pmp_cfg.rand_mode(pmp_cfg.pmp_randomize);
pmp_cfg.initialize(require_signature_addr);
setup_instr_distribution();
get_invalid_priv_lvl_csr();
'''
args = parse.parse_args()
return args
args = parse_args()
args_dict = vars(args)
cfg = riscv_instr_gen_config(args)

View file

@ -24,7 +24,7 @@ class mem_region_t:
xwr = auto()
class satp_mode_t(Enum):
class satp_mode_t(IntEnum):
BARE = 0b0000
SV32 = 0b0001
SV39 = 0b1000
@ -33,7 +33,7 @@ class satp_mode_t(Enum):
SV64 = 0b1011
class f_rounding_mode_t(Enum):
class f_rounding_mode_t(IntEnum):
RNE = 0b000
RTZ = 0b001
RDN = 0b010
@ -41,26 +41,26 @@ class f_rounding_mode_t(Enum):
RMM = 0b100
class mtvec_mode_t(Enum):
class mtvec_mode_t(IntEnum):
DIRECT = 0b00
VECTORED = 0b01
class imm_t(Enum):
class imm_t(IntEnum):
IMM = 0
UIMM = auto()
NZUIMM = auto()
NZIMM = auto()
class privileged_mode_t(Enum):
class privileged_mode_t(IntEnum):
USER_MODE = 0b00
SUPERVISOR_MODE = 0b01
RESERVED_MODE = 0b10
MACHINE_MODE = 0b11
class riscv_instr_group_t(Enum):
class riscv_instr_group_t(IntEnum):
RV32I = 0
RV64I = auto()
RV32M = auto()
@ -85,7 +85,7 @@ class riscv_instr_group_t(Enum):
RV64X = auto()
class riscv_instr_name_t(Enum):
class riscv_instr_name_t(IntEnum):
LUI = 0
AUIPC = auto()
JAL = auto()
@ -595,7 +595,7 @@ class riscv_reg_t(IntEnum):
T6 = auto()
class riscv_fpr_t(Enum):
class riscv_fpr_t(IntEnum):
FT0 = 0
FT1 = auto()
FT2 = auto()
@ -630,7 +630,7 @@ class riscv_fpr_t(Enum):
FT11 = auto()
class riscv_vreg_t(Enum):
class riscv_vreg_t(IntEnum):
V0 = 0
V1 = auto()
V2 = auto()
@ -665,7 +665,7 @@ class riscv_vreg_t(Enum):
V31 = auto()
class riscv_instr_format_t(Enum):
class riscv_instr_format_t(IntEnum):
J_FORMAT = 0
U_FORMAT = auto()
I_FORMAT = auto()
@ -689,7 +689,7 @@ class riscv_instr_format_t(Enum):
VS_FORMAT = auto()
class va_variant_t(Enum):
class va_variant_t(IntEnum):
VV = 0
VI = auto()
VX = auto()
@ -705,7 +705,7 @@ class va_variant_t(Enum):
VM = auto()
class riscv_instr_category_t(Enum):
class riscv_instr_category_t(IntEnum):
LOAD = 0
STORE = auto()
SHIFT = auto()
@ -727,7 +727,7 @@ class riscv_instr_category_t(Enum):
# typedef bit[11:0] riscv_csr_t;
class privileged_reg_t(Enum):
class privileged_reg_t(IntEnum):
USTATUS = 0x000
UIE = 0x004
UTVEC = 0x005
@ -958,7 +958,7 @@ class privileged_reg_t(Enum):
VLENB = 0xC22
class privileged_reg_fld_t(Enum):
class privileged_reg_fld_t(IntEnum):
RSVD = 0
MXL = auto()
EXTENSION = auto()
@ -967,30 +967,30 @@ class privileged_reg_fld_t(Enum):
PPN = auto()
class privileged_level_t(Enum):
class privileged_level_t(IntEnum):
M_LEVEL = 0b11
S_LEVEL = 0b01
U_LEVEL = 0b00
class reg_field_access_t(Enum):
class reg_field_access_t(IntEnum):
WPRI = 0
WLRL = auto()
WARL = auto()
class riscv_pseudo_instr_name_t(Enum):
class riscv_pseudo_instr_name_t(IntEnum):
LI = 0
LA = auto()
class data_pattern_t(Enum):
class data_pattern_t(IntEnum):
RAND_DATA = 0
ALL_ZERO = auto()
INCR_VAL = auto()
class pte_permission_t(Enum):
class pte_permission_t(IntEnum):
NEXT_LEVEL_PAGE = 0b000
READ_ONLY_PAGE = 0b001
READ_WRITE_PAGE = 0b011
@ -999,7 +999,7 @@ class pte_permission_t(Enum):
R_W_EXECUTE_PAGE = 0b111
class interrupt_cause_t(Enum):
class interrupt_cause_t(IntEnum):
U_SOFTWARE_INTR = 0x0
S_SOFTWARE_INTR = 0x1
M_SOFTWARE_INTR = 0x3
@ -1011,7 +1011,7 @@ class interrupt_cause_t(Enum):
M_EXTERNAL_INTR = 0xB
class exception_cause_t(Enum):
class exception_cause_t(IntEnum):
INSTRUCTION_ADDRESS_MISALIGNED = 0x0
INSTRUCTION_ACCESS_FAULT = 0x1
ILLEGAL_INSTRUCTION = 0x2
@ -1028,7 +1028,7 @@ class exception_cause_t(Enum):
STORE_AMO_PAGE_FAULT = 0xF
class misa_ext_t(Enum):
class misa_ext_t(IntEnum):
MISA_EXT_A = 0
MISA_EXT_B = auto()
MISA_EXT_C = auto()
@ -1071,6 +1071,15 @@ class branch_hazard_e(IntEnum):
NO_HAZARD = 0
RAW_HAZARD = auto()
# RV32I_MISC covergroup instructions
class rv32i_misc_instrs(IntEnum):
FENCE = 0
FENCE_I = auto()
EBREAK = auto()
ECALL = auto()
MRET = auto()
# Ignore RAW_HAZARD for store lsu hazard
class store_lsu_hazard_e(IntEnum):
NO_HAZARD = 0

View file

@ -16,7 +16,7 @@ import random
from collections import defaultdict
from pygen_src.riscv_instr_stream import riscv_rand_instr_stream
from pygen_src.riscv_instr_gen_config import cfg
from pygen_src.riscv_instr_pkg import pkg_ins
from pygen_src.riscv_instr_pkg import pkg_ins, riscv_instr_category_t
class riscv_instr_sequence:
@ -117,7 +117,7 @@ class riscv_instr_sequence:
self.branch_idx[i] = random.randint(1, cfg.max_branch_step)
while(j < len(self.instr_stream.instr_list)):
if((self.instr_stream.instr_list[j].category.name == "BRANCH") and
if((self.instr_stream.instr_list[j].category == riscv_instr_category_t.BRANCH) and
(not self.instr_stream.instr_list[j].branch_assigned) and
(not self.instr_stream.instr_list[j].is_illegal_instr)):
'''

View file

@ -13,12 +13,14 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import random
import logging
import sys
import vsc
from pygen_src.riscv_instr_pkg import riscv_instr_name_t,\
riscv_instr_category_t, riscv_reg_t
from pygen_src.isa.riscv_instr import riscv_instr, riscv_instr_ins
from pygen_src.riscv_instr_gen_config import cfg
@vsc.randobj
class riscv_instr_stream:
'''
Base class for RISC-V instruction stream
@ -30,9 +32,9 @@ class riscv_instr_stream:
def __init__(self):
self.instr_list = []
self.instr_cnt = 0
self.label = " "
self.label = ""
# User can specify a small group of available registers to generate various hazard condition
self.avail_regs = []
self.avail_regs = vsc.randsz_list_t(vsc.enum_t(riscv_reg_t))
# Some additional reserved registers that should not be used as rd register
# by this instruction stream
self.reserved_rd = []
@ -112,7 +114,7 @@ class riscv_instr_stream:
if idx == 0:
self.instr_list = new_instr + self.instr_list[idx:current_instr_cnt - 1]
else:
self.instr_list = self.instr_list[0:idx - 1] + new_instr + \
self.instr_list = self.instr_list[0:idx] + new_instr + \
self.instr_list[idx:current_instr_cnt - 1]
def mix_instr_stream(self, new_instr, contained = 0):

View file

@ -0,0 +1,48 @@
"""
Copyright 2020 Google LLC
Copyright 2020 PerfectVIPs Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
import vsc
from pygen_src.isa.riscv_instr import riscv_instr
from pygen_src.riscv_instr_pkg import (riscv_pseudo_instr_name_t, riscv_instr_format_t,
riscv_instr_category_t, riscv_instr_group_t, pkg_ins)
# from pygen_src.riscv_defines import add_pseudo_instr
# Psuedo instructions are used to simplify assembly program writing
@vsc.randobj
class riscv_pseudo_instr(riscv_instr):
def __init__(self):
super().__init__()
self.process_load_store = 0
self.format = riscv_instr_format_t.I_FORMAT
self.pseudo_instr_name = vsc.rand_enum_t(riscv_pseudo_instr_name_t)
'''
TODO
add_pseudo_instr(self, riscv_pseudo_instr_name_t.LI, riscv_instr_format_t.I_FORMAT,
riscv_instr_category_t.LOAD, riscv_instr_group_t.RV32I)
add_pseudo_instr(self, riscv_pseudo_instr_name_t.LA, riscv_instr_format_t.I_FORMAT,
riscv_instr_category_t.LOAD, riscv_instr_group_t.RV32I)
'''
def convert2asm(self, prefix = ""):
asm_str = pkg_ins.format_string(self.get_instr_name(), pkg_ins.MAX_INSTR_STR_LEN)
asm_str = "{}{}, {}".format(asm_str, self.rd.name, self.get_imm())
if(self.comment != ""):
asm_str = "{} #{}".format(asm_str, self.comment)
return asm_str.lower()
def get_instr_name(self):
return self.pseudo_instr_name.name

View file

@ -0,0 +1,30 @@
"""
Copyright 2020 Google LLC
Copyright 2020 PerfectVIPs Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
import sys
import logging
from pygen_src.riscv_directed_instr_lib import (riscv_directed_instr_stream,
riscv_int_numeric_corner_stream)
def factory(obj_of):
objs = {
"riscv_directed_instr_stream": riscv_directed_instr_stream,
"riscv_int_numeric_corner_stream": riscv_int_numeric_corner_stream
}
try:
return objs[obj_of]()
except KeyError:
logging.critical("Cannot Create object of %s", obj_of)
sys.exit(1)

View file

@ -22,10 +22,12 @@ from pygen_src.riscv_asm_program_gen import riscv_asm_program_gen # NOQA
class riscv_instr_base_test:
def __init__(self):
pass
asm = riscv_asm_program_gen()
for _ in range(cfg.num_of_tests):
cfg.randomize()
asm = riscv_asm_program_gen()
riscv_instr_ins.create_instr_list(cfg)
test_name = "riscv_asm_test_{}.S".format(_)
test_name = "riscv_arithmetic_basic_test_{}.S".format(_)
asm.get_directed_instr_stream()
asm.gen_program()
asm.gen_test_file(test_name)

View file

@ -116,6 +116,8 @@ class riscv_instr_cov_test:
file.write(tabulate(table, headers, tablefmt="grid",
numalign="center", stralign="center"))
file.close()
# Write in xml format to be read by pyucis-viewer (visualization)
vsc.write_coverage_db("cov_db.xml")
def post_process_trace(self):
pass

View file

@ -109,9 +109,9 @@ def get_rs1_val(iteration, xlen):
3) A randomly generated number
"""
if iteration == 0:
return bitarray(hex=f"0x{'a5'*int(xlen/8)}")
return bitarray(hex="0x{}".format('a5'*int(xlen/8)))
elif iteration == 1:
return bitarray(hex=f"0x{'5a'*int(xlen/8)}")
return bitarray(hex="0x{}".format('5a'*int(xlen/8)))
elif iteration == 2:
val = bitarray(uint=0, length=xlen)
# Must randomize all 32 bits, due to randomization library limitations
@ -193,7 +193,7 @@ def predict_csr_val(csr_op, rs1_val, csr_val, csr_write_mask, csr_read_mask):
elif csr_op == 'csrrci':
zero.append(rs1_val[-5:])
csr_write((~zero) & prediction, csr_val, csr_write_mask)
return f"0x{prediction.hex}"
return "0x{}".format(prediction.hex)
def gen_setup(test_file):
@ -203,12 +203,12 @@ def gen_setup(test_file):
Args:
test_file: the file containing the generated assembly code.
"""
test_file.write(f".macro init\n")
test_file.write(f".endm\n")
test_file.write(f".section .text.init\n")
test_file.write(f".globl _start\n")
test_file.write(f".option norvc\n")
test_file.write(f"_start:\n")
test_file.write(".macro init\n")
test_file.write(".endm\n")
test_file.write(".section .text.init\n")
test_file.write(".globl _start\n")
test_file.write(".option norvc\n")
test_file.write("_start:\n")
def gen_csr_test_fail(test_file, end_addr):
@ -221,13 +221,13 @@ def gen_csr_test_fail(test_file, end_addr):
test_file: the file containing the generated assembly test code.
end_addr: address that should be written to at end of test
"""
test_file.write(f"csr_fail:\n")
test_file.write(f"\tli x1, {TEST_FAIL}\n")
test_file.write(f"\tslli x1, x1, 8\n")
test_file.write(f"\taddi x1, x1, {TEST_RESULT}\n")
test_file.write(f"\tli x2, 0x{end_addr}\n")
test_file.write(f"\tsw x1, 0(x2)\n")
test_file.write(f"\tj csr_fail\n")
test_file.write("csr_fail:\n")
test_file.write("\tli x1, {}\n".format(TEST_FAIL))
test_file.write("\tslli x1, x1, 8\n")
test_file.write("\taddi x1, x1, {}\n".format(TEST_RESULT))
test_file.write("\tli x2, 0x{}\n".format(end_addr))
test_file.write("\tsw x1, 0(x2)\n")
test_file.write("\tj csr_fail\n")
def gen_csr_test_pass(test_file, end_addr):
@ -240,13 +240,13 @@ def gen_csr_test_pass(test_file, end_addr):
test_file: the file containing the generated assembly test code.
end_addr: address that should be written to at end of test
"""
test_file.write(f"csr_pass:\n")
test_file.write(f"\tli x1, {TEST_PASS}\n")
test_file.write(f"\tslli x1, x1, 8\n")
test_file.write(f"\taddi x1, x1, {TEST_RESULT}\n")
test_file.write(f"\tli x2, 0x{end_addr}\n")
test_file.write(f"\tsw x1, 0(x2)\n")
test_file.write(f"\tj csr_pass\n")
test_file.write("csr_pass:\n")
test_file.write("\tli x1, {}\n".format(TEST_PASS))
test_file.write("\tslli x1, x1, 8\n")
test_file.write("\taddi x1, x1, {}\n".format(TEST_RESULT))
test_file.write("\tli x2, 0x{}\n".format(end_addr))
test_file.write("\tsw x1, 0(x2)\n")
test_file.write("\tj csr_pass\n")
def gen_csr_instr(original_csr_map, csr_instructions, xlen,
@ -271,13 +271,13 @@ def gen_csr_instr(original_csr_map, csr_instructions, xlen,
# pick two GPRs at random to act as source and destination registers
# for CSR operations
csr_map = copy.deepcopy(original_csr_map)
source_reg, dest_reg = [f"x{i}" for i in random.sample(range(1, 16), 2)]
source_reg, dest_reg = ["x{}".format(i) for i in random.sample(range(1, 16), 2)]
csr_list = list(csr_map.keys())
with open(f"{out}/riscv_csr_test_{i}.S", "w") as csr_test_file:
with open("{}/riscv_csr_test_{}.S".format(out, i), "w") as csr_test_file:
gen_setup(csr_test_file)
for csr in csr_list:
csr_address, csr_val, csr_write_mask, csr_read_mask = csr_map.get(csr)
csr_test_file.write(f"\t# {csr}\n")
csr_test_file.write("\t# {}\n".format(csr))
for op in csr_instructions:
for i in range(3):
# hex string
@ -286,17 +286,17 @@ def gen_csr_instr(original_csr_map, csr_instructions, xlen,
first_li = ""
if op[-1] == "i":
imm = rand_rs1_val[-5:]
csr_inst = f"\t{op} {dest_reg}, {csr_address}, 0b{imm.bin}\n"
csr_inst = "\t{} {}, {}, 0b{}\n".format(op, dest_reg, csr_address, imm.bin)
imm_val = bitarray(uint=0, length=xlen-5)
imm_val.append(imm)
predict_li = (f"\tli {source_reg}, "
f"{predict_csr_val(op, imm_val, csr_val, csr_write_mask, csr_read_mask)}\n")
predict_li = ("\tli {}, "
"{}\n".format(source_reg, predict_csr_val(op, imm_val, csr_val, csr_write_mask, csr_read_mask)))
else:
first_li = f"\tli {source_reg}, 0x{rand_rs1_val.hex}\n"
csr_inst = f"\t{op} {dest_reg}, {csr_address}, {source_reg}\n"
predict_li = (f"\tli {source_reg}, "
f"{predict_csr_val(op, rand_rs1_val, csr_val, csr_write_mask, csr_read_mask)}\n")
branch_check = f"\tbne {source_reg}, {dest_reg}, csr_fail\n"
first_li = "\tli {}, 0x{}\n".format(source_reg, rand_rs1_val.hex)
csr_inst = "\t{} {}, {}, {}\n".format(op, dest_reg, csr_address, source_reg)
predict_li = ("\tli {}, "
"{}\n".format(source_reg, predict_csr_val(op, rand_rs1_val, csr_val, csr_write_mask, csr_read_mask)))
branch_check = "\tbne {}, {}, csr_fail\n".format(source_reg, dest_reg)
csr_test_file.write(first_li)
csr_test_file.write(csr_inst)
csr_test_file.write(predict_li)
@ -306,11 +306,11 @@ def gen_csr_instr(original_csr_map, csr_instructions, xlen,
been written to the CSR has not been tested.
"""
if csr == csr_list[-1] and op == csr_instructions[-1] and i == 2:
final_csr_read = f"\tcsrr {dest_reg}, {csr_address}\n"
final_csr_read = "\tcsrr {}, {}\n".format(dest_reg, csr_address)
csrrs_read_mask = bitarray(uint=0, length=xlen)
final_li = (f"\tli {source_reg}, "
f"{predict_csr_val('csrrs', csrrs_read_mask, csr_val, csr_write_mask, csr_read_mask)}\n")
final_branch_check = f"\tbne {source_reg}, {dest_reg}, csr_fail\n"
final_li = ("\tli {}, "
"{}\n".format(source_reg, predict_csr_val('csrrs', csrrs_read_mask, csr_val, csr_write_mask, csr_read_mask)))
final_branch_check = "\tbne {}, {}, csr_fail\n".format(source_reg, dest_reg)
csr_test_file.write(final_csr_read)
csr_test_file.write(final_li)
csr_test_file.write(final_branch_check)

View file

@ -20,7 +20,7 @@ class riscv_amo_instr extends riscv_instr;
rand bit rl;
constraint aq_rl_c {
aq && rl == 0;
(aq && rl) == 0;
}
`uvm_object_utils(riscv_amo_instr)