mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-23 13:47:13 -04:00
CVA6-DV : Add unsupported extension instruction for the embedded config (#1472)
This commit is contained in:
parent
1683c818c4
commit
0f4212eb2e
7 changed files with 749 additions and 42 deletions
285
verif/env/corev-dv/cva6_asm_program_gen.sv
vendored
285
verif/env/corev-dv/cva6_asm_program_gen.sv
vendored
|
@ -30,12 +30,121 @@
|
|||
|
||||
class cva6_asm_program_gen_c extends riscv_asm_program_gen;
|
||||
|
||||
cva6_instr_sequence_c cva6_main_program[NUM_HARTS];
|
||||
cva6_instr_gen_config_c cfg_cva6; // Configuration class handle
|
||||
|
||||
`uvm_object_utils(cva6_asm_program_gen_c)
|
||||
|
||||
function new (string name = "");
|
||||
super.new(name);
|
||||
endfunction
|
||||
|
||||
// This is the main function to generate all sections of the program.
|
||||
virtual function void gen_program();
|
||||
instr_stream.delete();
|
||||
// Generate program header
|
||||
`DV_CHECK_FATAL($cast(cfg_cva6, cfg), "Could not cast cfg into cfg_cva6")
|
||||
gen_program_header();
|
||||
for (int hart = 0; hart < cfg_cva6.num_of_harts; hart++) begin
|
||||
string sub_program_name[$];
|
||||
instr_stream.push_back($sformatf("h%0d_start:", hart));
|
||||
if (!cfg_cva6.bare_program_mode) begin
|
||||
setup_misa();
|
||||
// Create all page tables
|
||||
create_page_table(hart);
|
||||
// Setup privileged mode registers and enter target privileged mode
|
||||
pre_enter_privileged_mode(hart);
|
||||
end
|
||||
// Init section
|
||||
gen_init_section(hart);
|
||||
// If PMP is supported, we want to generate the associated trap handlers and the test_done
|
||||
// section at the start of the program so we can allow access through the pmpcfg0 CSR
|
||||
if (support_pmp) begin
|
||||
gen_trap_handlers(hart);
|
||||
// Ecall handler
|
||||
gen_ecall_handler(hart);
|
||||
// Instruction fault handler
|
||||
gen_instr_fault_handler(hart);
|
||||
// Load fault handler
|
||||
gen_load_fault_handler(hart);
|
||||
// Store fault handler
|
||||
gen_store_fault_handler(hart);
|
||||
gen_test_done();
|
||||
end
|
||||
// Generate sub program
|
||||
gen_sub_program(hart, sub_program[hart], sub_program_name, cfg_cva6.num_of_sub_program);
|
||||
// Generate main program
|
||||
cva6_main_program[hart] = cva6_instr_sequence_c::type_id::create(get_label("cva6_main", hart));
|
||||
cva6_main_program[hart].instr_cnt = cfg_cva6.main_program_instr_cnt;
|
||||
cva6_main_program[hart].is_debug_program = 0;
|
||||
cva6_main_program[hart].label_name = cva6_main_program[hart].get_name();
|
||||
generate_directed_instr_stream(.hart(hart),
|
||||
.label(cva6_main_program[hart].label_name),
|
||||
.original_instr_cnt(cva6_main_program[hart].instr_cnt),
|
||||
.min_insert_cnt(1),
|
||||
.instr_stream(cva6_main_program[hart].directed_instr));
|
||||
cva6_main_program[hart].cfg_cva6 = cfg_cva6;
|
||||
`DV_CHECK_RANDOMIZE_FATAL(cva6_main_program[hart])
|
||||
cva6_main_program[hart].gen_instr(.is_main_program(1), .no_branch(cfg_cva6.no_branch_jump));
|
||||
// Setup jump instruction among main program and sub programs
|
||||
gen_callstack(cva6_main_program[hart], sub_program[hart], sub_program_name,
|
||||
cfg_cva6.num_of_sub_program);
|
||||
`uvm_info(`gfn, "Generating callstack...done", UVM_LOW)
|
||||
cva6_main_program[hart].post_process_instr();
|
||||
`uvm_info(`gfn, "Post-processing main program...done", UVM_LOW)
|
||||
cva6_main_program[hart].generate_unsupported_instr_stream();
|
||||
`uvm_info(`gfn, "Generating main program instruction stream...done", UVM_LOW)
|
||||
instr_stream = {instr_stream, cva6_main_program[hart].instr_string_list};
|
||||
// If PMP is supported, need to jump from end of main program to test_done section at the end
|
||||
// of main_program, as the test_done will have moved to the beginning of the program
|
||||
instr_stream = {instr_stream, $sformatf("%sj test_done", indent)};
|
||||
// Test done section
|
||||
// If PMP isn't supported, generate this in the normal location
|
||||
if (hart == 0 & !support_pmp) begin
|
||||
gen_test_done();
|
||||
end
|
||||
// Shuffle the sub programs and insert to the instruction stream
|
||||
insert_sub_program(sub_program[hart], instr_stream);
|
||||
`uvm_info(`gfn, "Inserting sub-programs...done", UVM_LOW)
|
||||
`uvm_info(`gfn, "Main/sub program generation...done", UVM_LOW)
|
||||
// Program end
|
||||
gen_program_end(hart);
|
||||
if (!cfg_cva6.bare_program_mode) begin
|
||||
if (!riscv_instr_pkg::support_pmp) begin
|
||||
// Privileged mode switch routine
|
||||
gen_privileged_mode_switch_routine(hart);
|
||||
end
|
||||
// Generate debug rom section
|
||||
if (riscv_instr_pkg::support_debug_mode) begin
|
||||
gen_debug_rom(hart);
|
||||
end
|
||||
end
|
||||
gen_section({hart_prefix(hart), "instr_end"}, {"nop"});
|
||||
end
|
||||
for (int hart = 0; hart < cfg_cva6.num_of_harts; hart++) begin
|
||||
// Starting point of data section
|
||||
gen_data_page_begin(hart);
|
||||
if(!cfg_cva6.no_data_page) begin
|
||||
// User data section
|
||||
gen_data_page(hart);
|
||||
// AMO memory region
|
||||
if ((hart == 0) && (RV32A inside {supported_isa})) begin
|
||||
gen_data_page(hart, .amo(1));
|
||||
end
|
||||
end
|
||||
// Stack section
|
||||
gen_stack_section(hart);
|
||||
if (!cfg_cva6.bare_program_mode) begin
|
||||
// Generate kernel program/data/stack section
|
||||
gen_kernel_sections(hart);
|
||||
end
|
||||
// Page table
|
||||
if (!cfg_cva6.bare_program_mode) begin
|
||||
gen_page_table_section(hart);
|
||||
end
|
||||
end
|
||||
endfunction
|
||||
|
||||
virtual function void gen_program_header();
|
||||
string str[$];
|
||||
cva6_instr_gen_config_c cfg_cva6;
|
||||
|
@ -46,16 +155,16 @@ class cva6_asm_program_gen_c extends riscv_asm_program_gen;
|
|||
instr_stream.push_back(".include \"user_define.h\"");
|
||||
instr_stream.push_back(".globl _start");
|
||||
instr_stream.push_back(".section .text");
|
||||
if (cfg.disable_compressed_instr) begin
|
||||
if (cfg_cva6.disable_compressed_instr) begin
|
||||
instr_stream.push_back(".option norvc;");
|
||||
end
|
||||
str = {"csrr x5, mhartid"};
|
||||
for (int hart = 0; hart < cfg.num_of_harts; hart++) begin
|
||||
for (int hart = 0; hart < cfg_cva6.num_of_harts; hart++) begin
|
||||
str = {str, $sformatf("li x6, %0d", hart),
|
||||
$sformatf("beq x5, x6, %0df", hart)};
|
||||
end
|
||||
gen_section("_start", str);
|
||||
for (int hart = 0; hart < cfg.num_of_harts; hart++) begin
|
||||
for (int hart = 0; hart < cfg_cva6.num_of_harts; hart++) begin
|
||||
instr_stream.push_back($sformatf("%0d: j h%0d_start", hart, hart));
|
||||
end
|
||||
endfunction
|
||||
|
@ -72,58 +181,58 @@ class cva6_asm_program_gen_c extends riscv_asm_program_gen;
|
|||
bit is_interrupt = 'b1;
|
||||
string tvec_name;
|
||||
string instr[$];
|
||||
if (cfg.mtvec_mode == VECTORED) begin
|
||||
if (cfg_cva6.mtvec_mode == VECTORED) begin
|
||||
gen_interrupt_vector_table(hart, mode, status, cause, ie, ip, 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, cfg.sp, cfg.tp, instr);
|
||||
push_gpr_to_kernel_stack(status, scratch, cfg_cva6.mstatus_mprv, cfg_cva6.sp, cfg_cva6.tp, 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 x%0d, 0x%0x # %0s", cfg.gpr[0], status, status.name())};
|
||||
if (cfg_cva6.check_xstatus) begin
|
||||
instr = {instr, $sformatf("csrr x%0d, 0x%0x # %0s", cfg_cva6.gpr[0], 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 x%0d, 0x%0x # %0s", cfg.gpr[0], cause, cause.name()),
|
||||
$sformatf("srli x%0d, x%0d, %0d", cfg.gpr[0], cfg.gpr[0], XLEN-1),
|
||||
$sformatf("csrr x%0d, 0x%0x # %0s", cfg_cva6.gpr[0], cause, cause.name()),
|
||||
$sformatf("srli x%0d, x%0d, %0d", cfg_cva6.gpr[0], cfg_cva6.gpr[0], XLEN-1),
|
||||
$sformatf("bne x%0d, x0, %0s%0smode_intr_handler",
|
||||
cfg.gpr[0], hart_prefix(hart), mode)};
|
||||
cfg_cva6.gpr[0], hart_prefix(hart), mode)};
|
||||
end
|
||||
// The trap handler will occupy one 4KB page, it will be allocated one entry in the page table
|
||||
// with a specific privileged mode.
|
||||
if (SATP_MODE != BARE) begin
|
||||
instr_stream.push_back(".align 12");
|
||||
end else begin
|
||||
instr_stream.push_back($sformatf(".align %d", cfg.tvec_alignment));
|
||||
instr_stream.push_back($sformatf(".align %d", cfg_cva6.tvec_alignment));
|
||||
end
|
||||
tvec_name = tvec.name();
|
||||
gen_section(get_label($sformatf("%0s_handler", tvec_name.tolower()), hart), instr);
|
||||
// Exception handler
|
||||
instr = {};
|
||||
if (cfg.mtvec_mode == VECTORED) begin
|
||||
push_gpr_to_kernel_stack(status, scratch, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr);
|
||||
if (cfg_cva6.mtvec_mode == VECTORED) begin
|
||||
push_gpr_to_kernel_stack(status, scratch, cfg_cva6.mstatus_mprv, cfg_cva6.sp, cfg_cva6.tp, instr);
|
||||
end
|
||||
gen_signature_handshake(instr, CORE_STATUS, HANDLING_EXCEPTION);
|
||||
instr = {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).
|
||||
$sformatf("csrr x%0d, 0x%0x # %0s", cfg.gpr[0], epc, epc.name()),
|
||||
$sformatf("csrr x%0d, 0x%0x # %0s", cfg.gpr[0], cause, cause.name()),
|
||||
$sformatf("csrr x%0d, 0x%0x # %0s", cfg_cva6.gpr[0], epc, epc.name()),
|
||||
$sformatf("csrr x%0d, 0x%0x # %0s", cfg_cva6.gpr[0], cause, cause.name()),
|
||||
// Breakpoint
|
||||
$sformatf("li x%0d, 0x%0x # BREAKPOINT", cfg.gpr[1], BREAKPOINT),
|
||||
$sformatf("li x%0d, 0x%0x # BREAKPOINT", cfg_cva6.gpr[1], BREAKPOINT),
|
||||
$sformatf("beq x%0d, x%0d, %0sebreak_handler",
|
||||
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
|
||||
cfg_cva6.gpr[0], cfg_cva6.gpr[1], hart_prefix(hart)),
|
||||
// Check if it's an ECALL exception. Jump to ECALL exception handler
|
||||
$sformatf("li x%0d, 0x%0x # ECALL_UMODE", cfg.gpr[1], ECALL_UMODE),
|
||||
$sformatf("li x%0d, 0x%0x # ECALL_UMODE", cfg_cva6.gpr[1], ECALL_UMODE),
|
||||
$sformatf("beq x%0d, x%0d, %0secall_handler",
|
||||
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
|
||||
$sformatf("li x%0d, 0x%0x # ECALL_SMODE", cfg.gpr[1], ECALL_SMODE),
|
||||
cfg_cva6.gpr[0], cfg_cva6.gpr[1], hart_prefix(hart)),
|
||||
$sformatf("li x%0d, 0x%0x # ECALL_SMODE", cfg_cva6.gpr[1], ECALL_SMODE),
|
||||
$sformatf("beq x%0d, x%0d, %0secall_handler",
|
||||
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
|
||||
cfg_cva6.gpr[0], cfg_cva6.gpr[1], hart_prefix(hart)),
|
||||
$sformatf("li x%0d, 0x%0x # ECALL_MMODE", cfg.gpr[1], ECALL_MMODE),
|
||||
$sformatf("beq x%0d, x%0d, %0secall_handler",
|
||||
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
|
||||
|
@ -286,14 +395,43 @@ class cva6_asm_program_gen_c extends riscv_asm_program_gen;
|
|||
end
|
||||
endfunction
|
||||
|
||||
// ECALL trap handler
|
||||
virtual function void gen_ecall_handler(int hart);
|
||||
// Illegal instruction trap handler
|
||||
virtual function void gen_illegal_instr_handler(int hart);
|
||||
string instr[$];
|
||||
gen_signature_handshake(instr, CORE_STATUS, ECALL_EXCEPTION);
|
||||
string str = format_string("illegal_instr_handler_incr_mepc2:", LABEL_STR_LEN);
|
||||
gen_signature_handshake(instr, CORE_STATUS, LOAD_FAULT_EXCEPTION);
|
||||
gen_signature_handshake(.instr(instr), .signature_type(WRITE_CSR), .csr(MCAUSE));
|
||||
instr = {instr,
|
||||
$sformatf("csrr x%0d, mepc", cfg.gpr[0]),
|
||||
$sformatf("addi x%0d, x%0d, 4", cfg.gpr[0], cfg.gpr[0]),
|
||||
$sformatf("lbu x%0d, 0(x%0d)", cfg.gpr[3],cfg.gpr[0]),
|
||||
$sformatf("li x%0d, 0x3", cfg.gpr[2]),
|
||||
$sformatf("and x%0d, x%0d, x%0d", cfg.gpr[3], cfg.gpr[3], cfg.gpr[2]),
|
||||
$sformatf("bne x%0d, x%0d, illegal_instr_handler_incr_mepc2", cfg.gpr[3], cfg.gpr[2]),
|
||||
$sformatf("addi x%0d, x%0d, 2", cfg.gpr[0], cfg.gpr[0]),
|
||||
str,
|
||||
$sformatf("addi x%0d, x%0d, 2", cfg.gpr[0], cfg.gpr[0]),
|
||||
$sformatf("csrw mepc, x%0d", cfg.gpr[0])
|
||||
};
|
||||
pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr);
|
||||
instr.push_back("mret");
|
||||
gen_section(get_label("illegal_instr_handler", hart), instr);
|
||||
endfunction
|
||||
|
||||
// ECALL trap handler
|
||||
virtual function void gen_ecall_handler(int hart);
|
||||
string instr[$];
|
||||
string str = format_string("ecall_handler_incr_mepc2:", LABEL_STR_LEN);
|
||||
gen_signature_handshake(instr, CORE_STATUS, LOAD_FAULT_EXCEPTION);
|
||||
gen_signature_handshake(.instr(instr), .signature_type(WRITE_CSR), .csr(MCAUSE));
|
||||
instr = {instr,
|
||||
$sformatf("csrr x%0d, mepc", cfg.gpr[0]),
|
||||
$sformatf("lbu x%0d, 0(x%0d)", cfg.gpr[3],cfg.gpr[0]),
|
||||
$sformatf("li x%0d, 0x3", cfg.gpr[2]),
|
||||
$sformatf("and x%0d, x%0d, x%0d", cfg.gpr[3], cfg.gpr[3], cfg.gpr[2]),
|
||||
$sformatf("bne x%0d, x%0d, ecall_handler_incr_mepc2", cfg.gpr[3], cfg.gpr[2]),
|
||||
$sformatf("addi x%0d, x%0d, 2", cfg.gpr[0], cfg.gpr[0]),
|
||||
str,
|
||||
$sformatf("addi x%0d, x%0d, 2", cfg.gpr[0], cfg.gpr[0]),
|
||||
$sformatf("csrw mepc, x%0d", cfg.gpr[0])
|
||||
};
|
||||
pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr);
|
||||
|
@ -304,11 +442,18 @@ class cva6_asm_program_gen_c extends riscv_asm_program_gen;
|
|||
// TODO: handshake correct csr based on delegation
|
||||
virtual function void gen_instr_fault_handler(int hart);
|
||||
string instr[$];
|
||||
gen_signature_handshake(instr, CORE_STATUS, INSTR_FAULT_EXCEPTION);
|
||||
string str = format_string("instr_fault_handler_incr_mepc2:", LABEL_STR_LEN);
|
||||
gen_signature_handshake(instr, CORE_STATUS, LOAD_FAULT_EXCEPTION);
|
||||
gen_signature_handshake(.instr(instr), .signature_type(WRITE_CSR), .csr(MCAUSE));
|
||||
instr = {instr,
|
||||
$sformatf("csrr x%0d, mepc", cfg.gpr[0]),
|
||||
$sformatf("addi x%0d, x%0d, 4", cfg.gpr[0], cfg.gpr[0]),
|
||||
$sformatf("lbu x%0d, 0(x%0d)", cfg.gpr[3],cfg.gpr[0]),
|
||||
$sformatf("li x%0d, 0x3", cfg.gpr[2]),
|
||||
$sformatf("and x%0d, x%0d, x%0d", cfg.gpr[3], cfg.gpr[3], cfg.gpr[2]),
|
||||
$sformatf("bne x%0d, x%0d, instr_fault_handler_incr_mepc2", cfg.gpr[3], cfg.gpr[2]),
|
||||
$sformatf("addi x%0d, x%0d, 2", cfg.gpr[0], cfg.gpr[0]),
|
||||
str,
|
||||
$sformatf("addi x%0d, x%0d, 2", cfg.gpr[0], cfg.gpr[0]),
|
||||
$sformatf("csrw mepc, x%0d", cfg.gpr[0])
|
||||
};
|
||||
pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr);
|
||||
|
@ -319,11 +464,18 @@ class cva6_asm_program_gen_c extends riscv_asm_program_gen;
|
|||
// TODO: handshake correct csr based on delegation
|
||||
virtual function void gen_load_fault_handler(int hart);
|
||||
string instr[$];
|
||||
string str = format_string("load_fault_handler_incr_mepc2:", LABEL_STR_LEN);
|
||||
gen_signature_handshake(instr, CORE_STATUS, LOAD_FAULT_EXCEPTION);
|
||||
gen_signature_handshake(.instr(instr), .signature_type(WRITE_CSR), .csr(MCAUSE));
|
||||
instr = {instr,
|
||||
$sformatf("csrr x%0d, mepc", cfg.gpr[0]),
|
||||
$sformatf("addi x%0d, x%0d, 4", cfg.gpr[0], cfg.gpr[0]),
|
||||
$sformatf("lbu x%0d, 0(x%0d)", cfg.gpr[3],cfg.gpr[0]),
|
||||
$sformatf("li x%0d, 0x3", cfg.gpr[2]),
|
||||
$sformatf("and x%0d, x%0d, x%0d", cfg.gpr[3], cfg.gpr[3], cfg.gpr[2]),
|
||||
$sformatf("bne x%0d, x%0d, load_fault_handler_incr_mepc2", cfg.gpr[3], cfg.gpr[2]),
|
||||
$sformatf("addi x%0d, x%0d, 2", cfg.gpr[0], cfg.gpr[0]),
|
||||
str,
|
||||
$sformatf("addi x%0d, x%0d, 2", cfg.gpr[0], cfg.gpr[0]),
|
||||
$sformatf("csrw mepc, x%0d", cfg.gpr[0])
|
||||
};
|
||||
pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr);
|
||||
|
@ -334,11 +486,18 @@ class cva6_asm_program_gen_c extends riscv_asm_program_gen;
|
|||
// TODO: handshake correct csr based on delegation
|
||||
virtual function void gen_store_fault_handler(int hart);
|
||||
string instr[$];
|
||||
gen_signature_handshake(instr, CORE_STATUS, STORE_FAULT_EXCEPTION);
|
||||
string str = format_string("store_fault_handler_incr_mepc2:", LABEL_STR_LEN);
|
||||
gen_signature_handshake(instr, CORE_STATUS, LOAD_FAULT_EXCEPTION);
|
||||
gen_signature_handshake(.instr(instr), .signature_type(WRITE_CSR), .csr(MCAUSE));
|
||||
instr = {instr,
|
||||
$sformatf("csrr x%0d, mepc", cfg.gpr[0]),
|
||||
$sformatf("addi x%0d, x%0d, 4", cfg.gpr[0], cfg.gpr[0]),
|
||||
$sformatf("lbu x%0d, 0(x%0d)", cfg.gpr[3],cfg.gpr[0]),
|
||||
$sformatf("li x%0d, 0x3", cfg.gpr[2]),
|
||||
$sformatf("and x%0d, x%0d, x%0d", cfg.gpr[3], cfg.gpr[3], cfg.gpr[2]),
|
||||
$sformatf("bne x%0d, x%0d, store_fault_handler_incr_mepc2", cfg.gpr[3], cfg.gpr[2]),
|
||||
$sformatf("addi x%0d, x%0d, 2", cfg.gpr[0], cfg.gpr[0]),
|
||||
str,
|
||||
$sformatf("addi x%0d, x%0d, 2", cfg.gpr[0], cfg.gpr[0]),
|
||||
$sformatf("csrw mepc, x%0d", cfg.gpr[0])
|
||||
};
|
||||
pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr);
|
||||
|
@ -348,11 +507,18 @@ class cva6_asm_program_gen_c extends riscv_asm_program_gen;
|
|||
|
||||
virtual function void gen_pt_instr_fault_handler(int hart);
|
||||
string instr[$];
|
||||
gen_signature_handshake(instr, CORE_STATUS, INSTR_PAGE_FAULT_EXCEPTION);
|
||||
string str = format_string("pt_instr_fault_handler_incr_mepc2:", LABEL_STR_LEN);
|
||||
gen_signature_handshake(instr, CORE_STATUS, LOAD_FAULT_EXCEPTION);
|
||||
gen_signature_handshake(.instr(instr), .signature_type(WRITE_CSR), .csr(MCAUSE));
|
||||
instr = {instr,
|
||||
$sformatf("csrr x%0d, mepc", cfg.gpr[0]),
|
||||
$sformatf("addi x%0d, x%0d, 4", cfg.gpr[0], cfg.gpr[0]),
|
||||
$sformatf("lbu x%0d, 0(x%0d)", cfg.gpr[3],cfg.gpr[0]),
|
||||
$sformatf("li x%0d, 0x3", cfg.gpr[2]),
|
||||
$sformatf("and x%0d, x%0d, x%0d", cfg.gpr[3], cfg.gpr[3], cfg.gpr[2]),
|
||||
$sformatf("bne x%0d, x%0d, pt_instr_fault_handler_incr_mepc2", cfg.gpr[3], cfg.gpr[2]),
|
||||
$sformatf("addi x%0d, x%0d, 2", cfg.gpr[0], cfg.gpr[0]),
|
||||
str,
|
||||
$sformatf("addi x%0d, x%0d, 2", cfg.gpr[0], cfg.gpr[0]),
|
||||
$sformatf("csrw mepc, x%0d", cfg.gpr[0])
|
||||
};
|
||||
pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr);
|
||||
|
@ -362,11 +528,18 @@ class cva6_asm_program_gen_c extends riscv_asm_program_gen;
|
|||
|
||||
virtual function void gen_pt_load_fault_handler(int hart);
|
||||
string instr[$];
|
||||
gen_signature_handshake(instr, CORE_STATUS, LOAD_PAGE_FAULT_EXCEPTION);
|
||||
string str = format_string("pt_load_fault_handler_incr_mepc2:", LABEL_STR_LEN);
|
||||
gen_signature_handshake(instr, CORE_STATUS, LOAD_FAULT_EXCEPTION);
|
||||
gen_signature_handshake(.instr(instr), .signature_type(WRITE_CSR), .csr(MCAUSE));
|
||||
instr = {instr,
|
||||
$sformatf("csrr x%0d, mepc", cfg.gpr[0]),
|
||||
$sformatf("addi x%0d, x%0d, 4", cfg.gpr[0], cfg.gpr[0]),
|
||||
$sformatf("lbu x%0d, 0(x%0d)", cfg.gpr[3],cfg.gpr[0]),
|
||||
$sformatf("li x%0d, 0x3", cfg.gpr[2]),
|
||||
$sformatf("and x%0d, x%0d, x%0d", cfg.gpr[3], cfg.gpr[3], cfg.gpr[2]),
|
||||
$sformatf("bne x%0d, x%0d, pt_load_fault_handler_incr_mepc2", cfg.gpr[3], cfg.gpr[2]),
|
||||
$sformatf("addi x%0d, x%0d, 2", cfg.gpr[0], cfg.gpr[0]),
|
||||
str,
|
||||
$sformatf("addi x%0d, x%0d, 2", cfg.gpr[0], cfg.gpr[0]),
|
||||
$sformatf("csrw mepc, x%0d", cfg.gpr[0])
|
||||
};
|
||||
pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr);
|
||||
|
@ -376,11 +549,18 @@ class cva6_asm_program_gen_c extends riscv_asm_program_gen;
|
|||
|
||||
virtual function void gen_pt_store_fault_handler(int hart);
|
||||
string instr[$];
|
||||
gen_signature_handshake(instr, CORE_STATUS, STORE_PAGE_FAULT_EXCEPTION);
|
||||
string str = format_string("pt_store_fault_handler_incr_mepc2:", LABEL_STR_LEN);
|
||||
gen_signature_handshake(instr, CORE_STATUS, LOAD_FAULT_EXCEPTION);
|
||||
gen_signature_handshake(.instr(instr), .signature_type(WRITE_CSR), .csr(MCAUSE));
|
||||
instr = {instr,
|
||||
$sformatf("csrr x%0d, mepc", cfg.gpr[0]),
|
||||
$sformatf("addi x%0d, x%0d, 4", cfg.gpr[0], cfg.gpr[0]),
|
||||
$sformatf("lbu x%0d, 0(x%0d)", cfg.gpr[3],cfg.gpr[0]),
|
||||
$sformatf("li x%0d, 0x3", cfg.gpr[2]),
|
||||
$sformatf("and x%0d, x%0d, x%0d", cfg.gpr[3], cfg.gpr[3], cfg.gpr[2]),
|
||||
$sformatf("bne x%0d, x%0d, pt_store_fault_handler_incr_mepc2", cfg.gpr[3], cfg.gpr[2]),
|
||||
$sformatf("addi x%0d, x%0d, 2", cfg.gpr[0], cfg.gpr[0]),
|
||||
str,
|
||||
$sformatf("addi x%0d, x%0d, 2", cfg.gpr[0], cfg.gpr[0]),
|
||||
$sformatf("csrw mepc, x%0d", cfg.gpr[0])
|
||||
};
|
||||
pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr);
|
||||
|
@ -390,11 +570,18 @@ class cva6_asm_program_gen_c extends riscv_asm_program_gen;
|
|||
|
||||
virtual function void gen_load_misaligned_handler(int hart);
|
||||
string instr[$];
|
||||
gen_signature_handshake(instr, CORE_STATUS, LD_MISALIGNED_EXCEPTION);
|
||||
string str = format_string("load_misaligned_handler_incr_mepc2:", LABEL_STR_LEN);
|
||||
gen_signature_handshake(instr, CORE_STATUS, LOAD_FAULT_EXCEPTION);
|
||||
gen_signature_handshake(.instr(instr), .signature_type(WRITE_CSR), .csr(MCAUSE));
|
||||
instr = {instr,
|
||||
$sformatf("csrr x%0d, mepc", cfg.gpr[0]),
|
||||
$sformatf("addi x%0d, x%0d, 4", cfg.gpr[0], cfg.gpr[0]),
|
||||
$sformatf("lbu x%0d, 0(x%0d)", cfg.gpr[3],cfg.gpr[0]),
|
||||
$sformatf("li x%0d, 0x3", cfg.gpr[2]),
|
||||
$sformatf("and x%0d, x%0d, x%0d", cfg.gpr[3], cfg.gpr[3], cfg.gpr[2]),
|
||||
$sformatf("bne x%0d, x%0d, load_misaligned_handler_incr_mepc2", cfg.gpr[3], cfg.gpr[2]),
|
||||
$sformatf("addi x%0d, x%0d, 2", cfg.gpr[0], cfg.gpr[0]),
|
||||
str,
|
||||
$sformatf("addi x%0d, x%0d, 2", cfg.gpr[0], cfg.gpr[0]),
|
||||
$sformatf("csrw mepc, x%0d", cfg.gpr[0])
|
||||
};
|
||||
pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr);
|
||||
|
@ -404,11 +591,18 @@ class cva6_asm_program_gen_c extends riscv_asm_program_gen;
|
|||
|
||||
virtual function void gen_store_misaligned_handler(int hart);
|
||||
string instr[$];
|
||||
gen_signature_handshake(instr, CORE_STATUS, ST_MISALIGNED_EXCEPTION);
|
||||
string str = format_string("store_misaligned_handler_incr_mepc2:", LABEL_STR_LEN);
|
||||
gen_signature_handshake(instr, CORE_STATUS, LOAD_FAULT_EXCEPTION);
|
||||
gen_signature_handshake(.instr(instr), .signature_type(WRITE_CSR), .csr(MCAUSE));
|
||||
instr = {instr,
|
||||
$sformatf("csrr x%0d, mepc", cfg.gpr[0]),
|
||||
$sformatf("addi x%0d, x%0d, 4", cfg.gpr[0], cfg.gpr[0]),
|
||||
$sformatf("lbu x%0d, 0(x%0d)", cfg.gpr[3],cfg.gpr[0]),
|
||||
$sformatf("li x%0d, 0x3", cfg.gpr[2]),
|
||||
$sformatf("and x%0d, x%0d, x%0d", cfg.gpr[3], cfg.gpr[3], cfg.gpr[2]),
|
||||
$sformatf("bne x%0d, x%0d, store_misaligned_handler_incr_mepc2", cfg.gpr[3], cfg.gpr[2]),
|
||||
$sformatf("addi x%0d, x%0d, 2", cfg.gpr[0], cfg.gpr[0]),
|
||||
str,
|
||||
$sformatf("addi x%0d, x%0d, 2", cfg.gpr[0], cfg.gpr[0]),
|
||||
$sformatf("csrw mepc, x%0d", cfg.gpr[0])
|
||||
};
|
||||
pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr);
|
||||
|
@ -418,11 +612,18 @@ class cva6_asm_program_gen_c extends riscv_asm_program_gen;
|
|||
|
||||
virtual function void gen_instr_misaligned_handler(int hart);
|
||||
string instr[$];
|
||||
gen_signature_handshake(instr, CORE_STATUS, INSTR_MISALIGNED_EXCEPTION);
|
||||
string str = format_string("instr_misaligned_handler_incr_mepc2:", LABEL_STR_LEN);
|
||||
gen_signature_handshake(instr, CORE_STATUS, LOAD_FAULT_EXCEPTION);
|
||||
gen_signature_handshake(.instr(instr), .signature_type(WRITE_CSR), .csr(MCAUSE));
|
||||
instr = {instr,
|
||||
$sformatf("csrr x%0d, mepc", cfg.gpr[0]),
|
||||
$sformatf("addi x%0d, x%0d, 4", cfg.gpr[0], cfg.gpr[0]),
|
||||
$sformatf("lbu x%0d, 0(x%0d)", cfg.gpr[3],cfg.gpr[0]),
|
||||
$sformatf("li x%0d, 0x3", cfg.gpr[2]),
|
||||
$sformatf("and x%0d, x%0d, x%0d", cfg.gpr[3], cfg.gpr[3], cfg.gpr[2]),
|
||||
$sformatf("bne x%0d, x%0d, instr_misaligned_handler_incr_mepc2", cfg.gpr[3], cfg.gpr[2]),
|
||||
$sformatf("addi x%0d, x%0d, 2", cfg.gpr[0], cfg.gpr[0]),
|
||||
str,
|
||||
$sformatf("addi x%0d, x%0d, 2", cfg.gpr[0], cfg.gpr[0]),
|
||||
$sformatf("csrw mepc, x%0d", cfg.gpr[0])
|
||||
};
|
||||
pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr);
|
||||
|
|
8
verif/env/corev-dv/cva6_instr_base_test.sv
vendored
8
verif/env/corev-dv/cva6_instr_base_test.sv
vendored
|
@ -34,6 +34,7 @@ class cva6_instr_base_test_c extends riscv_instr_base_test;
|
|||
virtual function void build_phase(uvm_phase phase);
|
||||
override_asm_program_gen();
|
||||
override_gen_config();
|
||||
override_sequence_instr();
|
||||
super.build_phase(phase);
|
||||
endfunction
|
||||
|
||||
|
@ -51,4 +52,11 @@ class cva6_instr_base_test_c extends riscv_instr_base_test;
|
|||
`uvm_info("CVA6_DV", $sformatf("Overrid done "), UVM_LOW)
|
||||
endfunction
|
||||
|
||||
virtual function void override_sequence_instr();
|
||||
`uvm_info("CVA6_DV", $sformatf("Overriding ..."), UVM_LOW)
|
||||
uvm_factory::get().set_type_override_by_type(riscv_instr_sequence::get_type(),
|
||||
cva6_instr_sequence_c::get_type());
|
||||
`uvm_info("CVA6_DV", $sformatf("Overrid done "), UVM_LOW)
|
||||
endfunction
|
||||
|
||||
endclass : cva6_instr_base_test_c
|
||||
|
|
3
verif/env/corev-dv/cva6_instr_gen_config.sv
vendored
3
verif/env/corev-dv/cva6_instr_gen_config.sv
vendored
|
@ -31,6 +31,7 @@ class cva6_instr_gen_config_c extends riscv_instr_gen_config;
|
|||
bit enable_rdrs2_hazard;
|
||||
bit enable_same_reg;
|
||||
bit enable_zicond_extension;
|
||||
int unsupported_instr_ratio;
|
||||
|
||||
constraint hazard_reg_c {
|
||||
if (enable_same_reg) {
|
||||
|
@ -45,6 +46,7 @@ class cva6_instr_gen_config_c extends riscv_instr_gen_config;
|
|||
`uvm_field_int(enable_rdrs2_hazard, UVM_DEFAULT)
|
||||
`uvm_field_int(enable_same_reg, UVM_DEFAULT)
|
||||
`uvm_field_int(enable_zicond_extension, UVM_DEFAULT)
|
||||
`uvm_field_int(unsupported_instr_ratio, UVM_DEFAULT)
|
||||
`uvm_object_utils_end
|
||||
|
||||
function new (string name = "");
|
||||
|
@ -54,6 +56,7 @@ class cva6_instr_gen_config_c extends riscv_instr_gen_config;
|
|||
get_bool_arg_value("+enable_rdrs2_hazard=", enable_rdrs2_hazard);
|
||||
get_bool_arg_value("+enable_same_reg=", enable_same_reg);
|
||||
get_bool_arg_value("+enable_zicond_extension=", enable_zicond_extension);
|
||||
get_int_arg_value("+unsupported_instr_ratio=", unsupported_instr_ratio);
|
||||
endfunction
|
||||
|
||||
endclass : cva6_instr_gen_config_c
|
||||
|
|
90
verif/env/corev-dv/cva6_instr_sequence.sv
vendored
Normal file
90
verif/env/corev-dv/cva6_instr_sequence.sv
vendored
Normal file
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright 2018 Google LLC
|
||||
* Copyright 2023 Thales DIS
|
||||
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
// CVA6 instruction sequence, this add unsupported extension instructions to
|
||||
// hint/illegal instructions
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
class cva6_instr_sequence_c extends riscv_instr_sequence;
|
||||
|
||||
cva6_instr_gen_config_c cfg_cva6; // Configuration class handle
|
||||
cva6_unsupported_instr_c unsupported_instr; // unsupported instruction generator
|
||||
int unsupported_instr_pct; // Percentage of unsupported instruction
|
||||
|
||||
`uvm_object_utils(cva6_instr_sequence_c)
|
||||
|
||||
function new (string name = "");
|
||||
super.new(name);
|
||||
unsupported_instr = cva6_unsupported_instr_c::type_id::create("unsupported_instr");
|
||||
endfunction
|
||||
|
||||
function void insert_unsupported_instr();
|
||||
int bin_instr_cnt;
|
||||
int idx;
|
||||
string str;
|
||||
`DV_CHECK_FATAL($cast(cfg_cva6, cfg), "Could not cast cfg into cfg_cva6")
|
||||
bin_instr_cnt = instr_cnt * cfg_cva6.unsupported_instr_ratio / 1000;
|
||||
if (bin_instr_cnt >= 0) begin
|
||||
`uvm_info(`gfn, $sformatf("Injecting %0d unsupported instructions, ratio %0d/100",
|
||||
bin_instr_cnt, cfg_cva6.unsupported_instr_ratio), UVM_LOW)
|
||||
repeat (bin_instr_cnt) begin
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(unsupported_instr,
|
||||
unsupported_instr inside {rv64i_instr,rv64c_instr,rv64m_instr,rvfdq_instr};)
|
||||
str = {indent, $sformatf(".4byte 0x%s # %0s",
|
||||
unsupported_instr.get_bin_str(), unsupported_instr.comment)};
|
||||
idx = $urandom_range(0, instr_string_list.size());
|
||||
instr_string_list.insert(idx, str);
|
||||
end
|
||||
end
|
||||
endfunction
|
||||
|
||||
// Convert the instruction stream to the string format.
|
||||
// Label is attached to the instruction if available, otherwise attach proper space to make
|
||||
// the code indent consistent.
|
||||
function void generate_unsupported_instr_stream(bit no_label = 1'b0);
|
||||
string prefix, str;
|
||||
int i;
|
||||
instr_string_list = {};
|
||||
for(i = 0; i < instr_stream.instr_list.size(); i++) begin
|
||||
if(i == 0) begin
|
||||
if (no_label) begin
|
||||
prefix = format_string(" ", LABEL_STR_LEN);
|
||||
end else begin
|
||||
prefix = format_string($sformatf("%0s:", label_name), LABEL_STR_LEN);
|
||||
end
|
||||
instr_stream.instr_list[i].has_label = 1'b1;
|
||||
end else begin
|
||||
if(instr_stream.instr_list[i].has_label) begin
|
||||
prefix = format_string($sformatf("%0s:", instr_stream.instr_list[i].label),
|
||||
LABEL_STR_LEN);
|
||||
end else begin
|
||||
prefix = format_string(" ", LABEL_STR_LEN);
|
||||
end
|
||||
end
|
||||
str = {prefix, instr_stream.instr_list[i].convert2asm()};
|
||||
instr_string_list.push_back(str);
|
||||
end
|
||||
insert_unsupported_instr();
|
||||
insert_illegal_hint_instr();
|
||||
prefix = format_string($sformatf("%0d:", i), LABEL_STR_LEN);
|
||||
if(!is_main_program) begin
|
||||
generate_return_routine(prefix);
|
||||
end
|
||||
endfunction
|
||||
|
||||
endclass
|
2
verif/env/corev-dv/cva6_instr_test_pkg.sv
vendored
2
verif/env/corev-dv/cva6_instr_test_pkg.sv
vendored
|
@ -18,7 +18,9 @@ package cva6_instr_test_pkg;
|
|||
import cva6_signature_pkg::*;
|
||||
|
||||
`include "cva6_instr_gen_config.sv"
|
||||
`include "cva6_unsupported_instr.sv"
|
||||
`include "cva6_reg_hazard_stream.sv"
|
||||
`include "cva6_instr_sequence.sv"
|
||||
`include "cva6_asm_program_gen.sv"
|
||||
`include "cva6_instr_base_test.sv"
|
||||
`include "cva6_instr_hazard_test.sv"
|
||||
|
|
17
verif/env/corev-dv/cva6_reg_hazard_stream.sv
vendored
17
verif/env/corev-dv/cva6_reg_hazard_stream.sv
vendored
|
@ -1,3 +1,20 @@
|
|||
/*
|
||||
* Copyright 2018 Google LLC
|
||||
* Copyright 2023 Thales DIS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// class for hazard instruction stream (RAW)
|
||||
// that means destination register of previous instruction is the same source register of the current instruction
|
||||
|
||||
|
|
386
verif/env/corev-dv/cva6_unsupported_instr.sv
vendored
Normal file
386
verif/env/corev-dv/cva6_unsupported_instr.sv
vendored
Normal file
|
@ -0,0 +1,386 @@
|
|||
/*
|
||||
* Copyright 2019 Google LLC
|
||||
* Copyright 2023 Thales DIS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
// This class is used to generate instruction in extension that do not supported by a given configuration.
|
||||
// The illegal instruction will be generated in binary format and mixed with other valid instr.
|
||||
// The mixed instruction stream will be stored in data section and loaded to instruction pages
|
||||
// at run time.
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
|
||||
class cva6_unsupported_instr_c extends uvm_object;
|
||||
|
||||
string comment;
|
||||
|
||||
typedef enum bit [2:0] {
|
||||
rv64i_instr,
|
||||
rv64c_instr,
|
||||
rv64m_instr,
|
||||
rvfdq_instr
|
||||
} illegal_ext_instr_type_e;
|
||||
|
||||
// Default legal opcode for RV32I instructions
|
||||
bit [6:0] legal_rv64i_opcode[$] = '{7'b0000011,
|
||||
7'b0100011,
|
||||
7'b0011011,
|
||||
7'b0111011};
|
||||
|
||||
bit [6:0] legal_rvfdq_opcode[$] = '{7'b0000111,
|
||||
7'b0100111,
|
||||
7'b1000011,
|
||||
7'b1000111,
|
||||
7'b1001011,
|
||||
7'b1001111,
|
||||
7'b1010011};
|
||||
|
||||
bit [6:0] legal_rvfdq_func7[$] = '{7'b0000000,
|
||||
7'b0000100,
|
||||
7'b0001000,
|
||||
7'b0001100,
|
||||
7'b0101100,
|
||||
7'b0010000,
|
||||
7'b1010000,
|
||||
7'b1101000,
|
||||
7'b1111000,
|
||||
7'b0010100,
|
||||
7'b1100000,
|
||||
7'b1110000,
|
||||
7'b0000001,
|
||||
7'b0000101,
|
||||
7'b0001001,
|
||||
7'b0001101,
|
||||
7'b0101101,
|
||||
7'b0010001,
|
||||
7'b0010101,
|
||||
7'b0100000,
|
||||
7'b0100001,
|
||||
7'b1010001,
|
||||
7'b1110001,
|
||||
7'b1100001,
|
||||
7'b1101001,
|
||||
7'b1111001,
|
||||
7'b0000011,
|
||||
7'b0000111,
|
||||
7'b0001011,
|
||||
7'b0001111,
|
||||
7'b0101111,
|
||||
7'b0010011,
|
||||
7'b0010111,
|
||||
7'b0100011,
|
||||
7'b1010011,
|
||||
7'b1110011,
|
||||
7'b1100011,
|
||||
7'b1101011};
|
||||
|
||||
bit [2:0] legal_func3[$] = '{3'b000,
|
||||
3'b001,
|
||||
3'b010,
|
||||
3'b011,
|
||||
3'b100};
|
||||
|
||||
bit [1:0] legal_func2[$] = '{2'b00,
|
||||
2'b01,
|
||||
2'b11};
|
||||
|
||||
rand illegal_ext_instr_type_e unsupported_instr;
|
||||
rand bit [31:0] instr_bin;
|
||||
rand bit [6:0] opcode;
|
||||
rand bit [2:0] func3;
|
||||
rand bit [1:0] func2;
|
||||
rand bit [6:0] func7;
|
||||
rand bit has_func3;
|
||||
rand bit has_func7;
|
||||
rand bit has_func2;
|
||||
rand bit compressed;
|
||||
rand bit [1:0] c_op;
|
||||
rand bit [2:0] c_msb;
|
||||
cva6_instr_gen_config_c cfg_cva6;
|
||||
|
||||
constraint exception_dist_c {
|
||||
unsupported_instr dist {
|
||||
rv64i_instr := 1,
|
||||
rv64c_instr := 1,
|
||||
rv64m_instr := 1,
|
||||
rvfdq_instr := 1
|
||||
};
|
||||
}
|
||||
|
||||
constraint instr_bit_assignment_c {
|
||||
solve opcode before instr_bin;
|
||||
solve func3 before instr_bin;
|
||||
solve func2 before instr_bin;
|
||||
solve func7 before instr_bin;
|
||||
solve c_msb before instr_bin;
|
||||
solve c_op before instr_bin;
|
||||
if (compressed) {
|
||||
instr_bin[1:0] == c_op;
|
||||
instr_bin[15:13] == c_msb;
|
||||
} else {
|
||||
instr_bin[6:0] == opcode;
|
||||
if (has_func7) {
|
||||
instr_bin[31:25] == func7;
|
||||
}
|
||||
if (has_func3) {
|
||||
instr_bin[14:12] == func3;
|
||||
}
|
||||
if (has_func2) {
|
||||
instr_bin[26:25] == func3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RV64I instructions
|
||||
constraint rv64i_instr_c {
|
||||
if (unsupported_instr == rv64i_instr) {
|
||||
compressed == 0;
|
||||
opcode inside {legal_rv64i_opcode};
|
||||
func3 inside {3'b110, 3'b011, 3'b001, 3'b101, 3'b0};
|
||||
if (opcode == 7'b0000011) {
|
||||
func3 inside {3'b110, 3'b011};
|
||||
}
|
||||
if (opcode == 7'b0100011) {
|
||||
func3 == 3'b011;
|
||||
}
|
||||
if (opcode == 7'b0011011) {
|
||||
func3 inside {3'b101, 3'b001, 3'b0};
|
||||
if (func3 == 3'b101) {
|
||||
func7 inside {7'b0, 7'b0100000};
|
||||
}
|
||||
if (func3 == 3'b001) {
|
||||
func7 == 7'b0;
|
||||
}
|
||||
}
|
||||
if (opcode == 7'b0111011) {
|
||||
func3 inside {3'b101, 3'b001, 3'b0};
|
||||
if (func3 == 3'b0) {
|
||||
func7 inside {7'b0, 7'b0100000};
|
||||
}
|
||||
if (func3 == 3'b001) {
|
||||
func7 == 7'b0;
|
||||
}
|
||||
if (func3 == 3'b101) {
|
||||
func7 inside {7'b0, 7'b0100000};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RV64M instructions
|
||||
constraint rv64c_instr_c {
|
||||
if (unsupported_instr == rv64m_instr) {
|
||||
compressed == 0;
|
||||
opcode == 7'b0111011;
|
||||
func3 inside {3'b100, 3'b110, 3'b000, 3'b101, 3'b111};
|
||||
func7 == 7'b0000001;
|
||||
}
|
||||
}
|
||||
|
||||
// RV64C instructions
|
||||
constraint rv64m_instr_c {
|
||||
if (unsupported_instr == rv64c_instr) {
|
||||
compressed == 1;
|
||||
c_op != 2'b11;
|
||||
if (c_op == 2'b0) {
|
||||
!(c_msb inside {3'b0, 3'b010, 3'b110});
|
||||
}
|
||||
if (c_op == 2'b01) {
|
||||
c_msb == 3'b100;
|
||||
instr_bin[12:10] inside {3'b0, 3'b001, 3'b111};
|
||||
if (instr_bin[12:10] != 3'b111) {
|
||||
instr_bin[6:2] == 5'b0;
|
||||
}
|
||||
}
|
||||
if (c_op == 2'b10) {
|
||||
!(c_msb inside {3'b100, 3'b010, 3'b110});
|
||||
if (c_msb == 3'b0) {
|
||||
instr_bin[6:2] == 5'b0;
|
||||
instr_bin[12] == 1'b0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RV32FDQ, RV64FDQ instructions
|
||||
constraint rvfdq_instr_c {
|
||||
if (unsupported_instr == rvfdq_instr) {
|
||||
compressed == 0;
|
||||
opcode inside {legal_rvfdq_opcode};
|
||||
func7 inside {legal_rvfdq_func7};
|
||||
if (opcode == 7'b0000111) {
|
||||
func3 inside {3'b010, 3'b011, 3'b100};
|
||||
}
|
||||
if (opcode == 7'b0100111) {
|
||||
func3 inside {3'b010, 3'b011, 3'b100};
|
||||
}
|
||||
if (opcode == 7'b1000011) {
|
||||
func2 inside {legal_func2};
|
||||
}
|
||||
if (opcode == 7'b1000111) {
|
||||
func2 inside {legal_func2};
|
||||
}
|
||||
if (opcode == 7'b1001011) {
|
||||
func2 inside {legal_func2};
|
||||
}
|
||||
if (opcode == 7'b1001111) {
|
||||
func2 inside {legal_func2};
|
||||
}
|
||||
if (opcode == 7'b1010011) {
|
||||
func3 inside {3'b0, 3'b010, 3'b001};
|
||||
if (func3 == 3'b0) {
|
||||
func7 inside {7'b0010000,7'b0010100,7'b1110000,7'b1010000,
|
||||
7'b1111000,7'b0010001,7'b0010101,7'b1010001,
|
||||
7'b1110001,7'b1111001,7'b0010011,7'b0010111,
|
||||
7'b1010011};
|
||||
if (func7 == 7'b1110000) {
|
||||
instr_bin[24:20] == 5'b0;
|
||||
}
|
||||
if (func7 == 7'b1111000) {
|
||||
instr_bin[24:20] == 5'b0;
|
||||
}
|
||||
if (func7 == 7'b1110001) {
|
||||
instr_bin[24:20] == 5'b0;
|
||||
}
|
||||
if (func7 == 7'b1111001) {
|
||||
instr_bin[24:20] == 5'b0;
|
||||
}
|
||||
}
|
||||
if (func3 == 3'b001) {
|
||||
func7 inside {7'b0010000,7'b0010100,7'b1110000,7'b1010000,
|
||||
7'b0010001,7'b0010101,7'b1010001,7'b1110001,
|
||||
7'b1010011,7'b1110011,7'b0010011,7'b0010111};
|
||||
if (func7 == 7'b1110000) {
|
||||
instr_bin[24:20] == 5'b0;
|
||||
}
|
||||
if (func7 == 7'b1110001) {
|
||||
instr_bin[24:20] == 5'b0;
|
||||
}
|
||||
if (func7 == 7'b1110011) {
|
||||
instr_bin[24:20] == 5'b0;
|
||||
}
|
||||
}
|
||||
if (func3 == 3'b010) {
|
||||
func7 inside {7'b0010000,7'b1010000,7'b0010001,7'b1010001,
|
||||
7'b0010011,7'b1010011};
|
||||
}
|
||||
if (func7 == 7'b0101100) {
|
||||
instr_bin[24:20] == 5'b0;
|
||||
}
|
||||
if (func7 == 7'b1100000) {
|
||||
instr_bin[24:20] inside {5'b0, 5'b00001, 5'b00010, 5'b00011};
|
||||
}
|
||||
if (func7 == 7'b1101000) {
|
||||
instr_bin[24:20] inside {5'b0, 5'b00001, 5'b00010, 5'b00011};
|
||||
}
|
||||
if (func7 == 7'b0101101) {
|
||||
instr_bin[24:20] == 5'b0;
|
||||
}
|
||||
if (func7 == 7'b0100000) {
|
||||
instr_bin[24:20] inside {5'b00001, 5'b00011};
|
||||
}
|
||||
if (func7 == 7'b0100001) {
|
||||
instr_bin[24:20] inside {5'b0, 5'b00011};
|
||||
}
|
||||
if (func7 == 7'b1100001) {
|
||||
instr_bin[24:20] inside {5'b0, 5'b00001, 5'b00010, 5'b00011};
|
||||
}
|
||||
if (func7 == 7'b1101001) {
|
||||
instr_bin[24:20] inside {5'b0, 5'b00001, 5'b00010, 5'b00011};
|
||||
}
|
||||
if (func7 == 7'b0101111) {
|
||||
instr_bin[24:20] == 5'b0;
|
||||
}
|
||||
if (func7 == 7'b0100011) {
|
||||
instr_bin[24:20] inside {5'b0, 5'b00001};
|
||||
}
|
||||
if (func7 == 7'b1100011) {
|
||||
instr_bin[24:20] inside {5'b0, 5'b00001, 5'b00010, 5'b00011};
|
||||
}
|
||||
if (func7 == 7'b1101011) {
|
||||
instr_bin[24:20] inside {5'b0, 5'b00001, 5'b00010, 5'b00011};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constraint has_func7_c {
|
||||
solve opcode before func7;
|
||||
solve func7 before func3;
|
||||
if (opcode == 7'b0111011) {
|
||||
has_func3 == 1'b1;
|
||||
has_func7 == 1'b1;
|
||||
has_func2 == 1'b0;
|
||||
}
|
||||
if (opcode inside {legal_rv64i_opcode}) {
|
||||
has_func3 == 1'b1;
|
||||
has_func2 == 1'b0;
|
||||
if (((opcode == 7'b0011011) && (func3 == 3'b000)) ||
|
||||
(opcode inside {7'b0000011, 7'b0100011})) {
|
||||
has_func7 == 1'b0;
|
||||
} else {
|
||||
has_func7 == 1'b1;
|
||||
}
|
||||
}
|
||||
if (opcode inside {7'b0000111, 7'b0100111}) {
|
||||
has_func2 == 1'b0;
|
||||
has_func3 == 1'b1;
|
||||
has_func7 == 1'b0;
|
||||
}
|
||||
if (opcode inside {7'b1000011, 7'b1000111, 7'b1001011, 7'b1001111}) {
|
||||
has_func2 == 1'b1;
|
||||
has_func3 == 1'b0;
|
||||
has_func7 == 1'b0;
|
||||
}
|
||||
if (opcode == 7'b1010011) {
|
||||
has_func2 == 1'b0;
|
||||
has_func7 == 1'b1;
|
||||
if (func7 inside {7'b0010000, 7'b0010100, 7'b1110000, 7'b1010000, 7'b1110000, 7'b1111000,
|
||||
7'b0010001, 7'b0010101, 7'b1010001, 7'b1110001, 7'b1111001, 7'b0010011,
|
||||
7'b0010011, 7'b0010111, 7'b1010011, 7'b1110011}) {
|
||||
has_func3 == 1'b1;
|
||||
} else {
|
||||
has_func3 == 1'b0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
`uvm_object_utils(cva6_unsupported_instr_c)
|
||||
`uvm_object_new
|
||||
|
||||
function string get_bin_str();
|
||||
if (compressed) begin
|
||||
get_bin_str = $sformatf("%4h", instr_bin[15:0]);
|
||||
end else begin
|
||||
get_bin_str = $sformatf("%8h", instr_bin[31:0]);
|
||||
end
|
||||
`uvm_info(`gfn, $sformatf("unsupported extension instruction type: %0s, unsupported instruction: 0x%0x",
|
||||
unsupported_instr.name(), instr_bin), UVM_HIGH)
|
||||
endfunction
|
||||
|
||||
function void post_randomize();
|
||||
comment = unsupported_instr.name();
|
||||
if (unsupported_instr == rv64i_instr) begin
|
||||
comment = {comment};
|
||||
end else if (unsupported_instr == rv64m_instr) begin
|
||||
comment = {comment};
|
||||
end else if (unsupported_instr == rvfdq_instr) begin
|
||||
comment = {comment};
|
||||
end else if (unsupported_instr == rv64c_instr) begin
|
||||
comment = {comment};
|
||||
end
|
||||
endfunction
|
||||
|
||||
endclass
|
Loading…
Add table
Add a link
Reference in a new issue