def gen_trap_handler_section(self, hart, mode, cause, tvec, tval, epc, scratch, status, ie, ip): is_interrupt = 1 tvec_name = "" instr = [] if (cfg.mtvec_mode == mtvec_mode_t.VECTORED): self.gen_interrupt_vector_table(hart, mode, status, cause, ie, ip, scratch, instr) else: # Push user mode GPR to kernel stack before executing exception handling, # this is to avoid exception handling routine modify user program state # unexpectedly # TODO pkg_ins.push_gpr_to_kernel_stack(status, scratch, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr) # The trap handler will occupy one 4KB page, it will be allocated one entry in # the page table with a specific privileged mode. if (rcs.SATP_MODE != "BARE"): self.instr_stream.append(".align 12") else: self.instr_stream.append(".align {}".format(cfg.tvec_alignment)) tvec_name = tvec.name self.gen_section( pkg_ins.get_label("{}_handler".format(tvec_name.lower()), hart), instr)
def gen_interrupt_vector_table(self, hart, mode, status, cause, ie, ip, scratch, instr): '''In vector mode, the BASE address is shared between interrupt 0 and exception handling. When vectored interrupts are enabled, interrupt cause 0, which corresponds to user-mode software interrupts, are vectored to the same location as synchronous exceptions. This ambiguity does not arise in practice, since user-mode software interrupts are either disabled or delegated''' instr.extend( (".option norvc;", "j {}{}mode_exception_handler".format(pkg_ins.hart_prefix(hart), mode))) # Redirect the interrupt to the corresponding interrupt handler for i in range(1, rcs.max_interrupt_vector_num): instr.append("j {}{}mode_intr_vector_{}".format( pkg_ins.hart_prefix(hart), mode, i)) if not cfg.disable_compressed_instr: instr.append(".option rvc;") for i in range(1, rcs.max_interrupt_vector_num): intr_handler = [] pkg_ins.push_gpr_to_kernel_stack(status, scratch, cfg.mstatus_mprv, cfg.sp, cfg.tp, intr_handler) self.gen_signature_handshake( instr=intr_handler, signature_type=signature_type_t.CORE_STATUS, core_status=core_status_t.HANDLING_IRQ) intr_handler.extend(( "csrr x{}, {} # {}".format(cfg.gpr[0], hex(cause), cause.name), # Terminate the test if xCause[31] != 0 (indicating exception) "srli x{}, x{}, {}".format(cfg.gpr[0], cfg.gpr[0], hex(rcs.XLEN - 1)), "beqz x{}, 1f".format(cfg.gpr[0]))) csr_list = [status, cause, ie, ip] for csr_t in csr_list: self.gen_signature_handshake( instr=intr_handler, signature_type=signature_type_t.WRITE_CSR, csr=csr_t) # Jump to commmon interrupt handling routine intr_handler.extend( ("j {}{}mode_intr_handler".format(pkg_ins.hart_prefix(hart), mode), "1: la x{}, test_done".format(cfg.scratch_reg), "jalr x0, x{}, 0".format(cfg.scratch_reg))) self.gen_section( pkg_ins.get_label("{}mode_intr_vector_{}".format(mode, i), hart), intr_handler)
def gen_trap_handler_section(self, hart, mode, cause, tvec, tval, epc, scratch, status, ie, ip): is_interrupt = 1 tvec_name = "" instr = [] if cfg.mtvec_mode == mtvec_mode_t.VECTORED: self.gen_interrupt_vector_table(hart, mode, status, cause, ie, ip, scratch, instr) else: # Push user mode GPR to kernel stack before executing exception handling, # this is to avoid exception handling routine modify user program state # unexpectedly # TODO pkg_ins.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: instr.append("csrr x{}, {} # {}".format( cfg.gpr[0].value, hex(status.value), status.name)) instr.append("csrr x{}, {} # {}\n".format( cfg.gpr[0].value, hex(cause.value), cause.name) + "{}srli x{}, x{}, {}\n".format( pkg_ins.indent, cfg.gpr[0].value, cfg.gpr[0].value, rcs.XLEN - 1) + "{}bne x{}, x0, {}{}mode_instr_handler".format( pkg_ins.indent, cfg.gpr[0].value, pkg_ins.hart_prefix(hart), mode)) # The trap handler will occupy one 4KB page, it will be allocated one entry in # the page table with a specific privileged mode. if rcs.SATP_MODE != satp_mode_t.BARE: self.instr_stream.append(".align 12") else: self.instr_stream.append(".align {}".format(cfg.tvec_alignment)) tvec_name = tvec.name self.gen_section( pkg_ins.get_label("{}_handler".format(tvec_name.lower()), hart), instr) # TODO Exception handler instr = [] if cfg.mtvec_mode == mtvec_mode_t.VECTORED: pkg_ins.push_gpr_to_kernel_stack(status, scratch, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr)
def gen_trap_handler_section(self, hart, mode, cause, tvec, tval, epc, scratch, status, ie, ip): # is_interrupt = 1 tvec_name = "" instr = [] if cfg.mtvec_mode == mtvec_mode_t.VECTORED: self.gen_interrupt_vector_table(hart, mode, status, cause, ie, ip, scratch, instr) else: # Push user mode GPR to kernel stack before executing exception handling, # this is to avoid exception handling routine modify user program state # unexpectedly # TODO pkg_ins.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: instr.append("csrr x{}, {} # {}".format( cfg.gpr[0], hex(status), status.name)) instr.append("csrr x{}, {} # {}\n".format(cfg.gpr[0], hex( cause), cause.name) + "{}srli x{}, x{}, {}\n".format( pkg_ins.indent, cfg.gpr[0], cfg.gpr[0], rcs.XLEN - 1) + "{}bne x{}, x0, {}{}mode_intr_handler".format( pkg_ins.indent, cfg.gpr[0], pkg_ins.hart_prefix(hart), mode)) # The trap handler will occupy one 4KB page, it will be allocated one entry in # the page table with a specific privileged mode. if rcs.SATP_MODE != satp_mode_t.BARE: self.instr_stream.append(".align 12") else: self.instr_stream.append(".align {}".format(cfg.tvec_alignment)) tvec_name = tvec.name self.gen_section( pkg_ins.get_label("{}_handler".format(tvec_name.lower()), hart), instr) # TODO Exception handlers instr = [] if cfg.mtvec_mode == mtvec_mode_t.VECTORED: pkg_ins.push_gpr_to_kernel_stack(status, scratch, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr) self.gen_signature_handshake(instr, signature_type_t.CORE_STATUS, core_status_t.HANDLING_EXCEPTION) # 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). instr.extend(( "csrr x{}, 0x{} # {}".format(cfg.gpr[0], epc, epc.name), "csrr x{}, 0x{} # {}".format(cfg.gpr[0], cause, cause.name), # Illegal instruction exception "li x{}, {} # ILLEGAL_INSTRUCTION".format( cfg.gpr[1], hex(exception_cause_t.ILLEGAL_INSTRUCTION)), "beq x{}, x{}, {}illegal_instr_handler".format( cfg.gpr[0], cfg.gpr[1], pkg_ins.hart_prefix(hart)), # Skip checking tval for illegal instruction as it's implementation specific "csrr x{}, {} # {}".format(cfg.gpr[1], hex(tval), tval.name), # use JALR to jump to test_done. "1: la x{}, test_done".format(cfg.scratch_reg), "jalr x1, x{}, 0".format(cfg.scratch_reg))) self.gen_section( pkg_ins.get_label("{}mode_exception_handler".format(mode), hart), instr)