From dca17ccfe01b68d4633fb2432691f41a4f75a1c8 Mon Sep 17 00:00:00 2001 From: Yen-Fu Chen Date: Wed, 11 Oct 2023 16:24:42 +0800 Subject: [PATCH] Manipulate csr_cycle and PC by register --- src/decode.h | 2 +- src/emulate.c | 133 +++++++++++++++++++++++++++---------------- src/rv32_template.c | 134 ++++++++++++++++++++++++++------------------ 3 files changed, 165 insertions(+), 104 deletions(-) diff --git a/src/decode.h b/src/decode.h index 3c2a817e9..92fcdd36e 100644 --- a/src/decode.h +++ b/src/decode.h @@ -291,7 +291,7 @@ typedef struct rv_insn { * self-recursive version, enabling the compiler to leverage TCO. */ bool tailcall; - bool (*impl)(riscv_t *, const struct rv_insn *); + bool (*impl)(riscv_t *, const struct rv_insn *, uint64_t, uint32_t); /* Two pointers, 'branch_taken' and 'branch_untaken', are employed to * avoid the overhead associated with aggressive memory copying. Instead diff --git a/src/emulate.c b/src/emulate.c index efc31db9b..ac1f01d63 100644 --- a/src/emulate.c +++ b/src/emulate.c @@ -113,9 +113,11 @@ RV_EXCEPTION_LIST #define RV_EXC_MISALIGN_HANDLER(mask_or_pc, type, compress, IO) \ IIF(IO) \ (if (!rv->io.allow_misalign && unlikely(addr & (mask_or_pc))), \ - if (unlikely(insn_is_misaligned(rv->PC)))) \ + if (unlikely(insn_is_misaligned(PC)))) \ { \ rv->compressed = compress; \ + rv->csr_cycle = cycle; \ + rv->PC = PC; \ rv_except_##type##_misaligned(rv, IIF(IO)(addr, mask_or_pc)); \ return false; \ } @@ -368,17 +370,21 @@ static bool branch_taken = false; static uint32_t last_pc = 0; /* Interpreter-based execution path */ -#define RVOP(inst, code) \ - static bool do_##inst(riscv_t *rv, const rv_insn_t *ir) \ - { \ - rv->csr_cycle++; \ - code; \ - nextop: \ - rv->PC += ir->insn_len; \ - if (unlikely(RVOP_NO_NEXT(ir))) \ - return true; \ - const rv_insn_t *next = ir->next; \ - MUST_TAIL return next->impl(rv, next); \ +#define RVOP(inst, code) \ + static bool do_##inst(riscv_t *rv, const rv_insn_t *ir, uint64_t cycle, \ + uint32_t PC) \ + { \ + cycle++; \ + code; \ + nextop: \ + PC += ir->insn_len; \ + if (unlikely(RVOP_NO_NEXT(ir))) { \ + rv->csr_cycle = cycle; \ + rv->PC = PC; \ + return true; \ + } \ + const rv_insn_t *next = ir->next; \ + MUST_TAIL return next->impl(rv, next, cycle, PC); \ } #include "rv32_template.c" @@ -408,36 +414,42 @@ enum { }; /* multiple lui */ -static bool do_fuse1(riscv_t *rv, rv_insn_t *ir) +static bool do_fuse1(riscv_t *rv, rv_insn_t *ir, uint64_t cycle, uint32_t PC) { - rv->csr_cycle += ir->imm2; + cycle += ir->imm2; opcode_fuse_t *fuse = ir->fuse; for (int i = 0; i < ir->imm2; i++) rv->X[fuse[i].rd] = fuse[i].imm; - rv->PC += ir->imm2 * ir->insn_len; - if (unlikely(RVOP_NO_NEXT(ir))) + PC += ir->imm2 * ir->insn_len; + if (unlikely(RVOP_NO_NEXT(ir))) { + rv->csr_cycle = cycle; + rv->PC = PC; return true; + } const rv_insn_t *next = ir->next; - MUST_TAIL return next->impl(rv, next); + MUST_TAIL return next->impl(rv, next, cycle, PC); } /* LUI + ADD */ -static bool do_fuse2(riscv_t *rv, rv_insn_t *ir) +static bool do_fuse2(riscv_t *rv, rv_insn_t *ir, uint64_t cycle, uint32_t PC) { - rv->csr_cycle += 2; + cycle += 2; rv->X[ir->rd] = ir->imm; rv->X[ir->rs2] = rv->X[ir->rd] + rv->X[ir->rs1]; - rv->PC += 2 * ir->insn_len; - if (unlikely(RVOP_NO_NEXT(ir))) + PC += 2 * ir->insn_len; + if (unlikely(RVOP_NO_NEXT(ir))) { + rv->csr_cycle = cycle; + rv->PC = PC; return true; + } const rv_insn_t *next = ir->next; - MUST_TAIL return next->impl(rv, next); + MUST_TAIL return next->impl(rv, next, cycle, PC); } /* multiple SW */ -static bool do_fuse3(riscv_t *rv, rv_insn_t *ir) +static bool do_fuse3(riscv_t *rv, rv_insn_t *ir, uint64_t cycle, uint32_t PC) { - rv->csr_cycle += ir->imm2; + cycle += ir->imm2; opcode_fuse_t *fuse = ir->fuse; /* The memory addresses of the sw instructions are contiguous, thus only * the first SW instruction needs to be checked to determine if its memory @@ -448,17 +460,20 @@ static bool do_fuse3(riscv_t *rv, rv_insn_t *ir) RV_EXC_MISALIGN_HANDLER(3, store, false, 1); rv->io.mem_write_w(addr, rv->X[fuse[i].rs2]); } - rv->PC += ir->imm2 * ir->insn_len; - if (unlikely(RVOP_NO_NEXT(ir))) + PC += ir->imm2 * ir->insn_len; + if (unlikely(RVOP_NO_NEXT(ir))) { + rv->csr_cycle = cycle; + rv->PC = PC; return true; + } const rv_insn_t *next = ir->next; - MUST_TAIL return next->impl(rv, next); + MUST_TAIL return next->impl(rv, next, cycle, PC); } /* multiple LW */ -static bool do_fuse4(riscv_t *rv, rv_insn_t *ir) +static bool do_fuse4(riscv_t *rv, rv_insn_t *ir, uint64_t cycle, uint32_t PC) { - rv->csr_cycle += ir->imm2; + cycle += ir->imm2; opcode_fuse_t *fuse = ir->fuse; /* The memory addresses of the lw instructions are contiguous, therefore * only the first LW instruction needs to be checked to determine if its @@ -469,53 +484,74 @@ static bool do_fuse4(riscv_t *rv, rv_insn_t *ir) RV_EXC_MISALIGN_HANDLER(3, load, false, 1); rv->X[fuse[i].rd] = rv->io.mem_read_w(addr); } - rv->PC += ir->imm2 * ir->insn_len; - if (unlikely(RVOP_NO_NEXT(ir))) + PC += ir->imm2 * ir->insn_len; + if (unlikely(RVOP_NO_NEXT(ir))) { + rv->csr_cycle = cycle; + rv->PC = PC; return true; + } const rv_insn_t *next = ir->next; - MUST_TAIL return next->impl(rv, next); + MUST_TAIL return next->impl(rv, next, cycle, PC); } /* memset */ -static bool do_fuse5(riscv_t *rv, const rv_insn_t *ir) +static bool do_fuse5(riscv_t *rv, + const rv_insn_t *ir, + uint64_t cycle, + uint32_t PC) { - rv->csr_cycle += 2; + cycle += 2; memory_t *m = ((state_t *) rv->userdata)->mem; memset((char *) m->mem_base + rv->X[rv_reg_a0], rv->X[rv_reg_a1], rv->X[rv_reg_a2]); - rv->PC = rv->X[rv_reg_ra] & ~1U; - if (unlikely(RVOP_NO_NEXT(ir))) + PC = rv->X[rv_reg_ra] & ~1U; + if (unlikely(RVOP_NO_NEXT(ir))) { + rv->csr_cycle = cycle; + rv->PC = PC; return true; + } const rv_insn_t *next = ir->next; - MUST_TAIL return next->impl(rv, next); + MUST_TAIL return next->impl(rv, next, cycle, PC); } /* memcpy */ -static bool do_fuse6(riscv_t *rv, const rv_insn_t *ir) +static bool do_fuse6(riscv_t *rv, + const rv_insn_t *ir, + uint64_t cycle, + uint32_t PC) { - rv->csr_cycle += 2; + cycle += 2; memory_t *m = ((state_t *) rv->userdata)->mem; memcpy((char *) m->mem_base + rv->X[rv_reg_a0], (char *) m->mem_base + rv->X[rv_reg_a1], rv->X[rv_reg_a2]); - rv->PC = rv->X[rv_reg_ra] & ~1U; - if (unlikely(RVOP_NO_NEXT(ir))) + PC = rv->X[rv_reg_ra] & ~1U; + if (unlikely(RVOP_NO_NEXT(ir))) { + rv->csr_cycle = cycle; + rv->PC = PC; return true; + } const rv_insn_t *next = ir->next; - MUST_TAIL return next->impl(rv, next); + MUST_TAIL return next->impl(rv, next, cycle, PC); } /* multiple shift immediate */ -static bool do_fuse7(riscv_t *rv, const rv_insn_t *ir) +static bool do_fuse7(riscv_t *rv, + const rv_insn_t *ir, + uint64_t cycle, + uint32_t PC) { - rv->csr_cycle += ir->imm2; + cycle += ir->imm2; opcode_fuse_t *fuse = ir->fuse; for (int i = 0; i < ir->imm2; i++) shift_func(rv, (const rv_insn_t *) (&fuse[i])); - rv->PC += ir->imm2 * ir->insn_len; - if (unlikely(RVOP_NO_NEXT(ir))) + PC += ir->imm2 * ir->insn_len; + if (unlikely(RVOP_NO_NEXT(ir))) { + rv->csr_cycle = cycle; + rv->PC = PC; return true; + } const rv_insn_t *next = ir->next; - MUST_TAIL return next->impl(rv, next); + MUST_TAIL return next->impl(rv, next, cycle, PC); } /* clang-format off */ @@ -988,9 +1024,8 @@ void rv_step(riscv_t *rv, int32_t cycles) /* execute the block */ const rv_insn_t *ir = block->ir_head; - if (unlikely(!ir->impl(rv, ir))) + if (unlikely(!ir->impl(rv, ir, rv->csr_cycle, rv->PC))) break; - prev = block; } } diff --git a/src/rv32_template.c b/src/rv32_template.c index fddcbb74d..d757d909e 100644 --- a/src/rv32_template.c +++ b/src/rv32_template.c @@ -15,23 +15,25 @@ RVOP(lui, { rv->X[ir->rd] = ir->imm; }) * lowest 12 bits with zeros, adds this offset to the address of the AUIPC * instruction, then places the result in register rd. */ -RVOP(auipc, { rv->X[ir->rd] = ir->imm + rv->PC; }) +RVOP(auipc, { rv->X[ir->rd] = ir->imm + PC; }) /* JAL: Jump and Link * store successor instruction address into rd. * add next J imm (offset) to pc. */ RVOP(jal, { - const uint32_t pc = rv->PC; + const uint32_t pc = PC; /* Jump */ - rv->PC += ir->imm; + PC += ir->imm; /* link with return address */ if (ir->rd) rv->X[ir->rd] = pc + ir->insn_len; /* check instruction misaligned */ RV_EXC_MISALIGN_HANDLER(pc, insn, false, 0); if (ir->branch_taken) - return ir->branch_taken->impl(rv, ir->branch_taken); + return ir->branch_taken->impl(rv, ir->branch_taken, cycle, PC); + rv->csr_cycle = cycle; + rv->PC = PC; return true; }) @@ -43,39 +45,43 @@ RVOP(jal, { * not required. */ RVOP(jalr, { - const uint32_t pc = rv->PC; + const uint32_t pc = PC; /* jump */ - rv->PC = (rv->X[ir->rs1] + ir->imm) & ~1U; + PC = (rv->X[ir->rs1] + ir->imm) & ~1U; /* link */ if (ir->rd) rv->X[ir->rd] = pc + ir->insn_len; /* check instruction misaligned */ RV_EXC_MISALIGN_HANDLER(pc, insn, false, 0); - block_t *block = block_find(&rv->block_map, rv->PC); + block_t *block = block_find(&rv->block_map, PC); if (block) - return block->ir_head->impl(rv, block->ir_head); + return block->ir_head->impl(rv, block->ir_head, cycle, PC); + rv->csr_cycle = cycle; + rv->PC = PC; return true; }) /* clang-format off */ -#define BRANCH_FUNC(type, cond) \ - const uint32_t pc = rv->PC; \ - if ((type) rv->X[ir->rs1] cond (type) rv->X[ir->rs2]) { \ - branch_taken = false; \ - if (!ir->branch_untaken) \ - goto nextop; \ - rv->PC += ir->insn_len; \ - last_pc = rv->PC; \ - return ir->branch_untaken->impl(rv, ir->branch_untaken); \ - } \ - branch_taken = true; \ - rv->PC += ir->imm; \ - /* check instruction misaligned */ \ - RV_EXC_MISALIGN_HANDLER(pc, insn, false, 0); \ - if (ir->branch_taken) { \ - last_pc = rv->PC; \ - return ir->branch_taken->impl(rv, ir->branch_taken); \ - } \ +#define BRANCH_FUNC(type, cond) \ + const uint32_t pc = PC; \ + if ((type) rv->X[ir->rs1] cond (type)rv->X[ir->rs2]) { \ + branch_taken = false; \ + if (!ir->branch_untaken) \ + goto nextop; \ + PC += ir->insn_len; \ + last_pc = PC; \ + return ir->branch_untaken->impl(rv, ir->branch_untaken, cycle, PC); \ + } \ + branch_taken = true; \ + PC += ir->imm; \ + /* check instruction misaligned */ \ + RV_EXC_MISALIGN_HANDLER(pc, insn, false, 0); \ + if (ir->branch_taken) { \ + last_pc = PC; \ + return ir->branch_taken->impl(rv, ir->branch_taken, cycle, PC); \ + } \ + rv->csr_cycle = cycle; \ + rv->PC = PC; \ return true; /* clang-format on */ @@ -248,6 +254,8 @@ RVOP(and, { rv->X[ir->rd] = rv->X[ir->rs1] & rv->X[ir->rs2]; }) /* ECALL: Environment Call */ RVOP(ecall, { rv->compressed = false; + rv->csr_cycle = cycle; + rv->PC = PC; rv->io.on_ecall(rv); return true; }) @@ -255,6 +263,8 @@ RVOP(ecall, { /* EBREAK: Environment Break */ RVOP(ebreak, { rv->compressed = false; + rv->csr_cycle = cycle; + rv->PC = PC; rv->io.on_ebreak(rv); return true; }) @@ -292,8 +302,10 @@ RVOP(mret, { #if RV32_HAS(Zifencei) /* RV32 Zifencei Standard Extension */ RVOP(fencei, { - rv->PC += ir->insn_len; + PC += ir->insn_len; /* FIXME: fill real implementations */ + rv->csr_cycle = cycle; + rv->PC = PC; return true; }) #endif @@ -807,11 +819,13 @@ RVOP(caddi, { rv->X[ir->rd] += (int16_t) ir->imm; }) /* C.JAL */ RVOP(cjal, { - rv->X[rv_reg_ra] = rv->PC + ir->insn_len; - rv->PC += ir->imm; - RV_EXC_MISALIGN_HANDLER(rv->PC, insn, true, 0); + rv->X[rv_reg_ra] = PC + ir->insn_len; + PC += ir->imm; + RV_EXC_MISALIGN_HANDLER(PC, insn, true, 0); if (ir->branch_taken) - return ir->branch_taken->impl(rv, ir->branch_taken); + return ir->branch_taken->impl(rv, ir->branch_taken, cycle, PC); + rv->csr_cycle = cycle; + rv->PC = PC; return true; }) @@ -876,10 +890,12 @@ RVOP(cand, { rv->X[ir->rd] = rv->X[ir->rs1] & rv->X[ir->rs2]; }) * C.J expands to jal x0, offset[11:1]. */ RVOP(cj, { - rv->PC += ir->imm; - RV_EXC_MISALIGN_HANDLER(rv->PC, insn, true, 0); + PC += ir->imm; + RV_EXC_MISALIGN_HANDLER(PC, insn, true, 0); if (ir->branch_taken) - return ir->branch_taken->impl(rv, ir->branch_taken); + return ir->branch_taken->impl(rv, ir->branch_taken, cycle, PC); + rv->csr_cycle = cycle; + rv->PC = PC; return true; }) @@ -893,16 +909,18 @@ RVOP(cbeqz, { branch_taken = false; if (!ir->branch_untaken) goto nextop; - rv->PC += ir->insn_len; - last_pc = rv->PC; - return ir->branch_untaken->impl(rv, ir->branch_untaken); + PC += ir->insn_len; + last_pc = PC; + return ir->branch_untaken->impl(rv, ir->branch_untaken, cycle, PC); } branch_taken = true; - rv->PC += (uint32_t) ir->imm; + PC += (uint32_t) ir->imm; if (ir->branch_taken) { - last_pc = rv->PC; - return ir->branch_taken->impl(rv, ir->branch_taken); + last_pc = PC; + return ir->branch_taken->impl(rv, ir->branch_taken, cycle, PC); } + rv->csr_cycle = cycle; + rv->PC = PC; return true; }) @@ -912,16 +930,18 @@ RVOP(cbnez, { branch_taken = false; if (!ir->branch_untaken) goto nextop; - rv->PC += ir->insn_len; - last_pc = rv->PC; - return ir->branch_untaken->impl(rv, ir->branch_untaken); + PC += ir->insn_len; + last_pc = PC; + return ir->branch_untaken->impl(rv, ir->branch_untaken, cycle, PC); } branch_taken = true; - rv->PC += (uint32_t) ir->imm; + PC += (uint32_t) ir->imm; if (ir->branch_taken) { - last_pc = rv->PC; - return ir->branch_taken->impl(rv, ir->branch_taken); + last_pc = PC; + return ir->branch_taken->impl(rv, ir->branch_taken, cycle, PC); } + rv->csr_cycle = cycle; + rv->PC = PC; return true; }) @@ -940,10 +960,12 @@ RVOP(clwsp, { /* C.JR */ RVOP(cjr, { - rv->PC = rv->X[ir->rs1]; - block_t *block = block_find(&rv->block_map, rv->PC); + PC = rv->X[ir->rs1]; + block_t *block = block_find(&rv->block_map, PC); if (block) - return block->ir_head->impl(rv, block->ir_head); + return block->ir_head->impl(rv, block->ir_head, cycle, PC); + rv->csr_cycle = cycle; + rv->PC = PC; return true; }) @@ -953,6 +975,8 @@ RVOP(cmv, { rv->X[ir->rd] = rv->X[ir->rs2]; }) /* C.EBREAK */ RVOP(cebreak, { rv->compressed = true; + rv->csr_cycle = cycle; + rv->PC = PC; rv->io.on_ebreak(rv); return true; }) @@ -961,12 +985,14 @@ RVOP(cebreak, { RVOP(cjalr, { /* Unconditional jump and store PC+2 to ra */ const int32_t jump_to = rv->X[ir->rs1]; - rv->X[rv_reg_ra] = rv->PC + ir->insn_len; - rv->PC = jump_to; - RV_EXC_MISALIGN_HANDLER(rv->PC, insn, true, 0); - block_t *block = block_find(&rv->block_map, rv->PC); + rv->X[rv_reg_ra] = PC + ir->insn_len; + PC = jump_to; + RV_EXC_MISALIGN_HANDLER(PC, insn, true, 0); + block_t *block = block_find(&rv->block_map, PC); if (block) - return block->ir_head->impl(rv, block->ir_head); + return block->ir_head->impl(rv, block->ir_head, cycle, PC); + rv->csr_cycle = cycle; + rv->PC = PC; return true; })