diff --git a/vendor/google_riscv-dv.lock.hjson b/vendor/google_riscv-dv.lock.hjson index 6589483a..109a326a 100644 --- a/vendor/google_riscv-dv.lock.hjson +++ b/vendor/google_riscv-dv.lock.hjson @@ -9,6 +9,6 @@ upstream: { url: https://github.com/google/riscv-dv - rev: 42264b7782a10848935e995063c212893820e561 + rev: ace2805b63100f46c3dcd02b4fcf6a7184582110 } } diff --git a/vendor/google_riscv-dv/docs/source/extension_support.rst b/vendor/google_riscv-dv/docs/source/extension_support.rst new file mode 100644 index 00000000..012d0d14 --- /dev/null +++ b/vendor/google_riscv-dv/docs/source/extension_support.rst @@ -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: /bin/riscv64-unknown-elf-gcc) +3. Update environment variable RISCV_OBJCOPY to RISC-V objcopy executable + executable. (example: /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= + 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 diff --git a/vendor/google_riscv-dv/docs/source/index.rst b/vendor/google_riscv-dv/docs/source/index.rst index 1a9dc612..48200902 100644 --- a/vendor/google_riscv-dv/docs/source/index.rst +++ b/vendor/google_riscv-dv/docs/source/index.rst @@ -13,6 +13,7 @@ Welcome to riscv-dv's documentation! overview getting_started configuration + extension_support end_to_end_simulation generator_flow coverage_model diff --git a/vendor/google_riscv-dv/run.py b/vendor/google_riscv-dv/run.py index bae34b7f..9cf8538c 100644 --- a/vendor/google_riscv-dv/run.py +++ b/vendor/google_riscv-dv/run.py @@ -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" diff --git a/vendor/google_riscv-dv/src/isa/riscv_b_instr.sv b/vendor/google_riscv-dv/src/isa/riscv_b_instr.sv index 8478c7cc..82944aa8 100755 --- a/vendor/google_riscv-dv/src/isa/riscv_b_instr.sv +++ b/vendor/google_riscv-dv/src/isa/riscv_b_instr.sv @@ -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 { diff --git a/vendor/google_riscv-dv/src/isa/riscv_instr.sv b/vendor/google_riscv-dv/src/isa/riscv_instr.sv index f4422de1..dd81bc19 100644 --- a/vendor/google_riscv-dv/src/isa/riscv_instr.sv +++ b/vendor/google_riscv-dv/src/isa/riscv_instr.sv @@ -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 diff --git a/vendor/google_riscv-dv/src/isa/riscv_vector_instr.sv b/vendor/google_riscv-dv/src/isa/riscv_vector_instr.sv index def31c92..5fc70b4a 100644 --- a/vendor/google_riscv-dv/src/isa/riscv_vector_instr.sv +++ b/vendor/google_riscv-dv/src/isa/riscv_vector_instr.sv @@ -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 diff --git a/vendor/google_riscv-dv/src/riscv_asm_program_gen.sv b/vendor/google_riscv-dv/src/riscv_asm_program_gen.sv index c0a5127a..c29378bc 100644 --- a/vendor/google_riscv-dv/src/riscv_asm_program_gen.sv +++ b/vendor/google_riscv-dv/src/riscv_asm_program_gen.sv @@ -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); diff --git a/vendor/google_riscv-dv/src/riscv_instr_cov_item.sv b/vendor/google_riscv-dv/src/riscv_instr_cov_item.sv index abcab925..3893c929 100644 --- a/vendor/google_riscv-dv/src/riscv_instr_cov_item.sv +++ b/vendor/google_riscv-dv/src/riscv_instr_cov_item.sv @@ -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; diff --git a/vendor/google_riscv-dv/src/riscv_instr_cover_group.sv b/vendor/google_riscv-dv/src/riscv_instr_cover_group.sv index b0db34ed..f2153efa 100644 --- a/vendor/google_riscv-dv/src/riscv_instr_cover_group.sv +++ b/vendor/google_riscv-dv/src/riscv_instr_cover_group.sv @@ -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 diff --git a/vendor/google_riscv-dv/src/riscv_instr_gen_config.sv b/vendor/google_riscv-dv/src/riscv_instr_gen_config.sv index 4e88381e..f9541749 100644 --- a/vendor/google_riscv-dv/src/riscv_instr_gen_config.sv +++ b/vendor/google_riscv-dv/src/riscv_instr_gen_config.sv @@ -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}; } diff --git a/vendor/google_riscv-dv/src/riscv_instr_pkg.sv b/vendor/google_riscv-dv/src/riscv_instr_pkg.sv index 9c6b2a89..3b35521e 100644 --- a/vendor/google_riscv-dv/src/riscv_instr_pkg.sv +++ b/vendor/google_riscv-dv/src/riscv_instr_pkg.sv @@ -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
- 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
- automatically populated by the + // PMP generation routine. rand bit [XLEN - 1 : 0] offset; `endif } pmp_cfg_reg_t; diff --git a/vendor/google_riscv-dv/src/riscv_instr_sequence.sv b/vendor/google_riscv-dv/src/riscv_instr_sequence.sv index f6e4481e..e2a22e97 100644 --- a/vendor/google_riscv-dv/src/riscv_instr_sequence.sv +++ b/vendor/google_riscv-dv/src/riscv_instr_sequence.sv @@ -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 = {}; diff --git a/vendor/google_riscv-dv/src/riscv_pmp_cfg.sv b/vendor/google_riscv-dv/src/riscv_pmp_cfg.sv index f394eb7d..d0b5b943 100644 --- a/vendor/google_riscv-dv/src/riscv_pmp_cfg.sv +++ b/vendor/google_riscv-dv/src/riscv_pmp_cfg.sv @@ -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
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+
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 [
: 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 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 + // , 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 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 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 diff --git a/vendor/google_riscv-dv/target/rv64imcb/riscvOVPsim.ic b/vendor/google_riscv-dv/target/rv64imcb/riscvOVPsim.ic new file mode 100644 index 00000000..de88e8da --- /dev/null +++ b/vendor/google_riscv-dv/target/rv64imcb/riscvOVPsim.ic @@ -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 diff --git a/vendor/google_riscv-dv/target/rv64imcb/riscv_core_setting.sv b/vendor/google_riscv-dv/target/rv64imcb/riscv_core_setting.sv new file mode 100644 index 00000000..2f67acf2 --- /dev/null +++ b/vendor/google_riscv-dv/target/rv64imcb/riscv_core_setting.sv @@ -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 +}; diff --git a/vendor/google_riscv-dv/target/rv64imcb/testlist.yaml b/vendor/google_riscv-dv/target/rv64imcb/testlist.yaml new file mode 100644 index 00000000..612eabc7 --- /dev/null +++ b/vendor/google_riscv-dv/target/rv64imcb/testlist.yaml @@ -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: /target/rv32imcb/testlist.yaml diff --git a/vendor/google_riscv-dv/test/riscv_instr_cov_test.sv b/vendor/google_riscv-dv/test/riscv_instr_cov_test.sv index 668df7e2..1de70deb 100644 --- a/vendor/google_riscv-dv/test/riscv_instr_cov_test.sv +++ b/vendor/google_riscv-dv/test/riscv_instr_cov_test.sv @@ -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 diff --git a/vendor/google_riscv-dv/test/riscv_instr_test_lib.sv b/vendor/google_riscv-dv/test/riscv_instr_test_lib.sv index a290e615..cf83ffad 100644 --- a/vendor/google_riscv-dv/test/riscv_instr_test_lib.sv +++ b/vendor/google_riscv-dv/test/riscv_instr_test_lib.sv @@ -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);