diff --git a/src/emulate.c b/src/emulate.c index 293ce031e..626e15181 100644 --- a/src/emulate.c +++ b/src/emulate.c @@ -862,12 +862,9 @@ static block_t *block_find_or_translate(riscv_t *rv) block_translate(rv, next_blk); optimize_constant(rv, next_blk); -#if RV32_HAS(GDBSTUB) - if (likely(!rv->debug_mode)) -#endif #if RV32_HAS(MOP_FUSION) - /* macro operation fusion */ - match_pattern(rv, next_blk); + /* macro operation fusion */ + match_pattern(rv, next_blk); #endif #if !RV32_HAS(JIT) @@ -958,6 +955,41 @@ static bool rv_has_plic_trap(riscv_t *rv) return ((rv->csr_sstatus & SSTATUS_SIE || !rv->priv_mode) && (rv->csr_sip & rv->csr_sie)); } + +static void rv_check_interrupt(riscv_t *rv) +{ + vm_attr_t *attr = PRIV(rv); + if (peripheral_update_ctr-- == 0) { + peripheral_update_ctr = 64; + + u8250_check_ready(PRIV(rv)->uart); + if (PRIV(rv)->uart->in_ready) + emu_update_uart_interrupts(rv); + } + + if (ctr > attr->timer) + rv->csr_sip |= RV_INT_STI; + else + rv->csr_sip &= ~RV_INT_STI; + + if (rv_has_plic_trap(rv)) { + uint32_t intr_applicable = rv->csr_sip & rv->csr_sie; + uint8_t intr_idx = ilog2(intr_applicable); + switch (intr_idx) { + case (SUPERVISOR_SW_INTR & 0xf): + SET_CAUSE_AND_TVAL_THEN_TRAP(rv, SUPERVISOR_SW_INTR, 0); + break; + case (SUPERVISOR_TIMER_INTR & 0xf): + SET_CAUSE_AND_TVAL_THEN_TRAP(rv, SUPERVISOR_TIMER_INTR, 0); + break; + case (SUPERVISOR_EXTERNAL_INTR & 0xf): + SET_CAUSE_AND_TVAL_THEN_TRAP(rv, SUPERVISOR_EXTERNAL_INTR, 0); + break; + default: + break; + } + } +} #endif void rv_step(void *arg) @@ -975,38 +1007,8 @@ void rv_step(void *arg) while (rv->csr_cycle < cycles_target && !rv->halt) { #if RV32_HAS(SYSTEM) && !RV32_HAS(ELF_LOADER) /* check for any interrupt after every block emulation */ - - if (peripheral_update_ctr-- == 0) { - peripheral_update_ctr = 64; - - u8250_check_ready(PRIV(rv)->uart); - if (PRIV(rv)->uart->in_ready) - emu_update_uart_interrupts(rv); - } - - if (ctr > attr->timer) - rv->csr_sip |= RV_INT_STI; - else - rv->csr_sip &= ~RV_INT_STI; - - if (rv_has_plic_trap(rv)) { - uint32_t intr_applicable = rv->csr_sip & rv->csr_sie; - uint8_t intr_idx = ilog2(intr_applicable); - switch (intr_idx) { - case (SUPERVISOR_SW_INTR & 0xf): - SET_CAUSE_AND_TVAL_THEN_TRAP(rv, SUPERVISOR_SW_INTR, 0); - break; - case (SUPERVISOR_TIMER_INTR & 0xf): - SET_CAUSE_AND_TVAL_THEN_TRAP(rv, SUPERVISOR_TIMER_INTR, 0); - break; - case (SUPERVISOR_EXTERNAL_INTR & 0xf): - SET_CAUSE_AND_TVAL_THEN_TRAP(rv, SUPERVISOR_EXTERNAL_INTR, 0); - break; - default: - break; - } - } -#endif /* RV32_HAS(SYSTEM) && !RV32_HAS(ELF_LOADER) */ + rv_check_interrupt(rv); +#endif if (prev && prev->pc_start != last_pc) { /* update previous block */ @@ -1111,6 +1113,43 @@ void rv_step(void *arg) #endif } +void rv_step_debug(void *arg) +{ + assert(arg); + riscv_t *rv = arg; + +#if RV32_HAS(SYSTEM) && !RV32_HAS(ELF_LOADER) + rv_check_interrupt(rv); +#endif + +retranslate: + /* fetch the next instruction */ + rv_insn_t ir; + memset(&ir, 0, sizeof(rv_insn_t)); + + uint32_t insn = rv->io.mem_ifetch(rv, rv->PC); +#if RV32_HAS(SYSTEM) + if (!insn && need_retranslate) { + need_retranslate = false; + goto retranslate; + } +#endif + assert(insn); + + /* decode the instruction */ + if (!rv_decode(&ir, insn)) { + rv->compressed = is_compressed(insn); + SET_CAUSE_AND_TVAL_THEN_TRAP(rv, ILLEGAL_INSN, insn); + return; + } + + ir.impl = dispatch_table[ir.opcode]; + ir.pc = rv->PC; + ir.next = NULL; + ir.impl(rv, &ir, rv->csr_cycle, rv->PC); + return; +} + #if RV32_HAS(SYSTEM) static void __trap_handler(riscv_t *rv) { diff --git a/src/gdbstub.c b/src/gdbstub.c index d9d635b7e..a06bf5849 100644 --- a/src/gdbstub.c +++ b/src/gdbstub.c @@ -80,14 +80,12 @@ static gdb_action_t rv_cont(void *args) { riscv_t *rv = (riscv_t *) args; assert(rv); - vm_attr_t *attr = PRIV(rv); - attr->cycle_per_step = 1; for (; !rv_has_halted(rv) && !rv_is_interrupt(rv);) { if (breakpoint_map_find(rv->breakpoint_map, rv_get_pc(rv))) break; - rv_step(rv); + rv_step_debug(rv); } /* Clear the interrupt if it's pending */ @@ -100,10 +98,8 @@ static gdb_action_t rv_stepi(void *args) { riscv_t *rv = (riscv_t *) args; assert(rv); - vm_attr_t *attr = PRIV(rv); - attr->cycle_per_step = 1; - rv_step(rv); + rv_step_debug(rv); return ACT_RESUME; } diff --git a/src/riscv.h b/src/riscv.h index 9486a43af..01ef05ce7 100644 --- a/src/riscv.h +++ b/src/riscv.h @@ -454,6 +454,9 @@ void rv_debug(riscv_t *rv); /* step the RISC-V emulator */ void rv_step(void *arg); +/* step the RISC-V emulator for debug mode */ +void rv_step_debug(void *arg); + /* set the program counter of a RISC-V emulator */ bool rv_set_pc(riscv_t *rv, riscv_word_t pc); diff --git a/src/rv32_template.c b/src/rv32_template.c index 6f2a79f70..5f276f3e3 100644 --- a/src/rv32_template.c +++ b/src/rv32_template.c @@ -224,53 +224,61 @@ RVOP( * In addition, before relocate_enable_mmu, the block maybe retranslated, \ * thus the branch history lookup table should not be updated too. \ */ \ - IIF(RV32_HAS(SYSTEM)(if (!rv->is_trapped && !reloc_enable_mmu), )) \ + IIF(RV32_HAS(GDBSTUB)(if (!rv->debug_mode), )) \ { \ - for (int i = 0; i < HISTORY_SIZE; i++) { \ - if (ir->branch_table->PC[i] == PC) { \ - MUST_TAIL return ir->branch_table->target[i]->impl( \ - rv, ir->branch_table->target[i], cycle, PC); \ + IIF(RV32_HAS(SYSTEM)(if (!rv->is_trapped && !reloc_enable_mmu), )) \ + { \ + for (int i = 0; i < HISTORY_SIZE; i++) { \ + if (ir->branch_table->PC[i] == PC) { \ + MUST_TAIL return ir->branch_table->target[i]->impl( \ + rv, ir->branch_table->target[i], cycle, PC); \ + } \ + } \ + block_t *block = block_find(&rv->block_map, PC); \ + if (block) { \ + /* update branch history table */ \ + ir->branch_table->PC[ir->branch_table->idx] = PC; \ + ir->branch_table->target[ir->branch_table->idx] = \ + block->ir_head; \ + ir->branch_table->idx = \ + (ir->branch_table->idx + 1) % HISTORY_SIZE; \ + MUST_TAIL return block->ir_head->impl(rv, block->ir_head, \ + cycle, PC); \ } \ } \ - block_t *block = block_find(&rv->block_map, PC); \ + } +#else +#define LOOKUP_OR_UPDATE_BRANCH_HISTORY_TABLE() \ + IIF(RV32_HAS(GDBSTUB)(if (!rv->debug_mode), )) \ + { \ + block_t *block = cache_get(rv->block_cache, PC, true); \ if (block) { \ + for (int i = 0; i < HISTORY_SIZE; i++) { \ + if (ir->branch_table->PC[i] == PC) { \ + ir->branch_table->times[i]++; \ + if (cache_hot(rv->block_cache, PC)) \ + goto end_op; \ + } \ + } \ /* update branch history table */ \ - ir->branch_table->PC[ir->branch_table->idx] = PC; \ - ir->branch_table->target[ir->branch_table->idx] = block->ir_head; \ - ir->branch_table->idx = \ - (ir->branch_table->idx + 1) % HISTORY_SIZE; \ + int min_idx = 0; \ + for (int i = 0; i < HISTORY_SIZE; i++) { \ + if (!ir->branch_table->times[i]) { \ + min_idx = i; \ + break; \ + } else if (ir->branch_table->times[min_idx] > \ + ir->branch_table->times[i]) { \ + min_idx = i; \ + } \ + } \ + ir->branch_table->times[min_idx] = ir->branch_table->PC[min_idx] = \ + PC; \ + if (cache_hot(rv->block_cache, PC)) \ + goto end_op; \ MUST_TAIL return block->ir_head->impl(rv, block->ir_head, cycle, \ PC); \ } \ } -#else -#define LOOKUP_OR_UPDATE_BRANCH_HISTORY_TABLE() \ - block_t *block = cache_get(rv->block_cache, PC, true); \ - if (block) { \ - for (int i = 0; i < HISTORY_SIZE; i++) { \ - if (ir->branch_table->PC[i] == PC) { \ - ir->branch_table->times[i]++; \ - if (cache_hot(rv->block_cache, PC)) \ - goto end_op; \ - } \ - } \ - /* update branch history table */ \ - int min_idx = 0; \ - for (int i = 0; i < HISTORY_SIZE; i++) { \ - if (!ir->branch_table->times[i]) { \ - min_idx = i; \ - break; \ - } else if (ir->branch_table->times[min_idx] > \ - ir->branch_table->times[i]) { \ - min_idx = i; \ - } \ - } \ - ir->branch_table->times[min_idx] = 1; \ - ir->branch_table->PC[min_idx] = PC; \ - if (cache_hot(rv->block_cache, PC)) \ - goto end_op; \ - MUST_TAIL return block->ir_head->impl(rv, block->ir_head, cycle, PC); \ - } #endif /* The indirect jump instruction JALR uses the I-type encoding. The target