CVA6-DV : Update cva6-dv to support cvxif custom instruction base on new spec

This commit is contained in:
Ayoub Jalali 2023-06-23 10:31:10 +02:00
parent 76c10be0d9
commit 5009accd4f
11 changed files with 500 additions and 105 deletions

View file

@ -17,26 +17,25 @@
*/
class cvxif_custom_instr extends riscv_custom_instr;
riscv_instr_name_t instr_name;
rand riscv_reg_t rs1;
rand riscv_reg_t rs2;
rand riscv_reg_t rs3;
`uvm_object_utils(cvxif_custom_instr)
`uvm_object_new
static function bit register(riscv_instr_name_t instr_name);
`uvm_info("custom_cva6_instr", $sformatf("Registering %0s", instr_name.name()), UVM_LOW)
instr_registry[instr_name] = 1;
return 1;
endfunction : register
virtual function string get_instr_name();
get_instr_name = instr_name.name();
return get_instr_name;
endfunction : get_instr_name
constraint cus_rx {
if (instr_name inside {CUS_EXC}) {
rd == 0;
rs1 inside {[0:9],[11:13],15};
rs2 == 0;
}
}
// Convert the instruction to assembly code
virtual function string convert2asm(string prefix = "");
string asm_str;
@ -46,12 +45,9 @@ class cvxif_custom_instr extends riscv_custom_instr;
CUS_ADD_MULTI: asm_str = $sformatf("%0s %0s, %0s, %0s", asm_str, rd.name(), rs1.name(), rs2.name());
CUS_ADD_RS3: asm_str = $sformatf("%0s %0s, %0s, %0s, %0s", asm_str, rd.name(), rs1.name(), rs2.name(), rs3.name());
CUS_NOP: asm_str = "cus_nop";
/* following instructions are not yet supported by cva6 */
//CUS_EXC: asm_str = $sformatf("%0s %0s, %0s, %0s", asm_str, rd.name(), rs1.name(), rs2.name());
//CUS_U_ADD: asm_str = $sformatf("%0s %0s, %0s, %0s", asm_str, rd.name(), rs1.name(), rs2.name());
//CUS_S_ADD: asm_str = $sformatf("%0s %0s, %0s, %0s", asm_str, rd.name(), rs1.name(), rs2.name());
//CUS_NOP_EXC: asm_str = "cus_nop_exc";
//CUS_ISS_EXC: asm_str = $sformatf("%0s %0s, %0s, %0s", asm_str, rd.name(), rs1.name(), rs2.name());
CUS_S_ADD: asm_str = $sformatf("%0s %0s, %0s, %0s", asm_str, rd.name(), rs1.name(), rs2.name());
CUS_U_ADD: asm_str = $sformatf("%0s %0s, %0s, %0s", asm_str, rd.name(), rs1.name(), rs2.name());
CUS_EXC: asm_str = $sformatf("%0s %0s, %0s, %0s", asm_str, rd.name(), rs1.name(), rs2.name());
endcase
comment = {get_instr_name(), " ", comment};
if (comment != "") begin
@ -61,22 +57,21 @@ class cvxif_custom_instr extends riscv_custom_instr;
endfunction : convert2asm
virtual function void set_imm_len();
imm_len = 7;
imm_len = 6;
endfunction : set_imm_len
function bit [6:0] get_opcode();
case (instr_name) inside
{CUS_ADD, CUS_ADD_MULTI, CUS_ADD_RS3, CUS_NOP} : get_opcode = 7'b1111011;
// {CUS_ADD, CUS_ADD_MULTI, CUS_ADD_RS3, CUS_NOP, CUS_EXC, CUS_U_ADD, CUS_S_ADD} : get_opcode = 7'b1111011;
{CUS_ADD, CUS_ADD_MULTI, CUS_ADD_RS3, CUS_NOP, CUS_U_ADD, CUS_S_ADD, CUS_EXC} : get_opcode = 7'b1111011;
default : `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name()))
endcase
endfunction
virtual function bit [2:0] get_func3();
case (instr_name) inside
{CUS_ADD_MULTI, CUS_ADD_RS3, CUS_NOP} : get_func3 = 3'b000;
{CUS_ADD} : get_func3 = 3'b001;
// {CUS_ADD, CUS_ADD_MULTI, CUS_ADD_RS3, CUS_NOP, CUS_EXC, CUS_U_ADD, CUS_S_ADD} : get_func3 = 3'b000;
CUS_ADD_MULTI, CUS_ADD_RS3, CUS_U_ADD, CUS_S_ADD : get_func3 = 3'b000;
CUS_ADD : get_func3 = 3'b001;
CUS_EXC : get_func3 = 3'b010;
endcase
endfunction
@ -85,10 +80,9 @@ class cvxif_custom_instr extends riscv_custom_instr;
CUS_ADD : get_func7 = 7'b0000000;
CUS_NOP : get_func7 = 7'b0000000;
CUS_ADD_MULTI : get_func7 = 7'b0001000;
// CUS_EXC : get_func7 = 7'b1000000;
// CUS_M_ADD : get_func7 = 7'b0000010;
// CUS_S_ADD : get_func7 = 7'b0000110;
// CUS_EXC : get_func7 = 7'b0100000;
CUS_U_ADD : get_func7 = 7'b0000010;
CUS_S_ADD : get_func7 = 7'b0000110;
CUS_EXC : get_func7 = 7'b1100000;
endcase
endfunction
@ -99,17 +93,21 @@ class cvxif_custom_instr extends riscv_custom_instr;
endfunction
virtual function void set_rand_mode();
/*case (instr_name) inside
"CUS_EXC", "CUS_ISS_EXC": begin
has_rd= 1'b0;
has_rs2= 1'b0;
case (instr_name) inside
"CUS_NOP": begin
has_rd = 1'b0;
has_rs2 = 1'b0;
has_rs2 = 1'b0;
has_imm = 1'b0;
end
endcase*/
endcase
endfunction
function void pre_randomize();
rd.rand_mode(has_rd);
rs1.rand_mode(has_rs1);
rs2.rand_mode(has_rs2);
imm.rand_mode(has_imm);
endfunction
endclass

View file

@ -15,8 +15,6 @@ CUS_ADD,
CUS_ADD_MULTI,
CUS_NOP,
CUS_ADD_RS3,
// CUS_EXC,
// CUS_M_ADD,
// CUS_S_ADD,
// CUS_NOP_EXC,
// CUS_ISS_EXC,
CUS_EXC,
CUS_U_ADD,
CUS_S_ADD,

View file

@ -13,8 +13,6 @@
`DEFINE_CVXIF_CUSTOM_INSTR(CUS_ADD_MULTI, R_FORMAT, ARITHMETIC, RV32X)
`DEFINE_CVXIF_CUSTOM_INSTR(CUS_NOP, R_FORMAT, ARITHMETIC, RV32X)
`DEFINE_CVXIF_CUSTOM_INSTR(CUS_ADD_RS3, R4_FORMAT, ARITHMETIC, RV32X)
// `DEFINE_CVXIF_CUSTOM_INSTR(CUS_EXC, R_FORMAT, ARITHMETIC, RV32X)
// `DEFINE_CVXIF_CUSTOM_INSTR(CUS_M_ADD, R_FORMAT, ARITHMETIC, RV32X)
// `DEFINE_CVXIF_CUSTOM_INSTR(CUS_S_ADD, R_FORMAT, ARITHMETIC, RV32X)
// `DEFINE_CVXIF_CUSTOM_INSTR(CUS_NOP_EXC, R_FORMAT, ARITHMETIC, RV32X)
// `DEFINE_CVXIF_CUSTOM_INSTR(CUS_ISS_EXC, R_FORMAT, ARITHMETIC, RV32X)
`DEFINE_CVXIF_CUSTOM_INSTR(CUS_EXC, R_FORMAT, ARITHMETIC, RV32X)
`DEFINE_CVXIF_CUSTOM_INSTR(CUS_U_ADD, R_FORMAT, ARITHMETIC, RV32X)
`DEFINE_CVXIF_CUSTOM_INSTR(CUS_S_ADD, R_FORMAT, ARITHMETIC, RV32X)

View file

@ -15,6 +15,6 @@
+incdir+${CVA6_DV_ROOT}/user_extension
// SOURCES
${CVA6_DV_ROOT}/cva6_instr_pkg.sv
${CVA6_DV_ROOT}/cva6_signature_pkg.sv
${CVA6_DV_ROOT}/cva6_instr_test_pkg.sv

View file

@ -60,6 +60,375 @@ class cva6_asm_program_gen_c extends riscv_asm_program_gen;
end
endfunction
// Generate the interrupt and trap handler for different privileged mode.
// The trap handler checks the xCAUSE to determine the type of the exception and jumps to
// corresponding exeception handling routine.
virtual function void gen_trap_handler_section(int hart,
string mode,
privileged_reg_t cause, privileged_reg_t tvec,
privileged_reg_t tval, privileged_reg_t epc,
privileged_reg_t scratch, privileged_reg_t status,
privileged_reg_t ie, privileged_reg_t ip);
bit is_interrupt = 'b1;
string tvec_name;
string instr[$];
if (cfg.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);
// 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())};
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("bne x%0d, x0, %0s%0smode_intr_handler",
cfg.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));
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);
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()),
// Breakpoint
$sformatf("li x%0d, 0x%0x # BREAKPOINT", cfg.gpr[1], BREAKPOINT),
$sformatf("beq x%0d, x%0d, %0sebreak_handler",
cfg.gpr[0], cfg.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("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),
$sformatf("beq x%0d, x%0d, %0secall_handler",
cfg.gpr[0], cfg.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)),
// Page table fault or access fault conditions
$sformatf("li x%0d, 0x%0x", cfg.gpr[1], INSTRUCTION_ACCESS_FAULT),
$sformatf("beq x%0d, x%0d, %0sinstr_fault_handler",
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
$sformatf("li x%0d, 0x%0x", cfg.gpr[1], LOAD_ACCESS_FAULT),
$sformatf("beq x%0d, x%0d, %0sload_fault_handler",
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
$sformatf("li x%0d, 0x%0x", cfg.gpr[1], STORE_AMO_ACCESS_FAULT),
$sformatf("beq x%0d, x%0d, %0sstore_fault_handler",
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
$sformatf("li x%0d, 0x%0x", cfg.gpr[1], INSTRUCTION_PAGE_FAULT),
$sformatf("beq x%0d, x%0d, %0spt_instr_fault_handler",
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
$sformatf("li x%0d, 0x%0x", cfg.gpr[1], LOAD_PAGE_FAULT),
$sformatf("beq x%0d, x%0d, %0spt_load_fault_handler",
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
$sformatf("li x%0d, 0x%0x", cfg.gpr[1], STORE_AMO_PAGE_FAULT),
$sformatf("beq x%0d, x%0d, %0spt_store_fault_handler",
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
// Illegal instruction exception
$sformatf("li x%0d, 0x%0x # ILLEGAL_INSTRUCTION", cfg.gpr[1], ILLEGAL_INSTRUCTION),
$sformatf("beq x%0d, x%0d, %0sillegal_instr_handler",
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
// Instruction Address misaligned exception
$sformatf("li x%0d, 0x%0x # INSTR ADDR MISALIGNED", cfg.gpr[1], INSTRUCTION_ADDRESS_MISALIGNED),
$sformatf("beq x%0d, x%0d, %0sinstr_misaligned_handler",
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
// Load Address misaligned exception
$sformatf("li x%0d, 0x%0x # LOAD ADDR MISALIGNED", cfg.gpr[1], LOAD_ADDRESS_MISALIGNED),
$sformatf("beq x%0d, x%0d, %0sload_misaligned_handler",
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
// Store Address misaligned exception
$sformatf("li x%0d, 0x%0x # STORE ADDR MISALIGNED", cfg.gpr[1], STORE_AMO_ADDRESS_MISALIGNED),
$sformatf("beq x%0d, x%0d, %0sstore_misaligned_handler",
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
// Skip checking tval for illegal instruction as it's implementation specific
$sformatf("csrr x%0d, 0x%0x # %0s", cfg.gpr[1], tval, tval.name()),
"1: jal x1, test_done "
};
gen_section(get_label($sformatf("%0smode_exception_handler", mode), hart), instr);
endfunction
// Trap handling routine
virtual function void gen_all_trap_handler(int hart);
string instr[$];
// If PMP isn't supported, generate the relevant trap handler sections as per usual
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);
end
// Ebreak handler
gen_ebreak_handler(hart);
// Illegal instruction handler
gen_illegal_instr_handler(hart);
// Instruction page fault handler
gen_pt_instr_fault_handler(hart);
// Load page fault handler
gen_pt_load_fault_handler(hart);
// Store page fault handler
gen_pt_store_fault_handler(hart);
// Instruction Address Misaligned handler
gen_instr_misaligned_handler(hart);
// Load Address Misaligned handler
gen_load_misaligned_handler(hart);
// Store Address Misaligned handler
gen_store_misaligned_handler(hart);
// Generate page table fault handling routine
// Page table fault is always handled in machine mode, as virtual address translation may be
// broken when page fault happens.
gen_signature_handshake(instr, CORE_STATUS, HANDLING_EXCEPTION);
if(page_table_list != null) begin
page_table_list.gen_page_fault_handling_routine(instr);
end else begin
instr.push_back("nop");
end
gen_section(get_label("pt_fault_handler", hart), instr);
endfunction
// Helper function to generate the proper sequence of handshake instructions
// to signal the testbench (see riscv_signature_pkg.sv)
function void gen_signature_handshake(ref string instr[$],
input signature_type_t signature_type,
core_status_t core_status = INITIALIZED,
test_result_t test_result = TEST_FAIL,
privileged_reg_t csr = MSCRATCH,
string addr_label = "");
if (cfg.require_signature_addr) begin
string str[$];
str = {$sformatf("li x%0d, 0x%0h", cfg.gpr[1], cfg.signature_addr)};
instr = {instr, str};
case (signature_type)
// A single data word is written to the signature address.
// Bits [7:0] contain the signature_type of CORE_STATUS, and the upper
// XLEN-8 bits contain the core_status_t data.
CORE_STATUS: begin
str = {$sformatf("li x%0d, 0x%0h", cfg.gpr[0], core_status),
$sformatf("slli x%0d, x%0d, 8", cfg.gpr[0], cfg.gpr[0]),
$sformatf("addi x%0d, x%0d, 0x%0h", cfg.gpr[0],
cfg.gpr[0], signature_type),
$sformatf("sw x%0d, 0(x%0d)", cfg.gpr[0], cfg.gpr[1])};
instr = {instr, str};
end
// A single data word is written to the signature address.
// Bits [7:0] contain the signature_type of TEST_RESULT, and the upper
// XLEN-8 bits contain the test_result_t data.
TEST_RESULT: begin
str = {$sformatf("li x%0d, 0x%0h", cfg.gpr[0], test_result),
$sformatf("slli x%0d, x%0d, 8", cfg.gpr[0], cfg.gpr[0]),
$sformatf("addi x%0d, x%0d, 0x%0h", cfg.gpr[0],
cfg.gpr[0], signature_type),
$sformatf("sw x%0d, 0(x%0d)", cfg.gpr[0], cfg.gpr[1])};
instr = {instr, str};
end
// The first write to the signature address contains just the
// signature_type of WRITE_GPR.
// It is followed by 32 consecutive writes to the signature address,
// each writing the data contained in one GPR, starting from x0 as the
// first write, and ending with x31 as the 32nd write.
WRITE_GPR: begin
str = {$sformatf("li x%0d, 0x%0h", cfg.gpr[0], signature_type),
$sformatf("sw x%0d, 0(x%0d)", cfg.gpr[0], cfg.gpr[1])};
instr = {instr, str};
for(int i = 0; i < 32; i++) begin
str = {$sformatf("sw x%0x, 0(x%0d)", i, cfg.gpr[1])};
instr = {instr, str};
end
end
// The first write to the signature address contains the
// signature_type of WRITE_CSR in bits [7:0], and the CSR address in
// the upper XLEN-8 bits.
// It is followed by a second write to the signature address,
// containing the data stored in the specified CSR.
WRITE_CSR: begin
if (!(csr inside {implemented_csr})) begin
return;
end
str = {$sformatf("li x%0d, 0x%0h", cfg.gpr[0], csr),
$sformatf("slli x%0d, x%0d, 8", cfg.gpr[0], cfg.gpr[0]),
$sformatf("addi x%0d, x%0d, 0x%0h", cfg.gpr[0],
cfg.gpr[0], signature_type),
$sformatf("sw x%0d, 0(x%0d)", cfg.gpr[0], cfg.gpr[1]),
$sformatf("csrr x%0d, 0x%0h", cfg.gpr[0], csr),
$sformatf("sw x%0d, 0(x%0d)", cfg.gpr[0], cfg.gpr[1])};
instr = {instr, str};
end
default: begin
`uvm_fatal(`gfn, "signature_type is not defined")
end
endcase
end
endfunction
// ECALL trap handler
virtual function void gen_ecall_handler(int hart);
string instr[$];
gen_signature_handshake(instr, CORE_STATUS, ECALL_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("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("ecall_handler", hart), instr);
endfunction
// 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);
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("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("instr_fault_handler", hart), instr);
endfunction
// TODO: handshake correct csr based on delegation
virtual function void gen_load_fault_handler(int hart);
string instr[$];
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("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("load_fault_handler", hart), instr);
endfunction
// 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);
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("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("store_fault_handler", hart), instr);
endfunction
virtual function void gen_pt_instr_fault_handler(int hart);
string instr[$];
gen_signature_handshake(instr, CORE_STATUS, INSTR_PAGE_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("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("pt_instr_fault_handler", hart), instr);
endfunction
virtual function void gen_pt_load_fault_handler(int hart);
string instr[$];
gen_signature_handshake(instr, CORE_STATUS, LOAD_PAGE_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("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("pt_load_fault_handler", hart), instr);
endfunction
virtual function void gen_pt_store_fault_handler(int hart);
string instr[$];
gen_signature_handshake(instr, CORE_STATUS, STORE_PAGE_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("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("pt_store_fault_handler", hart), instr);
endfunction
virtual function void gen_load_misaligned_handler(int hart);
string instr[$];
gen_signature_handshake(instr, CORE_STATUS, LD_MISALIGNED_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("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("load_misaligned_handler", hart), instr);
endfunction
virtual function void gen_store_misaligned_handler(int hart);
string instr[$];
gen_signature_handshake(instr, CORE_STATUS, ST_MISALIGNED_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("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("store_misaligned_handler", hart), instr);
endfunction
virtual function void gen_instr_misaligned_handler(int hart);
string instr[$];
gen_signature_handshake(instr, CORE_STATUS, INSTR_MISALIGNED_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("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("instr_misaligned_handler", hart), instr);
endfunction
virtual function void gen_test_done();
string str = format_string("test_done:", LABEL_STR_LEN);

View file

@ -10,21 +10,6 @@
// -------------------------------------------------------------------------------------------
// Custom extension instruction for CVXIF
`define INSTR_BODY(instr_n, instr_format, instr_category, instr_group, imm_tp = IMM) \
static bit valid = cvxif_custom_instr::register(instr_n); \
`uvm_object_utils(riscv_``instr_n``_instr) \
function new(string name = ""); \
super.new(name); \
this.instr_name = ``instr_n; \
this.format = ``instr_format; \
this.group = ``instr_group; \
this.category = ``instr_category; \
this.imm_type = ``imm_tp; \
set_imm_len(); \
set_rand_mode(); \
endfunction \
endclass
`define DEFINE_CVXIF_CUSTOM_INSTR(instr_n, instr_format, instr_category, instr_group, imm_tp = IMM) \
class riscv_``instr_n``_instr extends cvxif_custom_instr; \
`INSTR_BODY(instr_n, instr_format, instr_category, instr_group, imm_tp)

View file

@ -1,36 +0,0 @@
// Copyright 2022 Thales DIS design services SAS
// Copyright 2022 OpenHW Group
//
// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0
// You may obtain a copy of the License at https://solderpad.org/licenses/
//
// Original Author: Zineb EL KACIMI (zineb.el-kacimi@external.thalesgroup.com)
// ------------------------------------------------------------------------------ //
package cva6_instr_pkg;
typedef enum {
// Add custom instruction name enum
CUS_ADD,
CUS_ADD_MULTI,
CUS_NOP,
CUS_ADD_RS3
// CUS_EXC,
// CUS_M_ADD,
// CUS_S_ADD,
// CUS_NOP_EXC,
// CUS_ISS_EXC,
} riscv_instr_name_t;
import uvm_pkg::*;
`include "cva6_defines.svh"
import riscv_instr_pkg::*;
`include "cva6_instr_gen_config.sv"
`include "cva6_asm_program_gen.sv"
`include "cvxif_custom_instr.sv"
`include "rv32x_instr.sv"
`include "riscv_core_setting.sv"
endpackage

View file

@ -12,11 +12,15 @@
package cva6_instr_test_pkg;
import uvm_pkg::*;
`include "cva6_defines.svh"
import riscv_instr_pkg::*;
import riscv_instr_test_pkg::*;
import cva6_instr_pkg::*;
import cva6_signature_pkg::*;
`include "cva6_instr_gen_config.sv"
`include "cva6_asm_program_gen.sv"
`include "cva6_instr_base_test.sv"
`include "cvxif_custom_instr.sv"
`include "rv32x_instr.sv"
endpackage : cva6_instr_test_pkg;

66
cva6/env/corev-dv/cva6_signature_pkg.sv vendored Normal file
View file

@ -0,0 +1,66 @@
/*
* Copyright 2019 Google LLC
*
* 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.
*/
package cva6_signature_pkg;
// Will be the lowest 8 bits of the data word
typedef enum bit[7:0] {
// Information sent to the core relating its current status.
// Bits [12:8] of the data word will be the core_status_t value
// corresponding to the current core status.
CORE_STATUS,
// Information sent to the core conveying the uvm simulation result.
// Bit [8] of the data word will be the test_result_t value.
TEST_RESULT,
// Sent to the core to indicate a dump of GPRs to testbench.
// Will be followed by 32 writes of registers x0-x32.
WRITE_GPR,
// Sent to the core to indicate a write of a CSR's data.
// Bits [19:8] of the data word will be the CSR address.
// Will be followed by a second write of the actual data from the CSR.
WRITE_CSR
} signature_type_t;
typedef enum bit[4:0] {
INITIALIZED,
IN_DEBUG_MODE,
IN_MACHINE_MODE,
IN_HYPERVISOR_MODE,
IN_SUPERVISOR_MODE,
IN_USER_MODE,
HANDLING_IRQ,
FINISHED_IRQ,
HANDLING_EXCEPTION,
INSTR_FAULT_EXCEPTION,
ILLEGAL_INSTR_EXCEPTION,
LOAD_FAULT_EXCEPTION,
STORE_FAULT_EXCEPTION,
EBREAK_EXCEPTION,
ECALL_EXCEPTION,
INSTR_MISALIGNED_EXCEPTION,
LD_MISALIGNED_EXCEPTION,
ST_MISALIGNED_EXCEPTION,
INSTR_PAGE_FAULT_EXCEPTION,
LOAD_PAGE_FAULT_EXCEPTION,
STORE_PAGE_FAULT_EXCEPTION
} core_status_t;
typedef enum bit {
TEST_PASS,
TEST_FAIL
} test_result_t;
endpackage

View file

@ -24,7 +24,7 @@ parameter int XLEN = 32;
parameter satp_mode_t SATP_MODE = BARE;
// Supported Privileged mode
privileged_mode_t supported_privileged_mode[] = {MACHINE_MODE};
privileged_mode_t supported_privileged_mode[] = {USER_MODE, SUPERVISOR_MODE, MACHINE_MODE};
// Unsupported instructions
riscv_instr_name_t unsupported_instr[];
@ -99,8 +99,14 @@ interrupt_cause_t implemented_interrupt[] = {
`else
const interrupt_cause_t implemented_interrupt[] = {
`endif
U_SOFTWARE_INTR,
S_SOFTWARE_INTR,
M_SOFTWARE_INTR,
U_TIMER_INTR,
S_TIMER_INTR,
M_TIMER_INTR,
U_EXTERNAL_INTR,
S_EXTERNAL_INTR,
M_EXTERNAL_INTR
};
@ -109,10 +115,18 @@ exception_cause_t implemented_exception[] = {
`else
const exception_cause_t implemented_exception[] = {
`endif
INSTRUCTION_ADDRESS_MISALIGNED,
INSTRUCTION_ACCESS_FAULT,
ILLEGAL_INSTRUCTION,
BREAKPOINT,
LOAD_ADDRESS_MISALIGNED,
LOAD_ACCESS_FAULT,
ECALL_MMODE
STORE_AMO_ADDRESS_MISALIGNED,
STORE_AMO_ACCESS_FAULT,
ECALL_UMODE,
ECALL_SMODE,
ECALL_MMODE,
INSTRUCTION_PAGE_FAULT,
LOAD_PAGE_FAULT,
STORE_AMO_PAGE_FAULT
};

View file

@ -27,14 +27,14 @@
.insn r CUSTOM_3, 0x0, 0x1, \rd, \rs1, \rs2, \rs3
.endm
# CUS_U_ADD rd, rs1, rs2 -> .insn r CUSTOM_3, 0x0, 0x6, rd, rs1, rs2
.macro cus_m_add rd, rs1, rs2
.insn r CUSTOM_3, 0x0, 0x6, \rd, \rs1, \rs2
# CUS_U_ADD rd, rs1, rs2 -> .insn r CUSTOM_3, 0x0, 0x2, rd, rs1, rs2
.macro cus_u_add rd, rs1, rs2
.insn r CUSTOM_3, 0x0, 0x2, \rd, \rs1, \rs2
.endm
# CUS_S_ADD rd, rs1, rs2 -> .insn r CUSTOM_3, 0x0, 0x2, rd, rs1, rs2
# CUS_S_ADD rd, rs1, rs2 -> .insn r CUSTOM_3, 0x0, 0x6, rd, rs1, rs2
.macro cus_s_add rd, rs1, rs2
.insn r CUSTOM_3, 0x0, 0x2, \rd, \rs1, \rs2
.insn r CUSTOM_3, 0x0, 0x6, \rd, \rs1, \rs2
.endm
# CUS_ADD_MULTI rd, rs1, rs2 -> .insn r CUSTOM_3, 0x0, 0x8, rd, rs1, rs2
@ -42,9 +42,8 @@
.insn r CUSTOM_3, 0x0, 0x8, \rd, \rs1, \rs2
.endm
# CUS_EXC rd, rs1, rs2 -> .insn r CUSTOM_3, 0x0, 0x40, rd, rs1, rs2
# CUS_EXC rd, rs1, rs2 -> .insn r CUSTOM_3, 0x2, 0x60, rd, rs1, rs2
.macro cus_exc rd, rs1, rs2
.insn r CUSTOM_3, 0x0, 0x40, \rd, \rs1, \rs2
.insn r CUSTOM_3, 0x2, 0x60, \rd, \rs1, \rs2
.endm