mirror of
https://github.com/openhwgroup/cve2.git
synced 2025-04-22 04:57:25 -04:00
Update google_riscv-dv to 73274f2 (#254)
Update code from upstream repository https://github.com/google/riscv- dv to revision 73274f227000f1316cb201a8503aad437e427948 * Merge pull request #88 from google/dev (taoliug) * Fix spike log processing issue (Tao Liu) * Merge pull request #87 from google/dev (udinator) * Add vectored interrupt support (Tao Liu) * Merge pull request #85 from udinator/debug (udinator) * Add debug sub-programs, and extra options to generator (Udi) * Merge pull request #84 from imphil/fix-apache-urls (taoliug) * Fix license URLs in comments (Philipp Wagner)
This commit is contained in:
parent
9311b25fdb
commit
a752277247
11 changed files with 263 additions and 110 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: 7cce16c0a212c8713a82516fbf8f2570d3dc4505
|
||||
rev: 73274f227000f1316cb201a8503aad437e427948
|
||||
}
|
||||
}
|
||||
|
|
39
vendor/google_riscv-dv/README.md
vendored
39
vendor/google_riscv-dv/README.md
vendored
|
@ -186,24 +186,27 @@ riscv_instr_group_t supported_isa[] = {RV32I, RV32M, RV64I, RV64M};
|
|||
|
||||
### Runtime options of the generator
|
||||
|
||||
| Option | Description | Default |
|
||||
|:---------------------------:|:-----------------------------------------------:|:-------:|
|
||||
| num_of_tests | Number of assembly tests to be generated | 1 |
|
||||
| num_of_sub_program | Number of sub-program in one test | 5 |
|
||||
| instr_cnt | Instruction count per test | 200 |
|
||||
| enable_page_table_exception | Enable page table exception | 0 |
|
||||
| no_ebreak | Disable ebreak instruction | 1 |
|
||||
| no_wfi | Disable WFI instruction | 1 |
|
||||
| no_branch_jump | Disable branch/jump instruction | 0 |
|
||||
| no_load_store | Disable load/store instruction | 0 |
|
||||
| no_csr_instr | Disable CSR instruction | 0 |
|
||||
| no_fence | Disable fence instruction | 0 |
|
||||
| enable_illegal_instruction | Enable illegal instructions | 0 |
|
||||
| enable_hint_instruction | Enable HINT instruction | 0 |
|
||||
| boot_mode | m:Machine mode, s:Supervisor mode, u:User mode | m |
|
||||
| no_directed_instr | Disable directed instruction stream | 0 |
|
||||
| enable_interrupt | Enable MStatus.MIE, used in interrupt test | 0 |
|
||||
| empty_debug_section | Disables randomized debug_rom section | 0 |
|
||||
| Option | Description | Default |
|
||||
|:---------------------------:|:-------------------------------------------------:|:-------:|
|
||||
| num_of_tests | Number of assembly tests to be generated | 1 |
|
||||
| num_of_sub_program | Number of sub-program in one test | 5 |
|
||||
| instr_cnt | Instruction count per test | 200 |
|
||||
| enable_page_table_exception | Enable page table exception | 0 |
|
||||
| no_ebreak | Disable ebreak instruction | 1 |
|
||||
| no_wfi | Disable WFI instruction | 1 |
|
||||
| no_branch_jump | Disable branch/jump instruction | 0 |
|
||||
| no_load_store | Disable load/store instruction | 0 |
|
||||
| no_csr_instr | Disable CSR instruction | 0 |
|
||||
| no_fence | Disable fence instruction | 0 |
|
||||
| enable_illegal_instruction | Enable illegal instructions | 0 |
|
||||
| enable_hint_instruction | Enable HINT instruction | 0 |
|
||||
| boot_mode | m:Machine mode, s:Supervisor mode, u:User mode | m |
|
||||
| no_directed_instr | Disable directed instruction stream | 0 |
|
||||
| require_signature_addr | Set to 1 if test needs to talk to testbench | 0 |
|
||||
| signature_addr | Write to this addr to send data to testbench | 0 |
|
||||
| enable_interrupt | Enable MStatus.MIE, used in interrupt test | 0 |
|
||||
| gen_debug_section | Disables randomized debug_rom section | 0 |
|
||||
| num_debug_sub_program | Number of debug sub-programs in test | 0 |
|
||||
|
||||
|
||||
### Setup Privileged CSR description
|
||||
|
|
|
@ -65,6 +65,9 @@ def process_spike_sim_log(spike_log, csv):
|
|||
rv_instr_trace.instr_str = spike_instr
|
||||
rv_instr_trace.addr = m.group("addr")
|
||||
rv_instr_trace.binary = m.group("bin")
|
||||
if spike_instr == "wfi":
|
||||
trace_csv.write_trace_entry(rv_instr_trace)
|
||||
continue
|
||||
nextline = f.readline()
|
||||
if nextline != "":
|
||||
m = RD_RE.search(nextline)
|
||||
|
|
|
@ -32,6 +32,9 @@ riscv_instr_name_t unsupported_instr[];
|
|||
// ISA supported by the processor
|
||||
riscv_instr_group_t supported_isa[$] = {RV32I, RV32M, RV64I, RV64M, RV32C, RV64C};
|
||||
|
||||
// Interrupt mode support
|
||||
mtvec_mode_t supported_interrupt_mode[$] = {DIRECT, VECTORED};
|
||||
|
||||
// Debug mode support
|
||||
bit support_debug_mode = 0;
|
||||
|
||||
|
|
245
vendor/google_riscv-dv/src/riscv_asm_program_gen.sv
vendored
245
vendor/google_riscv-dv/src/riscv_asm_program_gen.sv
vendored
|
@ -32,6 +32,7 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
// Program in binary format, stored in the data section, used to inject illegal/HINT instruction
|
||||
riscv_instr_sequence bin_program;
|
||||
riscv_instr_sequence debug_program;
|
||||
riscv_instr_sequence debug_sub_program[];
|
||||
string instr_binary[$];
|
||||
// Kernel programs
|
||||
// These programs are called in the interrupt/exception handling routine based on the privileged
|
||||
|
@ -96,23 +97,7 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
// Init section
|
||||
gen_init_section();
|
||||
// Generate sub program
|
||||
if(cfg.num_of_sub_program > 0) begin
|
||||
sub_program = new[cfg.num_of_sub_program];
|
||||
foreach(sub_program[i]) begin
|
||||
sub_program[i] = riscv_instr_sequence::type_id::create($sformatf("sub_%0d",i+1));
|
||||
sub_program[i].instr_cnt = cfg.sub_program_instr_cnt[i];
|
||||
sub_program[i].is_debug_program = 0;
|
||||
generate_directed_instr_stream(.label(sub_program[i].get_name()),
|
||||
.original_instr_cnt(sub_program[i].instr_cnt),
|
||||
.min_insert_cnt(0),
|
||||
.instr_stream(sub_program[i].directed_instr));
|
||||
sub_program[i].label_name = sub_program[i].get_name();
|
||||
sub_program[i].cfg = cfg;
|
||||
`DV_CHECK_RANDOMIZE_FATAL(sub_program[i])
|
||||
sub_program[i].gen_instr(0);
|
||||
sub_program_name.push_back(sub_program[i].label_name);
|
||||
end
|
||||
end
|
||||
gen_sub_program(sub_program, sub_program_name, cfg.num_of_sub_program);
|
||||
// Generate main program
|
||||
main_program = riscv_instr_sequence::type_id::create("main_program");
|
||||
main_program.instr_cnt = cfg.main_program_instr_cnt;
|
||||
|
@ -126,30 +111,7 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
`DV_CHECK_RANDOMIZE_FATAL(main_program)
|
||||
main_program.gen_instr(1);
|
||||
// Setup jump instruction among main program and sub programs
|
||||
if(cfg.num_of_sub_program != 0) begin
|
||||
callstack_gen = riscv_callstack_gen::type_id::create("callstack_gen");
|
||||
callstack_gen.init(cfg.num_of_sub_program+1);
|
||||
`uvm_info(get_full_name(), "Randomizing call stack", UVM_LOW)
|
||||
if(callstack_gen.randomize()) begin
|
||||
program_id_t pid;
|
||||
int idx;
|
||||
// Insert the jump instruction based on the call stack
|
||||
foreach(callstack_gen.program_h[i]) begin
|
||||
foreach(callstack_gen.program_h[i].sub_program_id[j]) begin
|
||||
idx++;
|
||||
pid = callstack_gen.program_h[i].sub_program_id[j] - 1;
|
||||
`uvm_info(get_full_name(), $sformatf(
|
||||
"Gen jump instr %0d -> sub[%0d] %0d", i, j, pid+1), UVM_HIGH)
|
||||
if(i == 0)
|
||||
main_program.insert_jump_instr(sub_program_name[pid], idx);
|
||||
else
|
||||
sub_program[i-1].insert_jump_instr(sub_program_name[pid], idx);
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
`uvm_fatal(get_full_name(), "Failed to generate callstack")
|
||||
end
|
||||
end
|
||||
gen_callstack(main_program, sub_program, sub_program_name, cfg.num_of_sub_program);
|
||||
if (bin_program != null) begin
|
||||
main_program.insert_jump_instr("sub_bin", 0);
|
||||
end
|
||||
|
@ -159,12 +121,7 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
// Test done section
|
||||
gen_test_done();
|
||||
// Shuffle the sub programs and insert to the instruction stream
|
||||
sub_program.shuffle();
|
||||
foreach(sub_program[i]) begin
|
||||
sub_program[i].post_process_instr();
|
||||
sub_program[i].generate_instr_stream();
|
||||
instr_stream = {instr_stream, sub_program[i].instr_string_list};
|
||||
end
|
||||
insert_sub_program(sub_program, instr_stream);
|
||||
// Reserve some space to copy instruction from data section
|
||||
if (instr_binary.size() > 0) begin
|
||||
instr_stream.push_back(".align 2");
|
||||
|
@ -179,9 +136,9 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
// Program end
|
||||
gen_program_end();
|
||||
// Generate debug rom section
|
||||
gen_debug_mode_section();
|
||||
gen_debug_rom();
|
||||
// Generate debug mode exception handler
|
||||
gen_debug_exception_section();
|
||||
gen_debug_exception_handler();
|
||||
// Starting point of data section
|
||||
gen_data_page_begin();
|
||||
// Generate the sub program in binary format
|
||||
|
@ -253,6 +210,79 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
instr_stream = {instr_stream, seq.instr_string_list};
|
||||
endfunction
|
||||
|
||||
//---------------------------------------------------------------------------------------
|
||||
// Generate any subprograms and set up the callstack
|
||||
//---------------------------------------------------------------------------------------
|
||||
|
||||
virtual function void gen_sub_program(ref riscv_instr_sequence sub_program[],
|
||||
ref string sub_program_name[$],
|
||||
input int num_sub_program,
|
||||
bit is_debug = 1'b0,
|
||||
string prefix = "sub");
|
||||
if(num_sub_program > 0) begin
|
||||
sub_program = new[num_sub_program];
|
||||
foreach(sub_program[i]) begin
|
||||
sub_program[i] = riscv_instr_sequence::type_id::create($sformatf("%s_%0d",prefix,i+1));
|
||||
`uvm_info(`gfn, $sformatf("sub program name: %s", prefix), UVM_LOW)
|
||||
sub_program[i].is_debug_program = is_debug;
|
||||
if (is_debug) begin
|
||||
sub_program[i].instr_cnt = cfg.debug_sub_program_instr_cnt[i];
|
||||
end else begin
|
||||
sub_program[i].instr_cnt = cfg.sub_program_instr_cnt[i];
|
||||
end
|
||||
generate_directed_instr_stream(.label(sub_program[i].get_name()),
|
||||
.original_instr_cnt(sub_program[i].instr_cnt),
|
||||
.min_insert_cnt(0),
|
||||
.instr_stream(sub_program[i].directed_instr));
|
||||
sub_program[i].label_name = sub_program[i].get_name();
|
||||
sub_program[i].cfg = cfg;
|
||||
`DV_CHECK_RANDOMIZE_FATAL(sub_program[i])
|
||||
sub_program[i].gen_instr(0);
|
||||
sub_program_name.push_back(sub_program[i].label_name);
|
||||
end
|
||||
end
|
||||
endfunction
|
||||
|
||||
virtual function void gen_callstack(riscv_instr_sequence main_program,
|
||||
ref riscv_instr_sequence sub_program[],
|
||||
ref string sub_program_name[$],
|
||||
input int num_sub_program);
|
||||
if(num_sub_program != 0) begin
|
||||
callstack_gen = riscv_callstack_gen::type_id::create("callstack_gen");
|
||||
callstack_gen.init(num_sub_program+1);
|
||||
`uvm_info(get_full_name(), "Randomizing call stack", UVM_LOW)
|
||||
if(callstack_gen.randomize()) begin
|
||||
program_id_t pid;
|
||||
int idx;
|
||||
// Insert the jump instruction based on the call stack
|
||||
foreach(callstack_gen.program_h[i]) begin
|
||||
foreach(callstack_gen.program_h[i].sub_program_id[j]) begin
|
||||
idx++;
|
||||
pid = callstack_gen.program_h[i].sub_program_id[j] - 1;
|
||||
`uvm_info(get_full_name(), $sformatf(
|
||||
"Gen jump instr %0d -> sub[%0d] %0d", i, j, pid+1), UVM_HIGH)
|
||||
if(i == 0)
|
||||
main_program.insert_jump_instr(sub_program_name[pid], idx);
|
||||
else
|
||||
sub_program[i-1].insert_jump_instr(sub_program_name[pid], idx);
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
`uvm_fatal(get_full_name(), "Failed to generate callstack")
|
||||
end
|
||||
end
|
||||
endfunction
|
||||
|
||||
virtual function void insert_sub_program(ref riscv_instr_sequence sub_program[],
|
||||
ref string instr_list[$]);
|
||||
sub_program.shuffle();
|
||||
foreach(sub_program[i]) begin
|
||||
sub_program[i].post_process_instr();
|
||||
sub_program[i].generate_instr_stream();
|
||||
instr_list = {instr_list, sub_program[i].instr_string_list};
|
||||
end
|
||||
endfunction
|
||||
|
||||
//---------------------------------------------------------------------------------------
|
||||
// Major sections - init, stack, data, test_done etc.
|
||||
//---------------------------------------------------------------------------------------
|
||||
|
@ -327,6 +357,7 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
str = {indent, "la sp, _user_stack_end"};
|
||||
setup_misa();
|
||||
instr_stream.push_back(str);
|
||||
core_is_initialized();
|
||||
// Copy the instruction from data section to instruction section
|
||||
if (instr_binary.size() > 0) begin
|
||||
instr_stream.push_back({indent, "la x31, instr_bin"});
|
||||
|
@ -363,6 +394,24 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
instr_stream.push_back({indent, "csrw misa, x15"});
|
||||
endfunction
|
||||
|
||||
// Write to the signature_addr with values to indicate to the core testbench
|
||||
// that is safe to start sending interrupt and debug stimulus
|
||||
virtual function void core_is_initialized();
|
||||
if (cfg.require_signature_addr) begin
|
||||
if (cfg.signature_addr != 32'hdead_beef) begin
|
||||
string str;
|
||||
str = {indent, $sformatf("li x5, 0x%0h", cfg.signature_addr)};
|
||||
instr_stream.push_back(str);
|
||||
str = {indent, $sformatf("li x6, 0x%0h", riscv_instr_pkg::CORE_INITIALIZATION_DONE)};
|
||||
instr_stream.push_back(str);
|
||||
str = {indent, "sw x6, 0(x5)"};
|
||||
instr_stream.push_back(str);
|
||||
end else begin
|
||||
`uvm_fatal(`gfn, "The signature_addr is not properly configured!")
|
||||
end
|
||||
end
|
||||
endfunction
|
||||
|
||||
// Initialize general purpose registers with random value
|
||||
virtual function void init_gpr();
|
||||
string str;
|
||||
|
@ -531,9 +580,9 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
USER_MODE: trap_vec_reg = UTVEC;
|
||||
endcase
|
||||
// Skip utvec init if trap delegation to u_mode is not supported
|
||||
// TODO: For now the default mode is direct mode, needs to support vector mode
|
||||
if((riscv_instr_pkg::supported_privileged_mode[i] == USER_MODE) && !riscv_instr_pkg::support_umode_trap) continue;
|
||||
if(riscv_instr_pkg::supported_privileged_mode[i] < cfg.init_privileged_mode) continue;
|
||||
if ((riscv_instr_pkg::supported_privileged_mode[i] == USER_MODE) &&
|
||||
!riscv_instr_pkg::support_umode_trap) continue;
|
||||
if (riscv_instr_pkg::supported_privileged_mode[i] < cfg.init_privileged_mode) continue;
|
||||
tvec_name = trap_vec_reg.name();
|
||||
instr = {instr, $sformatf("la a0, %0s_handler", tvec_name.tolower())};
|
||||
if(SATP_MODE != BARE && riscv_instr_pkg::supported_privileged_mode[i] != MACHINE_MODE) begin
|
||||
|
@ -544,6 +593,7 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
$sformatf("slli a0, a0, %0d", XLEN - 20),
|
||||
$sformatf("srli a0, a0, %0d", XLEN - 20)};
|
||||
end
|
||||
instr = {instr, $sformatf("ori a0, a0, %0d", cfg.mtvec_mode)};
|
||||
instr = {instr, $sformatf("csrw 0x%0x, a0 # %0s", trap_vec_reg, trap_vec_reg.name())};
|
||||
end
|
||||
gen_section("trap_vec_init", instr);
|
||||
|
@ -595,21 +645,32 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
bit is_interrupt = 'b1;
|
||||
string tvec_name;
|
||||
string instr[$];
|
||||
// Push user mode GPR to kernel stack before executing exception handling, this is to avoid
|
||||
// exception handling routine modify user program state unexpectedly
|
||||
push_gpr_to_kernel_stack(status, scratch, cfg.mstatus_mprv, instr);
|
||||
// Checking xStatus can be optional if ISS (like spike) has different implementation of certain
|
||||
// fields compared with the RTL processor.
|
||||
if (cfg.check_xstatus) begin
|
||||
instr = {instr, $sformatf("csrr x15, 0x%0x # %0s", status, status.name())};
|
||||
// The trap handler will occupy one 4KB page, it will be allocated one entry in the page table
|
||||
// with a specific privileged mode.
|
||||
instr_stream.push_back(".align 12");
|
||||
if (cfg.mtvec_mode == VECTORED) begin
|
||||
gen_interrupt_vector_table(mode, status, cause, scratch, instr);
|
||||
end else begin
|
||||
// Push user mode GPR to kernel stack before executing exception handling, this is to avoid
|
||||
// exception handling routine modify user program state unexpectedly
|
||||
push_gpr_to_kernel_stack(status, scratch, cfg.mstatus_mprv, instr);
|
||||
// Checking xStatus can be optional if ISS (like spike) has different implementation of certain
|
||||
// fields compared with the RTL processor.
|
||||
if (cfg.check_xstatus) begin
|
||||
instr = {instr, $sformatf("csrr x15, 0x%0x # %0s", status, status.name())};
|
||||
end
|
||||
instr = {instr,
|
||||
// Use scratch CSR to save a GPR value
|
||||
// Check if the exception is caused by an interrupt, if yes, jump to interrupt handler
|
||||
// Interrupt is indicated by xCause[XLEN-1]
|
||||
$sformatf("csrr a1, 0x%0x # %0s", cause, cause.name()),
|
||||
$sformatf("srli a1, a1, %0d", XLEN-1),
|
||||
$sformatf("bne a1, x0, %0smode_intr_handler", mode)};
|
||||
end
|
||||
instr = {instr,
|
||||
// Use scratch CSR to save a GPR value
|
||||
// Check if the exception is caused by an interrupt, if yes, jump to interrupt handler
|
||||
// Interrupt is indicated by xCause[XLEN-1]
|
||||
$sformatf("csrr a1, 0x%0x # %0s", cause, cause.name()),
|
||||
$sformatf("srli a1, a1, %0d", XLEN-1),
|
||||
$sformatf("bne a1, x0, %0smode_intr_handler", mode),
|
||||
tvec_name = tvec.name();
|
||||
gen_section($sformatf("%0s_handler", tvec_name.tolower()), instr);
|
||||
// Exception handler
|
||||
instr = {"",
|
||||
// The trap is caused by an exception, read back xCAUSE, xEPC to see if these
|
||||
// CSR values are set properly. The checking is done by comparing against the log
|
||||
// generated by ISA simulator (spike).
|
||||
|
@ -645,13 +706,41 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
$sformatf("csrr x30, 0x%0x # %0s", tval, tval.name()),
|
||||
"1: jal x1, test_done "
|
||||
};
|
||||
gen_section($sformatf("%0smode_exception_handler", mode), instr);
|
||||
endfunction
|
||||
|
||||
// The trap handler will occupy one 4KB page, it will be allocated one entry in the page table
|
||||
// with a specific privileged mode.
|
||||
instr_stream.push_back(".align 12");
|
||||
tvec_name = tvec.name();
|
||||
gen_section($sformatf("%0s_handler", tvec_name.tolower()), instr);
|
||||
// Generate for interrupt vector table
|
||||
virtual function void gen_interrupt_vector_table(string mode,
|
||||
privileged_reg_t status,
|
||||
privileged_reg_t cause,
|
||||
privileged_reg_t scratch,
|
||||
ref string instr[$]);
|
||||
|
||||
// In vector mode, the BASE address is shared between interrupt 0 and exception handling.
|
||||
// When vectored interrupts are enabled, interrupt cause 0, which corresponds to user-mode
|
||||
// software interrupts, are vectored to the same location as synchronous exceptions. This
|
||||
// ambiguity does not arise in practice, since user-mode software interrupts are either
|
||||
// disabled or delegated
|
||||
instr = {instr, ".option norvc;",
|
||||
$sformatf("j %0smode_exception_handler", mode)};
|
||||
// Redirect the interrupt to the corresponding interrupt handler
|
||||
for (int i = 1; i < 16; i++) begin
|
||||
instr.push_back($sformatf("j intr_vector_%0d", i));
|
||||
end
|
||||
instr = {instr, ".option rvc;"};
|
||||
for (int i = 1; i < 16; i++) begin
|
||||
string intr_handler[$];
|
||||
push_gpr_to_kernel_stack(status, scratch, cfg.mstatus_mprv, intr_handler);
|
||||
intr_handler = {intr_handler,
|
||||
$sformatf("csrr a1, 0x%0x # %0s", cause, cause.name()),
|
||||
// Terminate the test if xCause[31] != 0 (indicating exception)
|
||||
$sformatf("bltz a1, 1f"),
|
||||
// TODO(taliu) write xCause to the signature address
|
||||
// Jump to commmon interrupt handling routine
|
||||
$sformatf("j %0smode_intr_handler", mode),
|
||||
"1: j test_done"};
|
||||
gen_section($sformatf("intr_vector_%0d", i), intr_handler);
|
||||
end
|
||||
endfunction
|
||||
|
||||
// ECALL trap handler
|
||||
|
@ -932,21 +1021,26 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
|
||||
// Generate the program in the debug ROM
|
||||
// Processor will fetch instruction from here upon receiving debug request from debug module
|
||||
virtual function void gen_debug_mode_section();
|
||||
virtual function void gen_debug_rom();
|
||||
string push_gpr[$];
|
||||
string pop_gpr[$];
|
||||
string instr[$];
|
||||
string dret;
|
||||
string debug_sub_program_name[$] = {};
|
||||
if (riscv_instr_pkg::support_debug_mode) begin
|
||||
// The main debug rom
|
||||
if (!cfg.empty_debug_section) begin
|
||||
if (cfg.gen_debug_section) begin
|
||||
gen_sub_program(debug_sub_program, debug_sub_program_name,
|
||||
cfg.num_debug_sub_program, 1'b1, "debug_sub");
|
||||
debug_program = riscv_instr_sequence::type_id::create("debug_program");
|
||||
debug_program.instr_cnt = cfg.debug_program_instr_cnt;
|
||||
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'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();
|
||||
debug_program.generate_instr_stream(.no_label(1'b1));
|
||||
// Need to save off GPRs to avoid modifying program flow
|
||||
|
@ -955,6 +1049,7 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, pop_gpr);
|
||||
format_section(pop_gpr);
|
||||
instr = {push_gpr, debug_program.instr_string_list, pop_gpr};
|
||||
insert_sub_program(debug_sub_program, instr_stream);
|
||||
end
|
||||
dret = {format_string(" ", LABEL_STR_LEN), "dret"};
|
||||
instr = {instr, dret};
|
||||
|
@ -963,7 +1058,7 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
endfunction
|
||||
|
||||
// Generate exception handling routine for debug ROM
|
||||
virtual function void gen_debug_exception_section();
|
||||
virtual function void gen_debug_exception_handler();
|
||||
if (riscv_instr_pkg::support_debug_mode) begin
|
||||
string instr[];
|
||||
instr = {"dret"};
|
||||
|
|
|
@ -33,6 +33,9 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
// Instruction count of the debug rom
|
||||
rand int debug_program_instr_cnt;
|
||||
|
||||
// Instruction count of debug sub-programs
|
||||
rand int debug_sub_program_instr_cnt[];
|
||||
|
||||
// Pattern of data section: RAND_DATA, ALL_ZERO, INCR_VAL
|
||||
rand data_pattern_t data_page_pattern;
|
||||
|
||||
|
@ -55,6 +58,7 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
rand bit mstatus_mxr;
|
||||
rand bit mstatus_sum;
|
||||
rand bit mstatus_tvm;
|
||||
rand mtvec_mode_t mtvec_mode;
|
||||
|
||||
// Enable sfence.vma instruction
|
||||
rand bit enable_sfence;
|
||||
|
@ -65,12 +69,6 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
bit check_misa_init_val = 1'b0;
|
||||
bit check_xstatus = 1'b1;
|
||||
|
||||
// Enable a full or empty debug_rom section.
|
||||
// Full debug_rom will contain random instruction streams.
|
||||
// Empty debug_rom will contain just dret instruction and will return immediately.
|
||||
// Will be empty by default.
|
||||
bit empty_debug_section = 1'b0;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Command line options or control knobs
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -111,6 +109,18 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
bit force_m_delegation = 0;
|
||||
bit force_s_delegation = 0;
|
||||
bit support_supervisor_mode;
|
||||
// "Memory mapped" address that when written to will indicate some event to
|
||||
// the testbench - testbench will take action based on the value written
|
||||
int signature_addr = 32'hdead_beef;
|
||||
bit require_signature_addr = 1'b0;
|
||||
bit gen_debug_section = 1'b0;
|
||||
// Enable a full or empty debug_rom section.
|
||||
// Full debug_rom will contain random instruction streams.
|
||||
// Empty debug_rom will contain just dret instruction and will return immediately.
|
||||
// Will be empty by default.
|
||||
bit empty_debug_section = 1'b0;
|
||||
// Number of sub programs in the debug rom
|
||||
int num_debug_sub_program = 0;
|
||||
// Stack space allocated to each program, need to be enough to store necessary context
|
||||
// Example: RA, SP, T0, loop registers
|
||||
int min_stack_len_per_program = 10 * (XLEN/8);
|
||||
|
@ -132,13 +142,19 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
|
||||
constraint default_c {
|
||||
sub_program_instr_cnt.size() == num_of_sub_program;
|
||||
debug_sub_program_instr_cnt.size() == num_debug_sub_program;
|
||||
if (riscv_instr_pkg::support_debug_mode) {
|
||||
main_program_instr_cnt + sub_program_instr_cnt.sum() + debug_program_instr_cnt == instr_cnt;
|
||||
main_program_instr_cnt + sub_program_instr_cnt.sum()
|
||||
+ debug_program_instr_cnt
|
||||
+ debug_sub_program_instr_cnt.sum() == instr_cnt;
|
||||
debug_program_instr_cnt inside {[100 : 300]};
|
||||
foreach(debug_sub_program_instr_cnt[i]) {
|
||||
debug_sub_program_instr_cnt[i] inside {[100 : 300]};
|
||||
}
|
||||
} else {
|
||||
main_program_instr_cnt + sub_program_instr_cnt.sum() == instr_cnt;
|
||||
}
|
||||
main_program_instr_cnt inside {[1 : instr_cnt]};
|
||||
debug_program_instr_cnt inside {[1 : instr_cnt]};
|
||||
foreach(sub_program_instr_cnt[i]) {
|
||||
sub_program_instr_cnt[i] inside {[1 : instr_cnt]};
|
||||
}
|
||||
|
@ -169,6 +185,10 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
}
|
||||
}
|
||||
|
||||
constraint mtvec_c {
|
||||
mtvec_mode inside {supported_interrupt_mode};
|
||||
}
|
||||
|
||||
constraint mstatus_c {
|
||||
// This is default disabled at setup phase. It can be enabled in the exception and interrupt
|
||||
// handling routine
|
||||
|
@ -269,7 +289,12 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
get_bool_arg_value("+enable_hint_instruction=", enable_hint_instruction);
|
||||
get_bool_arg_value("+force_m_delegation=", force_m_delegation);
|
||||
get_bool_arg_value("+force_s_delegation=", force_s_delegation);
|
||||
get_bool_arg_value("+empty_debug_section=", empty_debug_section);
|
||||
get_bool_arg_value("+require_signature_addr=", require_signature_addr);
|
||||
if (this.require_signature_addr) begin
|
||||
get_hex_arg_value("+signature_addr=", signature_addr);
|
||||
end
|
||||
get_bool_arg_value("+gen_debug_section=", gen_debug_section);
|
||||
get_int_arg_value("+num_debug_sub_program=", num_debug_sub_program);
|
||||
if(inst.get_arg_value("+boot_mode=", boot_mode_opts)) begin
|
||||
`uvm_info(get_full_name(), $sformatf(
|
||||
"Got boot mode option - %0s", boot_mode_opts), UVM_LOW)
|
||||
|
@ -379,15 +404,25 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
// Get an integer argument from comand line
|
||||
function void get_int_arg_value(string cmdline_str, ref int val);
|
||||
string s;
|
||||
if(inst.get_arg_value(cmdline_str, s))
|
||||
if(inst.get_arg_value(cmdline_str, s)) begin
|
||||
val = s.atoi();
|
||||
end
|
||||
endfunction
|
||||
|
||||
// Get a bool argument from comand line
|
||||
function void get_bool_arg_value(string cmdline_str, ref bit val);
|
||||
string s;
|
||||
if(inst.get_arg_value(cmdline_str, s))
|
||||
if(inst.get_arg_value(cmdline_str, s)) begin
|
||||
val = s.atobin();
|
||||
end
|
||||
endfunction
|
||||
|
||||
// Get a hex argument from command line
|
||||
function void get_hex_arg_value(string cmdline_str, ref int val);
|
||||
string s;
|
||||
if(inst.get_arg_value(cmdline_str, s)) begin
|
||||
val = s.atohex();
|
||||
end
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
|
|
@ -24,6 +24,8 @@ package riscv_instr_pkg;
|
|||
|
||||
`define include_file(f) `include `"f`"
|
||||
|
||||
parameter CORE_INITIALIZATION_DONE = 2;
|
||||
|
||||
typedef enum bit [3:0] {
|
||||
BARE = 4'b0000,
|
||||
SV32 = 4'b0001,
|
||||
|
@ -33,6 +35,11 @@ package riscv_instr_pkg;
|
|||
SV64 = 4'b1011
|
||||
} satp_mode_t;
|
||||
|
||||
typedef enum bit [1:0] {
|
||||
DIRECT = 2'b00,
|
||||
VECTORED = 2'b01
|
||||
} mtvec_mode_t;
|
||||
|
||||
typedef enum bit [2:0] {
|
||||
IMM, // Signed immediate
|
||||
UIMM, // Unsigned immediate
|
||||
|
@ -729,7 +736,7 @@ package riscv_instr_pkg;
|
|||
// need to use the virtual address to access the kernel stack.
|
||||
if((status == MSTATUS) && (SATP_MODE != BARE)) begin
|
||||
// We temporarily use tp to check mstatus to avoid changing other GPR. The value of sp has
|
||||
// been saved to xStatus and can be restored later.
|
||||
// been saved to xScratch and can be restored later.
|
||||
if(mprv) begin
|
||||
instr.push_back($sformatf("csrr tp, 0x%0x // MSTATUS", status));
|
||||
instr.push_back("srli tp, tp, 11"); // Move MPP to bit 0
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
# 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
|
||||
# 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,
|
||||
|
|
2
vendor/google_riscv-dv/yaml/iss.yaml
vendored
2
vendor/google_riscv-dv/yaml/iss.yaml
vendored
|
@ -4,7 +4,7 @@
|
|||
# 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
|
||||
# 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,
|
||||
|
|
2
vendor/google_riscv-dv/yaml/simulator.yaml
vendored
2
vendor/google_riscv-dv/yaml/simulator.yaml
vendored
|
@ -4,7 +4,7 @@
|
|||
# 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
|
||||
# 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,
|
||||
|
|
9
vendor/google_riscv-dv/yaml/testlist.yaml
vendored
9
vendor/google_riscv-dv/yaml/testlist.yaml
vendored
|
@ -4,7 +4,7 @@
|
|||
# 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
|
||||
# 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,
|
||||
|
@ -185,10 +185,12 @@
|
|||
iterations: 2
|
||||
gen_test: riscv_rand_instr_test
|
||||
gen_opts: >
|
||||
+require_signature_addr=1
|
||||
+instr_cnt=6000
|
||||
+no_ebreak=0
|
||||
rtl_test: core_base_test
|
||||
sim_opts: >
|
||||
+require_signature_addr=1
|
||||
+enable_debug_seq=1
|
||||
compare_opts: >
|
||||
+compare_final_value_only=1
|
||||
|
@ -203,10 +205,12 @@
|
|||
iterations: 2
|
||||
gen_test: riscv_rand_instr_test
|
||||
gen_opts: >
|
||||
+require_signature_addr=1
|
||||
+skip_trap_handling=1
|
||||
+no_wfi=0
|
||||
rtl_test: core_base_test
|
||||
sim_opts: >
|
||||
+require_signature_addr=1
|
||||
+enable_irq_seq=1
|
||||
|
||||
- test: riscv_full_interrupt_test
|
||||
|
@ -214,8 +218,11 @@
|
|||
Random instruction test with complete interrupt handling
|
||||
iterations: 2
|
||||
gen_test: riscv_rand_instr_test
|
||||
gen_opts: >
|
||||
+require_signature_addr=1
|
||||
rtl_test: core_base_test
|
||||
sim_opts: >
|
||||
+require_signature_addr=1
|
||||
+enable_irq_seq=1
|
||||
compare_opts: >
|
||||
+compare_final_value_only=1
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue