Update google_riscv-dv to google/riscv-dv@68e3bca

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

* [pmp] Remove restriction on using NAPOT when granularity = 0 (Marno
  van der Maas)
* [pmp] Add PMP entries for data in case of MML or MMWP (Marno van der
  Maas)
* [pmp] Add already_configured flag to skip address in PMP routine
  (Marno van der Maas)
* [pmp] Fix constraint and CSR write test in MML mode (Marno van der
  Maas)
* [pmp] Use random address instead of offset for full random test
  (Marno van der Maas)
* [pmp] Allow specifying address zero in `+pmp_region_%0d` (Marno van
  der Maas)
* [pmp] Randomizing entry for instructions for PMP randomization
  (Marno van der Maas)
* [lint] Remove trailing whitespace (Marno van der Maas)
* Tweak CSR constraints for more even read/write distribution (Greg
  Chadwick)
* [lint] Replace tabs with spaces (Marno van der Maas)
* [pmp] No PMP exception handler when no PMP support (Greg Chadwick)
* Expand CSR instruction constraint functionality (Greg Chadwick)
* Refactor CSR instruction into their own class (Greg Chadwick)

Signed-off-by: Marno van der Maas <mvdmaas+git@lowrisc.org>
This commit is contained in:
Marno van der Maas 2022-08-19 12:20:33 +01:00 committed by Canberk Topal
parent 2669260aa0
commit 4990aa2684
74 changed files with 700 additions and 401 deletions

View file

@ -9,6 +9,6 @@
upstream:
{
url: https://github.com/google/riscv-dv
rev: 808fb162d66de5dd0dd2b45fd0b8d1fb1bf170f6
rev: 68e3bcac7293ac79067f0d8196bb973bd7c889cf
}
}

View file

@ -3,7 +3,7 @@
"list": [{
"name": "rv32imc",
"image": "ibex-toolchain:v2",
"memory" : "1",
"memory" : "1",
"cmd": "python3 run.py --test riscv_arithmetic_basic_test --simulator dsim --output out --verbose --co",
"wavesCmd": "python3 run.py --test riscv_arithmetic_basic_test --simulator dsim --output out --verbose --co"
}]
@ -36,7 +36,7 @@
"tests": {
"resultsDir": "/mux-flow/build/repo/out",
"builds": ["rv32imc"],
"memory": "1",
"memory": "1",
"listCmd": "<rootDir>/scripts/genMetricsList.py",
"listFile": "<rootDir>/regression_list.json"
}

View file

@ -86,7 +86,7 @@ You can find the prebuilt document under docs/build/singlehtml/index.html
RISC-V DV is now contributed to CHIPS Alliance. We have regular meetings to
discuss the issues, feature priorities, development progress etc. Please join
the [mail group](https://lists.chipsalliance.org/g/riscv-dv-wg) for latest
status.
status.
Please refer to CONTRIBUTING.md for license related questions.

View file

@ -155,9 +155,9 @@ def collect_cov(out, cfg, cwd):
logging.error("Cannot find {} directory, or it is empty".format(argv.dir))
sys.exit(RET_FAIL)
if argv.core:
"""If functional coverage is being collected from an RTL core
implementation, the flow assumes that the core's trace logs have
already been converted to CSV files by the post_compare step of the
"""If functional coverage is being collected from an RTL core
implementation, the flow assumes that the core's trace logs have
already been converted to CSV files by the post_compare step of the
flow. """
trace_log = ("{}/{}_trace_log".format(out, argv.core))
run_cmd("find {} -name \"*.csv\" | sort > {}".format(argv.dir, trace_log))

View file

@ -41,7 +41,7 @@ class riscv_custom_instr: riscv_instr
this(string name = "") {
super(name);
}
override string get_instr_name() {
import std.conv: to;
return instr_name.to!string();

View file

@ -1,4 +1,4 @@
module riscv.gen.isa.custom.riscv_custom_instr_enum;
//TODO custom instruction added
//TODO custom instruction added
// CUSTOM_i,

View file

@ -29,7 +29,7 @@ import uvm;
class riscv_amo_instr: riscv_instr
{
mixin uvm_object_utils;
@rand bool aq;
@rand bool rl;

View file

@ -36,7 +36,7 @@ import uvm;
class riscv_b_instr: riscv_instr
{
mixin uvm_object_utils;
mixin uvm_object_utils;
@rand riscv_reg_t rs3;
bool has_rs3 = false;
@ -102,7 +102,7 @@ class riscv_b_instr: riscv_instr
asm_str = format_string(get_instr_name(), MAX_INSTR_STR_LEN);
switch (instr_format) {
case riscv_instr_format_t.I_FORMAT:
case riscv_instr_format_t.I_FORMAT:
if ([riscv_instr_name_t.FSRI,
riscv_instr_name_t.FSRIW].canFind(instr_name)) { // instr rd,rs1,rs3,imm
asm_str_final = format("%0s%0s, %0s, %0s, %0s", asm_str, rd, rs1,
@ -414,7 +414,7 @@ class riscv_b_instr: riscv_instr
default:
if (binary == "") binary = super.convert2bin(prefix);
}
return prefix ~ binary;
}

View file

@ -165,14 +165,14 @@ class riscv_compressed_instr: riscv_instr
assert (rhs_ !is null);
this.imm_align = rhs_.imm_align;
}
override void extend_imm() {
if (instr_name != riscv_instr_name_t.C_LUI) {
super.extend_imm();
imm = imm << imm_align;
}
}
override void set_rand_mode() {
switch (instr_format) {
case riscv_instr_format_t.CR_FORMAT :
@ -269,7 +269,7 @@ class riscv_compressed_instr: riscv_instr
break;
default: uvm_info(get_full_name(),
format("Unsupported format %0s", instr_format), UVM_LOW);
break;
break;
}
}
else {
@ -498,10 +498,10 @@ class riscv_compressed_instr: riscv_instr
riscv_instr_name_t.C_SDSP : return toubvec!2(0b10);
default :
uvm_fatal(get_full_name(), format("Unsupported instruction %0s", instr_name));
assert (false);
assert (false);
}
}
//ubvec!3 get_func3()
override ubvec!3 get_func3() {
switch(instr_name) {

View file

@ -51,7 +51,7 @@ class riscv_floating_point_instr: riscv_instr
super(name);
}
// Convert the instruction to assembly code
override string convert2asm(string prefix = "") {
import std.conv: to;
@ -383,7 +383,7 @@ class riscv_floating_point_instr: riscv_instr
// riscv_floating_point_instr pre_fp_instr;
// super.check_hazard_condition(pre_instr);
// pre_fp_instr = cast(riscv_floating_point_instr) pre_instr;
// if (pre_fp_instr != null && pre_fp_instr.has_fd)
// {
// if ((has_fs1 && (fs1 == pre_fp_instr.fd)) || (has_fs2 && (fs2 == pre_fp_instr.fd))
@ -406,7 +406,7 @@ class riscv_floating_point_instr: riscv_instr
// gpr_hazard = hazard_e.NO_HAZARD;
// }
// }
// }
}

View file

@ -35,7 +35,7 @@ import uvm;
class riscv_instr: uvm_object
{
mixin uvm_object_utils;
riscv_instr_gen_config m_cfg;
// riscv_instr_registry m_registry;
@ -93,7 +93,7 @@ class riscv_instr: uvm_object
}
}
} imm_c;
constraint! q{
if (category == riscv_instr_category_t.CSR) {
if (m_cfg.instr_registry.include_reg.length > 0) {
@ -120,7 +120,7 @@ class riscv_instr: uvm_object
case riscv_instr_format_t.R_FORMAT:
has_imm = false;
break;
case riscv_instr_format_t.I_FORMAT:
case riscv_instr_format_t.I_FORMAT:
has_rs2 = false;
break;
case riscv_instr_format_t.S_FORMAT, riscv_instr_format_t.B_FORMAT:
@ -211,13 +211,13 @@ class riscv_instr: uvm_object
asm_str = format("%0s%0s, 0x%0x, %0s", asm_str,rd, csr, get_imm());
else
asm_str = format("%0s%0s, %0s, %0s", asm_str, rd, rs1, get_imm());
break;
break;
case riscv_instr_format_t.S_FORMAT, riscv_instr_format_t.B_FORMAT: // instr rs1,rs2,imm
if (category == riscv_instr_category_t.STORE) // Use psuedo instruction format
asm_str = format("%0s%0s, %0s(%0s)", asm_str, rs2, get_imm(), rs1);
else
asm_str = format("%0s%0s, %0s, %0s", asm_str, rs1, rs2, get_imm());
break;
break;
case riscv_instr_format_t.R_FORMAT: // instr rd,rs1,rs2
if (category == riscv_instr_category_t.CSR) {
asm_str = format("%0s%0s, 0x%0x, %0s", asm_str, rd, csr, rs1);
@ -228,7 +228,7 @@ class riscv_instr: uvm_object
else {
asm_str = format("%0s%0s, %0s, %0s", asm_str, rd, rs1, rs2);
}
break;
break;
default: uvm_fatal(get_full_name(), format("Unsupported format %0s [%0s]",
instr_format, instr_name));
break;
@ -479,8 +479,8 @@ class riscv_instr: uvm_object
string convert2bin(string prefix = "") {
import std.conv: to;
ubvec!32 vec;
switch (instr_format) {
case riscv_instr_format_t.J_FORMAT:
switch (instr_format) {
case riscv_instr_format_t.J_FORMAT:
vec = cast(ubvec!1) imm[20]
~ cast(ubvec!10) imm[1..11]
~ cast(ubvec!1) imm[11]
@ -488,12 +488,12 @@ class riscv_instr: uvm_object
~ toubvec!5(rd)
~ get_opcode();
break;
case riscv_instr_format_t.U_FORMAT:
case riscv_instr_format_t.U_FORMAT:
vec = cast(ubvec!20) imm[12..32]
~ toubvec!5(rd)
~ get_opcode();
break;
case riscv_instr_format_t.I_FORMAT:
case riscv_instr_format_t.I_FORMAT:
if (canFind( [riscv_instr_name_t.FENCE, riscv_instr_name_t.FENCE_I], instr_name)) {
vec = toubvec!17(0b00000000000000000)
~ get_func3()
@ -552,19 +552,19 @@ class riscv_instr: uvm_object
~ toubvec!5(rs1)
~ get_func3()
~ cast(ubvec!5) imm[0..5]
~ get_opcode();
~ get_opcode();
break;
case riscv_instr_format_t.B_FORMAT:
case riscv_instr_format_t.B_FORMAT:
vec = cast(ubvec!1) imm[12]
~ cast(ubvec!6) imm[5..11]
~ toubvec!5(rs2)
~ toubvec!5(rs1)
~ get_func3()
~ get_func3()
~ cast(ubvec!4) imm[1..5]
~ cast(ubvec!1) imm[11]
~ get_opcode();
break;
case riscv_instr_format_t.R_FORMAT:
case riscv_instr_format_t.R_FORMAT:
if (category == riscv_instr_category_t.CSR) {
vec = csr // cast(ubvec!11) csr[0..11] -- SV BUG?
~ toubvec!5(rs1)
@ -621,7 +621,7 @@ class riscv_instr: uvm_object
riscv_instr rhs_;
super.copy(rhs);
rhs_ = cast(riscv_instr) rhs;
if ( rhs_ !is null ) { //rhs_ = rhs;
if ( rhs_ !is null ) { //rhs_ = rhs;
this.group = rhs_.group;
this.instr_format = rhs_.instr_format;
this.category = rhs_.category;
@ -646,7 +646,7 @@ class riscv_instr: uvm_object
void update_imm_str() {
imm_str = format("%0d", cast(bvec!32) imm);
}
//`include "isa/riscv_instr_cov.svh"
}

View file

@ -35,11 +35,11 @@ void register(alias MOD, INSTRS...)(riscv_instr_registry registry) {
return;
}
}
void register_module(alias MOD)(riscv_instr_registry registry) {
register!(MOD, __traits(allMembers, MOD))(registry);
}
void register_isa(riscv_instr_registry registry) {
import riscv.gen.isa.rv128c_instr;
import riscv.gen.isa.rv32a_instr;

View file

@ -253,7 +253,7 @@ class riscv_vector_instr: riscv_floating_point_instr
// the source mask register (v0) when LMUL=1
constraint!q{
(vm == false) && (m_cfg.vector_cfg.vtype.vlmul > 1) -> (vd != 0);
} vmask_overlap_c;
} vmask_overlap_c;
constraint!q{
// Below instruction is always masked
@ -340,7 +340,7 @@ class riscv_vector_instr: riscv_floating_point_instr
(vm == false) -> (vd != 0);
} temp_c;
this(string name = "riscv_vector_instr") {
super(name);
}
@ -457,7 +457,7 @@ class riscv_vector_instr: riscv_floating_point_instr
asm_str = format("%0s.%0s ", get_instr_name(), va_variant);
asm_str = format_string(asm_str, MAX_INSTR_STR_LEN);
switch (va_variant) {
case va_variant_t.WV,
case va_variant_t.WV,
va_variant_t.VV,
va_variant_t.VVM,
va_variant_t.VM:
@ -585,7 +585,7 @@ class riscv_vector_instr: riscv_floating_point_instr
asm_str ~= vec_vm_str();
if (comment != "") {
asm_str ~= " #" ~ comment;
}
}
return asm_str.toLower();
}

View file

@ -48,7 +48,7 @@ class riscv_zbb_instr: riscv_instr
has_rs2 = true;
}
break;
case riscv_instr_format_t.I_FORMAT:
case riscv_instr_format_t.I_FORMAT:
if ([riscv_instr_name_t.CLZ, riscv_instr_name_t.CLZW,
riscv_instr_name_t.CTZ, riscv_instr_name_t.CTZW,
riscv_instr_name_t.CPOP, riscv_instr_name_t.CPOPW,
@ -192,7 +192,7 @@ class riscv_zbb_instr: riscv_instr
default: uvm_fatal(get_full_name(), format("Unsupported instruction %0s", instr_name));
assert (false);
}
}
}
override ubvec!7 get_func7() {
switch (instr_name) {
@ -229,7 +229,7 @@ class riscv_zbb_instr: riscv_instr
string binary = "";
switch (instr_format) {
case riscv_instr_format_t.R_FORMAT:
case riscv_instr_format_t.R_FORMAT:
if (instr_name == riscv_instr_name_t.ZEXT_H) {
binary = format("%8h", get_func7() ~ get_func5() ~ rs1 ~ get_func3() ~ rd ~ get_opcode());
}

View file

@ -32,7 +32,7 @@ import std.algorithm: canFind;
class riscv_zbc_instr: riscv_instr
{
mixin uvm_object_utils;
this(string name = "") {
super(name);
}

View file

@ -122,7 +122,7 @@ class riscv_zbs_instr: riscv_instr
}
return binary;
}
override bool is_supported(riscv_instr_gen_config cfg) {
return (cfg.enable_zbs_extension &&
(supported_isa.canFind(riscv_instr_group_t.RV32ZBS) ||

View file

@ -129,4 +129,4 @@ version (RISCV_INSTR_STRING_MIXIN) {
{ mixin RISCV_INSTR_MIXIN!(BDECOMPRESS, R_FORMAT, ARITHMETIC, RV32B); }
class riscv_BFP_instr: riscv_b_instr
{ mixin RISCV_INSTR_MIXIN!(BFP, R_FORMAT, ARITHMETIC, RV32B); }
}
}

View file

@ -102,4 +102,4 @@ version (RISCV_INSTR_STRING_MIXIN) {
{ mixin RISCV_INSTR_MIXIN!(FCVT_S_WU, I_FORMAT, ARITHMETIC, RV32F); }
class riscv_FMV_W_X_instr: riscv_floating_point_instr
{ mixin RISCV_INSTR_MIXIN!(FMV_W_X, I_FORMAT, ARITHMETIC, RV32F); }
}
}

View file

@ -51,4 +51,4 @@ version (RISCV_INSTR_STRING_MIXIN) {
class riscv_REMU_instr: riscv_instr
{ mixin RISCV_INSTR_MIXIN!(REMU, R_FORMAT, ARITHMETIC, RV32M); }
}

View file

@ -45,4 +45,4 @@ version (RISCV_INSTR_STRING_MIXIN) {
{ mixin RISCV_INSTR_MIXIN!(C_LDSP, CI_FORMAT, LOAD, RV64C, UIMM); }
class riscv_C_SDSP_instr: riscv_compressed_instr
{ mixin RISCV_INSTR_MIXIN!(C_SDSP, CSS_FORMAT, STORE, RV64C, UIMM); }
}
}

View file

@ -24,7 +24,7 @@ import riscv.gen.target: supported_isa, XLEN;
import riscv.gen.riscv_directed_instr_lib: riscv_mem_access_stream;
import riscv.gen.riscv_load_store_instr_lib: riscv_vector_load_store_instr_stream;
import riscv.gen.riscv_pseudo_instr: riscv_pseudo_instr;
import riscv.gen.isa.riscv_instr: riscv_instr;
import riscv.gen.isa.riscv_instr: riscv_instr;
import std.format: format;
import std.algorithm: canFind;
@ -150,7 +150,7 @@ class riscv_lr_sc_instr_stream : riscv_amo_base_instr_stream
allowed_lr_instr ~= riscv_instr_name_t.LR_D;
allowed_sc_instr ~= riscv_instr_name_t.SC_D;
}
lr_instr = cfg.instr_registry.get_rand_instr(allowed_lr_instr);
sc_instr = cfg.instr_registry.get_rand_instr(allowed_sc_instr);
@ -163,7 +163,7 @@ class riscv_lr_sc_instr_stream : riscv_amo_base_instr_stream
rd !inside [$2];
}
rd != $0;
} (rs1_reg[0], reserved_rd, cfg.reserved_regs);
} (rs1_reg[0], reserved_rd, cfg.reserved_regs);
sc_instr.randomize_with! q{
rs1 == $0;
if ($1.length > 0) {
@ -188,7 +188,7 @@ class riscv_lr_sc_instr_stream : riscv_amo_base_instr_stream
override void add_mixed_instr(int instr_cnt) {
riscv_instr instr;
int i;
setup_allowed_instr(true, true);
setup_allowed_instr(true, true);
//setup_allowed_instr(.no_branch(1), .no_load_store(1));
while (i < instr_cnt) {
instr = riscv_instr.type_id.create("instr");
@ -240,7 +240,7 @@ class riscv_amo_instr_stream: riscv_amo_base_instr_stream
rd !inside [$2];
} (reserved_rd, cfg.reserved_regs, rs1_reg);
append_instr(instr);
}
}
}
}
@ -251,7 +251,7 @@ class riscv_vector_amo_instr_stream: riscv_vector_load_store_instr_stream
// AMO operation uses indexed address mode
address_mode == address_mode_e.INDEXED;
} amo_address_mode_c;
mixin uvm_object_utils;
this(string name = "") {
super(name);

View file

@ -91,7 +91,7 @@ class riscv_asm_program_gen : uvm_object
mixin uvm_object_utils;
this(string name = "") {
super(name);
super(name);
}
//---------------------------------------------------------------------------------------
@ -731,7 +731,7 @@ class riscv_asm_program_gen : uvm_object
case 5: value[SINGLE_PRECISION_FRACTION_BITS..31] = 0; break;
default: break;
}
return value;
}
@ -1137,7 +1137,7 @@ class riscv_asm_program_gen : uvm_object
if (cfg.check_xstatus) {
instr ~= format("csrr x%0d, 0x%0x # %0s", cfg.gpr[0], status, status);
}
instr ~=
instr ~=
// Use scratch CSR to save a GPR value
// Check if the exception is caused by an interrupt, if yes, jump to interrupt
// handler Interrupt is indicated by xCause[XLEN-1]
@ -1172,9 +1172,9 @@ class riscv_asm_program_gen : uvm_object
format("beq x%0d, x%0d, %0sebreak_handler",
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
// Check if it's an ECALL exception. Jump to ECALL exception handler
format("li x%0d, 0x%0x # ECALL_UMODE", cfg.gpr[1], exception_cause_t.ECALL_UMODE),
format("li x%0d, 0x%0x # ECALL_UMODE", cfg.gpr[1], exception_cause_t.ECALL_UMODE),
format("beq x%0d, x%0d, %0secall_handler",
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
format("li x%0d, 0x%0x # ECALL_SMODE", cfg.gpr[1], exception_cause_t.ECALL_SMODE),
format("beq x%0d, x%0d, %0secall_handler",
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
@ -1184,13 +1184,13 @@ class riscv_asm_program_gen : uvm_object
// Page table fault or access fault conditions
format("li x%0d, 0x%0x", cfg.gpr[1], exception_cause_t.INSTRUCTION_ACCESS_FAULT),
format("beq x%0d, x%0d, %0sinstr_fault_handler",
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
format("li x%0d, 0x%0x", cfg.gpr[1], exception_cause_t.LOAD_ACCESS_FAULT),
format("beq x%0d, x%0d, %0sload_fault_handler",
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
format("li x%0d, 0x%0x", cfg.gpr[1], exception_cause_t.STORE_AMO_ACCESS_FAULT),
format("li x%0d, 0x%0x", cfg.gpr[1], exception_cause_t.STORE_AMO_ACCESS_FAULT),
format("beq x%0d, x%0d, %0sstore_fault_handler",
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
format("li x%0d, 0x%0x", cfg.gpr[1], exception_cause_t.INSTRUCTION_PAGE_FAULT),
format("beq x%0d, x%0d, %0spt_fault_handler",
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
@ -1338,7 +1338,7 @@ class riscv_asm_program_gen : uvm_object
void gen_instr_fault_handler(int hart) {
string[] instr;
riscv_reg_t[6] regs;
gen_signature_handshake(instr, signature_type_t.CORE_STATUS, core_status_t.INSTR_FAULT_EXCEPTION);
gen_signature_handshake(instr, signature_type_t.WRITE_CSR, core_status_t.INITIALIZED,
test_result_t.TEST_FAIL, privileged_reg_t.MCAUSE);
@ -1818,7 +1818,7 @@ class riscv_asm_program_gen : uvm_object
if (object_h is null) {
uvm_fatal(get_full_name(), format("Cannot create instr stream %0s", name));
}
riscv_rand_instr_stream new_instr_stream = cast(riscv_rand_instr_stream) object_h;
if (new_instr_stream !is null) {
assert (cfg !is null);

View file

@ -55,7 +55,7 @@ class riscv_program: uvm_object
} legal_c;
this(string name = "") {
super(name);
super(name);
}
override string convert2string() {
@ -114,7 +114,7 @@ class riscv_callstack_gen : uvm_object
//`endif
this(string name = "") {
super(name);
super(name);
}
// Init all program instances before randomization
@ -169,7 +169,7 @@ class riscv_callstack_gen : uvm_object
spid = next_program_list[nextid];
}
}
sub_program_id_pool.shuffle();
sub_program_cnt.length = program_list.length;

View file

@ -1,3 +1,3 @@
//TODO custom instruction added
//TODO custom instruction added
// CUSTOM_i,
module riscv.gen.riscv_custom_instr_enum;

View file

@ -36,7 +36,7 @@ import uvm;
class riscv_data_page_gen: uvm_object
{
import std.conv: to;
riscv_instr_gen_config cfg;
string[] data_page_str;
mem_region_t[] mem_region_setting;
@ -44,9 +44,9 @@ class riscv_data_page_gen: uvm_object
mixin uvm_object_utils;
this(string name = "cls_avail_regs") {
super(name);
super(name);
}
// The data section can be initialized with different data pattern:
// - Random value, incremental value, all zeros
void gen_data(in int idx,
@ -57,7 +57,7 @@ class riscv_data_page_gen: uvm_object
data.length = num_of_bytes;
foreach (i, ref dd; data) {
if (pattern == data_pattern_t.RAND_DATA) {
temp_data = toubvec!8(urandom!ubyte());
temp_data = toubvec!8(urandom!ubyte());
dd = temp_data;
}
else if (pattern == data_pattern_t.INCR_VAL) {

View file

@ -44,7 +44,7 @@ class riscv_directed_instr_stream: riscv_rand_instr_stream
string label;
this(string name = "") {
super(name);
super(name);
}
void post_randomize() {
@ -74,10 +74,10 @@ class riscv_mem_access_stream : riscv_directed_instr_stream
this(string name = "") {
super(name);
super(name);
}
void pre_randomize() {
if (load_store_shared_memory) {
data_page = cfg.amo_region;
@ -261,7 +261,7 @@ class riscv_jal_instr : riscv_rand_instr_stream
this(string name = "") {
super(name);
}
void post_randomize() {
int[] order;
order.length = num_of_jump_instr;
@ -291,7 +291,7 @@ class riscv_jal_instr : riscv_rand_instr_stream
jj = cfg.instr_registry.get_rand_instr(jal);
//DV_CHECK_RANDOMIZE_WITH_FATAL(jump[i],
// Giving randomization error
jj.randomize_with! q{
jj.randomize_with! q{
if (has_rd == true ) {
rd dist [riscv_reg_t.RA := 5, riscv_reg_t.T1 := 2, riscv_reg_t.SP..riscv_reg_t.T0 :/ 1, riscv_reg_t.T2..riscv_reg_t.T6 :/ 2];
rd !inside [$0];
@ -312,7 +312,7 @@ class riscv_jal_instr : riscv_rand_instr_stream
}
}
}
instr_list = jump_start ~ jump ~ jump_end;
foreach (instr; instr_list) {
instr.has_label = true;
@ -426,7 +426,7 @@ class riscv_pop_stack_instr: riscv_rand_instr_stream
this(string name = "") {
super(name);
}
//uvm_object_utils(riscv_pop_stack_instr)
void init() {
@ -490,11 +490,11 @@ class riscv_int_numeric_corner_stream: riscv_directed_instr_stream
Zero,
AllOne,
NegativeMax
}
}
uint num_of_avail_regs = 10;
@rand uint num_of_instr;
@rand ubvec!XLEN[] init_val; // becasue of compile error it has been commented.
@rand ubvec!XLEN[] init_val; // becasue of compile error it has been commented.
@rand int_numeric_e[] init_val_type;
riscv_pseudo_instr[] init_instr;
@ -511,14 +511,14 @@ class riscv_int_numeric_corner_stream: riscv_directed_instr_stream
areg !inside [cfg.reserved_regs];
areg != riscv_reg_t.ZERO;
}
} avail_regs_c;
} avail_regs_c;
mixin uvm_object_utils;
this(string name = "") {
super(name);
}
void pre_randomize() {
avail_regs.length = num_of_avail_regs;
// super.pre_randomize();

View file

@ -54,7 +54,7 @@ class riscv_illegal_instr: uvm_object
kReservedCompressedInstr,
kHintInstr,
kIllegalSystemInstr
}
}
enum reserved_c_instr_e: ubyte {
kIllegalCompressed,
@ -69,7 +69,7 @@ class riscv_illegal_instr: uvm_object
kReservedC0,
kReservedC1,
kReservedC2
}
}
// Default legal opcode for RV32I instructions
ubvec!7[] legal_opcode = [0b0000011.toubvec!7,
@ -353,7 +353,7 @@ class riscv_illegal_instr: uvm_object
solve opcode before func3;
if (compressed == false) {
if (exception == illegal_instr_type_e.kIllegalFunc3) {
(opcode == 0b1100111) -> (func3 != 0b000);
(opcode == 0b1100111) -> (func3 != 0b000);
(opcode == 0b1100011) -> (func3 inside [0b010, 0b011]);
if (XLEN == 32) {
@ -387,7 +387,7 @@ class riscv_illegal_instr: uvm_object
(opcode == 0b0111011) -> (func3 !inside [0b010, 0b011]);
}
}
} illegal_func3_c;
constraint! q{

View file

@ -289,7 +289,7 @@ class riscv_instr_gen_config: uvm_object
@UVM_DEFAULT bool enable_zbb_extension;
@UVM_DEFAULT bool enable_zbc_extension;
@UVM_DEFAULT bool enable_zbs_extension;
@UVM_DEFAULT b_ext_group_t[] enable_bitmanip_groups =
[b_ext_group_t.ZBB, b_ext_group_t.ZBS, b_ext_group_t.ZBP, b_ext_group_t.ZBE,
b_ext_group_t.ZBF, b_ext_group_t.ZBC, b_ext_group_t.ZBR, b_ext_group_t.ZBM,
@ -302,7 +302,7 @@ class riscv_instr_gen_config: uvm_object
uint[riscv_instr_category_t] category_dist;
riscv_instr_registry instr_registry;
CommandLine cmdl;
constraint! q{
@ -311,7 +311,7 @@ class riscv_instr_gen_config: uvm_object
main_program_instr_cnt inside [10:instr_cnt];
foreach (cnt; sub_program_instr_cnt) {
cnt inside [10:instr_cnt];
}
}
// Disable sfence if the program is not boot to supervisor mode
// If sfence exception is allowed, we can enable sfence instruction in any priviledged mode.
// When MSTATUS.TVM is set, executing sfence.vma will be treate as illegal instruction
@ -325,7 +325,7 @@ class riscv_instr_gen_config: uvm_object
|| no_fence) -> (enable_sfence == false);
}
} default_c;
constraint! q{
if (support_debug_mode) {
debug_program_instr_cnt inside [100:300];
@ -335,14 +335,14 @@ class riscv_instr_gen_config: uvm_object
}
main_program_instr_cnt + sub_program_instr_cnt.sum == instr_cnt;
} debug_mode_c;
// Keep the number of single step iterations relatively small
constraint! q{
if (enable_debug_single_step) {
single_step_iterations inside [10 : 50];
}
} debug_single_step_c;
// Boot privileged mode distribution
constraint! q{
// Boot to higher privileged mode more often
@ -359,9 +359,9 @@ class riscv_instr_gen_config: uvm_object
init_privileged_mode == supported_privileged_mode[0];
}
} boot_privileged_mode_dist_c;
immutable int tvec_align = clog2((XLEN*4)/8);
constraint! q{
mtvec_mode inside [supported_interrupt_mode];
if (mtvec_mode == mtvec_mode_t.DIRECT) {
@ -373,7 +373,7 @@ class riscv_instr_gen_config: uvm_object
}
} mtvec_c;
constraint! q{
// This is default disabled at setup phase. It can be enabled in the exception and interrupt
// handling routine
@ -388,7 +388,7 @@ class riscv_instr_gen_config: uvm_object
mstatus_tvm == false;
}
} mstatus_c;
// Exception delegation setting
constraint! q{
// Do not delegate instructino page fault to supervisor/user mode because this may introduce
@ -480,7 +480,7 @@ class riscv_instr_gen_config: uvm_object
constraint! q{
solve init_privileged_mode before virtual_addr_translation_on;
} addr_translation_rnd_order_c;
constraint! q{
if ((init_privileged_mode != privileged_mode_t.MACHINE_MODE) &&
(SATP_MODE != satp_mode_t.BARE)) {
@ -490,8 +490,8 @@ class riscv_instr_gen_config: uvm_object
virtual_addr_translation_on == false;
}
} addr_translation_c;
constraint! q{
if (enable_floating_point) {
mstatus_fs == 1;
@ -500,7 +500,7 @@ class riscv_instr_gen_config: uvm_object
mstatus_fs == 0;
}
} floating_point_c;
constraint! q{
if (enable_vector_extension) {
@ -510,7 +510,7 @@ class riscv_instr_gen_config: uvm_object
mstatus_vs == 0;
}
} mstatus_vs_c;
// `uvm_object_utils_begin(riscv_instr_gen_config)
// `uvm_field_int(main_program_instr_cnt, UVM_DEFAULT)
// `uvm_field_sarray_int(sub_program_instr_cnt, UVM_DEFAULT)

View file

@ -677,7 +677,7 @@ enum riscv_fpr_t: ubyte { // 5'b
enum riscv_vreg_t: ubyte {
V0, V1, V2, V3, V4, V5, V6, V7, V8, V9, V10, V11, V12, V13, V14, V15,
V16, V17, V18, V19, V20, V21, V22, V23, V24, V25, V26, V27, V28, V29, V30, V31
}
}
enum riscv_instr_format_t: ubyte { // 6'b
@ -727,7 +727,7 @@ enum va_variant_t: ubyte {
VFM,
VS,
VM
}
}
enum riscv_instr_category_t: ubyte { // 6'b
LOAD = 0,
@ -1175,7 +1175,7 @@ enum exception_cause_t: ubyte {
INSTRUCTION_PAGE_FAULT = 0xC,
LOAD_PAGE_FAULT = 0xD,
STORE_AMO_PAGE_FAULT = 0xF
}
}
enum misa_ext_t: int {
MISA_EXT_A = 0,
@ -1221,7 +1221,7 @@ enum pmp_addr_mode_t: ubyte {
TOR = 0b01,
NA4 = 0b10,
NAPOT = 0b11
}
}
// // PMP configuration register layout
// // This configuration struct includes the pmp address for simplicity
@ -1254,7 +1254,7 @@ struct pmp_cfg_reg_t {
// The offset from the address of <main> - automatically populated by the
// PMP generation routine.
@rand ubvec!XLEN offset;
}
}
string hart_prefix(int hart = 0) {
@ -1280,7 +1280,7 @@ struct vtype_t {
@rand uint vsew;
@rand uint vlmul;
}
}
}
enum vxrm_t: ubyte {
@ -1288,7 +1288,7 @@ enum vxrm_t: ubyte {
RoundToNearestEven,
RoundDown,
RoundToOdd
}
}
enum b_ext_group_t: int {
ZBA,
@ -1303,7 +1303,7 @@ enum b_ext_group_t: int {
ZBT,
ZB_TMP // for uncategorized instructions
}
// `VECTOR_INCLUDE("riscv_instr_pkg_inc_variables.sv")
alias program_id_t = ubvec!16;
@ -1521,7 +1521,7 @@ void get_val(string str, out bvec!XLEN val, bool hex = 0) {
val = str.to!int(16);
return;
}
if (hex) {
val = str.to!int(16);
}

View file

@ -38,7 +38,7 @@ import uvm;
class riscv_instr_registry: uvm_object
{
mixin uvm_object_utils;
// All derived instructions
string[riscv_instr_name_t] instr_registry;
@ -64,7 +64,7 @@ class riscv_instr_registry: uvm_object
void set_cfg(riscv_instr_gen_config cfg) {
this.cfg = cfg;
}
bool register(riscv_instr_name_t instr_name, string qualified_name) {
uvm_info("riscv_instr", format("Registering %0s", instr_name), UVM_LOW);
instr_registry[instr_name] = qualified_name;
@ -192,7 +192,7 @@ class riscv_instr_registry: uvm_object
return get_rand_instr(null, exclude_instr, include_category, null, null, null);
}
riscv_instr get_rand_instr(riscv_instr_category_t[] include_category,
riscv_instr_group_t[] exclude_group) {
return get_rand_instr(null, null, include_category, null, null, exclude_group);
@ -202,7 +202,7 @@ class riscv_instr_registry: uvm_object
return get_rand_instr(null, null, include_category, null, null, null);
}
riscv_instr get_rand_instr(riscv_instr_name_t[] include_instr) {
return get_rand_instr(include_instr, null, null, null, null, null);
}
@ -258,7 +258,7 @@ class riscv_instr_registry: uvm_object
import std.algorithm.sorting: sort;
import std.algorithm.setops: setIntersection, setDifference;
import std.array: array;
riscv_instr_name_t[] instr_set = instr_names.dup;
instr_set.sort();
@ -269,7 +269,7 @@ class riscv_instr_registry: uvm_object
include_set = include_instr;
include_set.sort();
}
if (allowed_instr.length > 0) {
allowed_set = allowed_instr;
allowed_set.sort();
@ -326,5 +326,5 @@ class riscv_instr_registry: uvm_object
instr.m_cfg = cfg;
return instr;
}
}

View file

@ -75,7 +75,7 @@ class riscv_instr_sequence: uvm_sequence!(uvm_sequence_item,uvm_sequence_item)
int hint_instr_pct; // Percentage of HINT instruction
mixin uvm_object_utils;
this(string name = "") {
super(name);
if(!uvm_config_db!(riscv_instr_gen_config).get(null, "*", "instr_cfg", cfg))
@ -318,7 +318,7 @@ class riscv_instr_sequence: uvm_sequence!(uvm_sequence_item,uvm_sequence_item)
}
}
void generate_return_routine(string prefix) {
import std.algorithm: countUntil;
string str;
@ -329,7 +329,7 @@ class riscv_instr_sequence: uvm_sequence!(uvm_sequence_item,uvm_sequence_item)
uint ra_idx;
auto zero_idx = cfg.reserved_regs.countUntil(riscv_reg_t.ZERO);
// if (zero_idx >= 0) {
ra_idx = urandom (0, cast(uint) cfg.reserved_regs.length);
if (ra_idx <= zero_idx) ra_idx += 1;

View file

@ -66,7 +66,7 @@ class riscv_instr_stream: uvm_object
}
// Initialize the instruction stream, create each instruction instance
void initialize_instr_list(uint instr_cnt) {
instr_list.length = 0;
this.instr_cnt = instr_cnt;
@ -109,7 +109,7 @@ class riscv_instr_stream: uvm_object
void insert_instr_map(Queue!riscv_instr new_instr, int idx = -1, bool replace = false) {
assert (replace == false);
}
// Insert an instruction to the existing instruction stream at the given index
// When index is -1, the instruction is injected at a random location
// When replace is 1, the original instruction at the inserted position will be replaced
@ -442,7 +442,7 @@ class riscv_rand_instr_stream: riscv_instr_stream
} (avail_regs, reserved_rd, cfg.reserved_regs);
// TODO: Add constraint for CSR, floating point register
}
riscv_instr get_init_gpr_instr(riscv_reg_t gpr, ubvec!XLEN val) {
riscv_pseudo_instr li_instr;
@ -588,7 +588,7 @@ class riscv_prog_instr_stream: riscv_rand_instr_stream
uint mixed_count = instr_count;
dir_n.length = instr_count;
this.dir_instr_list = dir_list;
foreach (size_t dir_idx, dir_instr; dir_instr_list) {

View file

@ -47,7 +47,7 @@ class riscv_load_store_base_instr_stream : riscv_mem_access_stream
HIGH,
MEDIUM,
SPARSE
}
}
@rand uint num_load_store;
@rand uint num_mixed_instr;
@ -333,7 +333,7 @@ class riscv_hazard_instr_stream : riscv_load_store_base_instr_stream
this(string name = "") {
super(name);
}
override void pre_randomize() {
avail_regs.length = num_of_avail_regs;
super.pre_randomize();
@ -412,7 +412,7 @@ class riscv_multi_page_load_store_instr_stream: riscv_mem_access_stream
constraint! q{
foreach (id; data_page_id) {
id < max_data_page_id;
}
}
data_page_id.length == num_of_instr_stream;
rs1_reg.length == num_of_instr_stream;
unique [rs1_reg];
@ -431,7 +431,7 @@ class riscv_multi_page_load_store_instr_stream: riscv_mem_access_stream
// Each page access needs a reserved register as the base address of load/store instruction
constraint! q{
num_of_instr_stream inside [2:8];
} reasonable_c;
} reasonable_c;
this(string name = "") {
super(name);
@ -611,7 +611,7 @@ class riscv_load_store_rand_addr_instr_stream : riscv_load_store_base_instr_stre
class riscv_vector_load_store_instr_stream : riscv_mem_access_stream
{
enum address_mode_e {UNIT_STRIDED, STRIDED, INDEXED}
enum address_mode_e {UNIT_STRIDED, STRIDED, INDEXED}
@rand ubvec!11 eew;
@rand uint data_page_id;
@ -656,7 +656,7 @@ class riscv_vector_load_store_instr_stream : riscv_mem_access_stream
riscv_vector_instr load_store_instr;
mixin uvm_object_utils;
this(string name = "") {
super(name);
}
@ -745,13 +745,13 @@ class riscv_vector_load_store_instr_stream : riscv_mem_access_stream
}
}
break;
case address_mode_e.STRIDED:
case address_mode_e.STRIDED:
allowed_instr = [riscv_instr_name_t.VLSE_V, riscv_instr_name_t.VSSE_V] ~ allowed_instr;
if (cfg.vector_cfg.enable_zvlsseg) {
allowed_instr = [riscv_instr_name_t.VLSSEGE_V, riscv_instr_name_t.VSSSEGE_V] ~ allowed_instr;
}
break;
case address_mode_e.INDEXED:
case address_mode_e.INDEXED:
allowed_instr = [riscv_instr_name_t.VLXEI_V, riscv_instr_name_t.VSXEI_V,
riscv_instr_name_t.VSUXEI_V] ~ allowed_instr;
if (cfg.vector_cfg.enable_zvlsseg) {

View file

@ -169,7 +169,7 @@ class riscv_loop_instr: riscv_rand_instr_stream
rs1 == riscv_reg_t.ZERO;
imm == $1;
} (loop_cnt_reg[i], loop_init_val[i]);
loop_init_instr[2*i].comment = format("init loop %0d counter", i);
// Instruction to init loop limit
@ -199,7 +199,7 @@ class riscv_loop_instr: riscv_rand_instr_stream
rd !inside [$0, $1];
}
} (reserved_rd, cfg.reserved_regs);
loop_branch_target_instr[i].label = format("%0s_%0d_t", label, i);
// Instruction to update loop counter
@ -247,7 +247,7 @@ class riscv_loop_instr: riscv_rand_instr_stream
loop_instr = [loop_init_instr[2*i],
loop_init_instr[2*i+1],
loop_branch_target_instr[i],
loop_update_instr[i]] ~
loop_update_instr[i]] ~
loop_instr ~
loop_branch_instr[i];
}

View file

@ -39,7 +39,7 @@ class riscv_page_table(satp_mode_t MODE): uvm_object
ubvec!2 level; // Page table level
ubvec!XLEN [] pte_binary; // Page table entry in binary format
@rand riscv_page_table_entry!(MODE)[] pte; // List of all page table// entries
mixin uvm_object_utils;
this(string name = "") {
@ -53,7 +53,7 @@ class riscv_page_table(satp_mode_t MODE): uvm_object
void init_page_table(uint num_of_pte = 1) {
this.num_of_pte = num_of_pte;
pte.length = num_of_pte;
pte_binary.length = num_of_pte;
pte_binary.length = num_of_pte;
}
// Generate the page table binary

View file

@ -174,7 +174,7 @@ class riscv_page_table_entry(satp_mode_t MODE = satp_mode_t.SV39) : uvm_object
break;
}
}
// Return the PPN field offset based on the page level
int get_ppn_offset(ubvec!2 page_level) {
@ -184,13 +184,13 @@ class riscv_page_table_entry(satp_mode_t MODE = satp_mode_t.SV39) : uvm_object
case 1:
return PPN0_WIDTH;
case 2:
return PPN0_WIDTH + PPN1_WIDTH;
return PPN0_WIDTH + PPN1_WIDTH;
case 3:
return PPN0_WIDTH + PPN1_WIDTH + PPN2_WIDTH;
default: uvm_fatal(get_full_name(),
format("Unsupported page_level %0x", page_level));
assert (false);
}
assert (false);
}
}
// Assign each PPN field based on the input physical address. This function //is used to setup the
@ -247,5 +247,5 @@ class riscv_page_table_entry(satp_mode_t MODE = satp_mode_t.SV39) : uvm_object
return retval;
}
}

View file

@ -38,7 +38,7 @@ class riscv_page_table_exception_cfg : uvm_object
@rand bool allow_privileged_mode_exception;
@rand bool allow_zero_access_bit_exception;
@rand bool allow_zero_dirty_bit_exception;
// Exception ratio control
uint page_access_fault_ratio = 10;
uint misaligned_superpage_ratio = 10;

View file

@ -60,7 +60,7 @@ class riscv_page_table_list(satp_mode_t MODE = satp_mode_t.SV39) : uvm_object
privileged_mode_t privileged_mode = privileged_mode_t.USER_MODE;
// Starting physical address of the program.
ubvec!XLEN start_pa = 0x80000000;
ubvec!XLEN start_pa = 0x80000000;
// Num of page table per level
uint[] num_of_page_table;
@ -134,7 +134,7 @@ class riscv_page_table_list(satp_mode_t MODE = satp_mode_t.SV39) : uvm_object
// Note:
// - The number of randomization call is optimized to improve performance
// - PPN assignment is done at program run time
void randomize_page_table() {
void randomize_page_table() {
int pte_index;
exception_cfg.enable_exception = enable_exception;
create_valid_pte();
@ -155,7 +155,7 @@ class riscv_page_table_list(satp_mode_t MODE = satp_mode_t.SV39) : uvm_object
// First few super pages are link PTE to the next level
// $cast(page_table[i].pte[j], valid_link_pte.clone());
}
else if (j < SuperLeafPtePerTable + LinkPtePerTable) {
else if (j < SuperLeafPtePerTable + LinkPtePerTable) {
entry = cast(riscv_page_table_entry!MODE) valid_leaf_pte.clone();
// Non-link superpage table entry
// $cast(page_table[i].pte[j], valid_leaf_pte.clone());
@ -188,7 +188,7 @@ class riscv_page_table_list(satp_mode_t MODE = satp_mode_t.SV39) : uvm_object
// Create the basic legal page table entries
void create_valid_pte() {
valid_leaf_pte.randomize_with! q{
valid_leaf_pte.randomize_with! q{
if ($0 == $1) {
u == true;
}
@ -250,7 +250,7 @@ class riscv_page_table_list(satp_mode_t MODE = satp_mode_t.SV39) : uvm_object
// Unaligned super leaf PTE
if (exception_cfg.allow_superpage_misaligned_exception &&
(level > 0) && (pte.xwr != pte_permission_t.NEXT_LEVEL_PAGE)) {
ubvec!(riscv_page_table_entry!(MODE).VPN_WIDTH) fault_ppn;
ubvec!(riscv_page_table_entry!(MODE).VPN_WIDTH) fault_ppn;
fault_ppn.randomize();
// `DV_CHECK_STD_RANDOMIZE_FATAL(fault_ppn)
if (level == 3) {
@ -287,7 +287,7 @@ class riscv_page_table_list(satp_mode_t MODE = satp_mode_t.SV39) : uvm_object
level = 3;
bit_mask = bit_mask >> (riscv_page_table_entry!(MODE).RSVD_WIDTH +
riscv_page_table_entry!(MODE).PPN3_WIDTH);
}
}
else if (MODE == satp_mode_t.SV39) {
load_store_unit = "d";
level = 2;

View file

@ -30,9 +30,9 @@ import esdl.rand: rand, constraint;
import uvm;
class riscv_pmp_cfg: uvm_object {
mixin uvm_object_utils;
// default to a single PMP region
@rand @UVM_DEFAULT int pmp_num_regions = 1;
@ -83,7 +83,7 @@ class riscv_pmp_cfg: uvm_object {
// constraints - apply when pmp_randomize is 1 //
/////////////////////////////////////////////////
constraint! q{
pmp_num_regions inside [1 : 16];
pmp_granularity inside [0 : XLEN + 3];
@ -132,7 +132,7 @@ class riscv_pmp_cfg: uvm_object {
}
}
} tor_addr_overlap_c;
this(string name = "") {
string s;
super(name);
@ -217,11 +217,11 @@ class riscv_pmp_cfg: uvm_object {
foreach (i, ref field; fields) {
import std.conv: to;
uvm_string_split(field, ':', field_vals);
field_type = field_vals[0];
field_val = field_vals[1];
field_vals.length = 0;
switch (field_type) {
case "L" :
pmp_cfg_reg.l = field_val.to!bool;
@ -257,7 +257,7 @@ class riscv_pmp_cfg: uvm_object {
uvm_fatal(get_full_name(), format("%s, Invalid PMP configuration field name!", field_val));
}
}
return pmp_cfg_reg;
}
@ -305,7 +305,7 @@ class riscv_pmp_cfg: uvm_object {
ubvec!8 cfg_byte;
int pmp_id;
foreach (i, ref cfg; pmp_cfg) {
// TODO(udinator) condense this calculations if possible
pmp_id = cast(int) (i/cfg_per_csr);
if (i == 0) {
@ -328,7 +328,7 @@ class riscv_pmp_cfg: uvm_object {
pmp_word = pmp_word | cfg_bitmask;
uvm_info(get_full_name(), format("pmp_word: 0x%0x", pmp_word), UVM_DEBUG);
cfg_bitmask = 0;
if (i == 0) {
// load the address of the <main> section into pmpaddr0
instr ~= format("la x%0d, main", scratch_reg[0]);
@ -423,7 +423,7 @@ class riscv_pmp_cfg: uvm_object {
////////////////////////////////////////////////////
format("0: csrr x%0d, 0x%0x", scratch_reg[0], privileged_reg_t.MSCRATCH),
format("mv x%0d, x%0d", scratch_reg[4], scratch_reg[0])];
// Generate a sequence of loads and branches that will compare the loop index to every
// value within [0 : pmp_num_regions] to manually check which PMP CSRs to read from
for (int i = 1; i < pmp_num_regions + 1; i++) {
@ -599,7 +599,7 @@ class riscv_pmp_cfg: uvm_object {
format("la x%0d, test_done", scratch_reg[0]),
format("jalr x0, x%0d, 0", scratch_reg[0]),
format("28: j 29f")];
// This case statement creates a bitmask that enables the correct access permissions
// and ORs it with the 8-bit configuration fields.
@ -662,7 +662,7 @@ class riscv_pmp_cfg: uvm_object {
format("33: csrw 0x%0x, x%0d", privileged_reg_t.PMPCFG3, scratch_reg[2]),
// End the pmp handler with a labeled nop instruction, this provides a branch target
// for the internal routine after it has "fixed" the pmp configuration CSR.
format("34: nop")];
format("34: nop")];
}
// This function is used for a directed PMP test to test writes to all the pmpcfg and pmpaddr
@ -683,7 +683,7 @@ class riscv_pmp_cfg: uvm_object {
// `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(pmp_val, pmp_val[31] == 1'b0;)
pmp_val = urandom!(ubvec!XLEN)();
pmp_val[31] = false;
instr ~= format("li x%0d, 0x%0x", scratch_reg[0], pmp_val);
instr ~= format("la x%0d, main", scratch_reg[1]);
instr ~= format("add x%0d, x%0d, x%0d",

View file

@ -35,7 +35,7 @@ class riscv_privil_reg: riscv_reg!(privileged_reg_t)
this(string name = "") {
super(name);
}
override void init_reg(privileged_reg_t reg_name) {
super.init_reg(reg_name);
switch(reg_name) {
@ -128,7 +128,7 @@ class riscv_privil_reg: riscv_reg!(privileged_reg_t)
add_field("SPF", 1, reg_field_access_t.WARL);
add_field("WARL2", XLEN-16, reg_field_access_t.WARL);
break;
// Machine Interrupt Delegation Register
case privileged_reg_t.MIDELEG:
privil_level = privileged_level_t.M_LEVEL;
@ -163,7 +163,7 @@ class riscv_privil_reg: riscv_reg!(privileged_reg_t)
add_field("MEIP", 1, reg_field_access_t.WARL);
add_field("WPRI3", XLEN - 12, reg_field_access_t.WPRI);
break;
// Machine Interrupt-enable register
case privileged_reg_t.MIE:
privil_level = privileged_level_t.M_LEVEL;
@ -215,7 +215,7 @@ class riscv_privil_reg: riscv_reg!(privileged_reg_t)
privil_level = privileged_level_t.M_LEVEL;
add_field(format("%s", reg_name), XLEN, reg_field_access_t.WARL);
break;
// Hardware Performance Monitor Counters - RV32I only
case privileged_reg_t.MHPMCOUNTER3H:
..
@ -338,7 +338,7 @@ class riscv_privil_reg: riscv_reg!(privileged_reg_t)
add_field("PMP13CFG", 8, reg_field_access_t.WARL);
add_field("PMP14CFG", 8, reg_field_access_t.WARL);
add_field("PMP15CFG", 8, reg_field_access_t.WARL);
break;
break;
// Physical Memory Protection Configuration Registers
case privileged_reg_t.PMPADDR0:
..

View file

@ -51,7 +51,7 @@ class riscv_privileged_common_seq : uvm_sequence!(uvm_sequence_item,uvm_sequence
mixin uvm_object_utils;
this(string name = "") {
super(name);
super(name);
}
void enter_privileged_mode(in privileged_mode_t mode,
@ -109,7 +109,7 @@ class riscv_privileged_common_seq : uvm_sequence!(uvm_sequence_item,uvm_sequence
}
// instrs.pushFront(label); // do it upfront
}
void setup_mmode_reg(privileged_mode_t mode, ref riscv_privil_reg[] regs) {
mstatus = riscv_privil_reg.type_id.create("mstatus");
mstatus.init_reg(privileged_reg_t.MSTATUS);
@ -168,7 +168,7 @@ class riscv_privileged_common_seq : uvm_sequence!(uvm_sequence_item,uvm_sequence
regs ~= mie;
}
}
void setup_smode_reg(privileged_mode_t mode, ref riscv_privil_reg [] regs) {
sstatus = riscv_privil_reg.type_id.create("sstatus");
sstatus.init_reg(privileged_reg_t.SSTATUS);

View file

@ -34,24 +34,24 @@ class riscv_pseudo_instr: riscv_instr
// `add_pseudo_instr(LI, I_FORMAT, LOAD, RV32I)
constraint! q{
if (pseudo_instr_name == riscv_pseudo_instr_name_t.LI) {
instr_format == riscv_instr_format_t.I_FORMAT;
category == riscv_instr_category_t.LOAD;
group == riscv_instr_group_t.RV32I;
}
if (pseudo_instr_name == riscv_pseudo_instr_name_t.LI) {
instr_format == riscv_instr_format_t.I_FORMAT;
category == riscv_instr_category_t.LOAD;
group == riscv_instr_group_t.RV32I;
}
} riscv_RV32I_LI_c;
// `add_pseudo_instr(LA, I_FORMAT, LOAD, RV32I)
constraint! q{
if (pseudo_instr_name == riscv_pseudo_instr_name_t.LA) {
instr_format == riscv_instr_format_t.I_FORMAT;
category == riscv_instr_category_t.LOAD;
group == riscv_instr_group_t.RV32I;
}
if (pseudo_instr_name == riscv_pseudo_instr_name_t.LA) {
instr_format == riscv_instr_format_t.I_FORMAT;
category == riscv_instr_category_t.LOAD;
group == riscv_instr_group_t.RV32I;
}
} riscv_RV32I_LA_c;
mixin uvm_object_utils;
this(string name = "") {
super(name);
process_load_store = false;

View file

@ -55,12 +55,12 @@ class riscv_reg_field: uvm_object
this(string name = "") {
super(name);
}
override string convert2string() {
return(format("%0s bit_width:%0d val:0x%0x type:%0s",
get_name(), bit_width, val, access_type));
}
void post_randomize() {
ubvec!XLEN mask = ubvec!XLEN.max();
@ -85,7 +85,7 @@ class riscv_reg(REG_T): uvm_object
this(string name = "") {
super(name);
}
void init_reg(REG_T reg_name) {
this.reg_name = reg_name;
offset = toubvec!12(reg_name);
@ -111,7 +111,7 @@ class riscv_reg(REG_T): uvm_object
}
return val;
}
void add_field(string fld_name, uint bit_width,
reg_field_access_t access_type,
ubvec!XLEN reset_val = 0) {
@ -127,7 +127,7 @@ class riscv_reg(REG_T): uvm_object
ubvec!XLEN val_ = val;
set_field_bvec(fld_name, val_, hard_wired);
}
void set_field_bvec(string fld_name, ubvec!XLEN val, bool hard_wired = false) {
foreach (f; fld) {
if (fld_name == (f.get_name())) {
@ -143,7 +143,7 @@ class riscv_reg(REG_T): uvm_object
}
riscv_reg_field get_field_by_name(string fld_name) {
foreach (f; fld) {
foreach (f; fld) {
if (fld_name == (f.get_name())) {
return f;
}
@ -151,13 +151,13 @@ class riscv_reg(REG_T): uvm_object
uvm_fatal(get_full_name(), format("Cannot match found field %0s", fld_name));
return null;
}
void rand_field(string fld_name) {
riscv_reg_field fld_hd = get_field_by_name(fld_name);
// `DV_CHECK_RANDOMIZE_FATAL(fld_hd)
fld_hd.randomize();
}
void set_field_rand_mode(string fld_name, bool rand_on) {
riscv_reg_field fld_hd = get_field_by_name(fld_name);
// rand_mode!q{fld_hd}(rand_on); // TBD

View file

@ -50,7 +50,7 @@ enum core_status_t: byte {
LOAD_FAULT_EXCEPTION,
STORE_FAULT_EXCEPTION,
EBREAK_EXCEPTION
}
}
enum test_result_t: bool {
TEST_PASS,

View file

@ -46,7 +46,7 @@ class riscv_vector_cfg : uvm_object
// Allow only vector instructions from the random sequences
@rand bool only_vec_instr;
constraint! q{@soft only_vec_instr == false;} only_vec_instr_c;
// Allow vector floating-point instructions (Allows vtype.vsew to be set <16 or >32).
@ -81,7 +81,7 @@ class riscv_vector_cfg : uvm_object
// Enable fault only first load ops
@rand @UVM_DEFAULT bool enable_fault_only_first_load;
constraint! q{
//solve vtype before vl;
//solve vl before vstart;
@ -107,7 +107,7 @@ class riscv_vector_cfg : uvm_object
if (vec_quad_widening) {
vtype.vlmul < 4 || (vtype.fractional_lmul == true);
}
} vlmul_c ;
} vlmul_c ;
constraint! q{
vtype.vsew inside [8, 16, 32, 64, 128];
@ -116,7 +116,7 @@ class riscv_vector_cfg : uvm_object
if (vec_fp) {vtype.vsew inside [32];}
if (vec_narrowing_widening) {vtype.vsew < ELEN;}
if (vec_quad_widening) {vtype.vsew < (ELEN >> 1);}
} vsew_c;
} vsew_c;
constraint! q{
enable_zvlsseg -> (vtype.vlmul < 8);
@ -126,7 +126,7 @@ class riscv_vector_cfg : uvm_object
vtype.vediv inside [1, 2, 4, 8];
vtype.vediv <= (vtype.vsew / SELEN);
} vdeiv_c;
this(string name = "") {
import esdl.base.cmdl: CommandLine;
@ -161,5 +161,5 @@ class riscv_vector_cfg : uvm_object
uvm_info(get_full_name(), format("Checking emul: %.2f", emul), UVM_LOW);
}
}
}

View file

@ -19,7 +19,7 @@
// Processor feature configuration
//-----------------------------------------------------------------------------
// XLEN
module riscv.gen.target.ml.riscv_core_setting;
module riscv.gen.target.ml.riscv_core_setting;
import riscv.gen.riscv_instr_pkg: satp_mode_t, privileged_mode_t,
riscv_instr_name_t, mtvec_mode_t, interrupt_cause_t,

View file

@ -19,7 +19,7 @@
// Processor feature configuration
//-----------------------------------------------------------------------------
// XLEN
module riscv.gen.target.multi_harts.riscv_core_setting;
module riscv.gen.target.multi_harts.riscv_core_setting;
import riscv.gen.riscv_instr_pkg: satp_mode_t, privileged_mode_t,
riscv_instr_name_t, mtvec_mode_t, interrupt_cause_t,

View file

@ -20,7 +20,7 @@
//-----------------------------------------------------------------------------
// XLEN
module riscv.gen.target.rv32i.riscv_core_setting;
module riscv.gen.target.rv32i.riscv_core_setting;
import riscv.gen.riscv_instr_pkg: satp_mode_t, privileged_mode_t,
riscv_instr_name_t, mtvec_mode_t, interrupt_cause_t,
@ -40,7 +40,7 @@ riscv_instr_name_t[] unsupported_instr = [];
// ISA supported by the processor
riscv_instr_group_t[] supported_isa = [riscv_instr_group_t.RV32I];
// Interrupt mode support
mtvec_mode_t[] supported_interrupt_mode = [mtvec_mode_t.DIRECT, mtvec_mode_t.VECTORED];
@ -120,7 +120,7 @@ enum privileged_reg_t[] implemented_csr = [
];
// Implementation-specific custom CSRs
ubvec!12[] custom_csr= [];
ubvec!12[] custom_csr= [];
// ----------------------------------------------------------------------------
// Supported interrupt/exception setting, used for functional coverage

View file

@ -20,7 +20,7 @@
//-----------------------------------------------------------------------------
// XLEN
module riscv.gen.target.rv32imafdc.riscv_core_setting;
module riscv.gen.target.rv32imafdc.riscv_core_setting;
import riscv.gen.riscv_instr_pkg: satp_mode_t, privileged_mode_t,
riscv_instr_name_t, mtvec_mode_t, interrupt_cause_t,

View file

@ -20,7 +20,7 @@
//-----------------------------------------------------------------------------
// XLEN
module riscv.gen.target.rv32imc.riscv_core_setting;
module riscv.gen.target.rv32imc.riscv_core_setting;
import riscv.gen.riscv_instr_pkg: satp_mode_t, privileged_mode_t,
riscv_instr_name_t, mtvec_mode_t, interrupt_cause_t,
@ -42,7 +42,7 @@ riscv_instr_name_t[] unsupported_instr = [];
riscv_instr_group_t[] supported_isa = [riscv_instr_group_t.RV32I,
riscv_instr_group_t.RV32M,
riscv_instr_group_t.RV32C];
// Interrupt mode support
mtvec_mode_t[] supported_interrupt_mode = [mtvec_mode_t.DIRECT, mtvec_mode_t.VECTORED];
@ -122,7 +122,7 @@ enum privileged_reg_t[] implemented_csr = [
];
// Implementation-specific custom CSRs
ubvec!12[] custom_csr= [];
ubvec!12[] custom_csr= [];
// ----------------------------------------------------------------------------
// Supported interrupt/exception setting, used for functional coverage

View file

@ -20,7 +20,7 @@
//-----------------------------------------------------------------------------
// XLEN
module riscv.gen.target.rv32imc_sv32.riscv_core_setting;
module riscv.gen.target.rv32imc_sv32.riscv_core_setting;
import riscv.gen.riscv_instr_pkg: satp_mode_t, privileged_mode_t,
riscv_instr_name_t, mtvec_mode_t, interrupt_cause_t,
@ -122,7 +122,7 @@ enum privileged_reg_t[] implemented_csr = [
];
// Implementation-specific custom CSRs
ubvec!12[] custom_csr= [];
ubvec!12[] custom_csr= [];
// ----------------------------------------------------------------------------
// Supported interrupt/exception setting, used for functional coverage

View file

@ -20,7 +20,7 @@
//-----------------------------------------------------------------------------
// XLEN
module riscv.gen.target.rv32imcb.riscv_core_setting;
module riscv.gen.target.rv32imcb.riscv_core_setting;
import riscv.gen.riscv_instr_pkg: satp_mode_t, privileged_mode_t,
riscv_instr_name_t, mtvec_mode_t, interrupt_cause_t,
@ -123,7 +123,7 @@ enum privileged_reg_t[] implemented_csr = [
];
// Implementation-specific custom CSRs
ubvec!12[] custom_csr = [];
ubvec!12[] custom_csr = [];
// ----------------------------------------------------------------------------
// Supported interrupt/exception setting, used for functional coverage

View file

@ -20,7 +20,7 @@
//-----------------------------------------------------------------------------
// XLEN
module riscv.gen.target.rv64gc.riscv_core_setting;
module riscv.gen.target.rv64gc.riscv_core_setting;
import riscv.gen.riscv_instr_pkg: satp_mode_t, privileged_mode_t,
riscv_instr_name_t, mtvec_mode_t, interrupt_cause_t,

View file

@ -20,7 +20,7 @@
//-----------------------------------------------------------------------------
// XLEN
module riscv.gen.target.rv64gcv.riscv_core_setting;
module riscv.gen.target.rv64gcv.riscv_core_setting;
import riscv.gen.riscv_instr_pkg: satp_mode_t, privileged_mode_t,
riscv_instr_name_t, mtvec_mode_t, interrupt_cause_t,

View file

@ -20,7 +20,7 @@
//-----------------------------------------------------------------------------
// XLEN
module riscv.gen.target.rv64imc.riscv_core_setting;
module riscv.gen.target.rv64imc.riscv_core_setting;
import riscv.gen.riscv_instr_pkg: satp_mode_t, privileged_mode_t,
riscv_instr_name_t, mtvec_mode_t, interrupt_cause_t,

View file

@ -20,7 +20,7 @@
//-----------------------------------------------------------------------------
// XLEN
module riscv.gen.target.rv64imcb.riscv_core_setting;
module riscv.gen.target.rv64imcb.riscv_core_setting;
import riscv.gen.riscv_instr_pkg: satp_mode_t, privileged_mode_t,
riscv_instr_name_t, mtvec_mode_t, interrupt_cause_t,

View file

@ -97,7 +97,7 @@ class riscv_instr_base_test: uvm_test
}
void apply_directed_instr() { }
override void run_phase(uvm_phase phase) {
int fd;

View file

@ -23,7 +23,7 @@ int main(string[] args) {
uint random_seed;
uint thread_index;
uint thread_count;
CommandLine cmdl = new CommandLine(args);
if (cmdl.plusArgs("random_seed=" ~ "%d", random_seed))
@ -34,7 +34,7 @@ int main(string[] args) {
thread_index = 0;
if (! cmdl.plusArgs("thread_count=" ~ "%d", thread_count))
thread_count = 1;
auto testbench = new uvm_testbench;
testbench.multicore(thread_index, thread_count);

View file

@ -65,7 +65,7 @@ class riscv_instr_test: riscv_instr_base_test
uvm_info(get_full_name(), "Creating instruction list", UVM_LOW);
cfg.instr_registry.create_instr_list(cfg);
uvm_info(get_full_name(), "Randomizing instruction list now...", UVM_LOW);
//10000.repeat();
for(int i = 0; i<100000; i++)
{
@ -77,14 +77,14 @@ class riscv_instr_test: riscv_instr_base_test
instr = cfg.instr_registry.get_rand_instr([riscv_instr_category_t.LOAD, riscv_instr_category_t.STORE]);
instr.randomize();
fd.writeln(instr.convert2asm());
// repeat (10000);
instr = cfg.instr_registry.get_rand_instr(([riscv_instr_category_t.LOAD, riscv_instr_category_t.STORE , riscv_instr_category_t.BRANCH]),
([riscv_instr_group_t.RV32I, riscv_instr_group_t.RV32M]));
instr.randomize();
fd.writeln(instr.convert2asm());
uvm_info(get_full_name(), format("%0s is generated", test_name), UVM_LOW);
uvm_info(get_full_name(), format("%0s is generated", test_name), UVM_LOW);
}

View file

@ -53,7 +53,7 @@ class riscv_rand_instr_test:riscv_instr_base_test
"riscv_debug_rom_gen",
get_full_name() ~ ".asm_gen.debug_rom");
}
}
override void randomize_cfg()
{
@ -111,7 +111,7 @@ class riscv_ml_test: riscv_instr_base_test
uvm_info(get_full_name(), "Create configuration instance...done", UVM_LOW);
uvm_info(get_full_name(), cfg.sprint(), UVM_LOW);
uvm_config_db!(riscv_instr_gen_config).set(null, "*", "instr_cfg", cfg);
}
}
override void randomize_cfg()
{
@ -120,7 +120,7 @@ class riscv_ml_test: riscv_instr_base_test
cfg.addr_translation_rnd_order_c.constraint_mode(1);
uvm_info(get_full_name(), format("riscv_instr_gen_config is randomized:\n%0s",cfg.sprint()), UVM_LOW);
}
override void run_phase(uvm_phase phase)
{
randomize_cfg();

View file

@ -5,7 +5,7 @@
## Limitation:
## Only generate tests targeted for build "rv32imc"
##
## Note: Currently available testlists
## Note: Currently available testlists
## <rootDir>/yaml/base_testlist.yaml
## <rootDir>/yaml/cov_testlist.yaml
## <rootDir>/target/rv64gcv/testlist.yaml
@ -58,7 +58,7 @@ for testName in base_testList + rv32imc_testList:
test["isPass"] = "Test passed"
test["metricsFile"] = "metrics.db"
test["seed"] = "random"
metricsList.append(test)
with open("regression_list.json", "w") as f:

View file

@ -11,7 +11,7 @@ def make_http_request( req_type, endpoint, params=None ):
headers = { 'Content-Type': 'application/json',
'Private-Token': str(os.environ['METRICS_CI_TOKEN'])
}
conn = http.client.HTTPSConnection(server)
conn.request(req_type, endpoint, params, headers)
response = conn.getresponse()
@ -48,7 +48,7 @@ else:
reqParams['branch'] = str(os.environ['GITHUB_REF'])
params = json.dumps(reqParams)
response, regressionData = make_http_request('POST', postRegression, params)
response, regressionData = make_http_request('POST', postRegression, params)
## Check response
if response.status != 201:
@ -105,7 +105,7 @@ print('\n')
print('Full results at: https://chipsalliance.metrics.ca/' + args.projectId + \
'/results/regressionRuns/' + regressionRunId)
## Set the exit code to be used by github action
if regressionData['testRuns']['failed'] > 0 or \
regressionData['testRuns']['incomplete'] > 0:
@ -115,8 +115,3 @@ else:
print('All tests have passed. Exit with code 0.')
exit(0)

View file

@ -0,0 +1,179 @@
/*
* Copyright 2019 Google LLC
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class riscv_csr_instr extends riscv_instr;
// Privileged CSR filter
static bit [11:0] exclude_reg[$];
static bit [11:0] include_reg[$];
static bit [11:0] include_write_reg[$];
// When set writes to read-only CSRs can be generated
static bit allow_ro_write;
rand bit write_csr;
constraint csr_addr_c {
if (include_reg.size() > 0) {
csr inside {include_reg};
}
if (exclude_reg.size() > 0) {
!(csr inside {exclude_reg});
}
}
constraint write_csr_c {
// We can only write a CSR if:
// - It's a read-only CSR and we're generating writes to read-only CSRs
// - Specific CSRs to write to are specified and this CSR is one
// - No specific CSRs to write to are specified and this isn't a read-only CSR
if(!((csr[11:10] == 2'b11 && allow_ro_write) ||
((include_write_reg.size() > 0) && (csr inside {include_write_reg})) ||
((csr[11:10] != 2'b11) && (include_write_reg.size() == 0)))) {
write_csr == 1'b0;
}
}
constraint csr_csrrw {
if (instr_name == CSRRW || instr_name == CSRRWI) {
write_csr == 1'b1;
}
}
constraint csr_csrrsc {
if (instr_name == CSRRS || instr_name == CSRRC) {
(write_csr == 1'b1) || rs1 == 0;
}
}
constraint csr_csrrsci {
if(instr_name == CSRRSI || instr_name == CSRRCI) {
(write_csr == 1'b1) || imm == 0;
}
}
constraint order {
// Choose a CSR before deciding whether we want to write to the CSR values. Then choose whether
// to read or write before choosing the rs1 and imm values. This ensures read-only accesses to
// read-only CSRs with similar probability to other CSR accesses and ensures a reasonable write
// vs read distribution for CSRs that can be written.
solve csr before write_csr, rs1, imm;
solve write_csr before rs1, imm;
}
`uvm_object_utils(riscv_csr_instr)
function new(string name = "");
super.new(name);
endfunction
static function void create_csr_filter(riscv_instr_gen_config cfg);
include_reg.delete();
exclude_reg.delete();
allow_ro_write = 1;
if (cfg.enable_illegal_csr_instruction) begin
exclude_reg = {implemented_csr};
end else if (cfg.enable_access_invalid_csr_level) begin
include_reg = {cfg.invalid_priv_mode_csrs};
end else if (cfg.gen_all_csrs_by_default) begin
allow_ro_write = cfg.gen_csr_ro_write;
include_reg = {implemented_csr, custom_csr};
create_include_write_reg(cfg.add_csr_write, cfg.remove_csr_write, default_include_csr_write);
end else begin
// Use scratch register to avoid the side effect of modifying other privileged mode CSR.
if (cfg.init_privileged_mode == MACHINE_MODE) begin
include_reg = {MSCRATCH};
end else if (cfg.init_privileged_mode == SUPERVISOR_MODE) begin
include_reg = {SSCRATCH};
end else begin
include_reg = {USCRATCH};
end
end
endfunction : create_csr_filter
static function void create_include_write_reg(privileged_reg_t add_csr[], privileged_reg_t remove_csr[], bit [11:0] initial_csrs[$]);
include_write_reg.delete();
foreach (initial_csrs[r]) begin
if (!(initial_csrs[r] inside {remove_csr})) begin
include_write_reg.push_back(initial_csrs[r]);
end
end
foreach (add_csr[r]) begin
include_write_reg.push_back(add_csr[r]);
end
endfunction
virtual function void set_rand_mode();
super.set_rand_mode();
has_rs2 = 1'b0;
if (format == I_FORMAT) begin
has_rs1 = 1'b0;
end
endfunction
// Convert the instruction to assembly code
virtual function string convert2asm(string prefix = "");
string asm_str;
asm_str = format_string(get_instr_name(), MAX_INSTR_STR_LEN);
case(format)
I_FORMAT: // instr rd,rs1,imm
asm_str = $sformatf("%0s%0s, 0x%0x, %0s", asm_str, rd.name(), csr, get_imm());
R_FORMAT: // instr rd,rs1,rs2
asm_str = $sformatf("%0s%0s, 0x%0x, %0s", asm_str, rd.name(), csr, rs1.name());
default:
`uvm_fatal(`gfn, $sformatf("Unsupported format %0s [%0s]", format.name(),
instr_name.name()))
endcase
if(comment != "")
asm_str = {asm_str, " #",comment};
return asm_str.tolower();
endfunction : convert2asm
function bit [6:0] get_opcode();
get_opcode = 7'b1110011;
endfunction
virtual function bit [2:0] get_func3();
case (instr_name)
CSRRW : get_func3 = 3'b001;
CSRRS : get_func3 = 3'b010;
CSRRC : get_func3 = 3'b011;
CSRRWI : get_func3 = 3'b101;
CSRRSI : get_func3 = 3'b110;
CSRRCI : get_func3 = 3'b111;
default : get_func3 = super.get_func3();
endcase
endfunction : get_func3
virtual function string convert2bin(string prefix = "");
string binary;
case(format)
I_FORMAT: binary = $sformatf("%8h", {csr[11:0], imm[4:0], get_func3(), rd, get_opcode()});
R_FORMAT: binary = $sformatf("%8h", {csr[11:0], rs1, get_func3(), rd, get_opcode()});
default: `uvm_fatal(`gfn, $sformatf("Unsupported format %0s", format.name()))
endcase
return {prefix, binary};
endfunction
endclass : riscv_csr_instr

View file

@ -80,7 +80,7 @@ class riscv_floating_point_instr extends riscv_instr;
CS_FORMAT:
asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, fs2.name(), get_imm(), rs1.name());
CSS_FORMAT:
asm_str = $sformatf("%0s%0s, %0s(sp)", asm_str, fs2.name(), get_imm());
asm_str = $sformatf("%0s%0s, %0s(sp)", asm_str, fs2.name(), get_imm());
CI_FORMAT:
asm_str = $sformatf("%0s%0s, %0s", asm_str, fd.name(), get_imm());
default:
@ -172,12 +172,12 @@ class riscv_floating_point_instr extends riscv_instr;
has_fd = 1'b0;
end
CSS_FORMAT: begin
has_rs1 = 1'b0;
has_fd = 1'b0;
has_rs1 = 1'b0;
has_fd = 1'b0;
end
CI_FORMAT: begin
has_rs1 = 1'b0;
has_fs2 = 1'b0;
has_rs1 = 1'b0;
has_fs2 = 1'b0;
end
default: `uvm_info(`gfn, $sformatf("Unsupported format %0s", format.name()), UVM_LOW)
endcase

View file

@ -28,9 +28,6 @@ class riscv_instr extends uvm_object;
static riscv_instr_name_t basic_instr[$];
static riscv_instr instr_template[riscv_instr_name_t];
// Privileged CSR filter
static privileged_reg_t exclude_reg[];
static privileged_reg_t include_reg[];
riscv_instr_gen_config m_cfg;
@ -83,16 +80,6 @@ class riscv_instr extends uvm_object;
}
}
constraint csr_c {
if (category == CSR) {
if (include_reg.size() > 0) {
csr inside {include_reg};
}
if (exclude_reg.size() > 0) {
!(csr inside {exclude_reg});
}
}
}
`uvm_object_utils(riscv_instr)
`uvm_object_new
@ -138,32 +125,12 @@ class riscv_instr extends uvm_object;
end
end
build_basic_instruction_list(cfg);
create_csr_filter(cfg);
endfunction : create_instr_list
virtual function bit is_supported(riscv_instr_gen_config cfg);
return 1;
endfunction
static function void create_csr_filter(riscv_instr_gen_config cfg);
include_reg.delete();
exclude_reg.delete();
if (cfg.enable_illegal_csr_instruction) begin
exclude_reg = implemented_csr;
end else if (cfg.enable_access_invalid_csr_level) begin
include_reg = cfg.invalid_priv_mode_csrs;
end else begin
// Use scratch register to avoid the side effect of modifying other privileged mode CSR.
if (cfg.init_privileged_mode == MACHINE_MODE) begin
include_reg = {MSCRATCH};
end else if (cfg.init_privileged_mode == SUPERVISOR_MODE) begin
include_reg = {SSCRATCH};
end else begin
include_reg = {USCRATCH};
end
end
endfunction : create_csr_filter
static function riscv_instr create_instr(riscv_instr_name_t instr_name);
uvm_object obj;
riscv_instr inst;
@ -319,12 +286,6 @@ class riscv_instr extends uvm_object;
has_rs2 = 1'b0;
end
endcase
if (category == CSR) begin
has_rs2 = 1'b0;
if (format == I_FORMAT) begin
has_rs1 = 1'b0;
end
end
endfunction
function void pre_randomize();
@ -385,8 +346,6 @@ class riscv_instr extends uvm_object;
asm_str = "fence.i";
else if(category == LOAD) // Use psuedo instruction format
asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, rd.name(), get_imm(), rs1.name());
else if(category == CSR)
asm_str = $sformatf("%0s%0s, 0x%0x, %0s", asm_str, rd.name(), csr, get_imm());
else
asm_str = $sformatf("%0s%0s, %0s, %0s", asm_str, rd.name(), rs1.name(), get_imm());
S_FORMAT, B_FORMAT: // instr rs1,rs2,imm
@ -395,9 +354,7 @@ class riscv_instr extends uvm_object;
else
asm_str = $sformatf("%0s%0s, %0s, %0s", asm_str, rs1.name(), rs2.name(), get_imm());
R_FORMAT: // instr rd,rs1,rs2
if(category == CSR) begin
asm_str = $sformatf("%0s%0s, 0x%0x, %0s", asm_str, rd.name(), csr, rs1.name());
end else if(instr_name == SFENCE_VMA) begin
if(instr_name == SFENCE_VMA) begin
asm_str = "sfence.vma x0, x0"; // TODO: Support all possible sfence
end else begin
asm_str = $sformatf("%0s%0s, %0s, %0s", asm_str, rd.name(), rs1.name(), rs2.name());
@ -432,7 +389,7 @@ class riscv_instr extends uvm_object;
ADDIW, SLLIW, SRLIW, SRAIW : get_opcode = 7'b0011011;
MULH, MULHSU, MULHU, DIV, DIVU, REM, REMU : get_opcode = 7'b0110011;
FENCE, FENCE_I : get_opcode = 7'b0001111;
ECALL, EBREAK, CSRRW, CSRRS, CSRRC, CSRRWI, CSRRSI, CSRRCI : get_opcode = 7'b1110011;
ECALL, EBREAK : get_opcode = 7'b1110011;
ADDW, SUBW, SLLW, SRLW, SRAW, MULW, DIVW, DIVUW, REMW, REMUW : get_opcode = 7'b0111011;
ECALL, EBREAK, URET, SRET, MRET, DRET, WFI, SFENCE_VMA : get_opcode = 7'b1110011;
default : `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name()))
@ -480,12 +437,6 @@ class riscv_instr extends uvm_object;
FENCE_I : get_func3 = 3'b001;
ECALL : get_func3 = 3'b000;
EBREAK : get_func3 = 3'b000;
CSRRW : get_func3 = 3'b001;
CSRRS : get_func3 = 3'b010;
CSRRC : get_func3 = 3'b011;
CSRRWI : get_func3 = 3'b101;
CSRRSI : get_func3 = 3'b110;
CSRRCI : get_func3 = 3'b111;
LWU : get_func3 = 3'b110;
LD : get_func3 = 3'b011;
SD : get_func3 = 3'b011;
@ -579,8 +530,6 @@ class riscv_instr extends uvm_object;
I_FORMAT: begin
if(instr_name inside {FENCE, FENCE_I})
binary = $sformatf("%8h", {17'b0, get_func3(), 5'b0, get_opcode()});
else if(category == CSR)
binary = $sformatf("%8h", {csr[11:0], imm[4:0], get_func3(), rd, get_opcode()});
else if(instr_name == ECALL)
binary = $sformatf("%8h", {get_func7(), 18'b0, get_opcode()});
else if(instr_name inside {URET, SRET, MRET})
@ -603,9 +552,7 @@ class riscv_instr extends uvm_object;
imm[4:1], imm[11], get_opcode()});
end
R_FORMAT: begin
if(category == CSR)
binary = $sformatf("%8h", {csr[11:0], rs1, get_func3(), rd, get_opcode()});
else if(instr_name == SFENCE_VMA)
if(instr_name == SFENCE_VMA)
binary = $sformatf("%8h", {get_func7(), 18'b0, get_opcode()});
else
binary = $sformatf("%8h", {get_func7(), rs2, rs1, get_func3(), rd, get_opcode()});

View file

@ -73,9 +73,9 @@
`DEFINE_INSTR(DRET, I_FORMAT, SYSTEM, RV32I)
`DEFINE_INSTR(WFI, I_FORMAT, INTERRUPT, RV32I)
// CSR instructions
`DEFINE_INSTR(CSRRW, R_FORMAT, CSR, RV32I, UIMM)
`DEFINE_INSTR(CSRRS, R_FORMAT, CSR, RV32I, UIMM)
`DEFINE_INSTR(CSRRC, R_FORMAT, CSR, RV32I, UIMM)
`DEFINE_INSTR(CSRRWI, I_FORMAT, CSR, RV32I, UIMM)
`DEFINE_INSTR(CSRRSI, I_FORMAT, CSR, RV32I, UIMM)
`DEFINE_INSTR(CSRRCI, I_FORMAT, CSR, RV32I, UIMM)
`DEFINE_CSR_INSTR(CSRRW, R_FORMAT, CSR, RV32I, UIMM)
`DEFINE_CSR_INSTR(CSRRS, R_FORMAT, CSR, RV32I, UIMM)
`DEFINE_CSR_INSTR(CSRRC, R_FORMAT, CSR, RV32I, UIMM)
`DEFINE_CSR_INSTR(CSRRWI, I_FORMAT, CSR, RV32I, UIMM)
`DEFINE_CSR_INSTR(CSRRSI, I_FORMAT, CSR, RV32I, UIMM)
`DEFINE_CSR_INSTR(CSRRCI, I_FORMAT, CSR, RV32I, UIMM)

View file

@ -62,6 +62,11 @@ class riscv_asm_program_gen extends uvm_object;
// This is the main function to generate all sections of the program.
virtual function void gen_program();
// Prevent generation of PMP exception handling code where PMP is not supported
if (!support_pmp) begin
cfg.pmp_cfg.enable_pmp_exception_handler = 1'b0;
end
instr_stream.delete();
// Generate program header
gen_program_header();

View file

@ -70,6 +70,11 @@
class riscv_``instr_n``_instr extends riscv_instr; \
`INSTR_BODY(instr_n, instr_format, instr_category, instr_group, imm_tp)
// CSR instructions
`define DEFINE_CSR_INSTR(instr_n, instr_format, instr_category, instr_group, imm_tp = IMM) \
class riscv_``instr_n``_instr extends riscv_csr_instr; \
`INSTR_BODY(instr_n, instr_format, instr_category, instr_group, imm_tp)
// Floating point instruction
`define DEFINE_FP_INSTR(instr_n, instr_format, instr_category, instr_group, imm_tp = IMM) \
class riscv_``instr_n``_instr extends riscv_floating_point_instr; \

View file

@ -167,6 +167,11 @@ class riscv_instr_gen_config extends uvm_object;
bit enable_unaligned_load_store;
int illegal_instr_ratio;
int hint_instr_ratio;
// CSR instruction control
bit gen_all_csrs_by_default = 0; // Generate CSR instructions that use all supported CSRs. Other options below only take effect if this is enabled.
bit gen_csr_ro_write = 0; // Generate CSR writes to read-only CSRs
privileged_reg_t add_csr_write[] = {}; // CSRs to add to the set of writeable CSRs
privileged_reg_t remove_csr_write[] = {}; // CSRs to remove from the set of writeable CSRs
// Number of harts to be simulated, must be <= NUM_HARTS
int num_of_harts = NUM_HARTS;
// Use SP as stack pointer
@ -487,6 +492,10 @@ class riscv_instr_gen_config extends uvm_object;
`uvm_field_int(enable_unaligned_load_store, UVM_DEFAULT)
`uvm_field_int(illegal_instr_ratio, UVM_DEFAULT)
`uvm_field_int(hint_instr_ratio, UVM_DEFAULT)
`uvm_field_int(gen_all_csrs_by_default, UVM_DEFAULT)
`uvm_field_int(gen_csr_ro_write, UVM_DEFAULT)
`uvm_field_array_enum(privileged_reg_t, add_csr_write, UVM_DEFAULT)
`uvm_field_array_enum(privileged_reg_t, remove_csr_write, UVM_DEFAULT)
`uvm_field_string(boot_mode_opts, UVM_DEFAULT)
`uvm_field_int(enable_page_table_exception, UVM_DEFAULT)
`uvm_field_int(no_directed_instr, UVM_DEFAULT)
@ -561,6 +570,12 @@ class riscv_instr_gen_config extends uvm_object;
get_bool_arg_value("+no_delegation=", no_delegation);
get_int_arg_value("+illegal_instr_ratio=", illegal_instr_ratio);
get_int_arg_value("+hint_instr_ratio=", hint_instr_ratio);
get_bool_arg_value("+gen_all_csrs_by_default=", gen_all_csrs_by_default);
get_bool_arg_value("+gen_csr_ro_write=", gen_csr_ro_write);
cmdline_enum_processor #(privileged_reg_t)::get_array_values("+add_csr_write=",
1'b1, add_csr_write);
cmdline_enum_processor #(privileged_reg_t)::get_array_values("+remove_csr_write=",
1'b1, remove_csr_write);
get_int_arg_value("+num_of_harts=", num_of_harts);
get_bool_arg_value("+enable_unaligned_load_store=", enable_unaligned_load_store);
get_bool_arg_value("+force_m_delegation=", force_m_delegation);
@ -590,7 +605,7 @@ class riscv_instr_gen_config extends uvm_object;
get_bool_arg_value("+enable_zbc_extension=", enable_zbc_extension);
get_bool_arg_value("+enable_zbs_extension=", enable_zbs_extension);
cmdline_enum_processor #(b_ext_group_t)::get_array_values("+enable_bitmanip_groups=",
enable_bitmanip_groups);
1'b0, 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)
@ -608,7 +623,7 @@ class riscv_instr_gen_config extends uvm_object;
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);
cmdline_enum_processor #(riscv_instr_group_t)::get_array_values("+march=", 1'b0, march_isa);
if (march_isa.size != 0) riscv_instr_pkg::supported_isa = march_isa;
if (!(RV32C inside {supported_isa})) begin
@ -638,7 +653,7 @@ class riscv_instr_gen_config extends uvm_object;
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);
pmp_cfg.initialize(signature_addr);
setup_instr_distribution();
get_invalid_priv_lvl_csr();
endfunction

View file

@ -1208,6 +1208,8 @@ package riscv_instr_pkg;
WAW_HAZARD
} hazard_e;
bit [11:0] default_include_csr_write[$] = {MSCRATCH};
`include "riscv_core_setting.sv"
// ePMP machine security configuration
@ -1252,7 +1254,7 @@ package riscv_instr_pkg;
rand bit r;
// RV32: the pmpaddr is the top 32 bits of a 34 bit PMP address
// RV64: the pmpaddr is the top 54 bits of a 56 bit PMP address
bit [XLEN - 1 : 0] addr;
rand bit [XLEN - 1 : 0] addr;
// The offset from the address of <main> - automatically populated by the
// PMP generation routine.
rand bit [XLEN - 1 : 0] offset;
@ -1453,7 +1455,7 @@ package riscv_instr_pkg;
endfunction
class cmdline_enum_processor #(parameter type T = riscv_instr_group_t);
static function void get_array_values(string cmdline_str, ref T vals[]);
static function void get_array_values(string cmdline_str, bit allow_raw_vals, ref T vals[]);
string s;
void'(inst.get_arg_value(cmdline_str, s));
if(s != "") begin
@ -1462,7 +1464,13 @@ package riscv_instr_pkg;
uvm_split_string(s, ",", cmdline_list);
vals = new[cmdline_list.size];
foreach (cmdline_list[i]) begin
if (uvm_enum_wrapper#(T)::from_name(
if (allow_raw_vals && cmdline_list[i].substr(0, 1) == "0x") begin
logic[$bits(T)-1:0] raw_val;
string raw_val_hex_digits = cmdline_list[i].substr(2, cmdline_list[i].len()-1);
raw_val = raw_val_hex_digits.atohex();
vals[i] = T'(raw_val);
end else if (uvm_enum_wrapper#(T)::from_name(
cmdline_list[i].toupper(), value)) begin
vals[i] = value;
end else begin
@ -1523,6 +1531,7 @@ package riscv_instr_pkg;
`include "isa/riscv_zbc_instr.sv"
`include "isa/riscv_zbs_instr.sv"
`include "isa/riscv_b_instr.sv"
`include "isa/riscv_csr_instr.sv"
`include "isa/riscv_floating_point_instr.sv"
`include "isa/riscv_vector_instr.sv"
`include "isa/riscv_compressed_instr.sv"

View file

@ -49,6 +49,10 @@ class riscv_pmp_cfg extends uvm_object;
// pmp CSR configurations
rand pmp_cfg_reg_t pmp_cfg[];
// Hints used during PMP generation
bit pmp_cfg_addr_valid[];
bit pmp_cfg_already_configured[];
// This value is the address offset between the minimum and maximum pmpaddr
// CSR values.
// As pmpaddr0 will be set to the address of the <main> label, the address stored
@ -57,6 +61,11 @@ class riscv_pmp_cfg extends uvm_object;
// Can be manually configured from the command line.
bit [XLEN - 1 : 0] pmp_max_offset = {XLEN{1'b1}};
// Value to hold the end signature address to that signals the end to the test environment.
// Currently the design assumes that the end signature is address is equal to the signature
// address minus 4 Bytes.
bit [XLEN - 1 : 0] end_signature_addr;
// used to parse addr_mode configuration from cmdline
typedef uvm_enum_wrapper#(pmp_addr_mode_t) addr_mode_wrapper;
pmp_addr_mode_t addr_mode;
@ -82,21 +91,19 @@ class riscv_pmp_cfg extends uvm_object;
constraint xwr_c {
foreach (pmp_cfg[i]) {
!(pmp_cfg[i].w && !pmp_cfg[i].r);
!(!mseccfg.mml && pmp_cfg[i].w && !pmp_cfg[i].r);
}
}
constraint grain_addr_mode_c {
foreach (pmp_cfg[i]) {
(pmp_granularity == 0) -> (pmp_cfg[i].a != NAPOT);
(pmp_granularity >= 1) -> (pmp_cfg[i].a != NA4);
}
}
constraint addr_range_c {
foreach (pmp_cfg[i]) {
// Offset of pmp_cfg[0] does not matter, since it will be set to <main>,
// so we do not constrain it here, as it will be overridden during generation
// Offset of pmp_cfg[0] is always set to 0 from main.
if (i != 0) {
pmp_cfg[i].offset inside {[1 : pmp_max_offset]};
} else {
@ -138,9 +145,12 @@ class riscv_pmp_cfg extends uvm_object;
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];
pmp_cfg_addr_valid = new[pmp_num_regions];
pmp_cfg_already_configured = new[pmp_num_regions];
endfunction
function void initialize(bit require_signature_addr);
function void initialize(bit [XLEN - 1 : 0] signature_addr);
end_signature_addr = signature_addr - 'h4;
if (!pmp_randomize) begin
set_defaults();
setup_pmp();
@ -162,12 +172,14 @@ class riscv_pmp_cfg extends uvm_object;
mseccfg.mmwp = 1'b0;
mseccfg.rlb = 1'b1;
foreach(pmp_cfg[i]) begin
pmp_cfg[i].l = 1'b0;
pmp_cfg[i].a = TOR;
pmp_cfg[i].x = 1'b1;
pmp_cfg[i].w = 1'b1;
pmp_cfg[i].r = 1'b1;
pmp_cfg[i].offset = assign_default_addr_offset(pmp_num_regions, i);
pmp_cfg[i].l = 1'b0;
pmp_cfg[i].a = TOR;
pmp_cfg[i].x = 1'b1;
pmp_cfg[i].w = 1'b1;
pmp_cfg[i].r = 1'b1;
pmp_cfg[i].offset = assign_default_addr_offset(pmp_num_regions, i);
pmp_cfg_addr_valid[i] = 1'b0;
pmp_cfg_already_configured[i] = 1'b0;
end
endfunction
@ -178,16 +190,21 @@ class riscv_pmp_cfg extends uvm_object;
return offset;
endfunction
typedef struct { pmp_cfg_reg_t pmp_cfg_reg; bit addr_valid; } parse_pmp_config_t;
function void setup_pmp();
string arg_name;
string arg_value;
parse_pmp_config_t tmp_value;
if (inst.get_arg_value("+mseccfg=", arg_value)) begin
mseccfg = parse_mseccfg(arg_value, mseccfg);
end
foreach (pmp_cfg[i]) begin
arg_name = $sformatf("+pmp_region_%0d=", i);
if (inst.get_arg_value(arg_name, arg_value)) begin
pmp_cfg[i] = parse_pmp_config(arg_value, pmp_cfg[i]);
tmp_value = parse_pmp_config(arg_value, pmp_cfg[i]);
pmp_cfg[i] = tmp_value.pmp_cfg_reg;
pmp_cfg_addr_valid[i] = tmp_value.addr_valid;
`uvm_info(`gfn, $sformatf("Configured pmp_cfg[%0d] from command line: %p",
i, pmp_cfg[i]), UVM_LOW)
end
@ -223,12 +240,14 @@ class riscv_pmp_cfg extends uvm_object;
return mseccfg_reg;
endfunction
function pmp_cfg_reg_t parse_pmp_config(string pmp_region, pmp_cfg_reg_t ref_pmp_cfg);
function parse_pmp_config_t parse_pmp_config(string pmp_region, pmp_cfg_reg_t ref_pmp_cfg);
string fields[$];
string field_vals[$];
string field_type;
string field_val;
pmp_cfg_reg_t pmp_cfg_reg = ref_pmp_cfg;
parse_pmp_config_t return_value;
return_value.pmp_cfg_reg = ref_pmp_cfg;
return_value.addr_valid = 1'b0;
uvm_split_string(pmp_region, ",", fields);
foreach (fields[i]) begin
uvm_split_string(fields[i], ":", field_vals);
@ -236,32 +255,33 @@ class riscv_pmp_cfg extends uvm_object;
field_val = field_vals.pop_front();
case (field_type)
"L": begin
pmp_cfg_reg.l = field_val.atobin();
return_value.pmp_cfg_reg.l = field_val.atobin();
end
"A": begin
`DV_CHECK(addr_mode_wrapper::from_name(field_val, addr_mode))
pmp_cfg_reg.a = addr_mode;
return_value.pmp_cfg_reg.a = addr_mode;
end
"X": begin
pmp_cfg_reg.x = field_val.atobin();
return_value.pmp_cfg_reg.x = field_val.atobin();
end
"W": begin
pmp_cfg_reg.w = field_val.atobin();
return_value.pmp_cfg_reg.w = field_val.atobin();
end
"R": begin
pmp_cfg_reg.r = field_val.atobin();
return_value.pmp_cfg_reg.r = field_val.atobin();
end
"ADDR": begin
// Don't have to convert address to "PMP format" here,
// since it must be masked off in hardware
pmp_cfg_reg.addr = format_addr(field_val.atohex());
return_value.addr_valid = 1'b1;
return_value.pmp_cfg_reg.addr = format_addr(field_val.atohex());
end
default: begin
`uvm_fatal(`gfn, $sformatf("%s, Invalid PMP configuration field name!", field_val))
end
endcase
end
return pmp_cfg_reg;
return return_value;
endfunction
function bit [XLEN - 1 : 0] format_addr(bit [XLEN - 1 : 0] addr);
@ -294,52 +314,181 @@ class riscv_pmp_cfg extends uvm_object;
// save some extraneous instructions from being performed.
//
// The general flow of this function:
// - Set address of region 0 before setting MSECCFG
// - If MML, initially set MSECCFG to MML=0, MMWP=0, RLB=1
// - If MML, set the config of region 0 to LXWR=1100 and TOR
// - If MMWP, set the config of region 0 to LXWR=0100 and TOR
// - If MML or MMWP, set requested MSECCFG with RLB hardcoded to 1
// - Don't override region 0 config if `+pmp_region_0` is passed
// - Set default region 0 config in MML mode to shared execute
// - Set all other addresses and configs
// - Set requested MSECCFG (including RLB)
// - If randomization, generate code region, otherwise select region 0.
// - Set address of code region before setting MSECCFG.
// - If MML, initially set MSECCFG to MML=0, MMWP=0, RLB=1.
// - If MML, set the config of code region to LXWR=1100 and TOR.
// - If MMWP, set the config of code region to LXWR=0100 and TOR.
// - If MML or MMWP, set requested MSECCFG with RLB hardcoded to 1.
// - Don't override code region config if corresponding `+pmp_region_` is passed.
// - If MML, set default code region config to shared execute.
// - If MML or MMWP, set stack and signature regions to shared read/write.
// - Set requested MSECCFG (including RLB).
// - Set all other addresses and configs.
function void gen_pmp_instr(riscv_reg_t scratch_reg[2], ref string instr[$]);
bit [XLEN - 1 : 0] pmp_word;
bit [XLEN - 1 : 0] cfg_bitmask;
bit [7 : 0] cfg_byte;
int pmp_id;
string arg_value;
// Load the address of the <main> section into pmpaddr0.
// This needs to be done before setting MSECCFG in the case of MML or MMWP.
instr.push_back($sformatf("la x%0d, main", scratch_reg[0]));
instr.push_back($sformatf("srli x%0d, x%0d, 2", scratch_reg[0], scratch_reg[0]));
instr.push_back($sformatf("csrw 0x%0x, x%0d", base_pmp_addr, scratch_reg[0]));
`uvm_info(`gfn, "Loaded the address of <main> section into pmpaddr0", UVM_LOW)
int code_entry;
pmp_cfg_reg_t tmp_pmp_cfg;
if (riscv_instr_pkg::support_epmp) begin
// In case of MML or MMWP we need to set region 0 to executable before setting MSECCFG.
if (mseccfg.mml == 1 || mseccfg.mmwp == 1) begin
if (mseccfg.mml == 1) begin
// Writing MSECCFG with RLB set to 1 to stop the config with L enabled from locking
// everything before configuration is done.
`uvm_info(`gfn, $sformatf("MSECCFG: MML 0, MMWP 0, RLB 1"), UVM_LOW)
cfg_byte = {1'b1, 1'b0, 1'b0};
instr.push_back($sformatf("csrwi 0x%0x, %0d", MSECCFG, cfg_byte));
// In case of MML or MMWP we need to set code region to executable before setting MSECCFG.
if (mseccfg.mml || mseccfg.mmwp) begin
// Writing MSECCFG with RLB set to 1 to stop the config with L enabled from locking
// everything before configuration is done.
`uvm_info(`gfn, $sformatf("MSECCFG: MML 0, MMWP 0, RLB 1"), UVM_LOW)
cfg_byte = {1'b1, 1'b0, 1'b0};
instr.push_back($sformatf("csrwi 0x%0x, %0d", MSECCFG, cfg_byte));
if (pmp_randomize) begin
// Randomly select a PMP region to contain the code for permitting execution and two
// extra regions to contain the stack and the signature address.
code_entry = $urandom_range(pmp_num_regions - 3);
// In case of full randomization we actually want the code region to cover main as well.
pmp_cfg[code_entry].offset = pmp_max_offset;
end else begin
code_entry = 0;
// This is the default offset.
pmp_cfg[code_entry].offset = assign_default_addr_offset(pmp_num_regions, 0);
end
if (code_entry > 0) begin
// Load _start into PMP address of previous entry to complete TOR region.
instr.push_back($sformatf("la x%0d, _start", scratch_reg[0]));
instr.push_back($sformatf("srli x%0d, x%0d, 2", scratch_reg[0], scratch_reg[0]));
instr.push_back($sformatf("csrw 0x%0x, x%0d", base_pmp_addr + code_entry - 1,
scratch_reg[0]));
`uvm_info(`gfn, $sformatf("Address of pmp_addr_%d is _start", code_entry - 1), UVM_LOW)
pmp_cfg_already_configured[code_entry - 1] = 1'b1;
end
// Load the address of the <main> + offset into PMP code entry.
instr.push_back($sformatf("la x%0d, main", scratch_reg[0]));
instr.push_back($sformatf("li x%0d, 0x%0x", scratch_reg[1], pmp_cfg[code_entry].offset));
instr.push_back($sformatf("add x%0d, x%0d, x%0d", scratch_reg[0], scratch_reg[0],
scratch_reg[1]));
instr.push_back($sformatf("srli x%0d, x%0d, 2", scratch_reg[0], scratch_reg[0]));
instr.push_back($sformatf("csrw 0x%0x, x%0d", base_pmp_addr + code_entry, scratch_reg[0]));
`uvm_info(`gfn, $sformatf("Offset of pmp_addr_%d from main: 0x%0x", code_entry,
pmp_cfg[code_entry].offset), UVM_LOW)
pmp_cfg_already_configured[code_entry] = 1'b1;
if (mseccfg.mml) begin
// This value is different from below (M-mode execute only) because we need code region
// to be executable in both M-mode and U-mode, since RISCV-DV switches priviledge before
// <main> but after <pmp_setup>. We choose not to use the shared code region that also
// allows read in M-mode because that is inconsistent with the execute-only in other
// modes.
tmp_pmp_cfg.l = 1'b1;
tmp_pmp_cfg.a = TOR;
tmp_pmp_cfg.x = 1'b0;
tmp_pmp_cfg.w = 1'b1;
tmp_pmp_cfg.r = 1'b0;
// This configuration needs to be executable in M-mode both before and after writing to
// MSECCFG. It will deny execution for U-Mode, but this is necessary because RWX=111 in
// MML means read only, and RW=01 is not allowed before MML is enabled.
cfg_byte = {1'b1, pmp_cfg[0].zero, TOR, 1'b1, 1'b0, 1'b0};
cfg_byte = {tmp_pmp_cfg.l, tmp_pmp_cfg.zero, tmp_pmp_cfg.a, 1'b1,
1'b0, tmp_pmp_cfg.r};
end else begin
// We must set pmp region 0 to executable before enabling MMWP. RW=00 to be consistend
// We must set pmp code region to executable before enabling MMWP. RW=00 to be consistent
// with MML configuration as much as possible.
cfg_byte = {1'b0, pmp_cfg[0].zero, TOR, 1'b1, 1'b0, 1'b0};
tmp_pmp_cfg.l = 1'b0;
tmp_pmp_cfg.a = TOR;
tmp_pmp_cfg.x = 1'b1;
tmp_pmp_cfg.w = 1'b0;
tmp_pmp_cfg.r = 1'b0;
cfg_byte = {tmp_pmp_cfg.l, tmp_pmp_cfg.zero, tmp_pmp_cfg.a,
tmp_pmp_cfg.x, tmp_pmp_cfg.w, tmp_pmp_cfg.r};
end
// In case the randomly selected code entry is not also configured in the arguments,
// overwrite it in pmp_cfg.
// The pmp_config has value LXWR = 1010, which means it is executable in both M and U mode.
if (!inst.get_arg_value($sformatf("+pmp_region_%d=", code_entry), arg_value)) begin
pmp_cfg[code_entry].l = tmp_pmp_cfg.l;
pmp_cfg[code_entry].a = tmp_pmp_cfg.a;
pmp_cfg[code_entry].x = tmp_pmp_cfg.x;
pmp_cfg[code_entry].w = tmp_pmp_cfg.w;
pmp_cfg[code_entry].r = tmp_pmp_cfg.r;
end
if (code_entry > 0) begin
// Disable all configs before the code entry because PMP regions can be initialized with
// any value and we need to make sure that the code entry is the first valid entry during
// PMP setup.
cfg_bitmask = 0;
instr.push_back($sformatf("li x%0d, 0x%0x", scratch_reg[0], cfg_bitmask));
for (int i = 0; i < (code_entry / cfg_per_csr); i++) begin
instr.push_back($sformatf("csrw 0x%0x, x%0d", base_pmpcfg_addr + i, scratch_reg[0]));
end
end
// Enable the selected config on region code_entry.
cfg_bitmask = cfg_byte << ((code_entry % cfg_per_csr) * 8);
`uvm_info(`gfn, $sformatf("temporary code config: 0x%0x", cfg_bitmask), UVM_DEBUG)
instr.push_back($sformatf("li x%0d, 0x%0x", scratch_reg[0], cfg_bitmask));
instr.push_back($sformatf("csrw 0x%0x, x%0d", base_pmpcfg_addr + (code_entry/cfg_per_csr),
scratch_reg[0]));
// Load the address of the kernel_stack_end into PMP stack entry.
instr.push_back($sformatf("la x%0d, kernel_stack_end", scratch_reg[0]));
instr.push_back($sformatf("srli x%0d, x%0d, 2", scratch_reg[0], scratch_reg[0]));
instr.push_back($sformatf("csrw 0x%0x, x%0d", base_pmp_addr + code_entry + 1,
scratch_reg[0]));
`uvm_info(`gfn, $sformatf("Address of pmp_addr_%d is kernel_stack_end", code_entry + 1),
UVM_LOW)
pmp_cfg_already_configured[code_entry + 1] = 1'b1;
// In case the randomly selected code_entry + 1 is not also specified in the arguments,
// overwrite it in pmp_cfg. We use this for the stack entry.
if (!inst.get_arg_value($sformatf("+pmp_region_%d=", code_entry + 1), arg_value)) begin
if (mseccfg.mml) begin
// Marking the pmp stack region as shared write/read region before starting main.
pmp_cfg[code_entry + 1].l = 1'b0;
pmp_cfg[code_entry + 1].a = TOR;
pmp_cfg[code_entry + 1].x = 1'b1;
pmp_cfg[code_entry + 1].w = 1'b1;
pmp_cfg[code_entry + 1].r = 1'b0;
end else begin
// We must set PMP stack region to write/read before starting main. X=0 to be consistent
// with MML mode.
pmp_cfg[code_entry + 1].l = 1'b0;
pmp_cfg[code_entry + 1].a = TOR;
pmp_cfg[code_entry + 1].x = 1'b0;
pmp_cfg[code_entry + 1].w = 1'b1;
pmp_cfg[code_entry + 1].r = 1'b1;
end
end
// Load the signature address into PMP signature entry. This assumes the
// end_signature_addr = signature_addr - 4. And that both are 4 Bytes.
instr.push_back($sformatf("li x%0d, 0x%0x", scratch_reg[0], end_signature_addr));
instr.push_back($sformatf("srli x%0d, x%0d, 2", scratch_reg[0], scratch_reg[0]));
instr.push_back($sformatf("csrw 0x%0x, x%0d", base_pmp_addr + code_entry + 2,
scratch_reg[0]));
`uvm_info(`gfn, $sformatf("Address of pmp_addr_%d is signature_addr", code_entry + 2),
UVM_LOW)
pmp_cfg_already_configured[code_entry + 2] = 1'b1;
// In case the randomly selected code_entry + 2 is not also specified in the arguments,
// overwrite it in pmp_cfg. This is used for the signature address.
if (!inst.get_arg_value($sformatf("+pmp_region_%d=", code_entry + 2), arg_value)) begin
if (mseccfg.mml) begin
// Marking the PMP signature region as shared write/read region before starting main.
pmp_cfg[code_entry + 2].l = 1'b0;
pmp_cfg[code_entry + 2].a = NAPOT;
pmp_cfg[code_entry + 2].x = 1'b1;
pmp_cfg[code_entry + 2].w = 1'b1;
pmp_cfg[code_entry + 2].r = 1'b0;
end else begin
// We must set PMP signature region to write/read before starting main. X=0 to be
// consistent with MML mode.
pmp_cfg[code_entry + 2].l = 1'b0;
pmp_cfg[code_entry + 2].a = NAPOT;
pmp_cfg[code_entry + 2].x = 1'b0;
pmp_cfg[code_entry + 2].w = 1'b1;
pmp_cfg[code_entry + 2].r = 1'b1;
end
end
// Enable the selected config on region 0.
`uvm_info(`gfn, $sformatf("temporary pmp_word: 0x%0x", cfg_byte), UVM_DEBUG)
instr.push_back($sformatf("li x%0d, 0x%0x", scratch_reg[0], cfg_byte));
instr.push_back($sformatf("csrw 0x%0x, x%0d", base_pmpcfg_addr, scratch_reg[0]));
end
// Writing MSECCFG with RLB still set to 1 otherwise we cannot complete configuration.
`uvm_info(`gfn, $sformatf("MSECCFG: MML %0x, MMWP %0x, RLB 1", mseccfg.mml, mseccfg.mmwp),
UVM_LOW)
@ -349,47 +498,33 @@ class riscv_pmp_cfg extends uvm_object;
foreach (pmp_cfg[i]) begin
pmp_id = i / cfg_per_csr;
// In case an argument is give, we want to allow the test writer to change region 0 to
// anything they like even if it means that a trap occurs on the next instruction. If no
// argument is given, we should set region 0 to have a configuration with execute enabled.
if (i == 0 && !inst.get_arg_value("+pmp_region_0=", arg_value)) begin
if(riscv_instr_pkg::support_epmp && mseccfg.mml) begin
// This value is different from above (M-mode execute only) because we need region 0 to
// be executable in both M-mode and U-mode, since RISCV-DV switches privledge before
// <main> but after <pmp_setup>. We choose not to use the shared code region that also
// allows read in M-mode because that is inconsitente with the execute-only in other
// modes.
cfg_byte = {1'b1, pmp_cfg[i].zero, TOR, 1'b0, 1'b1, 1'b0}; // Shared execute only.
end else begin
cfg_byte = {1'b0, pmp_cfg[i].zero, TOR, 1'b1, 1'b0, 1'b0}; // Execute only to match MML.
end
end else begin
cfg_byte = {pmp_cfg[i].l, pmp_cfg[i].zero, pmp_cfg[i].a,
pmp_cfg[i].x, pmp_cfg[i].w, pmp_cfg[i].r};
end
`uvm_info(`gfn, $sformatf("cfg_byte: 0x%0x", cfg_byte), UVM_DEBUG)
cfg_byte = {pmp_cfg[i].l, pmp_cfg[i].zero, pmp_cfg[i].a,
pmp_cfg[i].x, pmp_cfg[i].w, pmp_cfg[i].r};
`uvm_info(`gfn, $sformatf("cfg_byte: 0x%0x", cfg_byte), UVM_LOW)
// First write to the appropriate pmpaddr CSR.
cfg_bitmask = cfg_byte << ((i % cfg_per_csr) * 8);
`uvm_info(`gfn, $sformatf("cfg_bitmask: 0x%0x", cfg_bitmask), UVM_DEBUG)
pmp_word = pmp_word | cfg_bitmask;
`uvm_info(`gfn, $sformatf("pmp_word: 0x%0x", pmp_word), UVM_DEBUG)
cfg_bitmask = 0;
if (i != 0) begin
// If an actual address has been set from the command line, use this address,
// otherwise use the default offset+<main> address.
//
// TODO(udinator) - The practice of passing in a max offset from the command line
// is somewhat unintuitive, and is just an initial step. Eventually a max address
// should be passed in from the command line and this routine do all of the
// calculations to split the address range formed by [<main> : pmp_max_addr].
// This will likely require a complex assembly routine - the code below is a very simple
// first step towards this goal, allowing users to specify a PMP memory address
// from the command line instead of having to calculate an offset themselves.
if (pmp_cfg[i].addr != 0) begin
// If an actual address has been set from the command line, use this address,
// otherwise use the default <main> + offset.
//
// TODO(udinator) - The practice of passing in a max offset from the command line
// is somewhat unintuitive, and is just an initial step. Eventually a max address
// should be passed in from the command line and this routine do all of the
// calculations to split the address range formed by [<main> : pmp_max_addr].
// This will likely require a complex assembly routine - the code below is a very simple
// first step towards this goal, allowing users to specify a PMP memory address
// from the command line instead of having to calculate an offset themselves.
//
// Only set the address if it has not already been configured in the above routine.
if (pmp_cfg_already_configured[i] == 1'b0) begin
if (pmp_cfg_addr_valid[i] || pmp_randomize) begin
// In case an address was supplied by the test or full randomize is enabled.
instr.push_back($sformatf("li x%0d, 0x%0x", scratch_reg[0], pmp_cfg[i].addr));
instr.push_back($sformatf("csrw 0x%0x, x%0d", base_pmp_addr + i, scratch_reg[0]));
`uvm_info(`gfn,
$sformatf("Address 0x%0x loaded into pmpaddr[%d] CSR", base_pmp_addr + i, i),
`uvm_info(`gfn, $sformatf("Address 0x%0x loaded into pmpaddr[%d] CSR", pmp_cfg[i].addr, i),
UVM_LOW);
end else begin
// Add the offset to the base address to get the other pmpaddr values.
@ -399,8 +534,8 @@ class riscv_pmp_cfg extends uvm_object;
scratch_reg[0], scratch_reg[0], scratch_reg[1]));
instr.push_back($sformatf("srli x%0d, x%0d, 2", scratch_reg[0], scratch_reg[0]));
instr.push_back($sformatf("csrw 0x%0x, x%0d", base_pmp_addr + i, scratch_reg[0]));
`uvm_info(`gfn, $sformatf("Offset of pmp_addr_%d from pmpaddr0: 0x%0x", i,
pmp_cfg[i].offset), UVM_LOW)
`uvm_info(`gfn, $sformatf("Offset of pmp_addr_%d from main: 0x%0x", i,
pmp_cfg[i].offset), UVM_LOW)
end
end
// Now, check if we have to write to the appropriate pmpcfg CSR.
@ -416,6 +551,7 @@ class riscv_pmp_cfg extends uvm_object;
pmp_word = 0;
end
end
// Unsetting RLB if that was requested.
if (riscv_instr_pkg::support_epmp && !mseccfg.rlb) begin
`uvm_info(`gfn, $sformatf("MSECCFG: MML %0x, MMWP %0x, RLB %0x", mseccfg.mml, mseccfg.mmwp,
@ -752,7 +888,12 @@ class riscv_pmp_cfg extends uvm_object;
// 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;
if (mseccfg.mml) begin
// In case of MML make this a shared code region with LXWR='b1010.
pmp_val[7:0] = 'h8a;
end else begin
pmp_val[7:0] = 'h0f;
end
end
instr.push_back($sformatf("li x%0d, 0x%0x", scratch_reg[0], pmp_val));
// Write the randomized address to pmpcfg[i].

View file

@ -84,6 +84,7 @@ class riscv_instr_base_test extends uvm_test;
string test_name;
randomize_cfg();
riscv_instr::create_instr_list(cfg);
riscv_csr_instr::create_csr_filter(cfg);
asm_gen = riscv_asm_program_gen::type_id::create("asm_gen", , `gfn);
asm_gen.cfg = cfg;
asm_gen.get_directed_instr_stream();

View file

@ -38,6 +38,7 @@ class riscv_instr_cov_test extends uvm_test;
// disable_compressed_instr is not relevant to coverage test
cfg.disable_compressed_instr = 0;
riscv_instr::create_instr_list(cfg);
riscv_csr_instr::create_csr_filter(cfg);
instr_cg = new(cfg);
`uvm_info(`gfn, $sformatf("%0d CSV trace files to be processed", trace_csv.size()), UVM_LOW)
foreach (trace_csv[i]) begin

View file

@ -28,6 +28,7 @@ class riscv_instr_test extends riscv_instr_base_test;
fd = $fopen(test_name,"w");
`uvm_info(`gfn, "Creating instruction list", UVM_LOW)
riscv_instr::create_instr_list(cfg);
riscv_csr_instr::create_csr_filter(cfg);
`uvm_info(`gfn, "Randomizing instruction list now...", UVM_LOW)
repeat (10000) begin
instr = riscv_instr::get_rand_instr();