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:
taoliug 2019-08-27 11:23:31 -07:00 committed by GitHub
parent 7eee24c094
commit 6a88d1ed03
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 333 additions and 125 deletions

View file

@ -9,6 +9,6 @@
upstream:
{
url: https://github.com/google/riscv-dv
rev: faddfa49f456f3f8ef8c4231865994b7b13aa96d
rev: 102791dbb7eb992d3bc22336d2e4e5f0d688e761
}
}

View file

@ -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

View file

@ -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();

View file

@ -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();

View file

@ -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});

View file

@ -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

View file

@ -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

View file

@ -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"

View file

@ -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.

View file

@ -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

View file

@ -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],

View file

@ -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;

View file

@ -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

View file

@ -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