chipsalliance / riscv-dv

Random instruction generator for RISC-V processor verification
Apache License 2.0
996 stars 323 forks source link

mmode_exception_handler is not considering the instruction misaligned, load address misaligned, store/amo address misaligned #949

Open annasaikiran opened 12 months ago

annasaikiran commented 12 months ago

The mmode_exception_handler which is generated from riscv_asm_gen_program.sv is not handling Instruction misaglined, load address misaligned, store_amo_address misaligned exceptions.

So, when there is an exception due to the above-mentioned exceptions, the program ends without executing the subsequent instructions.

Also, when there is an exception due to the above, the instruction will not execute completely (The destination GPR wouldn't get an updated value due to the instr. exception). The GPR would still contain its previous value.

Is there any reason for not having the instruction misaligned, load address misaligned, store/amo address misaligned handlers where we can switch the MEPC (mepc=mepc+4) to return back to the subsequent instructions & execute remaining program?

Below is the code that is not handling the mentioned exceptions. ..................

// 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_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_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_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)), // Skip checking tval for illegal instruction as it's implementation specific $sformatf("csrr x%0d, 0x%0x # %0s", cfg.gpr[1], tval, tval.name()), // use JALR to jump to test_done. $sformatf("1: la x%0d, test_done", cfg.scratch_reg), $sformatf("jalr x1, x%0d, 0", cfg.scratch_reg) }; gen_section(get_label($sformatf("%0smode_exception_handler", mode), hart), instr); endfunction