Update google_riscv-dv to google/riscv-dv@ace2805

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

* Fix vector instruction randomization (google/riscv-dv#560) (taoliug)
* Change generate_instr_stream to a virtual function (google/riscv-
  dv#559) (taoliug)
* fix bug with compressed ebreak generation (google/riscv-dv#557)
  (udinator)
* update PMP exception handlers to 'fix' config CSRs (google/riscv-
  dv#546) (udinator)
* Add bitmanip doc (google/riscv-dv#555) (weicaiyang)
* specify physical pmp addresses from cmdline (Udi Jonnalagadda)
* Fix branch hit coverage issue (google/riscv-dv#551) (taoliug)
* B extension coverage part2 (google/riscv-dv#548) (weicaiyang)
* B extension coverage part1 (google/riscv-dv#542) (weicaiyang)
* Fix typo in riscv_instr_test_lib (google/riscv-dv#545) (ANIL SHARMA)
* Add target rv64imcb (google/riscv-dv#543) (weicaiyang)

Signed-off-by: Udi <udij@google.com>
This commit is contained in:
Udi 2020-05-06 11:33:49 -07:00 committed by udinator
parent b72d263eac
commit e1ec5b63f8
19 changed files with 1321 additions and 94 deletions

View file

@ -9,6 +9,6 @@
upstream:
{
url: https://github.com/google/riscv-dv
rev: 42264b7782a10848935e995063c212893820e561
rev: ace2805b63100f46c3dcd02b4fcf6a7184582110
}
}

View file

@ -0,0 +1,82 @@
Extension Support
=================
Bit Manipulation Extension
--------------------------------------------------------
Setup RISCV-GCC compiler toolchain and ISS simulator
--------------------------------------------------------
1. Install `riscv-gcc`_ toolchain
- Download the repo and add " --enable-commitlog" at the end of line 6 in
`build_file`_ as it's not enabled by default
- Follow the `steps`_ to install GCC and spike
2. Update environment variable RISCV_GCC to the RISC-V gcc executable
executable. (example: <install_dir>/bin/riscv64-unknown-elf-gcc)
3. Update environment variable RISCV_OBJCOPY to RISC-V objcopy executable
executable. (example: <install_dir>/bin/riscv64-unknown-elf-objcopy)
4. Update environment variable SPIKE_PATH to the directory of the spike binary
5. Update `riscv-ovpsim`_ to Nov 26, 2019 or later version
.. _steps: https://github.com/riscv/riscv-bitmanip/tree/master/tools#building-tools-with-draft-b-extension-instructions-support
.. _riscv-gcc: https://github.com/riscv/riscv-bitmanip
.. _build_file: https://github.com/riscv/riscv-bitmanip/blob/master/tools/riscv-isa-sim-build.sh
.. _riscv-ovpsim: https://github.com/riscv/riscv-ovpsim
Sample .bashrc setup::
export RISCV_TOOLCHAIN=<riscv_gcc_install_path>
export RISCV_GCC="$RISCV_TOOLCHAIN/bin/riscv64-unknown-elf-gcc"
export RISCV_OBJCOPY="$RISCV_TOOLCHAIN/bin/riscv64-unknown-elf-objcopy"
export SPIKE_PATH="$RISCV_TOOLCHAIN/bin"
Run bitmanip simulation
------------------------
Bit manipulation tests are added in target "rv32imcb" or "rv64imcb". Here is the
example to run bitmanip test with both ISS (spike and ovpsim). The instruction
trace from these ISS will be cross compared::
run --target rv32imcb --test riscv_b_ext_test --iss spike,ovpsim
In `bitmanip testlist`_, there are a few bitmanip tests. Run option
"+enable_b_extension=1" enables it and "+enable_bitmanip_groups=zbb,zbt"
allows user to only enable one or some groups of bit manipulation instructions.
.. _bitmanip testlist: https://github.com/google/riscv-dv/blob/master/target/rv32imcb/testlist.yaml
Functional Coverage Support For Bitmanip
-----------------------------------------
The functional covergroup is defined in `riscv_instr_cover_group.sv`_.
It includes below major categories:
- If the operand is a register, cover all possible reg values for each operand::
cp_rs1 : coverpoint instr.rs1;
cp_rs2 : coverpoint instr.rs2;
cp_rd : coverpoint instr.rd;
- If the operand is an integer value and the amount of these possible values is
less than XLEN*2, cover all the values::
// Cover all the count values of leading/Trailing zeros (0:XLEN-1) for clz, ctz
`B_R_INSTR_NO_RS2_CG_BEGIN(clz)
`CP_VALUE_RANGE(num_leading_zeros, instr.rd_value, 0, XLEN-1)
`CG_END
// Cover all the shift values (0:XLEN-1) for slo
`B_R_INSTR_CG_BEGIN(slo)
`CP_VALUE_RANGE(num_ones_shift, instr.rs2_value, 0, XLEN-1)
`CG_END
- Hazard conditions
Before this `issue`_ is resolved, functional coverage can only be run with OVPsim::
cov --dir out/ovpsim_sim --iss ovpsim --target rv32imc
.. _riscv_instr_cover_group.sv: https://github.com/google/riscv-dv/blob/master/src/riscv_instr_cover_group.sv
.. _issue: https://github.com/riscv/riscv-bitmanip/issues/60

View file

@ -13,6 +13,7 @@ Welcome to riscv-dv's documentation!
overview
getting_started
configuration
extension_support
end_to_end_simulation
generator_flow
coverage_model

View file

@ -784,6 +784,9 @@ def load_config(args, cwd):
elif args.target == "rv64imc":
args.mabi = "lp64"
args.isa = "rv64imc"
elif args.target == "rv64imcb":
args.mabi = "lp64"
args.isa = "rv64imcb"
elif args.target == "rv64gc":
args.mabi = "lp64"
args.isa = "rv64gc"

View file

@ -20,27 +20,6 @@ class riscv_b_instr extends riscv_instr;
rand riscv_reg_t rs3;
bit has_rs3 = 1'b0;
constraint single_bit_shift_c {
if (category == SHIFT) {
imm inside {[0:31]};
}
}
constraint shuffle_c {
if (instr_name inside {SHFLI, UNSHFLI}) {
imm inside {[0:15]};
}
}
constraint or_combine_c {
if (instr_name inside {GORCI}) {
imm inside {[0:31]};
}
if (instr_name inside {GORCIW}) {
imm inside {[0:63]};
}
}
`uvm_object_utils(riscv_b_instr)
function new(string name = "");
@ -51,6 +30,13 @@ class riscv_b_instr extends riscv_instr;
super.set_rand_mode();
has_rs3 = 1'b0;
case (format) inside
R_FORMAT: begin
if (instr_name inside {CLZW, CTZW, PCNTW, SEXT_B, SEXT_H, CLZ, CTZ, PCNT, BMATFLIP,
CRC32_B, CRC32_H, CRC32_W, CRC32C_B, CRC32C_H, CRC32C_W, CRC32_D,
CRC32C_D}) begin
has_rs2 = 1'b0;
end
end
R4_FORMAT: begin
has_imm = 1'b0;
has_rs3 = 1'b1;
@ -75,25 +61,19 @@ class riscv_b_instr extends riscv_instr;
if (format inside {I_FORMAT}) begin
if (category inside {SHIFT, LOGICAL}) begin
imm_len = 7;
if (group == RV64B) begin
imm_len = 5;
if (instr_name inside {SLLIU_W}) begin
imm_len = 6;
end
end
if ((group == RV32B) && (imm_type == UIMM)) begin
imm_len = 6;
if (group == RV64B && !(instr_name inside {SLLIU_W})) begin
imm_len = $clog2(XLEN) - 1;
end else begin
imm_len = $clog2(XLEN);
end
end
if ((category inside {ARITHMETIC}) && (group == RV32B)) begin
imm_len = 5;
// ARITHMETIC RV32B
if (instr_name inside {SHFLI, UNSHFLI}) begin
imm_len = $clog2(XLEN) - 1;
end
if ((category inside {ARITHMETIC}) && (group == RV64B)) begin
// ARITHMETIC RV64B
if (instr_name inside {ADDIWU}) begin
imm_len = 12;
end
end
@ -115,9 +95,7 @@ class riscv_b_instr extends riscv_instr;
end
R_FORMAT: begin //instr rd rs1
if (instr_name inside {CLZW, CTZW, PCNTW, SEXT_B, SEXT_H, CLZ, CTZ, PCNT, BMATFLIP,
CRC32_B, CRC32_H, CRC32_W, CRC32C_B, CRC32C_H, CRC32C_W, CRC32_D,
CRC32C_D}) begin
if (!has_rs2) begin
asm_str_final = $sformatf("%0s%0s, %0s", asm_str, rd.name(), rs1.name());
end
end
@ -473,9 +451,9 @@ class riscv_b_instr extends riscv_instr;
virtual function bit is_supported(riscv_instr_gen_config cfg);
return cfg.enable_b_extension && (
(ZBB inside {cfg.enable_bitmanip_groups} && instr_name inside {
CLZ, CTZ, PCNT,
CLZ, CTZ, CLZW, CTZW, PCNT, PCNTW,
SLO, SLOI, SLOW, SLOIW,
SRO, SLOI, SROW, SLOIW,
SRO, SROI, SROW, SROIW,
MIN, MINU, MAX, MAXU,
ADDWU, ADDIWU, SUBWU,
ADDU_W, SUBU_W,
@ -497,7 +475,9 @@ class riscv_b_instr extends riscv_instr;
}) ||
(ZBE inside {cfg.enable_bitmanip_groups} && instr_name inside {
BEXT, BEXTW,
BDEP, BDEPW
BDEP, BDEPW,
// TODO, spec 0.92 doesn't categorize these 2 instr in any group, put in ZBE for now
SEXT_B, SEXT_H
}) ||
(ZBF inside {cfg.enable_bitmanip_groups} && instr_name inside {BFP, BFPW}) ||
(ZBC inside {cfg.enable_bitmanip_groups} && instr_name inside {

View file

@ -111,8 +111,8 @@ class riscv_instr extends uvm_object;
riscv_instr instr_inst;
if (instr_name inside {unsupported_instr}) continue;
instr_inst = create_instr(instr_name);
if (!instr_inst.is_supported(cfg)) continue;
instr_template[instr_name] = instr_inst;
if (!instr_inst.is_supported(cfg)) continue;
// C_JAL is RV32C only instruction
if ((XLEN != 32) && (instr_name == C_JAL)) continue;
if ((SP inside {cfg.reserved_regs}) && (instr_name inside {C_ADDI16SP})) begin
@ -181,7 +181,8 @@ class riscv_instr extends uvm_object;
if (!cfg.no_ebreak) begin
basic_instr = {basic_instr, EBREAK};
foreach (riscv_instr_pkg::supported_isa[i]) begin
if (RV32C inside {riscv_instr_pkg::supported_isa[i]}) begin
if (RV32C inside {riscv_instr_pkg::supported_isa[i]} &&
!cfg.disable_compressed_instr) begin
basic_instr = {basic_instr, C_EBREAK};
break;
end

View file

@ -196,20 +196,12 @@ class riscv_vector_instr extends riscv_floating_point_instr;
if (allowed_va_variants.size() > 0) begin
has_va_variant = 1;
end
case (format) inside
VA_FORMAT : begin
if (va_variant inside {WI, VI, VIM}) begin
has_imm = 1'b1;
has_vs1 = 1'b0;
end else if (va_variant inside {WX, VX, VXM}) begin
has_rs1 = 1'b1;
has_vs1 = 1'b0;
end else if (va_variant inside {VF, VFM}) begin
has_fs1 = 1'b1;
has_vs1 = 1'b0;
end
end
endcase
// Set the rand mode based on the superset of all VA variants
if (format == VA_FORMAT) begin
has_imm = 1'b1;
has_rs1 = 1'b1;
has_fs1 = 1'b1;
end
endfunction : set_rand_mode
endclass : riscv_vector_instr

View file

@ -1048,6 +1048,11 @@ class riscv_asm_program_gen extends uvm_object;
string instr[$];
gen_signature_handshake(instr, CORE_STATUS, INSTR_FAULT_EXCEPTION);
gen_signature_handshake(.instr(instr), .signature_type(WRITE_CSR), .csr(MCAUSE));
if (cfg.pmp_cfg.enable_pmp_exception_handler) begin
cfg.pmp_cfg.gen_pmp_exception_routine({cfg.gpr, cfg.scratch_reg, cfg.pmp_reg},
INSTRUCTION_ACCESS_FAULT,
instr);
end
pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr);
instr.push_back("mret");
gen_section(get_label("instr_fault_handler", hart), instr);
@ -1058,6 +1063,11 @@ class riscv_asm_program_gen extends uvm_object;
string instr[$];
gen_signature_handshake(instr, CORE_STATUS, LOAD_FAULT_EXCEPTION);
gen_signature_handshake(.instr(instr), .signature_type(WRITE_CSR), .csr(MCAUSE));
if (cfg.pmp_cfg.enable_pmp_exception_handler) begin
cfg.pmp_cfg.gen_pmp_exception_routine({cfg.gpr, cfg.scratch_reg, cfg.pmp_reg},
LOAD_ACCESS_FAULT,
instr);
end
pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr);
instr.push_back("mret");
gen_section(get_label("load_fault_handler", hart), instr);
@ -1068,6 +1078,11 @@ class riscv_asm_program_gen extends uvm_object;
string instr[$];
gen_signature_handshake(instr, CORE_STATUS, STORE_FAULT_EXCEPTION);
gen_signature_handshake(.instr(instr), .signature_type(WRITE_CSR), .csr(MCAUSE));
if (cfg.pmp_cfg.enable_pmp_exception_handler) begin
cfg.pmp_cfg.gen_pmp_exception_routine({cfg.gpr, cfg.scratch_reg, cfg.pmp_reg},
STORE_AMO_ACCESS_FAULT,
instr);
end
pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr);
instr.push_back("mret");
gen_section(get_label("store_fault_handler", hart), instr);

View file

@ -20,8 +20,10 @@ class riscv_instr_cov_item extends riscv_instr;
NORMAL_VAL, MIN_VAL, MAX_VAL, ZERO_VAL
} special_val_e;
rand riscv_reg_t rs3;
rand bit [XLEN-1:0] rs1_value;
rand bit [XLEN-1:0] rs2_value;
rand bit [XLEN-1:0] rs3_value;
rand bit [XLEN-1:0] rd_value;
rand riscv_fpr_t fs1;
rand riscv_fpr_t fs2;
@ -42,6 +44,7 @@ class riscv_instr_cov_item extends riscv_instr;
div_result_e div_result;
operand_sign_e rs1_sign;
operand_sign_e rs2_sign;
operand_sign_e rs3_sign;
operand_sign_e fs1_sign;
operand_sign_e fs2_sign;
operand_sign_e fs3_sign;
@ -52,6 +55,7 @@ class riscv_instr_cov_item extends riscv_instr;
hazard_e lsu_hazard;
special_val_e rs1_special_val;
special_val_e rs2_special_val;
special_val_e rs3_special_val;
special_val_e rd_special_val;
special_val_e imm_special_val;
compare_result_e compare_result;
@ -67,6 +71,7 @@ class riscv_instr_cov_item extends riscv_instr;
unaligned_pc = (pc[1:0] != 2'b00);
rs1_sign = get_operand_sign(rs1_value);
rs2_sign = get_operand_sign(rs2_value);
rs3_sign = get_operand_sign(rs3_value);
rd_sign = get_operand_sign(rd_value);
fs1_sign = get_operand_sign(fs1_value);
fs2_sign = get_operand_sign(fs2_value);
@ -76,6 +81,7 @@ class riscv_instr_cov_item extends riscv_instr;
rs1_special_val = get_operand_special_val(rs1_value);
rd_special_val = get_operand_special_val(rd_value);
rs2_special_val = get_operand_special_val(rs2_value);
rs3_special_val = get_operand_special_val(rs3_value);
if ((format != R_FORMAT) && (format != CR_FORMAT)) begin
imm_special_val = get_imm_special_val(imm);
end
@ -195,12 +201,12 @@ class riscv_instr_cov_item extends riscv_instr;
case(instr_name)
BEQ : is_branch_hit = (rs1_value == rs2_value);
C_BEQZ : is_branch_hit = (rs1_value == 0);
BNE : is_branch_hit = (rs1_value == rs2_value);
BNE : is_branch_hit = (rs1_value != rs2_value);
C_BNEZ : is_branch_hit = (rs1_value != 0);
BLT : is_branch_hit = ($signed(rs1_value) < $signed(rs2_value));
BGE : is_branch_hit = ($signed(rs1_value) > $signed(rs2_value));
BGE : is_branch_hit = ($signed(rs1_value) >= $signed(rs2_value));
BLTU : is_branch_hit = (rs1_value < rs2_value);
BGEU : is_branch_hit = (rs1_value > rs2_value);
BGEU : is_branch_hit = (rs1_value >= rs2_value);
default: `uvm_error(get_name(), $sformatf("Unexpected instr %0s", instr_name.name()))
endcase
return is_branch_hit;

View file

@ -92,6 +92,12 @@
cp_imm_sign : coverpoint instr.imm_sign; \
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;)
`define B_I_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME) \
cp_rs1 : coverpoint instr.rs1; \
cp_rd : coverpoint instr.rd; \
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;)
`define U_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME) \
cp_rd : coverpoint instr.rd; \
@ -257,6 +263,38 @@
cp_fd_sign : coverpoint instr.fd_sign; \
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;) \
`define B_R_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME) \
cp_rs1 : coverpoint instr.rs1; \
cp_rs2 : coverpoint instr.rs2; \
cp_rd : coverpoint instr.rd; \
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;) \
`define B_R_INSTR_NO_RS2_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME) \
cp_rs1 : coverpoint instr.rs1; \
cp_rd : coverpoint instr.rd; \
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;) \
`define B_R4_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME) \
cp_rs1 : coverpoint instr.rs1; \
cp_rs2 : coverpoint instr.rs2; \
cp_rs3 : coverpoint instr.rs3; \
cp_rd : coverpoint instr.rd; \
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;) \
// only enable the coverpoint for a particular XLEN (32, 64, 128)
`define ENABLE_CP_BY_XLEN(XLEN_VAL) \
option.weight = (XLEN == XLEN_VAL); \
type_option.weight = (XLEN == XLEN_VAL); \
`define CP_VALUE_RANGE(NAME, VAL, START, END) \
cp_``NAME``: coverpoint VAL{ \
bins values[] = {[START:END]}; \
}
`define CG_END endgroup
`define CG_SELECTOR_BEGIN(CG_ISA) \
@ -554,6 +592,398 @@ class riscv_instr_cover_group;
`FP_R4_INSTR_CG_BEGIN(fnmsub_s)
`CG_END
// B extension
// Count Leading/Trailing Zeros (clz, ctz)
`B_R_INSTR_NO_RS2_CG_BEGIN(clz)
`CP_VALUE_RANGE(num_leading_zeros, instr.rd_value, 0, XLEN-1)
`CG_END
`B_R_INSTR_NO_RS2_CG_BEGIN(ctz)
`CP_VALUE_RANGE(num_trailing_zeros, instr.rd_value, 0, XLEN-1)
`CG_END
`B_R_INSTR_NO_RS2_CG_BEGIN(clzw)
`CP_VALUE_RANGE(num_leading_zeros, instr.rd_value, 0, XLEN/2-1)
`CG_END
`B_R_INSTR_NO_RS2_CG_BEGIN(ctzw)
`CP_VALUE_RANGE(num_trailing_zeros, instr.rd_value, 0, XLEN/2-1)
`CG_END
// Count Bits Set (pcnt)
`B_R_INSTR_NO_RS2_CG_BEGIN(pcnt)
`CP_VALUE_RANGE(num_set_bits, instr.rd_value, 0, XLEN-1)
`CG_END
`B_R_INSTR_NO_RS2_CG_BEGIN(pcntw)
`CP_VALUE_RANGE(num_set_bits, instr.rd_value, 0, XLEN/2-1)
`CG_END
// Logic-with-negate (andn, orn, xnor)
`B_R_INSTR_CG_BEGIN(andn)
`CG_END
`B_R_INSTR_CG_BEGIN(orn)
`CG_END
`B_R_INSTR_CG_BEGIN(xnor)
`CG_END
// Pack two words in one register (pack, packu, packh)
`B_R_INSTR_CG_BEGIN(pack)
`CG_END
`B_R_INSTR_CG_BEGIN(packu)
`CG_END
`B_R_INSTR_CG_BEGIN(packh)
`CG_END
`B_R_INSTR_CG_BEGIN(packw)
`CG_END
`B_R_INSTR_CG_BEGIN(packuw)
`CG_END
// Min/max instructions (min, max, minu, maxu)
`B_R_INSTR_CG_BEGIN(min)
cp_rs1_gt_rs2 : coverpoint (longint'(instr.rs1_value) > longint'(instr.rs2_value));
cp_rs1_eq_rs2 : coverpoint (instr.rs1_value == instr.rs2_value) {
bins equal = {1};
}
`CG_END
`B_R_INSTR_CG_BEGIN(max)
cp_rs1_gt_rs2 : coverpoint (longint'(instr.rs1_value) > longint'(instr.rs2_value));
cp_rs1_eq_rs2 : coverpoint (instr.rs1_value == instr.rs2_value) {
bins equal = {1};
}
`CG_END
`B_R_INSTR_CG_BEGIN(minu)
cp_rs1_gt_rs2 : coverpoint (instr.rs1_value > instr.rs2_value);
cp_rs1_eq_rs2 : coverpoint (instr.rs1_value == instr.rs2_value) {
bins equal = {1};
}
`CG_END
`B_R_INSTR_CG_BEGIN(maxu)
cp_rs1_gt_rs2 : coverpoint (instr.rs1_value > instr.rs2_value);
cp_rs1_eq_rs2 : coverpoint (instr.rs1_value == instr.rs2_value) {
bins equal = {1};
}
`CG_END
// Sign-extend instructions (sext.b, sext.h)
`B_R_INSTR_NO_RS2_CG_BEGIN(sext_b)
`CG_END
`B_R_INSTR_NO_RS2_CG_BEGIN(sext_h)
`CG_END
// Single-bit instructions (sbset, sbclr, sbinv, sbext)
`B_R_INSTR_CG_BEGIN(sbset)
`CP_VALUE_RANGE(bit_location, instr.rs2_value, 0, XLEN-1)
`CG_END
`B_R_INSTR_CG_BEGIN(sbclr)
`CP_VALUE_RANGE(bit_location, instr.rs2_value, 0, XLEN-1)
`CG_END
`B_R_INSTR_CG_BEGIN(sbinv)
`CP_VALUE_RANGE(bit_location, instr.rs2_value, 0, XLEN-1)
`CG_END
`B_R_INSTR_CG_BEGIN(sbext)
`CP_VALUE_RANGE(bit_location, instr.rs2_value, 0, XLEN-1)
`CG_END
`B_I_INSTR_CG_BEGIN(sbseti)
`CP_VALUE_RANGE(bit_location, instr.imm, 0, XLEN-1)
`CG_END
`B_I_INSTR_CG_BEGIN(sbclri)
`CP_VALUE_RANGE(bit_location, instr.imm, 0, XLEN-1)
`CG_END
`B_I_INSTR_CG_BEGIN(sbinvi)
`CP_VALUE_RANGE(bit_location, instr.imm, 0, XLEN-1)
`CG_END
`B_I_INSTR_CG_BEGIN(sbexti)
`CP_VALUE_RANGE(bit_location, instr.imm, 0, XLEN-1)
`CG_END
// Shift Ones (Left/Right) (slo, sloi, sro, sroi)
`B_R_INSTR_CG_BEGIN(slo)
`CP_VALUE_RANGE(num_ones_shift, instr.rs2_value, 0, XLEN-1)
`CG_END
`B_R_INSTR_CG_BEGIN(sro)
`CP_VALUE_RANGE(num_ones_shift, instr.rs2_value, 0, XLEN-1)
`CG_END
`B_I_INSTR_CG_BEGIN(sloi)
`CP_VALUE_RANGE(num_ones_shift, instr.imm, 0, XLEN-1)
`CG_END
`B_I_INSTR_CG_BEGIN(sroi)
`CP_VALUE_RANGE(num_ones_shift, instr.imm, 0, XLEN-1)
`CG_END
`B_R_INSTR_CG_BEGIN(slow)
`CP_VALUE_RANGE(num_ones_shift, instr.rs2_value, 0, XLEN/2-1)
`CG_END
`B_R_INSTR_CG_BEGIN(srow)
`CP_VALUE_RANGE(num_ones_shift, instr.rs2_value, 0, XLEN/2-1)
`CG_END
`B_I_INSTR_CG_BEGIN(sloiw)
`CP_VALUE_RANGE(num_ones_shift, instr.imm, 0, XLEN/2-1)
`CG_END
`B_I_INSTR_CG_BEGIN(sroiw)
`CP_VALUE_RANGE(num_ones_shift, instr.imm, 0, XLEN/2-1)
`CG_END
// Rotate (Left/Right) (rol, ror, rori)
`B_R_INSTR_CG_BEGIN(ror)
`CP_VALUE_RANGE(num_bit_rotate, instr.rs2_value, 0, XLEN-1)
`CG_END
`B_R_INSTR_CG_BEGIN(rol)
`CP_VALUE_RANGE(num_bit_rotate, instr.rs2_value, 0, XLEN-1)
`CG_END
`B_I_INSTR_CG_BEGIN(rori)
`CP_VALUE_RANGE(num_bit_rotate, instr.imm, 0, XLEN-1)
`CG_END
`B_R_INSTR_CG_BEGIN(rorw)
`CP_VALUE_RANGE(num_bit_rotate, instr.rs2_value, 0, XLEN/2-1)
`CG_END
`B_R_INSTR_CG_BEGIN(rolw)
`CP_VALUE_RANGE(num_bit_rotate, instr.rs2_value, 0, XLEN/2-1)
`CG_END
`B_I_INSTR_CG_BEGIN(roriw)
`CP_VALUE_RANGE(num_bit_rotate, instr.imm, 0, XLEN/2-1)
`CG_END
// Generalized Reverse (grev, grevi, rev)
`B_R_INSTR_CG_BEGIN(grev)
`CP_VALUE_RANGE(reverse_mode, instr.rs2_value, 0, XLEN-1)
`CG_END
`B_I_INSTR_CG_BEGIN(grevi)
`CP_VALUE_RANGE(reverse_mode, instr.imm, 0, XLEN-1)
`CG_END
`B_R_INSTR_CG_BEGIN(grevw)
`CP_VALUE_RANGE(reverse_mode, instr.rs2_value, 0, XLEN/2-1)
`CG_END
`B_I_INSTR_CG_BEGIN(greviw)
`CP_VALUE_RANGE(reverse_mode, instr.imm, 0, XLEN/2-1)
`CG_END
// Generalized Shuffle (shfl, unshfl, shfli, unshfli, zip, unzip)
`B_R_INSTR_CG_BEGIN(shfl)
`CP_VALUE_RANGE(shuffle_mode, instr.rs2_value, 0, XLEN/2-1)
`CG_END
`B_R_INSTR_CG_BEGIN(unshfl)
`CP_VALUE_RANGE(shuffle_mode, instr.rs2_value, 0, XLEN/2-1)
`CG_END
`B_I_INSTR_CG_BEGIN(shfli)
`CP_VALUE_RANGE(shuffle_mode, instr.imm, 0, XLEN/2-1)
`CG_END
`B_I_INSTR_CG_BEGIN(unshfli)
`CP_VALUE_RANGE(shuffle_mode, instr.imm, 0, XLEN/2-1)
`CG_END
`B_R_INSTR_CG_BEGIN(shflw)
`CP_VALUE_RANGE(shuffle_mode, instr.rs2_value, 0, XLEN/2-1)
`CG_END
`B_R_INSTR_CG_BEGIN(unshflw)
`CP_VALUE_RANGE(shuffle_mode, instr.rs2_value, 0, XLEN/2-1)
`CG_END
// Generalized OR-Combine (gorc, gorci)
`B_R_INSTR_CG_BEGIN(gorc)
`CP_VALUE_RANGE(or_combine_mode, instr.rs2_value, 0, XLEN-1)
`CG_END
`B_I_INSTR_CG_BEGIN(gorci)
`CP_VALUE_RANGE(or_combine_mode, instr.imm, 0, XLEN-1)
`CG_END
`B_R_INSTR_CG_BEGIN(gorcw)
`CP_VALUE_RANGE(or_combine_mode, instr.rs2_value, 0, XLEN/2-1)
`CG_END
`B_I_INSTR_CG_BEGIN(gorciw)
`CP_VALUE_RANGE(or_combine_mode, instr.imm, 0, XLEN/2-1)
`CG_END
// Bit-Field Place (bfp)
`B_R_INSTR_CG_BEGIN(bfp)
// cover all values of length and offset
cp_len: coverpoint instr.rs2_value[27:24] iff (XLEN == 32) {
`ENABLE_CP_BY_XLEN(32)
bins values[] = {[0:XLEN/2-1]};
}
cp_offset: coverpoint instr.rs2_value[20:16] iff (XLEN == 32) {
`ENABLE_CP_BY_XLEN(32)
bins values[] = {[0:XLEN-1]};
}
cp_len_64bit_sel01: coverpoint instr.rs2_value[60:56] iff (XLEN == 64 &&
instr.rs2_value[XLEN-1:XLEN-2] == 2'b10) {
`ENABLE_CP_BY_XLEN(64)
bins values[] = {[0:XLEN/2-1]};
}
cp_offset_64bit_sel01: coverpoint instr.rs2_value[53:48] iff (XLEN == 64 &&
instr.rs2_value[XLEN-1:XLEN-2] == 2'b10) {
`ENABLE_CP_BY_XLEN(64)
bins values = {[0:XLEN-1]};
}
cp_len_64bit_not_sel01: coverpoint instr.rs2_value[60:56] iff (XLEN == 64 &&
instr.rs2_value[XLEN-1:XLEN-2] != 2'b10) {
`ENABLE_CP_BY_XLEN(64)
bins values[] = {[0:XLEN/2-1]};
}
cp_offset_64bit_not_sel01: coverpoint instr.rs2_value[53:48] iff (XLEN == 64 &&
instr.rs2_value[XLEN-1:XLEN-2] != 2'b10) {
`ENABLE_CP_BY_XLEN(64)
bins values[] = {[0:XLEN-1]};
}
`CG_END
`B_R_INSTR_CG_BEGIN(bfpw)
// cover all values of length and offset
`CP_VALUE_RANGE(length, instr.rs2_value[27:24], 0, XLEN/2-1)
`CP_VALUE_RANGE(offset, instr.rs2_value[20:16], 0, XLEN/2-1)
`CG_END
`B_R_INSTR_CG_BEGIN(bext)
`CG_END
`B_R_INSTR_CG_BEGIN(bextw)
`CG_END
`B_R_INSTR_CG_BEGIN(bdep)
`CG_END
`B_R_INSTR_CG_BEGIN(bdepw)
`CG_END
`B_R_INSTR_CG_BEGIN(clmul)
`CG_END
`B_R_INSTR_CG_BEGIN(clmulh)
`CG_END
`B_R_INSTR_CG_BEGIN(clmulr)
`CG_END
`B_R_INSTR_CG_BEGIN(clmulw)
`CG_END
`B_R_INSTR_CG_BEGIN(clmulhw)
`CG_END
`B_R_INSTR_CG_BEGIN(clmulrw)
`CG_END
`B_R_INSTR_NO_RS2_CG_BEGIN(crc32_b)
`CG_END
`B_R_INSTR_NO_RS2_CG_BEGIN(crc32_h)
`CG_END
`B_R_INSTR_NO_RS2_CG_BEGIN(crc32_w)
`CG_END
`B_R_INSTR_NO_RS2_CG_BEGIN(crc32c_b)
`CG_END
`B_R_INSTR_NO_RS2_CG_BEGIN(crc32c_h)
`CG_END
`B_R_INSTR_NO_RS2_CG_BEGIN(crc32c_w)
`CG_END
`B_R_INSTR_NO_RS2_CG_BEGIN(crc32_d)
`CG_END
`B_R_INSTR_NO_RS2_CG_BEGIN(crc32c_d)
`CG_END
`B_R_INSTR_CG_BEGIN(bmator)
`CG_END
`B_R_INSTR_CG_BEGIN(bmatxor)
`CG_END
`B_R_INSTR_NO_RS2_CG_BEGIN(bmatflip)
`CG_END
`B_R4_INSTR_CG_BEGIN(cmix)
`CG_END
`B_R4_INSTR_CG_BEGIN(cmov)
`CG_END
`B_R4_INSTR_CG_BEGIN(fsl)
`CP_VALUE_RANGE(num_shift, instr.rs2_value, 0, 2*XLEN-1)
`CG_END
`B_R4_INSTR_CG_BEGIN(fsr)
`CP_VALUE_RANGE(num_shift, instr.rs2_value, 0, 2*XLEN-1)
`CG_END
`B_I_INSTR_CG_BEGIN(fsri)
cp_rs3 : coverpoint instr.rs3;
`CP_VALUE_RANGE(num_shift, instr.imm, 0, XLEN-1)
`CG_END
`B_R4_INSTR_CG_BEGIN(fslw)
`CP_VALUE_RANGE(num_shift, instr.rs2_value, 0, 2*XLEN-1)
`CG_END
`B_R4_INSTR_CG_BEGIN(fsrw)
`CP_VALUE_RANGE(num_shift, instr.rs2_value, 0, 2*XLEN-1)
`CG_END
`B_I_INSTR_CG_BEGIN(fsriw)
cp_rs3 : coverpoint instr.rs3;
`CP_VALUE_RANGE(num_shift, instr.imm, 0, XLEN/2-1)
`CG_END
`B_R_INSTR_CG_BEGIN(addwu)
`CG_END
`B_R_INSTR_CG_BEGIN(subwu)
`CG_END
`B_I_INSTR_CG_BEGIN(addiwu)
`CG_END
`B_R_INSTR_CG_BEGIN(addu_w)
`CG_END
`B_R_INSTR_CG_BEGIN(subu_w)
`CG_END
`B_I_INSTR_CG_BEGIN(slliu_w)
`CP_VALUE_RANGE(num_shift, instr.imm, 0, XLEN-1)
`CG_END
// CSR instructions
`CSR_INSTR_CG_BEGIN(csrrw)
cp_rs1 : coverpoint instr.rs1;
@ -1220,6 +1650,103 @@ class riscv_instr_cover_group;
fnmsub_s_cg = new();
`CG_SELECTOR_END
`CG_SELECTOR_BEGIN(RV32B)
clz_cg = new();
ctz_cg = new();
pcnt_cg = new();
andn_cg = new();
orn_cg = new();
xnor_cg = new();
pack_cg = new();
packh_cg = new();
min_cg = new();
max_cg = new();
minu_cg = new();
maxu_cg = new();
sext_b_cg = new();
sext_h_cg = new();
sbset_cg = new();
sbclr_cg = new();
sbinv_cg = new();
sbext_cg = new();
sbseti_cg = new();
sbclri_cg = new();
sbinvi_cg = new();
sbexti_cg = new();
slo_cg = new();
sro_cg = new();
sloi_cg = new();
sroi_cg = new();
ror_cg = new();
rol_cg = new();
rori_cg = new();
grev_cg = new();
grevi_cg = new();
shfli_cg = new();
unshfli_cg = new();
shfl_cg = new();
unshfl_cg = new();
gorc_cg = new();
gorci_cg = new();
bfp_cg = new();
bext_cg = new();
bdep_cg = new();
clmul_cg = new();
clmulh_cg = new();
clmulr_cg = new();
crc32_b_cg = new();
crc32_h_cg = new();
crc32_w_cg = new();
crc32c_b_cg = new();
crc32c_h_cg = new();
crc32c_w_cg = new();
cmix_cg = new();
cmov_cg = new();
fsl_cg = new();
fsr_cg = new();
fsri_cg = new();
`CG_SELECTOR_END
`CG_SELECTOR_BEGIN(RV64B)
clzw_cg = new();
ctzw_cg = new();
pcntw_cg = new();
packw_cg = new();
packuw_cg = new();
slow_cg = new();
srow_cg = new();
sloiw_cg = new();
sroiw_cg = new();
rorw_cg = new();
rolw_cg = new();
roriw_cg = new();
grevw_cg = new();
greviw_cg = new();
shflw_cg = new();
unshflw_cg = new();
gorcw_cg = new();
gorciw_cg = new();
bfpw_cg = new();
bextw_cg = new();
bdepw_cg = new();
clmulw_cg = new();
clmulhw_cg = new();
clmulrw_cg = new();
crc32_d_cg = new();
crc32c_d_cg = new();
bmator_cg = new();
bmatxor_cg = new();
bmatflip_cg = new();
fslw_cg = new();
fsrw_cg = new();
fsriw_cg = new();
addwu_cg = new();
subwu_cg = new();
addiwu_cg = new();
addu_w_cg = new();
subu_w_cg = new();
slliu_w_cg = new();
`CG_SELECTOR_END
// Ignore the exception which cannot be covered when running with ISS
if (iss_mode) begin
int i;
@ -1387,6 +1914,100 @@ class riscv_instr_cover_group;
FNMADD_S : `SAMPLE(fnmadd_s_cg, instr)
FMSUB_S : `SAMPLE(fmsub_s_cg, instr)
FNMSUB_S : `SAMPLE(fnmsub_s_cg, instr)
// RV32B
CLZ : `SAMPLE(clz_cg, instr)
CTZ : `SAMPLE(ctz_cg, instr)
PCNT : `SAMPLE(pcnt_cg, instr)
ANDN : `SAMPLE(andn_cg, instr)
ORN : `SAMPLE(orn_cg, instr)
XNOR : `SAMPLE(xnor_cg, instr)
PACK : `SAMPLE(pack_cg, instr)
PACKH : `SAMPLE(packh_cg, instr)
MIN : `SAMPLE(min_cg, instr)
MAX : `SAMPLE(max_cg, instr)
MINU : `SAMPLE(minu_cg, instr)
MAXU : `SAMPLE(maxu_cg, instr)
SEXT_B : `SAMPLE(sext_b_cg, instr)
SEXT_H : `SAMPLE(sext_h_cg, instr)
SBSET : `SAMPLE(sbset_cg, instr)
SBCLR : `SAMPLE(sbclr_cg, instr)
SBINV : `SAMPLE(sbinv_cg, instr)
SBEXT : `SAMPLE(sbext_cg, instr)
SBSETI : `SAMPLE(sbseti_cg, instr)
SBCLRI : `SAMPLE(sbclri_cg, instr)
SBINVI : `SAMPLE(sbinvi_cg, instr)
SBEXTI : `SAMPLE(sbexti_cg, instr)
SLO : `SAMPLE(slo_cg, instr)
SRO : `SAMPLE(sro_cg, instr)
SLOI : `SAMPLE(sloi_cg, instr)
SROI : `SAMPLE(sroi_cg, instr)
ROR : `SAMPLE(ror_cg, instr)
ROL : `SAMPLE(rol_cg, instr)
RORI : `SAMPLE(rori_cg, instr)
GREV : `SAMPLE(grev_cg, instr)
GREVI : `SAMPLE(grevi_cg, instr)
SHFLI : `SAMPLE(shfli_cg, instr)
UNSHFLI : `SAMPLE(unshfli_cg, instr)
SHFL : `SAMPLE(shfl_cg, instr)
UNSHFL : `SAMPLE(unshfl_cg, instr)
GORC : `SAMPLE(gorc_cg, instr)
GORCI : `SAMPLE(gorci_cg, instr)
BFP : `SAMPLE(bfp_cg, instr)
BEXT : `SAMPLE(bext_cg, instr)
BDEP : `SAMPLE(bdep_cg, instr)
CLMUL : `SAMPLE(clmul_cg, instr)
CLMULH : `SAMPLE(clmulh_cg, instr)
CLMULR : `SAMPLE(clmulr_cg, instr)
CRC32_B : `SAMPLE(crc32_b_cg, instr)
CRC32_H : `SAMPLE(crc32_h_cg, instr)
CRC32_W : `SAMPLE(crc32_w_cg, instr)
CRC32C_B : `SAMPLE(crc32c_b_cg, instr)
CRC32C_H : `SAMPLE(crc32c_h_cg, instr)
CRC32C_W : `SAMPLE(crc32c_w_cg, instr)
CMIX : `SAMPLE(cmix_cg, instr)
CMOV : `SAMPLE(cmov_cg, instr)
FSL : `SAMPLE(fsl_cg, instr)
FSR : `SAMPLE(fsr_cg, instr)
FSRI : `SAMPLE(fsri_cg, instr)
// RV64B
CLZW : `SAMPLE(clzw_cg, instr)
CTZW : `SAMPLE(ctzw_cg, instr)
PCNTW : `SAMPLE(pcntw_cg, instr)
PACKW : `SAMPLE(packw_cg, instr)
PACKUW : `SAMPLE(packuw_cg, instr)
SLOW : `SAMPLE(slow_cg, instr)
SROW : `SAMPLE(srow_cg, instr)
SLOIW : `SAMPLE(sloiw_cg, instr)
SROIW : `SAMPLE(sroiw_cg, instr)
RORW : `SAMPLE(rorw_cg, instr)
ROLW : `SAMPLE(rolw_cg, instr)
RORIW : `SAMPLE(roriw_cg, instr)
GREVW : `SAMPLE(grevw_cg, instr)
GREVIW : `SAMPLE(greviw_cg, instr)
SHFLW : `SAMPLE(shflw_cg, instr)
UNSHFLW : `SAMPLE(unshflw_cg, instr)
GORCW : `SAMPLE(gorcw_cg, instr)
GORCIW : `SAMPLE(gorciw_cg, instr)
BFPW : `SAMPLE(bfpw_cg, instr)
BEXTW : `SAMPLE(bextw_cg, instr)
BDEPW : `SAMPLE(bdepw_cg, instr)
CLMULW : `SAMPLE(clmulw_cg, instr)
CLMULHW : `SAMPLE(clmulhw_cg, instr)
CLMULRW : `SAMPLE(clmulrw_cg, instr)
CRC32_D : `SAMPLE(crc32_d_cg, instr)
CRC32C_D : `SAMPLE(crc32c_d_cg, instr)
BMATOR : `SAMPLE(bmator_cg, instr)
BMATXOR : `SAMPLE(bmatxor_cg, instr)
BMATFLIP : `SAMPLE(bmatflip_cg, instr)
FSLW : `SAMPLE(fslw_cg, instr)
FSRW : `SAMPLE(fsrw_cg, instr)
FSRIW : `SAMPLE(fsriw_cg, instr)
ADDWU : `SAMPLE(addwu_cg, instr)
SUBWU : `SAMPLE(subwu_cg, instr)
ADDIWU : `SAMPLE(addiwu_cg, instr)
ADDU_W : `SAMPLE(addu_w_cg, instr)
SUBU_W : `SAMPLE(subu_w_cg, instr)
SLLIU_W : `SAMPLE(slliu_w_cg, instr)
`VECTOR_INCLUDE("riscv_instr_cover_group_inc_cg_sample.sv")
default: begin
if (instr.group == RV32I) begin

View file

@ -80,6 +80,11 @@ class riscv_instr_gen_config extends uvm_object;
// Used by any DCSR operations inside of the debug rom.
// Also used by the PMP generation.
rand riscv_reg_t scratch_reg;
// Reg used exclusively by the PMP exception handling routine.
// Can overlap with the other GPRs used in the random generation,
// as PMP exception handler is hardcoded and does not include any
// random instructions.
rand riscv_reg_t pmp_reg;
// Use a random register for stack pointer/thread pointer
rand riscv_reg_t sp;
rand riscv_reg_t tp;
@ -395,9 +400,15 @@ class riscv_instr_gen_config extends uvm_object;
scratch_reg != tp;
}
constraint reserve_pmp_reg_c {
pmp_reg != ZERO;
pmp_reg != sp;
pmp_reg != tp;
}
constraint gpr_c {
foreach (gpr[i]) {
!(gpr[i] inside {sp, tp, scratch_reg, ZERO, RA, GP});
!(gpr[i] inside {sp, tp, scratch_reg, pmp_reg, ZERO, RA, GP});
}
unique {gpr};
}

View file

@ -1054,6 +1054,9 @@ package riscv_instr_pkg;
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;
// The offset from the address of <main> - automatically populated by the
// PMP generation routine.
bit [XLEN - 1 : 0] offset;
`else
typedef struct{
@ -1065,6 +1068,9 @@ 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;
// The offset from the address of <main> - automatically populated by the
// PMP generation routine.
rand bit [XLEN - 1 : 0] offset;
`endif
} pmp_cfg_reg_t;

View file

@ -252,7 +252,7 @@ class riscv_instr_sequence extends uvm_sequence;
// Convert the instruction stream to the string format.
// Label is attached to the instruction if available, otherwise attach proper space to make
// the code indent consistent.
function void generate_instr_stream(bit no_label = 1'b0);
virtual function void generate_instr_stream(bit no_label = 1'b0);
string prefix, str;
int i;
instr_string_list = {};

View file

@ -22,11 +22,22 @@ class riscv_pmp_cfg extends uvm_object;
// default to granularity of 0 (4 bytes grain)
int pmp_granularity = 0;
// number of configuration bytes per pmpcfg CSR
int cfg_per_csr;
// enable bit for pmp randomization
bit pmp_randomize = 0;
// allow pmp randomization to cause address range overlap
bit pmp_allow_addr_overlap = 0;
rand bit pmp_allow_addr_overlap = 0;
// By default, after returning from a PMP exception, we return to the exact same instruction that
// resulted in a PMP exception to begin with, creating an infinite loop of taking an exception.
// To avoid this situation, this configuration knob will enable the relevant PMP exception
// handlers to find the pmpcfg CSR that controls the address region resulting in the exception and
// change the relevant access bit to 1'b1, allowing forward progress in the code, while also
// allowing all access restrictions to be enforced.
bit enable_pmp_exception_handler = 1'b1;
// pmp CSR configurations
rand pmp_cfg_reg_t pmp_cfg[];
@ -43,6 +54,10 @@ class riscv_pmp_cfg extends uvm_object;
typedef uvm_enum_wrapper#(pmp_addr_mode_t) addr_mode_wrapper;
pmp_addr_mode_t addr_mode;
// Store the base addresses of pmpaddr0 and pmpcfg0
riscv_instr_pkg::privileged_reg_t base_pmp_addr = PMPADDR0;
riscv_instr_pkg::privileged_reg_t base_pmpcfg_addr = PMPCFG0;
`uvm_object_utils_begin(riscv_pmp_cfg)
`uvm_field_int(pmp_num_regions, UVM_DEFAULT)
`uvm_field_int(pmp_granularity, UVM_DEFAULT)
@ -92,9 +107,19 @@ class riscv_pmp_cfg extends uvm_object;
}
}
// Privileged spec states that in TOR mode, offset[i-1] < offset[i]
constraint tor_addr_overlap_c {
foreach (pmp_cfg[i]) {
if (pmp_cfg[i].a == TOR) {
pmp_allow_addr_overlap == 0;
}
}
}
function new(string name = "");
string s;
super.new(name);
cfg_per_csr = XLEN / 8;
inst = uvm_cmdline_processor::get_inst();
get_bool_arg_value("+pmp_randomize=", pmp_randomize);
get_bool_arg_value("+pmp_allow_addr_overlap=", pmp_allow_addr_overlap);
@ -117,7 +142,7 @@ class riscv_pmp_cfg extends uvm_object;
function void post_randomize();
`ifdef _VCP //GRK958
foreach(pmp_cfg[i]) pmp_cfg[i].zero = 2'b00;
`endif
`endif
setup_pmp();
endfunction
@ -146,18 +171,19 @@ class riscv_pmp_cfg extends uvm_object;
foreach (pmp_cfg[i]) begin
arg_name = $sformatf("+pmp_region_%0d=", i);
if (inst.get_arg_value(arg_name, pmp_region)) begin
parse_pmp_config(pmp_region, pmp_cfg[i]);
pmp_cfg[i] = parse_pmp_config(pmp_region, pmp_cfg[i]);
`uvm_info(`gfn, $sformatf("Configured pmp_cfg[%0d] from command line: %p",
i, pmp_cfg[i]), UVM_LOW)
end
end
endfunction
function void parse_pmp_config(string pmp_region, ref pmp_cfg_reg_t pmp_cfg_reg);
function pmp_cfg_reg_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;
uvm_split_string(pmp_region, ",", fields);
foreach (fields[i]) begin
uvm_split_string(fields[i], ":", field_vals);
@ -183,13 +209,14 @@ class riscv_pmp_cfg extends uvm_object;
"ADDR": begin
// Don't have to convert address to "PMP format" here,
// since it must be masked off in hardware
pmp_cfg_reg.offset = format_addr(field_val.atohex());
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;
endfunction
function bit [XLEN - 1 : 0] format_addr(bit [XLEN - 1 : 0] addr);
@ -221,12 +248,9 @@ class riscv_pmp_cfg extends uvm_object;
// CSR, this function waits until it has reached this maximum to write to the physical CSR to
// save some extraneous instructions from being performed.
function void gen_pmp_instr(riscv_reg_t scratch_reg[2], ref string instr[$]);
int cfg_per_csr = XLEN / 8;
bit [XLEN - 1 : 0] pmp_word;
bit [XLEN - 1 : 0] cfg_bitmask;
bit [7 : 0] cfg_byte;
riscv_instr_pkg::privileged_reg_t base_pmp_addr = PMPADDR0;
riscv_instr_pkg::privileged_reg_t base_pmpcfg_addr = PMPCFG0;
int pmp_id;
foreach (pmp_cfg[i]) begin
// TODO(udinator) condense this calculations if possible
@ -251,15 +275,33 @@ class riscv_pmp_cfg extends uvm_object;
instr.push_back($sformatf("csrw 0x%0x, x%0d", base_pmp_addr + i, scratch_reg[0]));
`uvm_info(`gfn, "Loaded the address of <main> section into pmpaddr0", UVM_LOW)
end else begin
// Add the offset to the base address to get the other pmpaddr values
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[i].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 + i, scratch_reg[0]));
`uvm_info(`gfn, $sformatf("Offset of pmp_addr_%d from pmpaddr0: 0x%0x",
i, pmp_cfg[i].offset), UVM_LOW)
// 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
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_LOW);
end else begin
// Add the offset to the base address to get the other pmpaddr values
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[i].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 + i, scratch_reg[0]));
`uvm_info(`gfn, $sformatf("Offset of pmp_addr_%d from pmpaddr0: 0x%0x",
i, pmp_cfg[i].offset), UVM_LOW)
end
end
// Now, check if we have to write to the appropriate pmpcfg CSR.
// Short circuit if we reach the end of the list
@ -280,4 +322,278 @@ class riscv_pmp_cfg extends uvm_object;
end
endfunction
// This function creates a special PMP exception routine that is generated within the
// instr_fault, load_fault, and store_fault exception routines to prevent infinite loops.
// This routine will first find the correct pmpcfg CSR that corresponds to the address that
// caused the exception in the first place, and then will enable the appropriate access bit
// (X for instruction faults, W for store faults, and R for load faults).
//
// Note: If a pmpcfg CSR is locked, it is unable to be written to until a full reset, so in this
// case we will immediately jump to the <test_done> label if the faulting address matches to
// this region, otherwise we'll keep looping through the remaining CSRs.
//
// TODO(udinator) : investigate switching branch targets to named labels instead of numbers
// to better clarify where the multitude of jumps are actually going to.
function void gen_pmp_exception_routine(riscv_reg_t scratch_reg[6],
exception_cause_t fault_type,
ref string instr[$]);
// mscratch : loop counter
// scratch_reg[0] : temporary storage
// scratch_reg[1] : &pmpaddr[i]
// scratch_reg[2] : &pmpcfg[i]
// scratch_reg[3] : 8-bit configuration fields
// scratch_reg[4] : 2-bit pmpcfg[i].A address matching mode
// scratch_reg[5] : holds the previous pmpaddr[i] value (necessary for TOR matching)
instr = {instr,
//////////////////////////////////////////////////
// Initialize loop counter and save to mscratch //
//////////////////////////////////////////////////
$sformatf("li x%0d, 0", scratch_reg[0]),
$sformatf("csrw 0x%0x, x%0d", MSCRATCH, scratch_reg[0]),
$sformatf("li x%0d, 0", scratch_reg[5]),
////////////////////////////////////////////////////
// calculate next pmpaddr and pmpcfg CSRs to read //
////////////////////////////////////////////////////
$sformatf("0: csrr x%0d, 0x%0x", scratch_reg[0], MSCRATCH),
$sformatf("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++) begin
int pmpaddr_addr = base_pmp_addr + i;
int pmpcfg_addr = base_pmpcfg_addr + (i / cfg_per_csr);
instr.push_back($sformatf("li x%0d, %0d", scratch_reg[4], i-1));
instr.push_back($sformatf("beq x%0d, x%0d, %0df", scratch_reg[0], scratch_reg[4], i));
end
// Generate the branch targets for the above sequence of loads and branches to actually
// read from the pmpaddr and pmpcfg CSRs
for (int i = 1; i < pmp_num_regions + 1; i++) begin
int pmpaddr_addr = base_pmp_addr + i;
int pmpcfg_addr = base_pmpcfg_addr + (i / cfg_per_csr);
instr.push_back($sformatf("%0d: csrr x%0d, 0x%0x", i, scratch_reg[1], base_pmp_addr + i - 1));
instr.push_back($sformatf("csrr x%0d, 0x%0x", scratch_reg[2], base_pmpcfg_addr + ((i-1)/4)));
instr.push_back("j 17f");
end
// Logic to store pmpaddr[i] and pmpcfg[i] and branch to a code section
// based on pmpcfg[i].A (address matching mode)
instr = {instr,
////////////////////////////////////////////
// get correct 8-bit configuration fields //
////////////////////////////////////////////
$sformatf("17: li x%0d, %0d", scratch_reg[3], cfg_per_csr),
$sformatf("csrr x%0d, 0x%0x", scratch_reg[0], MSCRATCH),
// calculate offset to left-shift pmpcfg[i] (scratch_reg[2]),
// use scratch_reg[4] as temporary storage
//
// First calculate (loop_counter % cfg_per_csr)
$sformatf("slli x%0d, x%0d, %0d", scratch_reg[0], scratch_reg[0],
XLEN - $clog2(cfg_per_csr)),
$sformatf("srli x%0d, x%0d, %0d", scratch_reg[0], scratch_reg[0],
XLEN - $clog2(cfg_per_csr)),
// Calculate (cfg_per_csr - modded_loop_counter - 1) to determine how many 8bit slots to
// the left this needs to be shifted
$sformatf("sub x%0d, x%0d, x%0d", scratch_reg[4], scratch_reg[3], scratch_reg[0]),
$sformatf("addi x%0d, x%0d, %0d", scratch_reg[4], scratch_reg[4], -1),
// Multiply this "slot offset" by 8 to get the actual number of bits it should
// be leftshifted.
$sformatf("slli x%0d, x%0d, 3", scratch_reg[4], scratch_reg[4]),
// Perform the leftshifting operation
$sformatf("sll x%0d, x%0d, x%0d", scratch_reg[3], scratch_reg[2], scratch_reg[4]),
// Add 8*modded_loop_counter to 8*(cfg_per_csr - modded_loop_counter - 1)
// stored in scratch_reg[4] to get "slot offset" for the pending rightshift operation.
$sformatf("slli x%0d, x%0d, 3", scratch_reg[0], scratch_reg[0]),
$sformatf("add x%0d, x%0d, x%0d", scratch_reg[4], scratch_reg[4], scratch_reg[0]),
// Perform the rightshift operation
$sformatf("srl x%0d, x%0d, x%0d", scratch_reg[3], scratch_reg[3], scratch_reg[4]),
///////////////////////////
// get pmpcfg[i].A field //
///////////////////////////
// pmpcfg[i].A will be bits [4:3] of the 8-bit configuration entry
$sformatf("slli x%0d, x%0d, %0d", scratch_reg[4], scratch_reg[3], XLEN - 5),
$sformatf("srli x%0d, x%0d, %0d", scratch_reg[4], scratch_reg[4], XLEN - 2),
//////////////////////////////////////////////////////////////////
// based on address match mode, branch to appropriate "handler" //
//////////////////////////////////////////////////////////////////
// pmpcfg[i].A == OFF
$sformatf("beqz x%0d, 20f", scratch_reg[4]),
// pmpcfg[i].A == TOR
// scratch_reg[5] will contain pmpaddr[i-1]
$sformatf("li x%0d, 1", scratch_reg[0]),
$sformatf("beq x%0d, x%0d, 21f", scratch_reg[4], scratch_reg[0]),
// pmpcfg[i].A == NA4
$sformatf("li x%0d, 2", scratch_reg[0]),
$sformatf("beq x%0d, x%0d, 25f", scratch_reg[4], scratch_reg[0]),
// pmpcfg[i].A == NAPOT
$sformatf("li x%0d, 3", scratch_reg[0]),
$sformatf("beq x%0d, x%0d, 27f", scratch_reg[4], scratch_reg[0]),
// Error check, if no address modes match, something has gone wrong
$sformatf("j test_done"),
/////////////////////////////////////////////////////////////////
// increment loop counter and branch back to beginning of loop //
/////////////////////////////////////////////////////////////////
$sformatf("18: csrr x%0d, 0x%0x", scratch_reg[0], MSCRATCH),
// load pmpaddr[i] into scratch_reg[5] to store for iteration [i+1]
$sformatf("mv x%0d, x%0d", scratch_reg[5], scratch_reg[1]),
// increment loop counter by 1
$sformatf("addi x%0d, x%0d, 1", scratch_reg[0], scratch_reg[0]),
// store loop counter to MSCRATCH
$sformatf("csrw 0x%0x, x%0d", MSCRATCH, scratch_reg[0]),
// load number of pmp regions - loop limit
$sformatf("li x%0d, %0d", scratch_reg[1], pmp_num_regions),
// if counter < pmp_num_regions => branch to beginning of loop
$sformatf("ble x%0d, x%0d, 19f", scratch_reg[1], scratch_reg[0]),
$sformatf("j 0b"),
// if counter >= pmp_num_regions, jump to the end of the handler, as in M-mode,
// no PMP match means the access succeeds
$sformatf("19: j 34f")
};
/////////////////////////////////////////////////
// Sub-sections for all address matching modes //
/////////////////////////////////////////////////
// scratch_reg[0] : temporary storage
// scratch_reg[1] : pmpaddr[i]
// scratch_reg[2] : pmpcfg[i]
// scratch_reg[3] : 8-bit configuration fields
// scratch_reg[4] : temporary storage
// scratch_reg[5] : pmpaddr[i-1]
// Sub-section to deal with address matching mode OFF.
// If entry is OFF, simply continue looping through other PMP CSR.
instr = {instr, "20: j 18b"};
// Sub-section to handle address matching mode TOR.
instr = {instr,
$sformatf("21: csrr x%0d, 0x%0x", scratch_reg[0], MSCRATCH),
$sformatf("csrr x%0d, 0x%0x", scratch_reg[4], MTVAL),
$sformatf("srli x%0d, x%0d, 2", scratch_reg[4], scratch_reg[4]),
// If loop_counter==0, compare fault_addr to 0
$sformatf("bnez x%0d, 22f", scratch_reg[0]),
// If fault_addr < 0 : continue looping
$sformatf("bltz x%0d, 18b", scratch_reg[4]),
$sformatf("j 23f"),
// If fault_addr < pmpaddr[i-1] : continue looping
$sformatf("22: bgtu x%0d, x%0d, 18b", scratch_reg[5], scratch_reg[4]),
// If fault_addr >= pmpaddr[i] : continue looping
$sformatf("23: bleu x%0d, x%0d, 18b", scratch_reg[1], scratch_reg[4]),
// If we get here, there is a TOR match, if the entry is locked jump to
// <test_done>, otherwise modify access bits and return
$sformatf("andi x%0d, x%0d, 128", scratch_reg[4], scratch_reg[3]),
$sformatf("beqz x%0d, 24f", scratch_reg[4]),
$sformatf("j test_done"),
// TODO : update with correct label
$sformatf("24: j 29f")
};
// Sub-section to handle address matching mode NA4.
// TODO(udinator) : add rv64 support
instr = {instr,
$sformatf("25: csrr x%0d, 0x%0x", scratch_reg[0], MTVAL),
$sformatf("srli x%0d, x%0d, 2", scratch_reg[0], scratch_reg[0]),
// Zero out pmpaddr[i][31:30]
$sformatf("slli x%0d, x%0d, 2", scratch_reg[4], scratch_reg[1]),
$sformatf("srli x%0d, x%0d, 2", scratch_reg[4], scratch_reg[4]),
// If fault_addr[31:2] != pmpaddr[i][29:0] => there is a mismatch,
// so continue looping
$sformatf("bne x%0d, x%0d, 18b", scratch_reg[0], scratch_reg[4]),
// If we get here, there is an NA4 address match, jump to <test_done> if the
// entry is locked, otherwise modify access bits
$sformatf("andi x%0d, x%0d, 128", scratch_reg[4], scratch_reg[3]),
$sformatf("beqz x%0d, 26f", scratch_reg[4]),
$sformatf("j test_done"),
// TODO : update with correct label
$sformatf("26: j 29f")
};
// Sub-section to handle address matching mode NAPOT.
instr = {instr,
$sformatf("27: csrr x%0d, 0x%0x", scratch_reg[0], MTVAL),
// get fault_addr[31:2]
$sformatf("srli x%0d, x%0d, 2", scratch_reg[0], scratch_reg[0]),
// mask the bottom pmp_granularity bits of fault_addr
$sformatf("srli x%0d, x%0d, %0d", scratch_reg[0], scratch_reg[0], pmp_granularity),
$sformatf("slli x%0d, x%0d, %0d", scratch_reg[0], scratch_reg[0], pmp_granularity),
// get pmpaddr[i][29:0]
$sformatf("slli x%0d, x%0d, 2", scratch_reg[4], scratch_reg[1]),
$sformatf("srli x%0d, x%0d, 2", scratch_reg[4], scratch_reg[4]),
// mask the bottom pmp_granularity bits of pmpaddr[i]
$sformatf("srli x%0d, x%0d, %0d", scratch_reg[4], scratch_reg[4], pmp_granularity),
$sformatf("slli x%0d, x%0d, %0d", scratch_reg[4], scratch_reg[4], pmp_granularity),
// If masked_fault_addr != masked_pmpaddr[i] : mismatch, so continue looping
$sformatf("bne x%0d, x%0d, 18b", scratch_reg[0], scratch_reg[4]),
// If we get here there is an NAPOT address match, jump to <test_done> if
// the entry is locked, otherwise modify access bits
$sformatf("andi x%0d, x%0d, 128", scratch_reg[4], scratch_reg[3]),
$sformatf("beqz x%0d, 29f", scratch_reg[4]),
$sformatf("j test_done"),
// TODO : update with correct label
$sformatf("28: j 29f")
};
// This case statement creates a bitmask that enables the correct access permissions
// and ORs it with the 8-bit configuration fields.
case (fault_type)
INSTRUCTION_ACCESS_FAULT: begin
instr.push_back($sformatf("29: ori x%0d, x%0d, 4", scratch_reg[3], scratch_reg[3]));
end
STORE_AMO_ACCESS_FAULT: begin
// The combination of W:1 and R:0 is reserved, so if we are enabling write
// permissions, also enable read permissions to adhere to the spec.
instr.push_back($sformatf("29: ori x%0d, x%0d, 3", scratch_reg[3], scratch_reg[3]));
end
LOAD_ACCESS_FAULT: begin
instr.push_back($sformatf("29: ori x%0d, x%0d, 1", scratch_reg[3], scratch_reg[3]));
end
endcase
instr = {instr,
$sformatf("csrr x%0d, 0x%0x", scratch_reg[0], MSCRATCH),
// Calculate (loop_counter % cfg_per_csr) to find the index of the correct
// entry in pmpcfg[i].
//
// Calculate XLEN - $clog2(cfg_per_csr) to give how many low order bits
// of loop_counter we need to keep around
$sformatf("li x%0d, %0d", scratch_reg[4], XLEN - $clog2(cfg_per_csr)),
// Now leftshift and rightshift loop_counter by this amount to clear all the upper
// bits
$sformatf("sll x%0d, x%0d, x%0d", scratch_reg[0], scratch_reg[0], scratch_reg[4]),
$sformatf("srl x%0d, x%0d, x%0d", scratch_reg[0], scratch_reg[0], scratch_reg[4]),
// Multiply the index by 8 to get the shift amount.
$sformatf("slli x%0d, x%0d, 3", scratch_reg[4], scratch_reg[0]),
// Shift the updated configuration byte to the proper alignment
$sformatf("sll x%0d, x%0d, x%0d", scratch_reg[3], scratch_reg[3], scratch_reg[4]),
// OR pmpcfg[i] with the updated configuration byte
$sformatf("or x%0d, x%0d, x%0d", scratch_reg[2], scratch_reg[2], scratch_reg[3]),
// Divide the loop counter by cfg_per_csr to determine which pmpcfg CSR to write to.
$sformatf("csrr x%0d, 0x%0x", scratch_reg[0], MSCRATCH),
$sformatf("srli x%0d, x%0d, %0d", scratch_reg[0], scratch_reg[0], $clog2(cfg_per_csr)),
// Write the updated pmpcfg[i] to the CSR bank and exit the handler.
//
// Don't touch scratch_reg[2], as it contains the updated pmpcfg[i] to be written.
// All other scratch_reg[*] can be used.
// scratch_reg[0] contains the index of the correct pmpcfg CSR.
// We simply check the index and then write to the correct pmpcfg CSR based on its value.
$sformatf("beqz x%0d, 30f", scratch_reg[0]),
$sformatf("li x%0d, 1", scratch_reg[4]),
$sformatf("beq x%0d, x%0d, 31f", scratch_reg[0], scratch_reg[4]),
$sformatf("li x%0d, 2", scratch_reg[4]),
$sformatf("beq x%0d, x%0d, 32f", scratch_reg[0], scratch_reg[4]),
$sformatf("li x%0d, 3", scratch_reg[4]),
$sformatf("beq x%0d, x%0d, 33f", scratch_reg[0], scratch_reg[4]),
$sformatf("30: csrw 0x%0x, x%0d", PMPCFG0, scratch_reg[2]),
$sformatf("j 34f"),
$sformatf("31: csrw 0x%0x, x%0d", PMPCFG1, scratch_reg[2]),
$sformatf("j 34f"),
$sformatf("32: csrw 0x%0x, x%0d", PMPCFG2, scratch_reg[2]),
$sformatf("j 34f"),
$sformatf("33: csrw 0x%0x, x%0d", 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.
$sformatf("34: nop")
};
endfunction
endclass

View file

@ -0,0 +1,22 @@
# riscOVPsim configuration file converted from YAML
--variant RV64I
--override riscvOVPsim/cpu/add_Extensions=MCB
--override riscvOVPsim/cpu/misa_MXL=2
--override riscvOVPsim/cpu/misa_MXL_mask=0x0 # 0
--override riscvOVPsim/cpu/misa_Extensions_mask=0x0 # 0
--override riscvOVPsim/cpu/unaligned=T
--override riscvOVPsim/cpu/mtvec_mask=0x0 # 0
--override riscvOVPsim/cpu/user_version=2.3
--override riscvOVPsim/cpu/priv_version=1.11
--override riscvOVPsim/cpu/mvendorid=0
--override riscvOVPsim/cpu/marchid=0
--override riscvOVPsim/cpu/mimpid=0
--override riscvOVPsim/cpu/mhartid=0
--override riscvOVPsim/cpu/cycle_undefined=F
--override riscvOVPsim/cpu/instret_undefined=F
--override riscvOVPsim/cpu/time_undefined=T
--override riscvOVPsim/cpu/reset_address=0x80000000
--override riscvOVPsim/cpu/simulateexceptions=T
--override riscvOVPsim/cpu/defaultsemihost=F
--override riscvOVPsim/cpu/wfi_is_nop=T
--exitonsymbol _exit

View file

@ -0,0 +1,118 @@
/*
* 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.
*/
//-----------------------------------------------------------------------------
// Processor feature configuration
//-----------------------------------------------------------------------------
// XLEN
parameter int XLEN = 64;
// Parameter for SATP mode, set to BARE if address translation is not supported
parameter satp_mode_t SATP_MODE = BARE;
// Supported Privileged mode
privileged_mode_t supported_privileged_mode[] = {MACHINE_MODE};
// Unsupported instructions
riscv_instr_name_t unsupported_instr[];
// ISA supported by the processor
riscv_instr_group_t supported_isa[$] = {RV32I, RV32M, RV32C, RV32B, RV64I, RV64M, RV64C, RV64B};
// Interrupt mode support
mtvec_mode_t supported_interrupt_mode[$] = {DIRECT, VECTORED};
// The number of interrupt vectors to be generated, only used if VECTORED interrupt mode is
// supported
int max_interrupt_vector_num = 16;
// Physical memory protection support
bit support_pmp = 0;
// Debug mode support
bit support_debug_mode = 0;
// Support delegate trap to user mode
bit support_umode_trap = 0;
// Support sfence.vma instruction
bit support_sfence = 0;
// Support unaligned load/store
bit support_unaligned_load_store = 1'b1;
// Parameter for vector extension
parameter int VECTOR_EXTENSION_ENABLE = 0;
parameter int VLEN = 512;
parameter int ELEN = 64;
parameter int SLEN = 64;
// Number of harts
parameter int NUM_HARTS = 1;
// ----------------------------------------------------------------------------
// Previleged CSR implementation
// ----------------------------------------------------------------------------
// Implemented previlieged CSR list
`ifdef DSIM
privileged_reg_t implemented_csr[] = {
`else
const privileged_reg_t implemented_csr[] = {
`endif
// Machine mode mode CSR
MVENDORID, // Vendor ID
MARCHID, // Architecture ID
MIMPID, // Implementation ID
MHARTID, // Hardware thread ID
MSTATUS, // Machine status
MISA, // ISA and extensions
MIE, // Machine interrupt-enable register
MTVEC, // Machine trap-handler base address
MCOUNTEREN, // Machine counter enable
MSCRATCH, // Scratch register for machine trap handlers
MEPC, // Machine exception program counter
MCAUSE, // Machine trap cause
MTVAL, // Machine bad address or instruction
MIP // Machine interrupt pending
};
// ----------------------------------------------------------------------------
// Supported interrupt/exception setting, used for functional coverage
// ----------------------------------------------------------------------------
`ifdef DSIM
interrupt_cause_t implemented_interrupt[] = {
`else
const interrupt_cause_t implemented_interrupt[] = {
`endif
M_SOFTWARE_INTR,
M_TIMER_INTR,
M_EXTERNAL_INTR
};
`ifdef DSIM
exception_cause_t implemented_exception[] = {
`else
const exception_cause_t implemented_exception[] = {
`endif
INSTRUCTION_ACCESS_FAULT,
ILLEGAL_INSTRUCTION,
BREAKPOINT,
LOAD_ADDRESS_MISALIGNED,
LOAD_ACCESS_FAULT,
ECALL_MMODE
};

View file

@ -0,0 +1,33 @@
# Copyright 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.
# ================================================================================
# Regression test list format
# --------------------------------------------------------------------------------
# test : Assembly test name
# description : Description of this test
# gen_opts : Instruction generator options
# iterations : Number of iterations of this test
# no_iss : Enable/disable ISS simulator (Optional)
# gen_test : Test name used by the instruction generator
# asm_tests : Path to directed, hand-coded assembly test file or directory
# rtl_test : RTL simulation test name
# cmp_opts : Compile options passed to the instruction generator
# sim_opts : Simulation options passed to the instruction generator
# no_post_compare : Enable/disable comparison of trace log and ISS log (Optional)
# compare_opts : Options for the RTL & ISS trace comparison
# gcc_opts : gcc compile options
# --------------------------------------------------------------------------------
- import: <riscv_dv_root>/target/rv32imcb/testlist.yaml

View file

@ -138,7 +138,7 @@ class riscv_instr_cov_test extends uvm_test;
if (riscv_instr::instr_template.exists(instr_name)) begin
instr.copy(riscv_instr::instr_template[instr_name]);
if (instr.group inside {RV32I, RV32M, RV32C, RV64I, RV64M, RV64C,
RV32F}) begin
RV32F, RV32B, RV64B}) begin
assign_trace_info_to_instr(instr);
end
instr.pre_sample();
@ -173,7 +173,11 @@ class riscv_instr_cov_test extends uvm_test;
I_FORMAT: begin
// TODO, support I_FORMAT floating point later
if (instr.group == RV32F) return;
`DV_CHECK_FATAL(operands.size() == 3, trace["instr_str"])
if (instr.instr_name inside {FSRI, FSRIW}) begin
`DV_CHECK_FATAL(operands.size() == 4, trace["instr_str"])
end else begin
`DV_CHECK_FATAL(operands.size() == 3, trace["instr_str"])
end
if(instr.category == LOAD) begin
// load rd, imm(rs1)
instr.rs1 = get_gpr(operands[2]);
@ -187,6 +191,13 @@ class riscv_instr_cov_test extends uvm_test;
end else begin
get_val(operands[1], instr.csr);
end
end else if (instr.instr_name inside {FSRI, FSRIW}) begin
// fsri rd, rs1, rs3, imm
instr.rs1 = get_gpr(operands[1]);
instr.rs1_value = get_gpr_state(operands[1]);
instr.rs3 = get_gpr(operands[2]);
instr.rs3_value = get_gpr_state(operands[2]);
get_val(operands[3], instr.imm);
end else begin
// addi rd, rs1, imm
instr.rs1 = get_gpr(operands[1]);
@ -215,8 +226,12 @@ class riscv_instr_cov_test extends uvm_test;
end
end
R_FORMAT: begin
if (!instr.instr_name inside {FCLASS_S, FCLASS_D}) `DV_CHECK_FATAL(operands.size() == 3)
else `DV_CHECK_FATAL(operands.size() == 2)
if ((instr.has_rs2 || instr.category == CSR) &&
!(instr.instr_name inside {FCLASS_S, FCLASS_D})) begin
`DV_CHECK_FATAL(operands.size() == 3)
end else begin
`DV_CHECK_FATAL(operands.size() == 2)
end
if(instr.category == CSR) begin
// csrrw rd, csr, rs1
if (preg_enum::from_name(operands[1].toupper(), preg)) begin
@ -240,18 +255,23 @@ class riscv_instr_cov_test extends uvm_test;
// add rd, rs1, rs2
instr.rs1 = get_gpr(operands[1]);
instr.rs1_value = get_gpr_state(operands[1]);
instr.rs2 = get_gpr(operands[2]);
instr.rs2_value = get_gpr_state(operands[2]);
if (instr.has_rs2) begin
instr.rs2 = get_gpr(operands[2]);
instr.rs2_value = get_gpr_state(operands[2]);
end
end
end
R4_FORMAT: begin
`DV_CHECK_FATAL(operands.size() == 4)
instr.fs1 = get_fpr(operands[1]);
instr.fs1_value = get_gpr_state(operands[1]);
instr.fs2 = get_fpr(operands[2]);
instr.fs2_value = get_gpr_state(operands[2]);
instr.fs3 = get_fpr(operands[3]);
instr.fs3_value = get_gpr_state(operands[3]);
update_instr_reg_by_abi_name(operands[1],
instr.rs1, instr.rs1_value,
instr.fs1, instr.fs1_value);
update_instr_reg_by_abi_name(operands[2],
instr.rs2, instr.rs2_value,
instr.fs2, instr.fs2_value);
update_instr_reg_by_abi_name(operands[3],
instr.rs3, instr.rs3_value,
instr.fs3, instr.fs3_value);
end
CI_FORMAT, CIW_FORMAT: begin
if (instr.instr_name == C_ADDI16SP) begin

View file

@ -29,7 +29,7 @@ class riscv_rand_instr_test extends riscv_instr_base_test;
endfunction
virtual function void apply_directed_instr();
// Mix below directed instructino streams with the random instructions
// Mix below directed instruction streams with the random instructions
asm_gen.add_directed_instr_stream("riscv_load_store_rand_instr_stream", 4);
asm_gen.add_directed_instr_stream("riscv_loop_instr", 3);
asm_gen.add_directed_instr_stream("riscv_jal_instr", 4);