mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-22 04:47:25 -04:00
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:
parent
2669260aa0
commit
4990aa2684
74 changed files with 700 additions and 401 deletions
2
vendor/google_riscv-dv.lock.hjson
vendored
2
vendor/google_riscv-dv.lock.hjson
vendored
|
@ -9,6 +9,6 @@
|
|||
upstream:
|
||||
{
|
||||
url: https://github.com/google/riscv-dv
|
||||
rev: 808fb162d66de5dd0dd2b45fd0b8d1fb1bf170f6
|
||||
rev: 68e3bcac7293ac79067f0d8196bb973bd7c889cf
|
||||
}
|
||||
}
|
||||
|
|
4
vendor/google_riscv-dv/.metrics.json
vendored
4
vendor/google_riscv-dv/.metrics.json
vendored
|
@ -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"
|
||||
}
|
||||
|
|
2
vendor/google_riscv-dv/README.md
vendored
2
vendor/google_riscv-dv/README.md
vendored
|
@ -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.
|
||||
|
||||
|
|
6
vendor/google_riscv-dv/cov.py
vendored
6
vendor/google_riscv-dv/cov.py
vendored
|
@ -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))
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
module riscv.gen.isa.custom.riscv_custom_instr_enum;
|
||||
|
||||
//TODO custom instruction added
|
||||
//TODO custom instruction added
|
||||
// CUSTOM_i,
|
||||
|
|
|
@ -29,7 +29,7 @@ import uvm;
|
|||
class riscv_amo_instr: riscv_instr
|
||||
{
|
||||
mixin uvm_object_utils;
|
||||
|
||||
|
||||
@rand bool aq;
|
||||
@rand bool rl;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
// }
|
||||
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ import std.algorithm: canFind;
|
|||
class riscv_zbc_instr: riscv_instr
|
||||
{
|
||||
mixin uvm_object_utils;
|
||||
|
||||
|
||||
this(string name = "") {
|
||||
super(name);
|
||||
}
|
||||
|
|
|
@ -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) ||
|
||||
|
|
|
@ -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); }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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); }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,4 +51,4 @@ version (RISCV_INSTR_STRING_MIXIN) {
|
|||
class riscv_REMU_instr: riscv_instr
|
||||
{ mixin RISCV_INSTR_MIXIN!(REMU, R_FORMAT, ARITHMETIC, RV32M); }
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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); }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
//TODO custom instruction added
|
||||
//TODO custom instruction added
|
||||
// CUSTOM_i,
|
||||
module riscv.gen.riscv_custom_instr_enum;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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:
|
||||
..
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -50,7 +50,7 @@ enum core_status_t: byte {
|
|||
LOAD_FAULT_EXCEPTION,
|
||||
STORE_FAULT_EXCEPTION,
|
||||
EBREAK_EXCEPTION
|
||||
}
|
||||
}
|
||||
|
||||
enum test_result_t: bool {
|
||||
TEST_PASS,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -97,7 +97,7 @@ class riscv_instr_base_test: uvm_test
|
|||
}
|
||||
|
||||
void apply_directed_instr() { }
|
||||
|
||||
|
||||
|
||||
override void run_phase(uvm_phase phase) {
|
||||
int fd;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
179
vendor/google_riscv-dv/src/isa/riscv_csr_instr.sv
vendored
Normal file
179
vendor/google_riscv-dv/src/isa/riscv_csr_instr.sv
vendored
Normal 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
|
|
@ -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
|
||||
|
|
59
vendor/google_riscv-dv/src/isa/riscv_instr.sv
vendored
59
vendor/google_riscv-dv/src/isa/riscv_instr.sv
vendored
|
@ -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()});
|
||||
|
|
12
vendor/google_riscv-dv/src/isa/rv32i_instr.sv
vendored
12
vendor/google_riscv-dv/src/isa/rv32i_instr.sv
vendored
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
|
5
vendor/google_riscv-dv/src/riscv_defines.svh
vendored
5
vendor/google_riscv-dv/src/riscv_defines.svh
vendored
|
@ -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; \
|
||||
|
|
|
@ -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
|
||||
|
|
15
vendor/google_riscv-dv/src/riscv_instr_pkg.sv
vendored
15
vendor/google_riscv-dv/src/riscv_instr_pkg.sv
vendored
|
@ -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"
|
||||
|
|
317
vendor/google_riscv-dv/src/riscv_pmp_cfg.sv
vendored
317
vendor/google_riscv-dv/src/riscv_pmp_cfg.sv
vendored
|
@ -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].
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue