def gen_data_page(self, hart_id, pattern, is_kernel=0, amo=0):
     temp_data = []
     self.data_page_str.clear()
     if is_kernel:
         self.mem_region_setting = cfg.s_mem_region
     elif amo:
         self.mem_region_setting = cfg.amo_region
     else:
         self.mem_region_setting = cfg.mem_region
     for i in range(len(self.mem_region_setting)):
         logging.info("Generate data section: {} size:0x{} xwr:0x{}".format(
             self.mem_region_setting[i].name,
             self.mem_region_setting[i].size_in_bytes,
             self.mem_region_setting[i].xwr))
         if amo:
             if cfg.use_push_data_section:
                 self.data_page_str.append(
                     ".pushsection .{},\"aw\",@progbits;".format(
                         self.mem_region_setting[i].name))
             else:
                 self.data_page_str.append(
                     ".section .{},\"aw\",@progbits;".format(
                         self.mem_region_setting[i].name))
             self.data_page_str.append("{}:".format(
                 self.mem_region_setting[i].name))
         else:
             if cfg.use_push_data_section:
                 self.data_page_str.append(
                     ".pushsection .{},\"aw\",@progbits;".format(
                         pkg_ins.hart_prefix(hart_id) +
                         self.mem_region_setting[i].name))
             else:
                 self.data_page_str.append(
                     ".section .{},\"aw\",@progbits;".format(
                         pkg_ins.hart_prefix(hart_id) +
                         self.mem_region_setting[i].name))
             self.data_page_str.append("{}:".format(
                 pkg_ins.hart_prefix(hart_id) +
                 self.mem_region_setting[i].name))
         page_size = self.mem_region_setting[i].size_in_bytes
         for i in range(0, page_size, 32):
             if page_size - 1 >= 32:
                 temp_data = self.gen_data(idx=i,
                                           pattern=pattern,
                                           num_of_bytes=32,
                                           data=temp_data)
             else:
                 temp_data = self.gen_data(idx=i,
                                           pattern=pattern,
                                           num_of_bytes=page_size - 1,
                                           data=temp_data)
             tmp_str = pkg_ins.format_string(
                 ".word {}".format(pkg_ins.format_data(temp_data)),
                 pkg_ins.LABEL_STR_LEN)
             self.data_page_str.append(tmp_str)
             if cfg.use_push_data_section:
                 self.data_page_str.append(".popsection")
    def setup_epc(self, hart):
        instr = []
        instr.append("la x{}, {}init".format(cfg.gpr[0].value, pkg_ins.hart_prefix(hart)))
        # if(cfg.virtual_addr_translation_on):
        # instr.append("slli x{}, x{}")
        # TODO
        mode_name = cfg.init_privileged_mode
        instr.append("csrw mepc, x{}".format(cfg.gpr[0].value))
        if(not rcs.support_pmp):  # TODO
            instr.append("j {}init_{}".format(pkg_ins.hart_prefix(hart), mode_name.name.lower()))

        self.gen_section(pkg_ins.get_label("mepc_setup", hart), instr)
Beispiel #3
0
 def add_rs1_init_la_instr(self, gpr, idx, base = 0):
     la_instr = riscv_pseudo_instr()
     la_instr.pseudo_instr_name = riscv_pseudo_instr_name_t.LA
     la_instr.rd = gpr
     if self.load_store_shared_memory:
         la_instr.imm_str = "{}+{}".format(cfg.amo_region[idx].name, base)
     elif self.kernel_mode:
         la_instr.imm_str = "{}{}+{}".format(pkg_ins.hart_prefix(self.hart),
                                             cfg.s_mem_region[idx].name, base)
     else:
         la_instr.imm_str = "{}{}+{}".format(pkg_ins.hart_prefix(self.hart),
                                             cfg.mem_region[idx].name, base)
     self.instr_list.insert(0, la_instr)
Beispiel #4
0
 def setup_epc(self, hart):
     instr = []
     instr.append("la x{}, {}init".format(cfg.gpr[0], pkg_ins.hart_prefix(hart)))
     if cfg.virtual_addr_translation_on:
         # For supervisor and user mode, use virtual address instead of physical address.
         # Virtual address starts from address 0x0, here only the lower 12 bits are kept
         # as virtual address offset.
         instr.append("slli x{}, x{}, {}".format(cfg.gpr[0], cfg.gpr[0], rcs.XLEN - 12) +
                      "srli x{}, x{}, {}".format(cfg.gpr[0], cfg.gpr[0], rcs.XLEN - 12))
     mode_name = cfg.init_privileged_mode.name
     instr.append("csrw {}, x{}".format(hex(privileged_reg_t.MEPC), cfg.gpr[0]))
     if not rcs.support_pmp:
         instr.append("j {}init_{}".format(pkg_ins.hart_prefix(hart), mode_name.lower()))
     self.gen_section(pkg_ins.get_label("mepc_setup", hart), instr)
    def trap_vector_init(self, hart):
        instr = []
        for items in rcs.supported_privileged_mode:
            if(items == "MACHINE_MODE"):
                trap_vec_reg = privileged_reg_t.MTVEC
            elif(items == "SUPERVISOR_MODE"):
                trap_vec_reg = privileged_reg_t.STVEC
            elif(items == "USER_MODE"):
                trap_vec_reg = privileged_reg_t.UTVEC
            else:
                logging.critical(
                    "[riscv_asm_program_gen] Unsupported privileged_mode {}".format(items))

            if(items == "USER_MODE" and not (rcs.support_umode_trap)):
                continue

            if(items < cfg.init_privileged_mode.name):
                continue

            tvec_name = trap_vec_reg.name
            tvec_name = tvec_name.lower()
            instr.append("la x{}, {}{}_handler".format(
                cfg.gpr[0].value, pkg_ins.hart_prefix(hart), tvec_name))
            if(rcs.SATP_MODE != "BARE" and items != "MACHINE_MODE"):
                instr.append("slli x{}, x{}, {}\n".format(cfg.gpr[0].value,
                                                          cfg.gpr[0].value, rcs.XLEN - 20) +
                             "srli x{}, x{}, {}".format(cfg.gpr[0].value,
                                                        cfg.gpr[0].value, rcs.XLEN - 20))

            instr.append("ori x{}, x{}, {}".format(
                cfg.gpr[0].value, cfg.gpr[0].value, cfg.mtvec_mode.value))
            instr.append("csrw {}, x{} # {}".format(
                hex(trap_vec_reg.value), cfg.gpr[0].value, trap_vec_reg.name))

        self.gen_section(pkg_ins.get_label("trap_vec_init", hart), instr)
Beispiel #6
0
    def trap_vector_init(self, hart):
        instr = []
        for mode in rcs.supported_privileged_mode:
            if mode == privileged_mode_t.MACHINE_MODE:
                trap_vec_reg = privileged_reg_t.MTVEC
            elif mode == privileged_mode_t.SUPERVISOR_MODE:
                trap_vec_reg = privileged_reg_t.STVEC
            elif mode == privileged_mode_t.USER_MODE:
                trap_vec_reg = privileged_reg_t.UTVEC
            else:
                logging.critical("Unsupported privileged_mode {}".format(mode.name))
                sys.exit(1)

            if(mode == privileged_mode_t.USER_MODE and not (rcs.support_umode_trap)):
                continue

            if mode < cfg.init_privileged_mode:
                continue

            tvec_name = trap_vec_reg.name
            tvec_name = tvec_name.lower()
            instr.append("la x{}, {}{}_handler".format(
                cfg.gpr[0], pkg_ins.hart_prefix(hart), tvec_name))
            if(rcs.SATP_MODE != satp_mode_t.BARE and mode != privileged_mode_t.MACHINE_MODE):
                instr.append("slli x{}, x{}, {}\n".format(cfg.gpr[0], cfg.gpr[0], rcs.XLEN - 20) +
                             "srli x{}, x{}, {}".format(cfg.gpr[0], cfg.gpr[0], rcs.XLEN - 20))

            instr.append("ori x{}, x{}, {}".format(cfg.gpr[0], cfg.gpr[0], cfg.mtvec_mode))
            instr.append("csrw {}, x{} # {}".format(
                hex(trap_vec_reg), cfg.gpr[0], trap_vec_reg.name))

        self.gen_section(pkg_ins.get_label("trap_vec_init", 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)
Beispiel #8
0
    def pre_enter_privileged_mode(self, hart):
        instr = []
        string = []

        string.append("la x{}, {}kernel_stack_end".format(cfg.tp.value, pkg_ins.hart_prefix(hart)))
        self.gen_section(pkg_ins.get_label("kernel_sp", hart), string)

        if not cfg.no_delegation and (cfg.init_privileged_mode != privileged_mode_t.MACHINE_MODE):
            self.gen_delegation(hart)
        self.trap_vector_init(hart)
        self.setup_pmp(hart)

        if(cfg.virtual_addr_translation_on):
            self.page_table_list.process_page_table(instr)
            self.gen_section(pkg_ins.get_label("process_pt", hart), instr)
        self.setup_epc(hart)
        self.gen_privileged_mode_switch_routine(hart)
Beispiel #9
0
 def gen_init_section(self, hart):
     string = pkg_ins.format_string("init:", pkg_ins.LABEL_STR_LEN)
     self.instr_stream.append(string)
     if (cfg.enable_floating_point):
         self.init_floating_point_gpr()
     self.init_gpr()
     # Init stack pointer to point to the end of the user stack
     string = "{}la x{}, {}user_stack_end".format(
         pkg_ins.indent, cfg.sp.value, pkg_ins.hart_prefix(hart))
     self.instr_stream.append(string)
     if (cfg.enable_vector_extension):
         self.init_vector_engine()
     self.core_is_initialized()
     self.gen_dummy_csr_write()
     if (rcs.support_pmp):
         string = pkg_ins.indent + "j main"
         self.instr_stream.append(string)
Beispiel #10
0
    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)
Beispiel #11
0
 def enter_privileged_mode(self, mode, instrs):
     label = pkg_ins.format_string("{}init_{}:"
                                   .format(pkg_ins.hart_prefix(self.hart), mode),
                                   pkg_ins.LABEL_STR_LEN)
     ret_instr = ["mret"]
     regs = vsc.list_t(vsc.attr(riscv_privil_reg()))
     label = label.lower()
     self.setup_mmode_reg(mode, regs)
     if mode == "SUPERVISOR_MODE":
         self.setup_smode_reg(mode, regs)
     if mode == "USER_MODE":
         self.setup_umode_reg(mode, regs)
     if cfg.virtual_addr_translation_on:
         self.setup_satp(instrs)
     self.gen_csr_instr(regs, instrs)
     # Use mret/sret to switch to the target privileged mode
     instrs.append(ret_instr[0])
     for i in range(len(instrs)):
         instrs[i] = pkg_ins.indent + instrs[i]
     instrs.insert(0, label)
    def gen_kernel_stack_section(self, hart):
        hart_prefix_string = pkg_ins.hart_prefix(hart)
        if(cfg.use_push_data_section):
            self.instr_stream.append(
                ".pushsection .{}kernel_stack,\"aw\",@progbits;".format(hart_prefix_string))
        else:
            self.instr_stream.append(
                ".section .{}kernel_stack,\"aw\",@progbits;".format(hart_prefix_string))
        if(rcs.SATP_MODE != "BARE"):
            self.instr_stream.append(".align 12")
        else:
            self.instr_stream.append(".align 2")

        self.instr_stream.append(pkg_ins.get_label("kernel_stack_start:", hart))
        self.instr_stream.append(".rept {}".format(cfg.kernel_stack_len - 1))
        self.instr_stream.append(".{}byte 0x0".format(rcs.XLEN // 8))
        self.instr_stream.append(".endr")
        self.instr_stream.append(pkg_ins.get_label("kernel_stack_end:", hart))
        self.instr_stream.append(".{}byte 0x0".format(rcs.XLEN // 8))
        if (cfg.use_push_data_section):
            self.instr_stream.push_back(".popsection;")
    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)
    def gen_program(self):
        # Generate program header
        self.instr_stream.clear()
        self.gen_program_header()
        for hart in range(cfg.num_of_harts):
            # Commenting out for now
            # sub_program_name = []
            self.instr_stream.append(f"h{int(hart)}_start:")
            if not cfg.bare_program_mode:
                self.setup_misa()
                # Create all page tables
                self.create_page_table(hart)
                # Setup privileged mode registers and enter target privileged mode
                self.pre_enter_privileged_mode(hart)
            # Init section
            self.gen_init_section(hart)
            # To DO
            '''
            If PMP is supported, we want to generate the associated trap handlers and the test_done
            section at the start of the program so we can allow access through the pmpcfg0 CSR
            '''
            if (rcs.support_pmp and not (cfg.bare_program_mode)):
                self.gen_trap_handlers(hart)
                # Ecall handler
                self.gen_ecall_handler(hart)
                # Instruction fault handler
                self.gen_instr_fault_handler(hart)
                # Load fault handler
                self.gen_load_fault_handler(hart)
                # Store fault handler
                self.gen_store_fault_handler(hart)
                if hart == 0:
                    self.gen_test_done()

            # Generate main program
            gt_lbl_str = pkg_ins.get_label("main", hart)
            label_name = gt_lbl_str
            gt_lbl_str = riscv_instr_sequence()
            self.main_program.append(gt_lbl_str)
            self.main_program[hart].instr_cnt = cfg.main_program_instr_cnt
            self.main_program[hart].is_debug_program = 0
            self.main_program[hart].label_name = label_name
            self.generate_directed_instr_stream(
                hart=hart,
                label=self.main_program[hart].label_name,
                original_instr_cnt=self.main_program[hart].instr_cnt,
                min_insert_cnt=1,
                instr_stream=self.main_program[hart].directed_instr)
            self.main_program[hart].gen_instr(is_main_program=1,
                                              no_branch=cfg.no_branch_jump)

            self.main_program[hart].post_process_instr()
            self.main_program[hart].generate_instr_stream()
            logging.info("Generating main program instruction stream...done")
            self.instr_stream.extend(self.main_program[hart].instr_string_list)
            """
            If PMP is supported, need to jump from end of main program
            to test_done section at the end of main_program, as the test_done
            will have moved to the beginning of the program
            """
            self.instr_stream.append("{}j test_done".format(pkg_ins.indent))
            '''
            Test done section
            If PMP isn't supported, generate this in the normal location
            '''
            if (hart == 0 and not (rcs.support_pmp)):
                self.gen_test_done()

            logging.info("Main/sub program generation...done")
            # program end
            self.gen_program_end(hart)
            if not cfg.bare_program_mode:
                # Generate debug rom section
                if rcs.support_debug_mode:
                    self.gen_debug_rom(hart)
                self.gen_section(
                    pkg_ins.hart_prefix(hart) + "instr_end", ["nop"])
        for hart in range(cfg.num_of_harts):
            # Starting point of data section
            self.gen_data_page_begin(hart)
            if not cfg.no_data_page:
                # User data section
                self.gen_data_page(hart)
                # AMO memory region
                if (hart == 0
                        and riscv_instr_group_t.RV32A in rcs.supported_isa):
                    self.gen_data_page(hart, amo=1)
            self.gen_stack_section(hart)
            if not cfg.bare_program_mode:
                # Generate kernel program/data/stack section
                self.gen_kernel_sections(hart)
                # Page table
                self.gen_page_table_section(hart)