mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-23 21:39:13 -04:00
Update google_riscv-dv to 102791d (#266)
Update code from upstream repository https://github.com/google/riscv- dv to revision 102791dbb7eb992d3bc22336d2e4e5f0d688e761 * Merge pull request #104 from google/flow (taoliug) * Remove debug print (Tao Liu) * Merge pull request #103 from google/flow (taoliug) * Improve randomization performance (Tao Liu) * Merge pull request #102 from udinator/debug (taoliug) * Prevent x0 from being used as load adress register (Udi)
This commit is contained in:
parent
7eee24c094
commit
6a88d1ed03
14 changed files with 333 additions and 125 deletions
2
vendor/google_riscv-dv.lock.hjson
vendored
2
vendor/google_riscv-dv.lock.hjson
vendored
|
@ -9,6 +9,6 @@
|
|||
upstream:
|
||||
{
|
||||
url: https://github.com/google/riscv-dv
|
||||
rev: faddfa49f456f3f8ef8c4231865994b7b13aa96d
|
||||
rev: 102791dbb7eb992d3bc22336d2e4e5f0d688e761
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ def process_spike_sim_log(spike_log, csv):
|
|||
INSTR_RE = re.compile(r"(?P<instr>[a-z\.]+?)(\s+?)(?P<operand>.*)")
|
||||
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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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});
|
||||
|
|
146
vendor/google_riscv-dv/src/riscv_instr_base.sv
vendored
146
vendor/google_riscv-dv/src/riscv_instr_base.sv
vendored
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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.
|
||||
|
|
105
vendor/google_riscv-dv/src/riscv_instr_stream.sv
vendored
105
vendor/google_riscv-dv/src/riscv_instr_stream.sv
vendored
|
@ -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
|
||||
|
||||
|
|
|
@ -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],
|
||||
|
|
14
vendor/google_riscv-dv/src/riscv_rand_instr.sv
vendored
14
vendor/google_riscv-dv/src/riscv_rand_instr.sv
vendored
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
3
vendor/google_riscv-dv/yaml/testlist.yaml
vendored
3
vendor/google_riscv-dv/yaml/testlist.yaml
vendored
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue