diff --git a/vendor/google_riscv-dv.lock.hjson b/vendor/google_riscv-dv.lock.hjson index 114c777e..b4e5d34c 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: faddfa49f456f3f8ef8c4231865994b7b13aa96d + rev: 102791dbb7eb992d3bc22336d2e4e5f0d688e761 } } diff --git a/vendor/google_riscv-dv/scripts/spike_log_to_trace_csv.py b/vendor/google_riscv-dv/scripts/spike_log_to_trace_csv.py index 1f4f6d27..45a23f83 100644 --- a/vendor/google_riscv-dv/scripts/spike_log_to_trace_csv.py +++ b/vendor/google_riscv-dv/scripts/spike_log_to_trace_csv.py @@ -42,6 +42,7 @@ def process_spike_sim_log(spike_log, csv): INSTR_RE = re.compile(r"(?P[a-z\.]+?)(\s+?)(?P.*)") GPR_RE = re.compile(r"^[a-z][0-9a-z]$") CSR_RE = re.compile(r"csr") + ILLE_RE = re.compile(r"trap_illegal_instruction") # Remove all the init spike boot instructions cmd = ("sed -i '/core.*0x0000000000001010/,$!d' %s" % spike_log) @@ -70,6 +71,8 @@ def process_spike_sim_log(spike_log, csv): continue nextline = f.readline() if nextline != "": + if ILLE_RE.search(nextline): + continue m = RD_RE.search(nextline) if m: # Extract RD information 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 7817ae57..9011cb98 100644 --- a/vendor/google_riscv-dv/src/riscv_asm_program_gen.sv +++ b/vendor/google_riscv-dv/src/riscv_asm_program_gen.sv @@ -91,7 +91,7 @@ class riscv_asm_program_gen extends uvm_object; bin_program.hint_instr_pct = $urandom_range(5, 20); end `DV_CHECK_RANDOMIZE_FATAL(bin_program) - bin_program.gen_instr(.is_main_program(0), .enable_hint_instr(cfg.enable_hint_instruction)); + bin_program.gen_instr(.is_main_program(0)); bin_program.post_process_instr(); bin_program.generate_binary_stream(instr_binary); end @@ -272,6 +272,7 @@ class riscv_asm_program_gen extends uvm_object; `uvm_fatal(get_full_name(), "Failed to generate callstack") end end + `uvm_info(get_full_name(), "Randomizing call stack..done", UVM_LOW) endfunction virtual function void insert_sub_program(ref riscv_instr_sequence sub_program[], @@ -1130,8 +1131,7 @@ class riscv_asm_program_gen extends uvm_object; debug_program.is_debug_program = 1; debug_program.cfg = cfg; `DV_CHECK_RANDOMIZE_FATAL(debug_program) - debug_program.gen_instr(.is_main_program(1'b1), .enable_hint_instr(1'b0), - .no_branch(1'b0)); + debug_program.gen_instr(.is_main_program(1'b1), .no_branch(1'b0)); gen_callstack(debug_program, debug_sub_program, debug_sub_program_name, cfg.num_debug_sub_program); debug_program.post_process_instr(); diff --git a/vendor/google_riscv-dv/src/riscv_directed_instr_lib.sv b/vendor/google_riscv-dv/src/riscv_directed_instr_lib.sv index 66d09482..bd86547c 100644 --- a/vendor/google_riscv-dv/src/riscv_directed_instr_lib.sv +++ b/vendor/google_riscv-dv/src/riscv_directed_instr_lib.sv @@ -94,6 +94,7 @@ class riscv_jump_instr extends riscv_rand_instr_stream; rand riscv_instr_base addi; rand riscv_pseudo_instr la; rand riscv_rand_instr branch; + rand int imm; rand bit enable_branch; rand int mixed_instr_cnt; riscv_instr_base stack_exit_instr[]; @@ -110,6 +111,7 @@ class riscv_jump_instr extends riscv_rand_instr_stream; addi.rd == la.rd; // Avoid using negative offset -1024 addi.imm != 'hFFFF_FC00; + addi.imm != 1024; jump.imm == ~addi.imm + 1; jump.rs1 == addi.rd; addi.instr_name == ADDI; @@ -335,9 +337,7 @@ class riscv_long_branch_instr extends riscv_rand_instr_stream; backward_branch_instr_stream.initialize_instr_list(branch_instr_stream_len); endfunction - virtual function void gen_instr(bit no_branch = 1'b0, - bit no_load_store = 1'b1, - bit enable_hint_instr = 1'b0); + virtual function void gen_instr(bit no_branch = 1'b0, bit no_load_store = 1'b1); int branch_offset; super.gen_instr(1'b1); forward_branch_instr_stream.gen_instr(); diff --git a/vendor/google_riscv-dv/src/riscv_illegal_instr.sv b/vendor/google_riscv-dv/src/riscv_illegal_instr.sv index 03b354b5..2cd25c66 100644 --- a/vendor/google_riscv-dv/src/riscv_illegal_instr.sv +++ b/vendor/google_riscv-dv/src/riscv_illegal_instr.sv @@ -125,14 +125,25 @@ class riscv_illegal_instr extends uvm_object; } } + // TODO: Enable atomic instruction + constraint no_atomic_c { + opcode != 7'b0101111; + } + constraint illegal_func3_c { solve opcode before func3; if (!compressed) { if (exception == kIllegalFunc3) { (opcode == 7'b1100111) -> (func3 != 3'b000); (opcode == 7'b1100011) -> (func3 inside {3'b010, 3'b011}); - (opcode == 7'b0000011) -> (func3 == 3'b111); - (opcode == 7'b0100011) -> (func3 >= 3'b011); + + if (XLEN == 32) { + (opcode == 7'b0100011) -> (func3 >= 3'b011); + (opcode == 7'b0000011) -> (func3 inside {3'b011, 3'b111}); + } else { + (opcode == 7'b0100011) -> (func3 > 3'b011); + (opcode == 7'b0000011) -> (func3 == 3'b111); + } (opcode == 7'b0001111) -> (!(func3 inside {3'b000, 3'b001})); (opcode == 7'b1110011) -> (func3 == 3'b100); (opcode == 7'b0011011) -> (!(func3 inside {3'b000, 3'b001, 3'b101})); @@ -142,8 +153,13 @@ class riscv_illegal_instr extends uvm_object; } else { (opcode == 7'b1100111) -> (func3 == 3'b000); (opcode == 7'b1100011) -> (!(func3 inside {3'b010, 3'b011})); - (opcode == 7'b0000011) -> (func3 != 3'b111); - (opcode == 7'b0100011) -> (func3 < 3'b011); + if (XLEN == 32) { + (opcode == 7'b0100011) -> (func3 < 3'b011); + (opcode == 7'b0000011) -> !(func3 inside {3'b011, 3'b111}); + } else { + (opcode == 7'b0100011) -> (func3 <= 3'b011); + (opcode == 7'b0000011) -> (func3 != 3'b111); + } (opcode == 7'b0001111) -> (func3 inside {3'b000, 3'b001}); (opcode == 7'b1110011) -> (func3 != 3'b100); (opcode == 7'b0011011) -> (func3 inside {3'b000, 3'b001, 3'b101}); diff --git a/vendor/google_riscv-dv/src/riscv_instr_base.sv b/vendor/google_riscv-dv/src/riscv_instr_base.sv index 97b47c15..9f9bf87e 100644 --- a/vendor/google_riscv-dv/src/riscv_instr_base.sv +++ b/vendor/google_riscv-dv/src/riscv_instr_base.sv @@ -18,7 +18,6 @@ class riscv_instr_base extends uvm_object; rand riscv_instr_group_t group; rand riscv_instr_format_t format; - rand bit [3:0] latency; rand riscv_instr_cateogry_t category; rand riscv_instr_name_t instr_name; rand bit [11:0] csr; @@ -40,27 +39,20 @@ class riscv_instr_base extends uvm_object; bit is_compressed; bit is_illegal_instr; bit is_hint_instr; - + bit has_imm; + bit has_rs1; + bit has_rs2; + bit has_rd; + bit [31:0] imm_mask = '1; string imm_str; string comment; string label; bit is_local_numeric_label; int idx = -1; - `uvm_object_utils_begin(riscv_instr_base) - `uvm_field_enum(riscv_instr_group_t, group, UVM_DEFAULT) - `uvm_field_enum(riscv_instr_format_t, format, UVM_DEFAULT) - `uvm_field_enum(riscv_instr_cateogry_t, category, UVM_DEFAULT) - `uvm_field_enum(riscv_instr_name_t, instr_name, UVM_DEFAULT) - `uvm_field_enum(riscv_reg_t, rs2, UVM_DEFAULT) - `uvm_field_enum(riscv_reg_t, rs1, UVM_DEFAULT) - `uvm_field_enum(riscv_reg_t, rd, UVM_DEFAULT) - `uvm_field_int(imm, UVM_DEFAULT) - `uvm_field_enum(imm_t, imm_type, UVM_DEFAULT) - `uvm_object_utils_end + `uvm_object_utils(riscv_instr_base) constraint default_c { - soft latency == 1; soft is_pseudo_instr == 0; instr_name != INVALID_INSTR; } @@ -182,6 +174,20 @@ class riscv_instr_base extends uvm_object; } } + constraint rvc_csr_c { + // Registers specified by the three-bit rs1’, rs2’, and rd’ fields of the CIW, CL, CS, + // and CB formats + if(format inside {CIW_FORMAT, CL_FORMAT, CS_FORMAT, CB_FORMAT}) { + rs1 inside {[S0:A5]}; + rs2 inside {[S0:A5]}; + rd inside {[S0:A5]}; + } + // C_ADDI16SP is only valid when rd == SP + if(instr_name == C_ADDI16SP) { + rd == SP; + } + } + //////////// RV32I instructions ////////////// // LOAD instructions `add_instr(LB, I_FORMAT, LOAD, RV32I) @@ -238,7 +244,7 @@ class riscv_instr_base extends uvm_object; `add_instr(URET, I_FORMAT, SYSTEM, RV32I) `add_instr(SRET, I_FORMAT, SYSTEM, RV32I) `add_instr(MRET, I_FORMAT, SYSTEM, RV32I) - `add_instr(WFI, I_FORMAT, SYSTEM, RV32I) + `add_instr(WFI, I_FORMAT, INTERRUPT, RV32I) // CSR instructions `add_instr(CSRRW, R_FORMAT, CSR, RV32I, UIMM) `add_instr(CSRRS, R_FORMAT, CSR, RV32I, UIMM) @@ -402,25 +408,93 @@ class riscv_instr_base extends uvm_object; `add_instr(SFENCE_VMA, R_FORMAT,SYNCH,RV32I) function void post_randomize(); + if (group inside {RV32C, RV64C, RV128C, RV32DC, RV32FC}) begin + is_compressed = 1'b1; + end + if (!(format inside {R_FORMAT, CR_FORMAT})) begin + imm_mask = '1; + imm_mask = imm_mask << imm_len; + has_imm = 1'b1; + mask_imm(); + if (imm_str == "") begin + update_imm_str(); + end + end + if (format inside {R_FORMAT, S_FORMAT, B_FORMAT, CSS_FORMAT, CS_FORMAT}) begin + has_rs2 = 1'b1; + end + if (!(format inside {J_FORMAT, U_FORMAT, CJ_FORMAT, CSS_FORMAT})) begin + has_rs1 = 1'b1; + end + if (!(format inside {CJ_FORMAT, CB_FORMAT, CS_FORMAT, CSS_FORMAT, B_FORMAT, S_FORMAT})) begin + has_rd = 1'b1; + end + endfunction + + function void mask_imm(); // Process the immediate value and sign extension - bit [31:0] imm_mask = '1; - imm_mask = imm_mask << imm_len; - if(imm_type inside {UIMM, NZUIMM}) begin + if (imm_type inside {UIMM, NZUIMM}) begin imm = imm & ~imm_mask; end else begin - if(imm[imm_len-1]) + if (imm[imm_len-1]) begin imm = imm | imm_mask; - else + end else begin imm = imm & ~imm_mask; + end end // Give a random value if imm is zero after masking unexpectedly if((imm_type inside {NZIMM, NZUIMM}) && (imm == '0)) begin imm = $urandom_range(2 ** (imm_len-1) - 1, 1); end - if (group inside {RV32C, RV64C, RV128C, RV32DC, RV32FC}) - is_compressed = 1'b1; - if(imm_str == "") - imm_str = $sformatf("%0d", $signed(imm)); + endfunction + + function void gen_rand_imm(); + if (!randomize(imm)) begin + `uvm_fatal(`gfn, "Cannot randomize imm") + end + mask_imm(); + update_imm_str(); + endfunction + + function void update_imm_str(); + imm_str = $sformatf("%0d", $signed(imm)); + endfunction + + function void set_imm(int imm); + this.imm = imm; + mask_imm(); + update_imm_str(); + endfunction + + function riscv_reg_t gen_rand_gpr(riscv_reg_t included_reg[] = {}, + riscv_reg_t excluded_reg[] = {}); + riscv_reg_t gpr; + `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(gpr, + if (is_compressed) { + gpr inside {[S0:A5]}; + } + if (excluded_reg.size() != 0) { + !(gpr inside {excluded_reg}); + } + if (included_reg.size() != 0) { + gpr inside {included_reg}; + }) + return gpr; + endfunction + + function void gen_rand_csr(bit illegal_csr_instr = 0, + privileged_mode_t privileged_mode = MACHINE_MODE); + if (illegal_csr_instr) begin + `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(csr, !(csr inside {implemented_csr});) + end else begin + // Use scratch register to avoid the side effect of modifying other privileged mode CSR. + if (privileged_mode == MACHINE_MODE) + csr = MSCRATCH; + else if (privileged_mode == SUPERVISOR_MODE) + csr = SSCRATCH; + else + csr = USCRATCH; + end endfunction function new(string name = ""); @@ -903,6 +977,30 @@ class riscv_instr_base extends uvm_object; end endfunction + // Copy the rand fields of the base instruction + virtual function void copy_base_instr(riscv_instr_base obj); + this.group = obj.group; + this.format = obj.format; + this.category = obj.category; + this.instr_name = obj.instr_name; + this.rs2 = obj.rs2; + this.rs1 = obj.rs1; + this.rd = obj.rd; + this.imm = obj.imm; + this.imm_type = obj.imm_type; + this.imm_len = obj.imm_len; + this.imm_mask = obj.imm_mask; + this.imm_str = obj.imm_str; + this.is_pseudo_instr = obj.is_pseudo_instr; + this.aq = obj.aq; + this.rl = obj.rl; + this.is_compressed = obj.is_compressed; + this.has_imm = obj.has_imm; + this.has_rs1 = obj.has_rs1; + this.has_rs2 = obj.has_rs2; + this.has_rd = obj.has_rd; + endfunction + endclass // Psuedo instructions are used to simplify assembly program writing 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 031ef7b0..7ce2bc92 100644 --- a/vendor/google_riscv-dv/src/riscv_instr_gen_config.sv +++ b/vendor/google_riscv-dv/src/riscv_instr_gen_config.sv @@ -69,6 +69,14 @@ class riscv_instr_gen_config extends uvm_object; bit check_misa_init_val = 1'b0; bit check_xstatus = 1'b1; + //----------------------------------------------------------------------------- + // Instruction list based on the config, generate by build_instruction_template + //----------------------------------------------------------------------------- + riscv_instr_base instr_template[riscv_instr_name_t]; + riscv_instr_name_t basic_instr[$]; + riscv_instr_name_t instr_group[riscv_instr_cateogry_t][$]; + riscv_instr_name_t instr_category[riscv_instr_cateogry_t][$]; + //----------------------------------------------------------------------------- // Command line options or control knobs //----------------------------------------------------------------------------- @@ -156,9 +164,9 @@ class riscv_instr_gen_config extends uvm_object; } else { main_program_instr_cnt + sub_program_instr_cnt.sum() == instr_cnt; } - main_program_instr_cnt inside {[1 : instr_cnt]}; + main_program_instr_cnt inside {[10 : instr_cnt]}; foreach(sub_program_instr_cnt[i]) { - sub_program_instr_cnt[i] inside {[1 : instr_cnt]}; + sub_program_instr_cnt[i] inside {[10 : instr_cnt]}; } // Disable sfence if the program is not boot to supervisor mode // If sfence exception is allowed, we can enable sfence instruction in any priviledged mode. @@ -247,8 +255,8 @@ class riscv_instr_gen_config extends uvm_object; foreach(loop_regs[i]) { !(loop_regs[i] inside {default_reserved_regs}); } - !(signature_addr_reg inside {default_reserved_regs, loop_regs}); - !(signature_data_reg inside {default_reserved_regs, loop_regs}); + !(signature_addr_reg inside {ZERO, default_reserved_regs, loop_regs}); + !(signature_data_reg inside {ZERO, default_reserved_regs, loop_regs}); signature_addr_reg != signature_data_reg; } @@ -430,4 +438,59 @@ class riscv_instr_gen_config extends uvm_object; end endfunction + // Build instruction template + virtual function void build_instruction_template(); + riscv_instr_name_t instr_name; + riscv_instr_name_t excluded_instr[$]; + get_excluded_instr(excluded_instr); + instr_name = instr_name.first; + do begin + riscv_instr_base instr; + if (!(instr_name inside {unsupported_instr, excluded_instr})) begin + instr = riscv_instr_base::type_id::create("instr"); + `DV_CHECK_RANDOMIZE_WITH_FATAL(instr, instr_name == local::instr_name;) + if (instr.group inside {supported_isa}) begin + `uvm_info(`gfn, $sformatf("Adding [%s] %s to the list", + instr.group.name(), instr.instr_name.name()), UVM_HIGH) + if (instr.category inside {SHIFT, ARITHMETIC, LOGICAL, COMPARE}) begin + basic_instr.push_back(instr_name); + end + instr_group[instr.group].push_back(instr_name); + instr_category[instr.category].push_back(instr_name); + instr_template[instr_name] = instr; + end + end + instr_name = instr_name.next; + end + while (instr_name != instr_name.first); + if (no_ebreak == 0) begin + basic_instr = {basic_instr, EBREAK}; + end + if (no_fence == 0) begin + basic_instr = {basic_instr, instr_category[SYNCH]}; + end + // TODO: Support CSR instruction in other mode + if ((no_csr_instr == 0) && (init_privileged_mode == MACHINE_MODE)) begin + basic_instr = {basic_instr, instr_category[CSR]}; + end + if (no_wfi == 0) begin + basic_instr = {basic_instr, WFI}; + end + endfunction + + virtual function void get_excluded_instr(ref riscv_instr_name_t excluded[$]); + excluded = {excluded, INVALID_INSTR}; + // Below instrutions will modify stack pointer, not allowed in normal instruction stream. + // It can be used in stack operation instruction stream. + excluded = {excluded, C_SWSP, C_SDSP, C_ADDI16SP}; + if (!enable_sfence) begin + excluded = {excluded, SFENCE_VMA}; + end + if (no_fence) begin + excluded = {excluded, FENCE, FENCEI, SFENCE_VMA}; + end + // TODO: Support C_ADDI4SPN + excluded = {excluded, C_ADDI4SPN}; + endfunction + endclass diff --git a/vendor/google_riscv-dv/src/riscv_instr_pkg.sv b/vendor/google_riscv-dv/src/riscv_instr_pkg.sv index 5e44ec68..d76ae8ad 100644 --- a/vendor/google_riscv-dv/src/riscv_instr_pkg.sv +++ b/vendor/google_riscv-dv/src/riscv_instr_pkg.sv @@ -800,7 +800,7 @@ package riscv_instr_pkg; end endfunction - + `include "riscv_instr_base.sv" `include "riscv_instr_gen_config.sv" `include "riscv_illegal_instr.sv" `include "riscv_reg.sv" @@ -811,7 +811,6 @@ package riscv_instr_pkg; `include "riscv_page_table_list.sv" `include "riscv_privileged_common_seq.sv" `include "riscv_callstack_gen.sv" - `include "riscv_instr_base.sv" `include "riscv_data_page_gen.sv" `include "riscv_rand_instr.sv" `include "riscv_instr_stream.sv" diff --git a/vendor/google_riscv-dv/src/riscv_instr_sequence.sv b/vendor/google_riscv-dv/src/riscv_instr_sequence.sv index 5da0fcdd..b29be226 100644 --- a/vendor/google_riscv-dv/src/riscv_instr_sequence.sv +++ b/vendor/google_riscv-dv/src/riscv_instr_sequence.sv @@ -48,7 +48,6 @@ class riscv_instr_sequence extends uvm_sequence; riscv_instr_stream directed_instr[]; // List of all directed instruction stream riscv_illegal_instr illegal_instr; // Illegal instruction generator int illegal_instr_pct; // Percentage of illegal instruction - bit enable_hint_instr; // Enable HINT instruction int hint_instr_pct; // Percentage of HINT instruction `uvm_object_utils(riscv_instr_sequence) @@ -71,8 +70,7 @@ class riscv_instr_sequence extends uvm_sequence; // considerably as the instruction stream becomes longer. The downside is we cannot specify // constraints between instructions. The way to solve it is to have a dedicated directed // instruction stream for such scenarios, like hazard sequence. - virtual function void gen_instr(bit is_main_program, bit enable_hint_instr = 1'b0, - bit no_branch = 1'b0); + virtual function void gen_instr(bit is_main_program, bit no_branch = 1'b0); this.is_main_program = is_main_program; instr_stream.cfg = cfg; instr_stream.initialize_instr_list(instr_cnt); @@ -80,8 +78,7 @@ class riscv_instr_sequence extends uvm_sequence; instr_stream.instr_list.size()), UVM_LOW) // Do not generate load/store instruction here // The load/store instruction will be inserted as directed instruction stream - instr_stream.gen_instr(.no_branch(no_branch), .no_load_store(1'b1), - .enable_hint_instr(enable_hint_instr)); + instr_stream.gen_instr(.no_branch(no_branch), .no_load_store(1'b1)); if(!is_main_program) begin gen_stack_enter_instr(); gen_stack_exit_instr(); @@ -238,9 +235,9 @@ class riscv_instr_sequence extends uvm_sequence; jump_instr.jump.rd == RA; }, "Cannot randomize jump_instr") - `uvm_info(get_full_name(), $sformatf("%0s -> %0s", - jump_instr.jump.instr_name.name(), label_name), UVM_HIGH) instr_stream.insert_instr_stream(jump_instr.instr_list); + `uvm_info(get_full_name(), $sformatf("%0s -> %0s...done", + jump_instr.jump.instr_name.name(), label_name), UVM_LOW) endfunction // Convert the instruction stream to the string format. diff --git a/vendor/google_riscv-dv/src/riscv_instr_stream.sv b/vendor/google_riscv-dv/src/riscv_instr_stream.sv index 77c21419..3441c7b8 100644 --- a/vendor/google_riscv-dv/src/riscv_instr_stream.sv +++ b/vendor/google_riscv-dv/src/riscv_instr_stream.sv @@ -23,6 +23,8 @@ class riscv_instr_stream extends uvm_object; rand riscv_instr_base instr_list[$]; int unsigned instr_cnt; string label = ""; + // User can specify a small group of available registers to generate various hazard condition + rand riscv_reg_t avail_regs[]; `uvm_object_utils(riscv_instr_stream) `uvm_object_new @@ -64,11 +66,27 @@ class riscv_instr_stream extends uvm_object; function void insert_instr_stream(riscv_instr_base new_instr[], int idx = -1, bit replace = 1'b0); int current_instr_cnt = instr_list.size(); int new_instr_cnt = new_instr.size(); + if(current_instr_cnt == 0) begin + instr_list = new_instr; + return; + end if(idx == -1) begin idx = $urandom_range(0, current_instr_cnt-1); - while(instr_list[idx].atomic) begin + repeat(10) begin + if (instr_list[idx].atomic) break; idx = $urandom_range(0, current_instr_cnt-1); end + if (instr_list[idx].atomic) begin + foreach (instr_list[i]) begin + if (!instr_list[i].atomic) begin + idx = i; + break; + end + end + if (instr_list[idx].atomic) begin + `uvm_fatal(`gfn, $sformatf("Cannot inject the instruction")) + end + end end else if((idx > current_instr_cnt) || (idx < 0)) begin `uvm_error(`gfn, $sformatf("Cannot insert instr stream at idx %0d", idx)) end @@ -129,10 +147,11 @@ class riscv_rand_instr_stream extends riscv_instr_stream; bit access_u_mode_mem = 1'b1; int max_load_store_offset; int max_data_page_id; + riscv_instr_name_t allowed_instr[$]; // Some additional reserved registers that should not be used as rd register // by this instruction stream - riscv_reg_t reserved_rd[]; + riscv_reg_t reserved_rd[]; constraint avoid_reserved_rd_c { if(reserved_rd.size() > 0) { @@ -146,14 +165,9 @@ class riscv_rand_instr_stream extends riscv_instr_stream; `uvm_object_new virtual function void create_instr_instance(); - riscv_rand_instr instr; - if(cfg == null) begin - `uvm_fatal(get_full_name(), "cfg object is null") - end + riscv_instr_base instr; for(int i = 0; i < instr_cnt; i++) begin - instr = riscv_rand_instr::type_id::create($sformatf("instr_%0d", i)); - instr.cfg = cfg; - instr.reserved_rd = reserved_rd; + instr = riscv_instr_base::type_id::create($sformatf("instr_%0d", i)); instr_list.push_back(instr); end endfunction @@ -168,18 +182,69 @@ class riscv_rand_instr_stream extends riscv_instr_stream; end endfunction - virtual function void gen_instr(bit no_branch = 1'b0, - bit no_load_store = 1'b1, - bit enable_hint_instr = 1'b0); + virtual function setup_allowed_instr(bit no_branch = 1'b0, bit no_load_store = 1'b1); + allowed_instr = cfg.basic_instr; + if (no_branch == 0) begin + allowed_instr = {allowed_instr, cfg.instr_category[BRANCH]}; + end + if (no_load_store == 0) begin + allowed_instr = {allowed_instr, cfg.instr_category[LOAD], cfg.instr_category[STORE]}; + end + endfunction + + virtual function void gen_instr(bit no_branch = 1'b0, bit no_load_store = 1'b1); + setup_allowed_instr(no_branch, no_load_store); foreach(instr_list[i]) begin - `DV_CHECK_RANDOMIZE_WITH_FATAL(instr_list[i], - // The last instruction cannot be branch instruction as there's no forward branch target. - if((i == instr_list.size() - 1) || no_branch) { - category != BRANCH; - } - if(no_load_store) { - !(category inside {LOAD, STORE}); - }) + randomize_instr(instr_list[i]); + end + // Do not allow branch instruction as the last instruction because there's no + // forward branch target + while (instr_list[$].category == BRANCH) begin + void'(instr_list.pop_back()); + if (instr_list.size() == 0) break; + end + endfunction + + function void randomize_instr(riscv_instr_base instr, + bit skip_rs1 = 1'b0, + bit skip_rs2 = 1'b0, + bit skip_rd = 1'b0, + bit skip_imm = 1'b0, + bit skip_csr = 1'b0); + riscv_instr_name_t instr_name; + `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(instr_name, + instr_name inside {allowed_instr};) + instr.copy_base_instr(cfg.instr_template[instr_name]); + `uvm_info(`gfn, $sformatf("%s: rs1:%0d, rs2:%0d, rd:%0d, imm:%0d", + instr.instr_name.name(), + instr.has_rs1, + instr.has_rs2, + instr.has_rd, + instr.has_imm), UVM_HIGH) + if (instr.has_imm && !skip_imm) begin + instr.gen_rand_imm(); + end + if (instr.has_rs1 && !skip_rs1) begin + if (instr.is_compressed) begin + // Compressed instruction could use the same register for rs1 and rd + instr.rs1 = instr.gen_rand_gpr( + .included_reg(avail_regs), + .excluded_reg({reserved_rd, cfg.reserved_regs})); + end else begin + instr.rs1 = instr.gen_rand_gpr(.included_reg(avail_regs)); + end + end + if (instr.has_rs2 && !skip_rs2) begin + instr.rs2 = instr.gen_rand_gpr(.included_reg(avail_regs)); + end + if (instr.has_rd && !skip_rd) begin + instr.rd = instr.gen_rand_gpr( + .included_reg(avail_regs), + .excluded_reg({reserved_rd, cfg.reserved_regs})); + end + if ((instr.category == CSR) && !skip_csr) begin + instr.gen_rand_csr(.privileged_mode(cfg.init_privileged_mode), + .illegal_csr_instr(cfg.enable_illegal_csr_instruction)); end endfunction diff --git a/vendor/google_riscv-dv/src/riscv_load_store_instr_lib.sv b/vendor/google_riscv-dv/src/riscv_load_store_instr_lib.sv index df789be3..f019616e 100644 --- a/vendor/google_riscv-dv/src/riscv_load_store_instr_lib.sv +++ b/vendor/google_riscv-dv/src/riscv_load_store_instr_lib.sv @@ -15,7 +15,6 @@ */ // Base class for all load/store instruction stream -// TODO: Support load/store from instruction section. class riscv_load_store_base_instr_stream extends riscv_directed_instr_stream; @@ -26,9 +25,6 @@ class riscv_load_store_base_instr_stream extends riscv_directed_instr_stream; rand int addr[]; rand int unsigned data_page_id; rand riscv_reg_t rs1_reg; - riscv_reg_t reserved_rd[$]; - // User can specify a small group of available registers to generate various hazard condition - rand riscv_reg_t avail_regs[]; `uvm_object_utils(riscv_load_store_base_instr_stream) @@ -58,11 +54,11 @@ class riscv_load_store_base_instr_stream extends riscv_directed_instr_stream; endfunction function void post_randomize(); - gen_load_store_instr(); // rs1 cannot be modified by other instructions if(!(rs1_reg inside {reserved_rd})) begin - reserved_rd.push_back(rs1_reg); + reserved_rd = {reserved_rd, rs1_reg}; end + gen_load_store_instr(); add_mixed_instr(); add_rs1_init_la_instr(); super.post_randomize(); @@ -87,23 +83,21 @@ class riscv_load_store_base_instr_stream extends riscv_directed_instr_stream; // Generate each load/store instruction virtual function void gen_load_store_instr(); bit enable_compressed_load_store; - riscv_rand_instr rand_instr; - riscv_instr_name_t allowed_instr[]; - if (rs1_reg inside {[S0 : A5]}) begin - enable_compressed_load_store = 1; - end + riscv_instr_base instr; if(avail_regs.size() > 0) begin `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(avail_regs, unique{avail_regs}; + avail_regs[0] inside {[S0 : A5]}; foreach(avail_regs[i]) { - !(avail_regs[i] inside {cfg.reserved_regs}); + !(avail_regs[i] inside {cfg.reserved_regs, reserved_rd}); }, "Cannot randomize avail_regs") end + if (rs1_reg inside {[S0 : A5]}) begin + enable_compressed_load_store = 1; + end foreach(addr[i]) begin - rand_instr = riscv_rand_instr::type_id::create("rand_instr"); - rand_instr.cfg = cfg; - rand_instr.reserved_rd = reserved_rd; + instr = riscv_instr_base::type_id::create("instr"); // Assign the allowed load/store instructions based on address alignment // This is done separately rather than a constraint to improve the randomization performance allowed_instr = {LB, LBU, SB}; @@ -143,38 +137,22 @@ class riscv_load_store_base_instr_stream extends riscv_directed_instr_stream; end end end - `DV_CHECK_RANDOMIZE_WITH_FATAL(rand_instr, - solve rs1 before rd; - rs1 == rs1_reg; - instr_name inside {allowed_instr}; - if(avail_regs.size() > 0) { - rd inside {avail_regs}; - } - if (num_load_store > 1) { - rd != rs1; - } - ) - rand_instr.process_load_store = 0; - rand_instr.imm_str = $sformatf("%0d", offset[i]); - instr_list.push_back(rand_instr); + randomize_instr(instr, .skip_rs1(1'b1), .skip_imm(1'b1)); + instr.rs1 = rs1_reg; + instr.set_imm(offset[i]); + instr.process_load_store = 0; + instr_list.push_back(instr); end endfunction // Insert some other instructions to mix with load/store instruction virtual function void add_mixed_instr(); - riscv_rand_instr rand_instr; + riscv_instr_base instr; + setup_allowed_instr(1, 1); for(int i = 0; i < num_mixed_instr; i ++) begin - rand_instr = riscv_rand_instr::type_id::create("rand_instr"); - rand_instr.cfg = cfg; - rand_instr.reserved_rd = reserved_rd; - `DV_CHECK_RANDOMIZE_WITH_FATAL(rand_instr, - if(avail_regs.size() > 0) { - rs1 inside {avail_regs}; - rd inside {avail_regs}; - } - !(category inside {LOAD, STORE, BRANCH, JUMP});, - "Cannot randomize instruction") - insert_instr(rand_instr); + instr = riscv_instr_base::type_id::create("instr"); + randomize_instr(instr); + insert_instr(instr); end endfunction @@ -337,7 +315,8 @@ class riscv_multi_page_load_store_instr_stream extends riscv_directed_instr_stre // Make sure each load/store sequence doesn't override the rs1 of other sequences. foreach(rs1_reg[j]) begin if(i != j) begin - load_store_instr_stream[i].reserved_rd.push_back(rs1_reg[j]); + load_store_instr_stream[i].reserved_rd = + {load_store_instr_stream[i].reserved_rd, rs1_reg[j]}; end end `DV_CHECK_RANDOMIZE_WITH_FATAL(load_store_instr_stream[i], diff --git a/vendor/google_riscv-dv/src/riscv_rand_instr.sv b/vendor/google_riscv-dv/src/riscv_rand_instr.sv index 3ec45d3a..b43f5fe4 100644 --- a/vendor/google_riscv-dv/src/riscv_rand_instr.sv +++ b/vendor/google_riscv-dv/src/riscv_rand_instr.sv @@ -68,20 +68,6 @@ class riscv_rand_instr extends riscv_instr_base; instr_name != C_ADDI4SPN; } - constraint rvc_csr_c { - // Registers specified by the three-bit rs1’, rs2’, and rd’ fields of the CIW, CL, CS, - // and CB formats - if(format inside {CIW_FORMAT, CL_FORMAT, CS_FORMAT, CB_FORMAT}) { - rs1 inside {[S0:A5]}; - rs2 inside {[S0:A5]}; - rd inside {[S0:A5]}; - } - // C_ADDI16SP is only valid when rd == SP - if(instr_name == C_ADDI16SP) { - rd == SP; - } - } - constraint constraint_cfg_knob_c { if(cfg.no_ebreak) { instr_name != EBREAK; diff --git a/vendor/google_riscv-dv/test/riscv_instr_base_test.sv b/vendor/google_riscv-dv/test/riscv_instr_base_test.sv index 99729e97..f1d81863 100644 --- a/vendor/google_riscv-dv/test/riscv_instr_base_test.sv +++ b/vendor/google_riscv-dv/test/riscv_instr_base_test.sv @@ -99,6 +99,7 @@ class riscv_instr_base_test extends uvm_test; test_name = $sformatf("%0s.%0d.S", asm_file_name, i); apply_directed_instr(); `uvm_info(`gfn, "All directed instruction is applied", UVM_LOW) + cfg.build_instruction_template(); asm_gen.gen_program(); asm_gen.gen_test_file(test_name); end diff --git a/vendor/google_riscv-dv/yaml/testlist.yaml b/vendor/google_riscv-dv/yaml/testlist.yaml index a6bd9f6e..22ce9186 100644 --- a/vendor/google_riscv-dv/yaml/testlist.yaml +++ b/vendor/google_riscv-dv/yaml/testlist.yaml @@ -80,10 +80,11 @@ +directed_instr_5=riscv_multi_page_load_store_instr_stream,4 rtl_test: core_base_test +# TODO: Temporarily disable this as compiler seems to generate compressed instruction with rv64im - test: riscv_non_compressed_instr_test description: > Random instruction test without compressed instructions - iterations: 2 + iterations: 0 gen_test: riscv_rand_instr_test gen_opts: > +march=RV32I,RV32M,RV64I,RV64M