diff --git a/cva6/env/corev-dv/custom/cvxif_custom_instr.sv b/cva6/env/corev-dv/custom/cvxif_custom_instr.sv index e847ad32b..7d0b70722 100644 --- a/cva6/env/corev-dv/custom/cvxif_custom_instr.sv +++ b/cva6/env/corev-dv/custom/cvxif_custom_instr.sv @@ -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 diff --git a/cva6/env/corev-dv/custom/riscv_custom_instr_enum.sv b/cva6/env/corev-dv/custom/riscv_custom_instr_enum.sv index e994fb7d5..314a3078d 100644 --- a/cva6/env/corev-dv/custom/riscv_custom_instr_enum.sv +++ b/cva6/env/corev-dv/custom/riscv_custom_instr_enum.sv @@ -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, diff --git a/cva6/env/corev-dv/custom/rv32x_instr.sv b/cva6/env/corev-dv/custom/rv32x_instr.sv index 0caec3571..098e15b0f 100644 --- a/cva6/env/corev-dv/custom/rv32x_instr.sv +++ b/cva6/env/corev-dv/custom/rv32x_instr.sv @@ -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) diff --git a/cva6/env/corev-dv/cva6-files.f b/cva6/env/corev-dv/cva6-files.f index c9c84a59b..31ac1e72e 100644 --- a/cva6/env/corev-dv/cva6-files.f +++ b/cva6/env/corev-dv/cva6-files.f @@ -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 diff --git a/cva6/env/corev-dv/cva6_asm_program_gen.sv b/cva6/env/corev-dv/cva6_asm_program_gen.sv index d89101c87..9fb9e2e45 100644 --- a/cva6/env/corev-dv/cva6_asm_program_gen.sv +++ b/cva6/env/corev-dv/cva6_asm_program_gen.sv @@ -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); diff --git a/cva6/env/corev-dv/cva6_defines.svh b/cva6/env/corev-dv/cva6_defines.svh index 1b8395170..4ce0352ce 100644 --- a/cva6/env/corev-dv/cva6_defines.svh +++ b/cva6/env/corev-dv/cva6_defines.svh @@ -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) diff --git a/cva6/env/corev-dv/cva6_instr_pkg.sv b/cva6/env/corev-dv/cva6_instr_pkg.sv deleted file mode 100644 index 39c62036e..000000000 --- a/cva6/env/corev-dv/cva6_instr_pkg.sv +++ /dev/null @@ -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 diff --git a/cva6/env/corev-dv/cva6_instr_test_pkg.sv b/cva6/env/corev-dv/cva6_instr_test_pkg.sv index 5948ac0e2..df23d5ca7 100644 --- a/cva6/env/corev-dv/cva6_instr_test_pkg.sv +++ b/cva6/env/corev-dv/cva6_instr_test_pkg.sv @@ -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; diff --git a/cva6/env/corev-dv/cva6_signature_pkg.sv b/cva6/env/corev-dv/cva6_signature_pkg.sv new file mode 100644 index 000000000..ffe40a508 --- /dev/null +++ b/cva6/env/corev-dv/cva6_signature_pkg.sv @@ -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 diff --git a/cva6/env/corev-dv/target/rv32imc/riscv_core_setting.sv b/cva6/env/corev-dv/target/rv32imc/riscv_core_setting.sv index 1b7042a32..9cbbe98d9 100644 --- a/cva6/env/corev-dv/target/rv32imc/riscv_core_setting.sv +++ b/cva6/env/corev-dv/target/rv32imc/riscv_core_setting.sv @@ -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 }; diff --git a/cva6/env/corev-dv/user_extension/x_extn_user_define.h b/cva6/env/corev-dv/user_extension/x_extn_user_define.h index d8a7764ca..69be79870 100644 --- a/cva6/env/corev-dv/user_extension/x_extn_user_define.h +++ b/cva6/env/corev-dv/user_extension/x_extn_user_define.h @@ -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 -