Update google_riscv-dv to google/riscv-dv@61755c0

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

* Adds new PMP directed sequence. (Udi Jonnalagadda)
* Fix typo (aneels3)
* Add gpr_c constraint (aneels3)
* Corrections of a code formatting. (Dariusz Stachanczyk)
* Modify asm, config and pkg files. (aneels3)
* fix riscv_privil_reg compile error (google/riscv-dv#666) (udinator)
* Added methods to the coverage test file (Hodjat Asghari Esfeden)
* Constraints should contain only intergral types - fix added for a
  string variable used in nfields_c constraint. (Dariusz Stachanczyk)
* Minor fixes on coverage test (Hodjat Asghari Esfeden)
* fix pmpcfg csr definitions (Udi Jonnalagadda)
* Pygen: minor fix (danghai)
* Pre_sampling extension (Hodjat Asghari Esfeden)
* Fix opcode in b_extension_c constraint (google/riscv-dv#659)
  (udinator)
* Add vector AMO instruction support (google/riscv-dv#658) (taoliug)
* Terminate when it cannot insert instruction (danghai)
* Riscv_instr_cov added, riscv_instr_cov_test extended, comment
  applied (except for csv_dir) (Hodjat Asghari Esfeden)
* Fix Indentation (aneels3)
* fix imm constraint issue (aneels3)
* fix typo in extend_imm() (aneels3)
* Hodjat (Hodjat Asghari Esfeden)

Signed-off-by: Udi <udij@google.com>
This commit is contained in:
Udi 2020-08-04 14:57:11 -07:00 committed by udinator
parent 7eaf0e4a6e
commit 3ddc92a0fa
20 changed files with 907 additions and 49 deletions

View file

@ -9,6 +9,6 @@
upstream:
{
url: https://github.com/google/riscv-dv
rev: 3cf691dcb96f2cd72250690216b60f2b0c0ac804
rev: 61755c001bec0433fb69458f74d95476d2101cf3
}
}

View file

@ -19,7 +19,7 @@ import os
import vsc
from collections import defaultdict
from bitstring import BitArray
from pygen_src.riscv_instr_pkg import pkg_ins, riscv_reg_t
from pygen_src.riscv_instr_pkg import pkg_ins, riscv_reg_t, riscv_instr_name_t
from pygen_src.isa import rv32i_instr # NOQA
from pygen_src.target.rv32i import riscv_core_setting as rcs
@ -271,14 +271,31 @@ class riscv_instr:
sign = (self.imm & 0x80000000) >> 31
self.imm = self.imm >> (32 - self.imm_len) & self.shift_t
# Signed extension
if((sign and not(self.format == "U_FORMAT")) or (self.imm_type in ["UIMM", "NZUIMM"])):
if(sign and not((self.format.name == "U_FORMAT") or
(self.imm_type.name in ["UIMM", "NZUIMM"]))):
self.imm = self.imm_mask | self.imm
def imm_c(self):
imm_t = BitArray(uint = self.imm, length = 32)
if self.instr_name in [riscv_instr_name_t.SLLIW.name, riscv_instr_name_t.SRLIW.name,
riscv_instr_name_t.SRAIW.name]:
imm_t[20:27:1] = 0
self.imm = imm_t.uint
if self.instr_name in [riscv_instr_name_t.SLLI.name, riscv_instr_name_t.SRLI.name,
riscv_instr_name_t.SRAI.name]:
if rcs.XLEN == 32:
imm_t[20:27:1] = 0
self.imm = imm_t.uint
else:
self.imm_t[20:26:1] = 0
self.imm = imm_t.uint
def post_randomize(self):
self.imm_c()
self.extend_imm()
self.update_imm_str()
def convert2asm(self, prefix=" "):
def convert2asm(self, prefix = " "):
asm_str = pkg_ins.format_string(string = self.get_instr_name(),
length = pkg_ins.MAX_INSTR_STR_LEN)
if(self.category.name != "SYSTEM"):

View file

@ -0,0 +1,46 @@
import sys
import vsc
import logging
from enum import Enum, auto
from pygen_src.riscv_instr_pkg import riscv_reg_t
class operand_sign_e(Enum):
POSITIVE = 0
NEGATIVE = auto()
class div_result_e(Enum):
DIV_NORMAL = 0
DIV_BY_ZERO = auto()
DIV_OVERFLOW = auto()
class compare_result_e(Enum):
EQUAL = 0
LARGER = auto()
SMALLER = auto()
class logical_similarity_e(Enum):
IDENTICAL = 0
OPPOSITE = auto()
SIMILAR = auto()
DIFFERENT = auto()
class special_val_e(Enum):
NORMAL_VAL = 0
MIN_VAL = auto()
MAX_VAL = auto()
ZERO_VAL = auto()
def get_gpr(reg_name):
reg_name = reg_name.upper()
if not reg_name in riscv_reg_t:
logging.fatal("Cannot convert {} to GPR".format(reg_name))
return riscv_reg_t[reg_name]
def get_gpr_state(reg_name):
if reg_name in ["zero", "x0"]:
return 0
elif reg_name in gpr_state:
return gpr_state[reg_name]
else:
logging.warning("Cannot find GPR state: {}".format(reg_name))

View file

@ -17,7 +17,7 @@ import logging
import random
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)
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.target.rv32i import riscv_core_setting as rcs
'''
@ -103,9 +103,31 @@ class riscv_asm_program_gen:
logging.info("Main/sub program generation...done")
# program end
self.gen_program_end(hart)
for hart in range(cfg.num_of_harts):
self.gen_data_page_begin(hart)
if(cfg.no_data_page):
self.gen_data_page()
if((hart == 0) and ("RV32A" in rcs.supported_isa)):
self.gen_data_page(hart, amo = 1)
self.gen_stack_section(hart)
if(not cfg.bare_program_mode):
self.gen_kernel_sections(hart)
def gen_kernel_sections(self, hart):
pass
if(rcs.SATP_MODE != "BARE"):
self.instr_stream.append(".align 12")
else:
self.instr_stream.append(".align 2")
self.instr_stream.append(pkg_ins.get_label("kernel_instr_start:", hart))
self.instr_stream.append(".text")
self.gen_all_trap_handler(hart)
for mode in rcs.supported_privileged_mode:
self.gen_interrupt_handler_section(mode, hart)
self.gen_kernel_stack_section(hart)
def gen_kernel_program(self, hart, seq):
pass
@ -146,16 +168,57 @@ class riscv_asm_program_gen:
self.gen_section("_exit", ["j write_tohost"])
def gen_data_page_begin(self, hart):
pass
self.instr_stream.append(".section .data")
if (hart == 0):
self.instr_stream.append(".align 6; .global tohost; tohost: .dword 0;")
self.instr_stream.append(".align 6; .global fromhost; fromhost: .dword 0;")
def gen_data_page(self, hart, is_kernel = 0, amo = 0):
pass
def gen_stack_section(self, hart):
pass
hart_prefix_string = pkg_ins.hart_prefix(hart)
if(cfg.use_push_data_section):
self.instr_stream.append(
".pushsection .{}user_stack,\"aw\",@progbits;".format(hart_prefix_string))
else:
self.instr_stream.append(
".section .{}user_stack,\"aw\",@progbits;".format(hart_prefix_string))
if(rcs.SATP_MODE != "BARE"):
self.instr_stream.append(".align 12")
else:
self.instr_stream.append(".align 2")
self.instr_stream.append(pkg_ins.get_label("user_stack_start:", hart))
self.instr_stream.append(".rept {}".format(cfg.kernel_stack_len - 1))
self.instr_stream.append(".{}byte 0x0".format(rcs.XLEN // 8))
self.instr_stream.append(".endr")
self.instr_stream.append(pkg_ins.get_label("user_stack_end:", hart))
self.instr_stream.append(".{}byte 0x0".format(rcs.XLEN // 8))
if (cfg.use_push_data_section):
self.instr_stream.push_back(".popsection;")
def gen_kernel_stack_section(self, hart):
pass
hart_prefix_string = pkg_ins.hart_prefix(hart)
if(cfg.use_push_data_section):
self.instr_stream.append(
".pushsection .{}kernel_stack,\"aw\",@progbits;".format(hart_prefix_string))
else:
self.instr_stream.append(
".section .{}kernel_stack,\"aw\",@progbits;".format(hart_prefix_string))
if(rcs.SATP_MODE != "BARE"):
self.instr_stream.append(".align 12")
else:
self.instr_stream.append(".align 2")
self.instr_stream.append(pkg_ins.get_label("kernel_stack_start:", hart))
self.instr_stream.append(".rept {}".format(cfg.kernel_stack_len - 1))
self.instr_stream.append(".{}byte 0x0".format(rcs.XLEN // 8))
self.instr_stream.append(".endr")
self.instr_stream.append(pkg_ins.get_label("kernel_stack_end:", hart))
self.instr_stream.append(".{}byte 0x0".format(rcs.XLEN // 8))
if (cfg.use_push_data_section):
self.instr_stream.push_back(".popsection;")
def gen_init_section(self, hart):
string = pkg_ins.format_string("init:", pkg_ins.LABEL_STR_LEN)
@ -246,8 +309,8 @@ class riscv_asm_program_gen:
if(cfg.virtual_addr_translation_on):
self.page_table_list.process_page_table(instr)
self.gen_section(pkg_ins.get_label("process_pt", hart), instr)
self.setup_epc(hart)
# Commenting for now
# self.setup_epc(hart)
if(rcs.support_pmp):
self.gen_privileged_mode_switch_routine(hart)
@ -321,14 +384,46 @@ class riscv_asm_program_gen:
self.gen_section(pkg_ins.get_label("trap_vec_init", hart), instr)
def gen_all_trap_handler(self, hart):
pass
if(not rcs.support_pmp):
self.gen_trap_handlers(hart)
self.gen_ecall_handler(hart)
self.gen_instr_fault_handler(hart)
self.gen_load_fault_handler(hart)
self.gen_store_fault_handler(hart)
def gen_trap_handlers(self, hart):
pass
self.gen_trap_handler_section(hart, "m", privileged_reg_t.MCAUSE,
privileged_reg_t.MTVEC, privileged_reg_t.MTVAL,
privileged_reg_t.MEPC, privileged_reg_t.MSCRATCH,
privileged_reg_t.MSTATUS, privileged_reg_t.MIE,
privileged_reg_t.MIP)
def gen_trap_handler_section(self, hart, mode, cause, tvec,
tval, epc, scratch, status, ie, ip):
pass
is_interrupt = 1
tvec_name = ""
instr = []
if (cfg.mtvec_mode == mtvec_mode_t.VECTORED):
self.gen_interrupt_vector_table(hart, mode, status, cause, ie, ip, scratch, instr)
else:
# Push user mode GPR to kernel stack before executing exception handling,
# this is to avoid exception handling routine modify user program state
# unexpectedly
# TODO
pkg_ins.push_gpr_to_kernel_stack(
status, scratch, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr)
# The trap handler will occupy one 4KB page, it will be allocated one entry in
# the page table with a specific privileged mode.
if (rcs.SATP_MODE != "BARE"):
self.instr_stream.append(".align 12")
else:
self.instr_stream.append(".align {}".format(cfg.tvec_alignment))
tvec_name = tvec.name
self.gen_section(pkg_ins.get_label("{}_handler".format(tvec_name.lower()), hart), instr)
# TODO Exception handler
def gen_interrupt_vector_table(self, hart, mode, status, cause, ie,
ip, scratch, instr):
@ -362,7 +457,74 @@ class riscv_asm_program_gen:
pass
def gen_interrupt_handler_section(self, mode, hart):
pass
interrupt_handler_instr = []
ls_unit = "w" if (rcs.XLEN == 32) else "d"
# TODO
# if(mode.value < cfg.init_privileged_mode):
# return
if(mode is privileged_mode_t.USER_MODE.name and not (rcs.support_umode_trap)):
return
if(mode == privileged_mode_t.MACHINE_MODE.name):
mode_prefix = "m"
status = privileged_reg_t.MSTATUS
ip = privileged_reg_t.MIP
ie = privileged_reg_t.MIE
scratch = privileged_reg_t.MSCRATCH
elif(mode is privileged_mode_t.SUPERVISOR_MODE.name):
mode_prefix = "s"
status = privileged_reg_t.SSTATUS
ip = privileged_reg_t.SIP
ie = privileged_reg_t.SIE
scratch = privileged_reg_t.SSCRATCH
elif(mode == privileged_mode_t.USER_MODE.name):
mode_prefix = "u"
status = privileged_reg_t.USTATUS
ip = privileged_reg_t.UIP
ie = privileged_reg_t.UIE
scratch = privileged_reg_t.USCRATCH
else:
logging.critical("Unsupported mode: %0s" % (mode))
if(cfg.enable_nested_interrupt):
interrupt_handler_instr.append("csrr x%0d, 0x%0x" % (cfg.gpr[0].value, scratch.value))
interrupt_handler_instr.append("bgtz x%0d, 1f" % (cfg.gpr[0].value))
interrupt_handler_instr.append("csrwi 0x%0x, 0x1" % (scratch.value))
if(status == privileged_reg_t.MSTATUS):
interrupt_handler_instr.append("csrsi 0x%0x, 0x%0x" % (status.value, 8))
elif(status == privileged_reg_t.SSTATUS):
interrupt_handler_instr.append("csrsi 0x%0x, 0x%0x" % (status.value, 2))
elif(status == privileged_reg_t.USTATUS):
interrupt_handler_instr.append("csrsi 0x%0x, 0x%0x" % (status.value, 1))
else:
logging.critical("Unsupported status %0s" % (status.value))
interrupt_handler_instr.append("1: csrwi 0x%0x,0" % (scratch.value))
to_extend_interrupt_hanlder_instr = ["csrr x%0d, 0x%0x # %0s;" % (cfg.gpr[0].value,
status.value,
status.name),
"csrr x%0d, 0x%0x # %0s;" % (cfg.gpr[0].value,
ie.value, ie.name),
"csrr x%0d, 0x%0x # %0s;" % (cfg.gpr[0].value,
ip.value, ip.name),
"csrrc x%0d, 0x%0x, x%0d # %0s;" % (cfg.gpr[0].value,
ip.value,
cfg.gpr[0].value,
ip.name)]
interrupt_handler_instr.extend(to_extend_interrupt_hanlder_instr)
self.gen_plic_section(interrupt_handler_instr)
pkg_ins.pop_gpr_from_kernel_stack(status.name, scratch.name, cfg.mstatus_mprv,
cfg.sp, cfg.tp, interrupt_handler_instr)
interrupt_handler_instr.append("%0sret;" % (mode_prefix))
if(rcs.SATP_MODE != "BARE"):
self.instr_stream.append(".align 12")
else:
self.instr_stream.append(".align 2")
self.gen_section(pkg_ins.get_label("%0smode_intr_handler" %
(mode_prefix), hart), interrupt_handler_instr)
def format_section(self, instr):
pass

View file

@ -63,7 +63,14 @@ class riscv_instr_gen_config:
self.fcsr_rm = list(map(lambda csr_rm: csr_rm.name, f_rounding_mode_t))
self.enable_sfence = 0
self.gpr = vsc.rand_list_t(vsc.enum_t(riscv_reg_t), sz =4)
self.gpr = []
# Helper fields for gpr
self.gpr0 = vsc.rand_enum_t(riscv_reg_t)
self.gpr1 = vsc.rand_enum_t(riscv_reg_t)
self.gpr2 = vsc.rand_enum_t(riscv_reg_t)
self.gpr3 = vsc.rand_enum_t(riscv_reg_t)
self.scratch_reg = vsc.rand_enum_t(riscv_reg_t)
self.pmp_reg = vsc.rand_enum_t(riscv_reg_t)
self.sp = vsc.rand_enum_t(riscv_reg_t)
@ -154,7 +161,15 @@ class riscv_instr_gen_config:
@vsc.constraint
def gpr_c(self):
pass # TODO
self.gpr0.not_inside(vsc.rangelist(self.sp, self.tp, self.scratch_reg, self.pmp_reg,
riscv_reg_t.ZERO, riscv_reg_t.RA, riscv_reg_t.GP))
self.gpr1.not_inside(vsc.rangelist(self.sp, self.tp, self.scratch_reg, self.pmp_reg,
riscv_reg_t.ZERO, riscv_reg_t.RA, riscv_reg_t.GP))
self.gpr2.not_inside(vsc.rangelist(self.sp, self.tp, self.scratch_reg, self.pmp_reg,
riscv_reg_t.ZERO, riscv_reg_t.RA, riscv_reg_t.GP))
self.gpr3.not_inside(vsc.rangelist(self.sp, self.tp, self.scratch_reg, self.pmp_reg,
riscv_reg_t.ZERO, riscv_reg_t.RA, riscv_reg_t.GP))
vsc.unique(self.gpr0, self.gpr1, self.gpr2, self.gpr3)
def check_setting(self):
support_64b = 0
@ -221,6 +236,9 @@ class riscv_instr_gen_config:
self.s_mode_interrupt_delegation[j] = 0
def pre_randomize(self):
# Clearing the contents of self.gpr after each randomization.
# As it is being extended in post_randomize function.
self.gpr.clear()
for x in rcs.supported_privileged_mode:
if(x == "SUPERVISOR_MODE"):
self.support_supervisor_mode = 1
@ -229,6 +247,9 @@ class riscv_instr_gen_config:
pass
def post_randomize(self):
# Temporary fix for gpr_c constraint.
self.gpr.extend((self.gpr0, self.gpr1, self.gpr2, self.gpr3))
self.reserved_regs.append(self.tp)
self.reserved_regs.append(self.sp)
self.reserved_regs.append(self.scratch_reg)
@ -252,7 +273,7 @@ class riscv_instr_gen_config:
for mode in self.init_privileged_mode:
if mode == "MACHINE_MODE":
continue
elif mode == 'SUPERVISOR_MODE':
if mode == 'SUPERVISOR_MODE':
invalid_lvl.append('M')
logging.info("supr_mode---")
logging.debug(invalid_lvl)
@ -295,8 +316,10 @@ def parse_args():
parse.add_argument('--no_ebreak', help = 'no_ebreak', choices = [0, 1], type = int, default = 1)
parse.add_argument('--no_dret', help = 'no_dret', choices = [0, 1], type = int, default = 1)
parse.add_argument('--no_wfi', help = 'no_wfi', choices = [0, 1], type = int, default = 1)
# TODO : Enabling no_branch_jump default to 1 for now.
parse.add_argument('--no_branch_jump', help = 'no_branch_jump',
choices = [0, 1], type = int, default = 0)
choices = [0, 1], type = int, default = 1)
parse.add_argument('--no_load_store', help = 'no_load_store',
choices = [0, 1], type = int, default = 0)
parse.add_argument('--no_csr_instr', help = 'no_csr_instr',

View file

@ -12,6 +12,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
import logging
from enum import Enum, auto
from bitstring import BitArray
from pygen_src.target.rv32i import riscv_core_setting as rcs
@ -1160,6 +1161,23 @@ class all_categories(Enum):
INTERRUPT = auto()
AMO = auto()
def get_val(in_string, hexa=0):
if len(in_string) > 2:
if "0x" in in_string:
out_val = hex(int(in_string, base=16))
return out_val
if hexa:
out_val = hex(int(in_string, base=16))
else:
out_val = int(in_string)
logging.info("riscv_instr_pkg: imm: {} -> {}".format(in_string, out_val))
return out_val
class hazard_e(Enum):
NO_HAZARD = 0
RAW_HAZARD = auto()
WAR_HAZARD = auto()
WAW_HAZARD = auto()
class riscv_instr_pkg:
def __init__(self):
@ -1191,7 +1209,7 @@ class riscv_instr_pkg:
formatted_str = length * " "
if (int(length) < len(string)):
return string
formatted_str = string + formatted_str[0: (int(length) - len(string) - 1)]
formatted_str = string + formatted_str[0: (int(length) - len(string))]
return formatted_str
def format_data(self, data, byte_per_group = 4):
@ -1202,5 +1220,11 @@ class riscv_instr_pkg:
string = string + f"{hex(data[i])}"
return string
def push_gpr_to_kernel_stack(self, status, scratch, mprv, sp, tp, instr):
pass
def pop_gpr_from_kernel_stack(self, status, scratch, mprv, sp, tp, instr):
pass
pkg_ins = riscv_instr_pkg()

View file

@ -63,6 +63,7 @@ class riscv_instr_stream:
return
elif idx > current_instr_cnt or idx < 0:
logging.error("Cannot insert instr:%0s at idx %0d", instr.convert2asm(), idx)
sys.exit(1)
self.instr_list.insert(idx, instr)
def insert_instr_stream(self, new_instr, idx = -1, replace = 0):
@ -128,7 +129,7 @@ class riscv_instr_stream:
if len(insert_instr_position) > 0:
insert_instr_position.sort()
for i in range(new_instr_cnt):
insert_instr_position[i] = random.rangeint(0, current_instr_cnt)
insert_instr_position[i] = random.randint(0, current_instr_cnt)
if len(insert_instr_position) > 0:
insert_instr_position.sort()
if contained:
@ -201,7 +202,7 @@ class riscv_rand_instr_stream(riscv_instr_stream):
if len(self.instr_list) == 0:
break
def randomize_instr(self, instr, is_in_debug = 0, disable_dist = 0):
def randomize_instr(self, instr, is_in_debug = 0):
exclude_instr = []
is_SP_in_reserved_rd = riscv_reg_t.SP in self.reserved_rd
is_SP_in_reserved_regs = riscv_reg_t.SP in cfg.reserved_regs

View file

@ -16,7 +16,7 @@ XLEN = 32
implemented_csr = ['MVENDORID', 'MARCHID', 'MIMPID', 'MHARTID', 'MSTATUS', 'MISA', 'MIE',
'MTVEC', 'MCOUNTEREN', 'MSCRATCH', 'MEPC', 'MCAUSE', 'MTVAL', 'MIP']
SATP_MODE = ['BARE']
SATP_MODE = 'BARE'
supported_isa = ['RV32I']

View file

@ -0,0 +1,407 @@
# Lint as: python3
"""Tests for riscv_instr_cov."""
import sys
import os
import logging
import argparse
import vsc # PyVSC library
import csv # Python library to read/write from/to CSV files
from bitstring import BitArray
from pygen.pygen_src.isa.riscv_instr_cov import *
from pygen.pygen_src.riscv_instr_pkg import *
from pygen.pygen_src.target.rv32i import riscv_core_setting as rcs
logging.basicConfig(filename='logging.log',level=logging.DEBUG)
class riscv_instr():
""" Class for a riscv instruction; data parsed from the CSV file will fill
different fields of an instruction """
# class attr. to keep track of reg_name:reg_value throughout the program
gpr_state = {}
def __init__(self, instr_name):
self.pc = 0 # Program counter (PC) of the instruction
self.instr = instr_name
self.gpr = None # destination operand of the instruction
self.csr = None
self.binary = 0 # Instruction binary
self.mode = None # Instruction mode
self.trace = "None" # String representation of the instruction
self.operands = "None" # Instruction operands (srcss/dests)
self.pad = None # Not used
self.rs1_value = None
self.rs2_value = None
self.rs3_value = None
self.rd_value = None
self.fs1_value = None
self.fs2_value = None
self.fs3_value = None
self.fd_value = None
self.mem_addr = None
self.unaligned_pc = 0
self.unaligned_mem_access = 0
self.compressed = 0
self.branch_hit = 0
self.div_result = None
self.rs1_sign = None
self.rs2_sign = None
self.rs3_sign = None
self.fs1_sign = None
self.fs2_sign = None
self.fs3_sign = None
self.imm_sign = None
self.rd_sign = None
self.gpr_hazard = None
self.lsu_hazard = None
self.rs1_special_value = None
self.rs2_special_value = None
self.rs3_special_value = None
self.rd_special_value = None
self.imm_special_value = None
self.compare_result = None
self.logical_similarity = None
# TODO: add & map...
#self.imm
#self.format
#self.category
def pre_sample(self):
unaligned_pc = self.pc[-2:] != "00"
self.rs1_sign = self.get_operand_sign(self.rs1_value)
self.rs2_sign = self.get_operand_sign(self.rs2_value)
self.rs3_sign = self.get_operand_sign(self.rs3_value)
self.rd_sign = self.get_operand_sign(self.rd_value)
self.fs1_sign = self.get_operand_sign(self.fs1_value)
self.fs2_sign = self.get_operand_sign(self.fs2_value)
self.fs3_sign = self.get_operand_sign(self.fs3_value)
self.fd_sign = self.get_operand_sign(self.fd_value)
self.imm_sign = self.get_imm_sign(self.imm)
self.rs1_special_value = self.get_operand_special_value(self.rs1_value)
self.rd_special_value = self.get_operand_special_value(self.rd_value)
self.rs2_special_value = self.get_operand_special_value(self.rs2_value)
self.rs3_special_value = self.get_operand_special_value(self.rs3_value)
if (self.format != riscv_instr_format_t.R_FORMAT and
self.format != riscv_instr_format_t.CR_FORMAT):
self.imm_special_value = self.get_imm_special_val(self.imm)
if self.category in [riscv_instr_category_t.COMPARE,
riscv_instr_category_t.BRANCH]:
self.compare_result = self.get_compare_result()
if self.category in [riscv_instr_category_t.LOAD,
riscv_instr_category_t.STORE]:
self.mem_addr = self.rs1_value + self.imm
self.unaligned_mem_access = self.is_unaligned_mem_access()
if self.unaligned_mem_access:
logging.info("Unaligned: {}, mem_addr: {}".format(
self.instr, self.mem_addr))
if self.category == riscv_instr_category_t.LOGICAL:
self.logical_similarity = self.get_logical_similarity()
if self.category == riscv_instr_category_t.BRANCH:
self.branch_hit = self.is_branch_hit()
#TODO: string > enumeration
if self.instr in ["DIV", "DIVU", "REM", "REMU", "DIVW", "DIVUW",
"REMW", "REMUW"]:
self.div_result = self.get_div_result()
def get_operand_sign(self, operand):
#TODO: change operand to vsc.bit_t
out = BitArray(int=operand.val, length=rcs.XLEN)
if out[0]:
return operand_sign_e["NEGATIVE"]
else:
return operand_sign_e["POSITIVE"]
def is_unaligned_mem_access(self):
#TODO: string > enumeration
if (self.instr in ["LWU", "LD", "SD", "C_LD", "C_SD"] and
self.mem_addr % 8 != 0):
return True
elif (self.instr in ["LW", "SW", "C_LW", "C_SW"] and
self.mem_addr % 4 != 0):
return True
elif (self.instr in ["LH", "LHU", "SH"] and
self.mem_addr % 2 != 0):
return True
return False
def get_imm_sign(self, imm):
#TODO: change imm to vsc.int_t(32)
out = BitArray(int=imm.val, length=rcs.XLEN)
if out[0]:
return operand_sign_e["NEGATIVE"]
else:
return operand_sign_e["POSITIVE"]
def get_div_result(self):
#TODO: change rs2_value to vsc.int_t(32)
if self.rs2_value.val == 0:
return div_result_e["DIV_BY_ZERO"]
elif self.rs2_value.val == 1 and self.rs1_value.val == (1 << (rcs.XLEN-1)):
return div_result_e["DIV_OVERFLOW"]
else:
return div_result_e["DIV_NORMAL"]
def get_operand_special_value(self, operand):
if operand.val == 0:
return special_val_e["ZERO_VAL"]
elif operand.val == 1 << (rcs.XLEN-1):
return special_val_e["MIN_VAL"]
elif operand.val == 1 >> 1:
return special_val_e["MAX_VAL"]
else:
return special_val_e["NORMAL_VAL"]
def get_imm_special_val(self, imm):
if imm.val == 0:
return special_val_e["ZERO_VAL"]
elif self.format == riscv_instr_format_t.U_FORMAT:
# unsigned immediate value
# TODO: self.imm_len
max = vsc.int_t(32, (1 << self.imm_len)-1)
if imm.val == 0:
return special_val_e["MIN_VAL"]
if imm.val == max.val:
return special_val_e["MAX_VAL"]
else:
# signed immediate value
max = vsc.int_t(32, (2 ** (self.imm_len - 1)) - 1)
min = vsc.int_t(32, -2 ** (self.imm_len - 1))
if min.val == imm.val:
return special_val_e["MIN_VAL"]
if max.val == imm.val:
return special_val_e["MAX_VAL"]
return special_val_e["NORMAL_VAL"]
def get_compare_result(self):
val1 = vsc.int_t(rcs.XLEN)
val2 = vsc.int_t(rcs.XLEN)
val1.val = self.rs1_value.val
val2.val = self.imm.val if (
self.format == riscv_instr_format_t.I_FORMAT) \
else self.rs2_value.val
if val1.val == val2.val:
return compare_result_e["EQUAL"]
elif val1.val < val2.val:
return compare_result_e["SMALLER"]
else:
return compare_result_e["LARGER"]
def is_branch_hit(self):
# TODO: string/enumeration
if self.instr == "BEQ":
return self.rs1_value.val == self.rs2_value.val
elif self.instr == "C_BEQZ":
return self.rs1_value.val == 0
elif self.instr == "BNE":
return self.rs1_value.val != self.rs2_value.val
elif self.instr == "C_BNEZ":
return self.rs1_value.val != 0
elif self.instr == "BLT" or self.instr == "BLTU":
return self.rs1_value.val < self.rs2_value.val
elif self.instr == "BGE" or self.instr == "BGEU":
return self.rs1_value.val >= self.rs2_value.val
else:
logging.error("Unexpected instruction {}".format(self.instr))
def get_logical_similarity(self):
val1 = vsc.int_t(rcs.XLEN, self.rs1_value.val)
val2 = vsc.int_t(rcs.XLEN)
val2.val = (self.imm.val if self.format == riscv_instr_format_t.I_FORMAT
else self.rs2_value.val)
temp = bin(val1.val ^ val2.val)
bit_difference = len([[ones for ones in temp[2:] if ones=='1']])
if val1.val == val2.val:
return logical_similarity_e["IDENTICAL"]
elif bit_difference == 32:
return logical_similarity_e["OPPOSITE"]
elif bit_difference < 5:
return logical_similarity_e["SIMILAR"]
else:
return logical_similarity_e["DIFFERENT"]
def check_hazard_condition(self, pre_instr):
# TODO: has_rd(), has_rs1, has_rs2, rd, category, convert2asm (from IG)
if pre_instr.has_rd():
if ((self.has_rs1 and self.rs1 == pre_instr.rd) or
(self.has_rs2 and self.rs1 == pre_instr.rd)):
self.gpr_hazard = hazard_e["RAW_HAZARD"]
elif self.has_rd and self.rd == pre_instr.rd:
self.gpr_hazard = hazard_e["WAW_HAZARD"]
elif (self.has_rd and
((pre_instr.has_rs1 and (pre_instr.rs1 == self.rd)) or
(pre_instr.has_rs2 and (pre_instr.rs2 == self.rd)))):
self.gpr_hazard = hazard_e["WAR_HAZARD"]
else:
self.gpr_hazard = hazard_e["NO_HAZARD"]
if self.category == riscv_instr_category_t.LOAD:
# TODO: change mem_addr to vsc type
if (pre_instr.category == riscv_instr_category_t.STORE and
pre_instr.mem_addr == self.mem_addr):
self.lsu_hazard = hazard_e["RAW_HAZARD"]
else:
self.lsu_hazard = hazard_e["NO_HAZARD"]
if self.category == riscv_instr_category_t.STORE:
if (pre_instr.category == riscv_instr_category_t.STORE and
pre_instr.mem_addr == self.mem_addr):
self.lsu_hazard = hazard_e["WAW_HAZARD"]
elif (pre_instr.category == riscv_instr_category_t.LOAD and
pre_instr.mem_addr == self.mem_addr):
self.lsu_hazard = hazard_e["WAR_HAZARD"]
else:
self.lsu_hazard = hazard_e["NO_HAZARD"]
logging.info("Pre: {}, Cur: {}, Hazard: {}/{}".format(
pre_instr.convert2asm(), self.convert2asm(),
self.gpr_hazard.name, self.lsu_hazard.name))
def update_src_regs(self, operands):
pass
def update_dst_regs(self, reg_name, val_str):
pass
class riscv_instr_cov_test():
""" Main class for applying the functional coverage test """
def __init__(self, argv):
self.trace = {}
self.csv_trace = argv
self.entry_cnt, self.total_entry_cnt, self.skipped_cnt, \
self.unexpected_illegal_instr_cnt = 0, 0, 0, 0
def run_phase(self):
if not self.csv_trace:
sys.exit("No CSV file found!")
logging.info("{} CSV trace files to be "
"processed...\n".format(len(self.csv_trace)))
expect_illegal_instr = False
# Assuming we get list of csv files pathname from cov.py in argv
for csv_file in self.csv_trace:
with open("{}".format(csv_file)) as trace_file:
self.entry_cnt = 0
header = []
entry = []
csv_reader = csv.reader(trace_file, delimiter=',')
line_count = 0
# Get the header line
for row in csv_reader:
if line_count == 0:
header = row
logging.info("Header: {}".format(header))
else:
entry = row
if len(entry) != len(header):
logging.info("Skipping malformed entry[{}]: "
"[{}]".format(self.entry_cnt, entry))
self.skipped_cnt += 1
else:
self.trace["csv_entry"] = row
for idx in range(len(header)):
if "illegal" in entry[idx]:
expect_illegal_instr = True
self.trace[header[idx]] = entry[idx]
if header[idx] != "pad":
logging.info("{} = {}".format(header[idx],
entry[idx]))
self.post_process_trace()
if self.trace["instr"] in ["li", "ret", "la"]:
pass
if "amo" in self.trace["instr"] or \
"lr" in self.trace["instr"] or \
"sc" in self.trace["instr"]:
# TODO: Enable functional coverage for AMO test
pass
if not self.sample():
if not expect_illegal_instr:
logging.error("Found unexpected illegal "
"instr: {} "
"[{}]".format(self.trace[
"instr"],entry))
self.unexpected_illegal_instr_cnt += 1
self.entry_cnt += 1
line_count += 1
logging.info("[{}]: {} instr processed".format(csv_file,
self.entry_cnt))
self.total_entry_cnt += self.entry_cnt
logging.info("Finished processing {} trace CSV, {} "
"instructions".format(len(self.csv_trace),
self.total_entry_cnt))
if self.skipped_cnt > 0 or self.unexpected_illegal_instr_cnt > 0:
logging.error("{} instruction skipped, {} illegal "
"instructions".format(self.skipped_cnt),
self.unexpected_illegal_instr_cnt)
def post_process_trace(self):
pass
def sample(self):
instr_name, binary = "", ""
binary = get_val(self.trace["binary"], hexa=1)
if binary[-2:] != "11": #TODO: and RV32C in supported_isa
#TODO: sample compressed instruction
pass
if binary[-2:] == "11":
#TODO: sampling
pass
#TODO: buch of if statements to check if the instruction name is valid
# and is a member of registered ones
instr_name = self.process_instr_name(self.trace["instr"])
instruction = riscv_instr(instr_name)
#TODO: check the instruction group...
self.assign_trace_info_to_instr(instruction)
#TODO: instruction.pre_sample() and sample(instruction)
return True
def assign_trace_info_to_instr(self, instruction):
operands, gpr_update, pair = [], [], []
instruction.pc = get_val(self.trace["pc"], hexa=1)
instruction.binary = get_val(self.trace["binary"], hexa=1)
instruction.gpr = self.trace["gpr"]
instruction.csr = self.trace["csr"]
instruction.mode = self.trace["mode"]
instruction.trace = self.trace["instr_str"]
instruction.operands = self.trace["operand"]
operands = self.trace["operand"].split(",")
instruction.update_src_regs(operands)
gpr_update = self.trace["gpr"].split(";")
if len(gpr_update) == 1 and gpr_update[0] == "":
gpr_update = []
for dest in gpr_update:
pair = dest.split(":")
if len(pair) != 2:
logging.error("Illegal gpr update format: {}".format(dest))
instruction.update_dst_regs(pair[0], pair[1])
instruction.pad = self.trace["pad"]
def process_instr_name(self, instruction):
instruction = instruction.upper()
instruction.replace(".", "_")
instruction = self.update_instr_name(instruction)
return instruction
def update_instr_name(self, instruction):
switcher = {
# Rename to new name as ovpsim still uses old name
"FMV_S_X": "FMV_W_X",
"FMV_X_S": "FMV_X_W",
# Convert pseudoinstructions
"FMV_S": "FSGNJ_S",
"FABS_S": "FSGNJX_S",
"FNEG_S": "FSGNJN_S",
"FMV_D": "FSGNJ_D",
"FABS_D": "FSGNJX_D",
"FNEG_D": "FSGNJN_D",
}
# if instruction is not present in the dictionary,second argument well
# be assigned as default value of passed argument
instruction = switcher.get(instruction, instruction)
return instruction
def main(argv):
cov_test = riscv_instr_cov_test(argv)
cov_test.run_phase()
if __name__ == "__main__":
main(sys.argv)

View file

@ -183,7 +183,7 @@ class riscv_vector_instr extends riscv_floating_point_instr;
// Vector register numbers accessed by the segment load or store would increment
// cannot past 31
constraint nfields_c {
if (sub_extension == "zvlsseg") {
if (check_sub_extension(sub_extension, "zvlsseg")) {
if (m_cfg.vector_cfg.vtype.vlmul < 8) {
(nfields + 1) * m_cfg.vector_cfg.vtype.vlmul <= 8;
if (category == LOAD) {
@ -261,13 +261,13 @@ class riscv_vector_instr extends riscv_floating_point_instr;
}
// 7.8.3 For vector indexed segment loads, the destination vector register groups
// cannot overlap the source vectorregister group (specied by vs2), nor can they
// overlap the mask register if maske
if (format == VLX_FORMAT) {
// overlap the mask register if masked
// AMO instruction uses indexed address mode
if (format inside {VLX_FORMAT, VAMO_FORMAT}) {
vd != vs2;
}
}
`uvm_object_utils(riscv_vector_instr)
`uvm_object_new
@ -421,6 +421,15 @@ class riscv_vector_instr extends riscv_floating_point_instr;
vs3.name(), rs1.name(), vs2.name());
end
end
VAMO_FORMAT: begin
if (wd) begin
asm_str = $sformatf("%0s %0s,(%0s),%0s,%0s", get_instr_name(), vd.name(),
rs1.name(), vs2.name(), vd.name());
end else begin
asm_str = $sformatf("%0s x0,(%0s),%0s,%0s", get_instr_name(),
rs1.name(), vs2.name(), vs3.name());
end
end
default: begin
`uvm_fatal(`gfn, $sformatf("Unsupported format %0s", format.name()))
end
@ -495,5 +504,9 @@ class riscv_vector_instr extends riscv_floating_point_instr;
string suffix = instr_name.substr(prefix.len(), instr_name.len() - 1);
return $sformatf("%0s%0d%0s", prefix, nfields + 1, suffix);
endfunction
function bit check_sub_extension(string s, string literal);
return s == literal;
endfunction
endclass : riscv_vector_instr

View file

@ -298,3 +298,27 @@
`DEFINE_VA_INSTR(VSUXSEGH_V, VSX_FORMAT, STORE, RVV, {}, "zvlsseg")
`DEFINE_VA_INSTR(VSUXSEGW_V, VSX_FORMAT, STORE, RVV, {}, "zvlsseg")
`DEFINE_VA_INSTR(VSUXSEGE_V, VSX_FORMAT, STORE, RVV, {}, "zvlsseg")
// -------------------------------------------------------------------------
// Section 8. Vector AMO Operations (Zvamo)
// -------------------------------------------------------------------------
// 32-bit vector AMOs
`DEFINE_VA_INSTR(VAMOSWAPW_V, VAMO_FORMAT, AMO, RVV, {}, "zvamo")
`DEFINE_VA_INSTR(VAMOADDW_V, VAMO_FORMAT, AMO, RVV, {}, "zvamo")
`DEFINE_VA_INSTR(VAMOXORW_V, VAMO_FORMAT, AMO, RVV, {}, "zvamo")
`DEFINE_VA_INSTR(VAMOANDW_V, VAMO_FORMAT, AMO, RVV, {}, "zvamo")
`DEFINE_VA_INSTR(VAMOORW_V, VAMO_FORMAT, AMO, RVV, {}, "zvamo")
`DEFINE_VA_INSTR(VAMOMINW_V, VAMO_FORMAT, AMO, RVV, {}, "zvamo")
`DEFINE_VA_INSTR(VAMOMAXW_V, VAMO_FORMAT, AMO, RVV, {}, "zvamo")
`DEFINE_VA_INSTR(VAMOMINUW_V, VAMO_FORMAT, AMO, RVV, {}, "zvamo")
`DEFINE_VA_INSTR(VAMOMAXUW_V, VAMO_FORMAT, AMO, RVV, {}, "zvamo")
// SEW-bit vector AMOs
`DEFINE_VA_INSTR(VAMOSWAPE_V, VAMO_FORMAT, AMO, RVV, {}, "zvamo")
`DEFINE_VA_INSTR(VAMOADDE_V, VAMO_FORMAT, AMO, RVV, {}, "zvamo")
`DEFINE_VA_INSTR(VAMOXORE_V, VAMO_FORMAT, AMO, RVV, {}, "zvamo")
`DEFINE_VA_INSTR(VAMOANDE_V, VAMO_FORMAT, AMO, RVV, {}, "zvamo")
`DEFINE_VA_INSTR(VAMOORE_V, VAMO_FORMAT, AMO, RVV, {}, "zvamo")
`DEFINE_VA_INSTR(VAMOMINE_V, VAMO_FORMAT, AMO, RVV, {}, "zvamo")
`DEFINE_VA_INSTR(VAMOMAXE_V, VAMO_FORMAT, AMO, RVV, {}, "zvamo")
`DEFINE_VA_INSTR(VAMOMINUE_V, VAMO_FORMAT, AMO, RVV, {}, "zvamo")
`DEFINE_VA_INSTR(VAMOMAXUE_V, VAMO_FORMAT, AMO, RVV, {}, "zvamo")

View file

@ -188,3 +188,32 @@ class riscv_amo_instr_stream extends riscv_amo_base_instr_stream;
endfunction
endclass : riscv_amo_instr_stream
class riscv_vector_amo_instr_stream extends riscv_vector_load_store_instr_stream;
constraint amo_address_mode_c {
// AMO operation only supports word alignment or element alignemt
alignment inside {W_ALIGNMENT, E_ALIGNMENT};
// AMO operation uses indexed address mode
address_mode == INDEXED;
// For the 32-bit vector AMO operations, SEW must be at least 32 bit
(cfg.vector_cfg.vtype.vsew < 32) -> (alignment != W_ALIGNMENT);
}
`uvm_object_utils(riscv_vector_amo_instr_stream)
`uvm_object_new
virtual function void add_element_vec_load_stores();
allowed_instr = {VAMOSWAPE_V, VAMOADDE_V, VAMOXORE_V,
VAMOANDE_V, VAMOORE_V, VAMOMINE_V,
VAMOMAXE_V, VAMOMINUE_V, VAMOMAXUE_V, allowed_instr};
endfunction
virtual function void add_w_vec_load_stores();
allowed_instr = {VAMOSWAPW_V, VAMOADDW_V, VAMOXORW_V,
VAMOANDW_V, VAMOORW_V, VAMOMINW_V,
VAMOMAXW_V, VAMOMINUW_V, VAMOMAXUW_V, allowed_instr};
endfunction
endclass : riscv_vector_amo_instr_stream

View file

@ -740,6 +740,8 @@ class riscv_asm_program_gen extends uvm_object;
trap_vector_init(hart);
// Setup PMP CSRs
setup_pmp(hart);
// Generate PMPADDR write test sequence
gen_pmp_csr_write(hart);
// Initialize PTE (link page table based on their real physical address)
if(cfg.virtual_addr_translation_on) begin
page_table_list.process_page_table(instr);
@ -831,6 +833,17 @@ class riscv_asm_program_gen extends uvm_object;
end
endfunction
// Generates a directed stream of instructions to write random values to all supported
// pmpaddr CSRs to test write accessibility.
// The original CSR values are restored afterwards.
virtual function void gen_pmp_csr_write(int hart);
string instr[$];
if (riscv_instr_pkg::support_pmp && cfg.pmp_cfg.enable_write_pmp_csr) begin
cfg.pmp_cfg.gen_pmp_write_test({cfg.scratch_reg, cfg.pmp_reg}, instr);
gen_section(get_label("pmp_csr_write_test", hart), instr);
end
endfunction
// Handles creation of a subroutine to initialize any custom CSRs
virtual function void setup_custom_csrs(int hart);
string instr[$];

View file

@ -166,11 +166,13 @@ class riscv_illegal_instr extends uvm_object;
c_op != 2'b11;
}
// Avoid generating illegal func3/func7 errors for opcode used by B-extension
// Avoid generating illegal func3/func7 errors for opcode used by B-extension for now
//
// TODO(udi): add support for generating illegal B-extension instructions
constraint b_extension_c {
if (RV32B inside {supported_isa}) {
if (exception inside {kIllegalFunc3, kIllegalFunc7}) {
!(opcode inside {7'b0011011, 7'b0010011, 7'b0111011});
!(opcode inside {7'b0110011, 7'b0010011, 7'b0111011});
}
}
}
@ -356,8 +358,8 @@ class riscv_illegal_instr extends uvm_object;
if (riscv_instr_pkg::RV32A inside {riscv_instr_pkg::supported_isa}) begin
legal_opcode = {legal_opcode, 7'b0101111};
end
if ((riscv_instr_pkg::RV64I inside {riscv_instr_pkg::supported_isa}) ||
riscv_instr_pkg::RV64M inside {riscv_instr_pkg::supported_isa}) begin
if (riscv_instr_pkg::RV64I inside {riscv_instr_pkg::supported_isa} ||
riscv_instr_pkg::RV64M inside {riscv_instr_pkg::supported_isa}) begin
legal_opcode = {legal_opcode, 7'b0111011};
end
if (riscv_instr_pkg::RV64I inside {riscv_instr_pkg::supported_isa}) begin

View file

@ -641,6 +641,7 @@ package riscv_instr_pkg;
VLHUFF_V,
VLWUFF_V,
VLEFF_V,
// Segmented load/store instruction
VLSEGE_V,
VSSEGE_V,
VLSEGB_V,
@ -685,6 +686,27 @@ package riscv_instr_pkg;
VSUXSEGH_V,
VSUXSEGW_V,
VSUXSEGE_V,
// Vector AMO instruction
// 32-bit vector AMOs
VAMOSWAPW_V,
VAMOADDW_V,
VAMOXORW_V,
VAMOANDW_V,
VAMOORW_V,
VAMOMINW_V,
VAMOMAXW_V,
VAMOMINUW_V,
VAMOMAXUW_V,
// SEW-bit vector AMOs
VAMOSWAPE_V,
VAMOADDE_V,
VAMOXORE_V,
VAMOANDE_V,
VAMOORE_V,
VAMOMINE_V,
VAMOMAXE_V,
VAMOMINUE_V,
VAMOMAXUE_V,
// Supervisor instruction
DRET,
MRET,
@ -747,7 +769,8 @@ package riscv_instr_pkg;
VLX_FORMAT,
VSX_FORMAT,
VLS_FORMAT,
VSS_FORMAT
VSS_FORMAT,
VAMO_FORMAT
} riscv_instr_format_t;

View file

@ -519,7 +519,7 @@ class riscv_load_store_rand_addr_instr_stream extends riscv_load_store_base_inst
endclass
class riscv_vector_stride_load_store_instr_stream extends riscv_mem_access_stream;
class riscv_vector_load_store_instr_stream extends riscv_mem_access_stream;
typedef enum {B_ALIGNMENT, H_ALIGNMENT, W_ALIGNMENT, E_ALIGNMENT} alignment_e;
typedef enum {UNIT_STRIDED, STRIDED, INDEXED} address_mode_e;
@ -573,7 +573,7 @@ class riscv_vector_stride_load_store_instr_stream extends riscv_mem_access_strea
int max_load_store_addr;
riscv_vector_instr load_store_instr;
`uvm_object_utils(riscv_vector_stride_load_store_instr_stream)
`uvm_object_utils(riscv_vector_load_store_instr_stream)
`uvm_object_new
virtual function int get_addr_alignment_mask(int alignment_bytes);
@ -590,6 +590,7 @@ class riscv_vector_stride_load_store_instr_stream extends riscv_mem_access_strea
if (address_mode == STRIDED) begin
instr_list.push_front(get_init_gpr_instr(rs2_reg, stride_byte_offset));
end else if (address_mode == INDEXED) begin
// TODO: Support different index address for each element
add_init_vector_gpr_instr(vs2_reg, index_addr);
end
super.post_randomize();

View file

@ -39,6 +39,10 @@ class riscv_pmp_cfg extends uvm_object;
// allowing all access restrictions to be enforced.
bit enable_pmp_exception_handler = 1'b1;
// Setting this bit to 1'b1 enables generation of the directed stream of instructions to test
// write accesses to all supported pmpaddr[i] CSRs.
bit enable_write_pmp_csr;
// pmp CSR configurations
rand pmp_cfg_reg_t pmp_cfg[];
@ -129,6 +133,7 @@ class riscv_pmp_cfg extends uvm_object;
get_int_arg_value("+pmp_granularity=", pmp_granularity);
get_bool_arg_value("+pmp_randomize=", pmp_randomize);
get_bool_arg_value("+pmp_allow_addr_overlap=", pmp_allow_addr_overlap);
get_bool_arg_value("+enable_write_pmp_csr=", enable_write_pmp_csr);
get_hex_arg_value("+pmp_max_offset=", pmp_max_offset);
`uvm_info(`gfn, $sformatf("pmp max offset: 0x%0x", pmp_max_offset), UVM_LOW)
pmp_cfg = new[pmp_num_regions];
@ -606,4 +611,61 @@ class riscv_pmp_cfg extends uvm_object;
endfunction
// This function is used for a directed PMP test to test writes to all the pmpcfg and pmpaddr
// CSRs to test that writes succeed or fail appropriately.
virtual function void gen_pmp_write_test(riscv_reg_t scratch_reg[2],
ref string instr[$]);
bit [11:0] pmp_addr;
bit [11:0] pmpcfg_addr;
bit [XLEN-1:0] pmp_val;
for (int i = 0; i < pmp_num_regions; i++) begin
pmp_addr = base_pmp_addr + i;
pmpcfg_addr = base_pmpcfg_addr + (i / cfg_per_csr);
// We randomize the upper 31 bits of pmp_val and then add this to the
// address of <main>, guaranteeing that the random value written to
// pmpaddr[i] doesn't interfere with the safe region.
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(pmp_val, pmp_val[31] == 1'b0;)
instr.push_back($sformatf("li x%0d, 0x%0x", scratch_reg[0], pmp_val));
instr.push_back($sformatf("la x%0d, main", scratch_reg[1]));
instr.push_back($sformatf("add x%0d, x%0d, x%0d",
scratch_reg[0], scratch_reg[0], scratch_reg[1]));
// Write the randomized address to pmpaddr[i].
// Original value of pmpaddr[i] will be written to scratch_reg[0].
instr.push_back($sformatf("csrrw x%0d, 0x%0x, x%0d",
scratch_reg[0], pmp_addr, scratch_reg[0]));
// Restore the original address to pmpaddr[i].
// New value of pmpaddr[i] will be written to scratch_reg[0].
instr.push_back($sformatf("csrrw x%0d, 0x%0x, x%0d",
scratch_reg[0], pmp_addr, scratch_reg[0]));
// Randomize value to be written to pmpcfg CSR.
//
// TODO: support rv64.
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(pmp_val,
// Need to constrain pmp_val[7], pmp_val[15], ... to 1'b0
// to ensure that the random config regions aren't locked
foreach (pmp_val[i]) {
if ((i+1) % 8 == 0) {
pmp_val[i] == 1'b0;
}
}
)
// If we're writing to the pmpcfg CSR that contains region0 config information,
// ensure that the "safe" region remains fully accessible.
if (pmpcfg_addr == base_pmpcfg_addr) begin
pmp_val[7:0] = 'h0f;
end
instr.push_back($sformatf("li x%0d, 0x%0x", scratch_reg[0], pmp_val));
// Write the randomized address to pmpcfg[i].
// Original value of pmpcfg[i] will be written to scratch_reg[0].
instr.push_back($sformatf("csrrw x%0d, 0x%0x, x%0d",
scratch_reg[0], pmpcfg_addr, scratch_reg[0]));
// Restore the original address to pmpcfg[i].
// New value of pmpcfg[i] will be written to scratch_reg[0].
instr.push_back($sformatf("csrrw x%0d, 0x%0x, x%0d",
scratch_reg[0], pmpcfg_addr, scratch_reg[0]));
end
endfunction
endclass

View file

@ -282,15 +282,8 @@ class riscv_privil_reg extends riscv_reg#(privileged_reg_t);
// Physical Memory Protection Configuration Register
PMPCFG1: begin
privil_level = M_LEVEL;
if(XLEN==64) begin
add_field("PMP8CFG", 8, WARL);
add_field("PMP9CFG", 8, WARL);
add_field("PMP10CFG", 8, WARL);
add_field("PMP11CFG", 8, WARL);
add_field("PMP12CFG", 8, WARL);
add_field("PMP13CFG", 8, WARL);
add_field("PMP14CFG", 8, WARL);
add_field("PMP15CFG", 8, WARL);
if(XLEN!=32) begin
`uvm_fatal(`gfn, "CSR PMPCFG1 only exists in RV32.")
end else begin
add_field("PMP4CFG", 8, WARL);
add_field("PMP5CFG", 8, WARL);
@ -300,14 +293,17 @@ class riscv_privil_reg extends riscv_reg#(privileged_reg_t);
end
// Physical Memory Protection Configuration Register
PMPCFG2: begin
if(XLEN!=32) begin
`uvm_fatal(get_full_name(), "CSR PMPCFG2 only exists in RV32.")
end
privil_level = M_LEVEL;
add_field("PMP8CFG", 8, WARL);
add_field("PMP9CFG", 8, WARL);
add_field("PMP10CFG", 8, WARL);
add_field("PMP11CFG", 8, WARL);
if(XLEN==64) begin
add_field("PMP12CFG", 8, WARL);
add_field("PMP13CFG", 8, WARL);
add_field("PMP14CFG", 8, WARL);
add_field("PMP15CFG", 8, WARL);
end
end
// Physical Memory Protection Configuration Register
PMPCFG3: begin

View file

@ -74,8 +74,23 @@
+num_of_sub_program=0
+enable_floating_point=1
+enable_vector_extension=1
+directed_instr_0=riscv_vector_stride_load_store_instr_stream,4
+enable_fault_only_first_load=1
+directed_instr_0=riscv_vector_load_store_instr_stream,10
+no_branch_jump=1
+boot_mode=m
+no_csr_instr=1
iterations: 5
gen_test: riscv_instr_base_test
rtl_test: core_base_test
- test: riscv_vector_amo_test
description: >
Vector AMO random test
gen_opts: >
+instr_cnt=10000
+num_of_sub_program=0
+enable_floating_point=1
+enable_vector_extension=1
+directed_instr_0=riscv_vector_amo_instr_stream,10
+no_branch_jump=1
+boot_mode=m
+no_csr_instr=1