Skip to content

Commit

Permalink
Merge pull request #530 from RinHizakura/debug-mode-optimize
Browse files Browse the repository at this point in the history
Use instruction-based emulation for debug mode
  • Loading branch information
jserv authored Dec 28, 2024
2 parents f7fd15b + ecb20c8 commit d8bf69a
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 81 deletions.
113 changes: 76 additions & 37 deletions src/emulate.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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 */
Expand Down Expand Up @@ -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)
{
Expand Down
8 changes: 2 additions & 6 deletions src/gdbstub.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -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;
}

Expand Down
3 changes: 3 additions & 0 deletions src/riscv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
84 changes: 46 additions & 38 deletions src/rv32_template.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit d8bf69a

Please sign in to comment.