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
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