Skip to content

Commit 7fe0c6a

Browse files
committed
Introduce basic block
This commit introduces the basic block in emulator, meaning that it makes emulator decode and execute numerous instructions at a time.
1 parent 2aa7154 commit 7fe0c6a

File tree

4 files changed

+153
-30
lines changed

4 files changed

+153
-30
lines changed

src/decode.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1663,9 +1663,9 @@ static inline bool op_unimp(struct rv_insn_t *rv_insn UNUSED,
16631663
typedef bool (*decode_t)(struct rv_insn_t *rv_insn, uint32_t insn);
16641664

16651665
/* decode RISC-V instruction */
1666-
bool rv_decode(struct rv_insn_t *ir, uint32_t insn, uint8_t *insn_len)
1666+
bool rv_decode(struct rv_insn_t *ir, uint32_t insn)
16671667
{
1668-
assert(ir && insn_len);
1668+
assert(ir);
16691669

16701670
#define OP_UNIMP op_unimp
16711671
#define OP(insn) op_##insn
@@ -1704,7 +1704,7 @@ bool rv_decode(struct rv_insn_t *ir, uint32_t insn, uint8_t *insn_len)
17041704
if ((insn & FC_OPCODE) != 3) {
17051705
insn &= 0x0000FFFF;
17061706
const uint16_t c_index = (insn & FC_FUNC3) >> 11 | (insn & FC_OPCODE);
1707-
*insn_len = INSN_16;
1707+
ir->insn_len = INSN_16;
17081708

17091709
/* decode instruction (compressed instructions) */
17101710
const decode_t op = rvc_jump_table[c_index];
@@ -1715,7 +1715,7 @@ bool rv_decode(struct rv_insn_t *ir, uint32_t insn, uint8_t *insn_len)
17151715

17161716
/* standard uncompressed instruction */
17171717
const uint32_t index = (insn & INSN_6_2) >> 2;
1718-
*insn_len = INSN_32;
1718+
ir->insn_len = INSN_32;
17191719

17201720
/* decode instruction */
17211721
const decode_t op = rv_jump_table[index];

src/decode.h

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,19 @@ struct rv_insn_t {
236236
#if RV32_HAS(EXT_C)
237237
uint8_t shamt;
238238
#endif
239+
240+
/* instruction length */
241+
uint8_t insn_len;
242+
};
243+
244+
/* a translated basic block */
245+
struct block_t {
246+
/* memory blocks */
247+
struct rv_insn_t *ir;
248+
/* index of memory blocks */
249+
uint32_t front, rear;
250+
/* maximum of instructions encompased */
251+
uint32_t capacity;
239252
};
240253

241254
/* sign extend a 16 bit value */
@@ -250,7 +263,29 @@ static inline uint32_t sign_extend_b(const uint32_t x)
250263
return (int32_t) ((int8_t) x);
251264
}
252265

266+
static inline bool mem_block_is_full(struct block_t *block)
267+
{
268+
assert(block);
269+
return (block->front - block->rear) == block->capacity;
270+
}
271+
272+
static inline struct rv_insn_t *get_rear_mem_block(struct block_t *block)
273+
{
274+
assert(block);
275+
return block->ir + block->rear;
276+
}
277+
278+
static inline struct rv_insn_t *alloc_mem_block(struct block_t *block)
279+
{
280+
assert(block);
281+
return block->ir + block->front++;
282+
}
283+
284+
static inline void free_mem_block(struct block_t *block)
285+
{
286+
assert(block);
287+
block->rear++;
288+
}
289+
253290
/* decode the RISC-V instruction */
254-
bool rv_decode(struct rv_insn_t *rv_insn,
255-
const uint32_t insn,
256-
uint8_t *insn_len);
291+
bool rv_decode(struct rv_insn_t *rv_insn, const uint32_t insn);

src/emulate.c

Lines changed: 108 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ enum {
5252

5353
static void rv_exception_default_handler(struct riscv_t *rv)
5454
{
55-
rv->csr_mepc += rv->insn_len;
55+
struct rv_insn_t *ir = get_rear_mem_block(&rv->block);
56+
rv->csr_mepc += ir->insn_len;
5657
rv->PC = rv->csr_mepc; /* mret */
5758
}
5859

@@ -286,7 +287,7 @@ static bool rv_emulate(struct riscv_t *rv, struct rv_insn_t *ir)
286287
rv->PC += ir->imm;
287288
/* link with return address */
288289
if (ir->rd)
289-
rv->X[ir->rd] = pc + rv->insn_len;
290+
rv->X[ir->rd] = pc + ir->insn_len;
290291
/* check instruction misaligned */
291292
if (insn_is_misaligned(rv->PC)) {
292293
rv_except_insn_misaligned(rv, pc);
@@ -308,7 +309,7 @@ static bool rv_emulate(struct riscv_t *rv, struct rv_insn_t *ir)
308309
rv->PC = (rv->X[ir->rs1] + ir->imm) & ~1U;
309310
/* link */
310311
if (ir->rd)
311-
rv->X[ir->rd] = pc + rv->insn_len;
312+
rv->X[ir->rd] = pc + ir->insn_len;
312313
/* check instruction misaligned */
313314
if (insn_is_misaligned(rv->PC)) {
314315
rv_except_insn_misaligned(rv, pc);
@@ -963,7 +964,7 @@ static bool rv_emulate(struct riscv_t *rv, struct rv_insn_t *ir)
963964
rv->X[ir->rd] += (int16_t) ir->imm;
964965
break;
965966
case rv_insn_cjal:
966-
rv->X[1] = rv->PC + rv->insn_len;
967+
rv->X[1] = rv->PC + ir->insn_len;
967968
rv->PC += ir->imm;
968969
if (rv->PC & 0x1) {
969970
rv_except_insn_misaligned(rv, rv->PC);
@@ -1055,11 +1056,11 @@ static bool rv_emulate(struct riscv_t *rv, struct rv_insn_t *ir)
10551056
* the value in register rs1' is zero. It expands to beq rs1', x0,
10561057
* offset[8:1].
10571058
*/
1058-
rv->PC += (!rv->X[ir->rs1]) ? (uint32_t) ir->imm : rv->insn_len;
1059+
rv->PC += (!rv->X[ir->rs1]) ? (uint32_t) ir->imm : ir->insn_len;
10591060
/* can branch */
10601061
return true;
10611062
case rv_insn_cbnez: /* C.BEQZ */
1062-
rv->PC += (rv->X[ir->rs1]) ? (uint32_t) ir->imm : rv->insn_len;
1063+
rv->PC += (rv->X[ir->rs1]) ? (uint32_t) ir->imm : ir->insn_len;
10631064
/* can branch */
10641065
return true;
10651066
case rv_insn_cslli: /* C.SLLI */
@@ -1093,7 +1094,7 @@ static bool rv_emulate(struct riscv_t *rv, struct rv_insn_t *ir)
10931094
case rv_insn_cjalr: { /* C.JALR */
10941095
/* Unconditional jump and store PC+2 to ra */
10951096
const int32_t jump_to = rv->X[ir->rs1];
1096-
rv->X[rv_reg_ra] = rv->PC + rv->insn_len;
1097+
rv->X[rv_reg_ra] = rv->PC + ir->insn_len;
10971098
rv->PC = jump_to;
10981099
if (rv->PC & 0x1) {
10991100
rv_except_insn_misaligned(rv, rv->PC);
@@ -1125,33 +1126,96 @@ static bool rv_emulate(struct riscv_t *rv, struct rv_insn_t *ir)
11251126
}
11261127

11271128
/* step over instruction */
1128-
rv->PC += rv->insn_len;
1129+
rv->PC += ir->insn_len;
11291130
return true;
11301131
}
11311132

1132-
void rv_step(struct riscv_t *rv, int32_t cycles)
1133+
static bool rv_emulate_block(struct riscv_t *rv, struct block_t *block)
11331134
{
1134-
assert(rv);
1135-
uint32_t insn;
1136-
struct rv_insn_t ir;
1137-
const uint64_t cycles_target = rv->csr_cycle + cycles;
1138-
1139-
while (rv->csr_cycle < cycles_target && !rv->halt) {
1135+
/* execute the block */
1136+
while (block->front != block->rear) {
11401137
/* enforce zero register */
11411138
rv->X[rv_reg_zero] = 0;
11421139

1140+
/* execute the instruction */
1141+
if (!rv_emulate(rv, get_rear_mem_block(&rv->block)))
1142+
return false;
1143+
1144+
free_mem_block(block);
1145+
}
1146+
return true;
1147+
}
1148+
1149+
static bool insn_is_branch(uint8_t opcode)
1150+
{
1151+
switch (opcode) {
1152+
case rv_insn_jal:
1153+
case rv_insn_jalr:
1154+
case rv_insn_beq:
1155+
case rv_insn_bne:
1156+
case rv_insn_blt:
1157+
case rv_insn_bge:
1158+
case rv_insn_bltu:
1159+
case rv_insn_bgeu:
1160+
case rv_insn_ecall:
1161+
case rv_insn_ebreak:
1162+
case rv_insn_mret:
1163+
#if RV32_HAS(EXT_C)
1164+
case rv_insn_cj:
1165+
case rv_insn_cjr:
1166+
case rv_insn_cjal:
1167+
case rv_insn_cjalr:
1168+
case rv_insn_cbeqz:
1169+
case rv_insn_cbnez:
1170+
case rv_insn_cebreak:
1171+
#endif
1172+
#if RV32_HAS(Zifencei)
1173+
case rv_insn_fencei:
1174+
#endif
1175+
return true;
1176+
}
1177+
return false;
1178+
}
1179+
1180+
static void rv_translate_block(struct riscv_t *rv, struct block_t *block)
1181+
{
1182+
/* translate the basic block */
1183+
uint32_t pc = rv->PC;
1184+
block->front = 0;
1185+
block->rear = 0;
1186+
while (!mem_block_is_full(block)) {
1187+
struct rv_insn_t *ir = alloc_mem_block(block);
1188+
memset(ir, 0, sizeof(struct rv_insn_t));
1189+
11431190
/* fetch the next instruction */
1144-
insn = rv->io.mem_ifetch(rv, rv->PC);
1145-
memset(&ir, 0, sizeof(struct rv_insn_t));
1191+
const uint32_t insn = rv->io.mem_ifetch(rv, pc);
11461192

11471193
/* decode the instruction */
1148-
if (!rv_decode(&ir, insn, &rv->insn_len)) {
1194+
if (!rv_decode(ir, insn)) {
11491195
rv_except_illegal_insn(rv, insn);
11501196
break;
11511197
}
11521198

1153-
/* execute the instruciton */
1154-
if (!rv_emulate(rv, &ir))
1199+
/* stop on branch */
1200+
if (insn_is_branch(ir->opcode))
1201+
break;
1202+
1203+
/* compute next pc */
1204+
pc += ir->insn_len;
1205+
}
1206+
}
1207+
1208+
void rv_step(struct riscv_t *rv, int32_t cycles)
1209+
{
1210+
assert(rv);
1211+
const uint64_t cycles_target = rv->csr_cycle + cycles;
1212+
1213+
while (rv->csr_cycle < cycles_target && !rv->halt) {
1214+
/* translate basic block */
1215+
rv_translate_block(rv, &rv->block);
1216+
1217+
/* execute the block */
1218+
if (!rv_emulate_block(rv, &rv->block))
11551219
break;
11561220

11571221
/* increment the cycles csr */
@@ -1201,6 +1265,19 @@ riscv_word_t rv_get_reg(struct riscv_t *rv, uint32_t reg)
12011265
return ~0U;
12021266
}
12031267

1268+
/* allocate a new code block */
1269+
static bool block_init(struct block_t *block, uint32_t bit)
1270+
{
1271+
assert(block);
1272+
1273+
block->capacity = 1 << bit;
1274+
block->ir = malloc(sizeof(struct rv_insn_t) * block->capacity);
1275+
if (!block->ir)
1276+
return false;
1277+
1278+
return true;
1279+
}
1280+
12041281
struct riscv_t *rv_create(const struct riscv_io_t *io, riscv_user_t userdata)
12051282
{
12061283
assert(io);
@@ -1213,6 +1290,10 @@ struct riscv_t *rv_create(const struct riscv_io_t *io, riscv_user_t userdata)
12131290
/* copy over the userdata */
12141291
rv->userdata = userdata;
12151292

1293+
/* place a new block */
1294+
if (!block_init(&rv->block, 10))
1295+
return NULL;
1296+
12161297
/* reset */
12171298
rv_reset(rv, 0U);
12181299

@@ -1229,9 +1310,16 @@ bool rv_has_halted(struct riscv_t *rv)
12291310
return rv->halt;
12301311
}
12311312

1313+
static void block_free(struct block_t *block)
1314+
{
1315+
assert(block);
1316+
free(block->ir);
1317+
}
1318+
12321319
void rv_delete(struct riscv_t *rv)
12331320
{
12341321
assert(rv);
1322+
block_free(&rv->block);
12351323
free(rv);
12361324
}
12371325

@@ -1242,7 +1330,6 @@ void rv_reset(struct riscv_t *rv, riscv_word_t pc)
12421330

12431331
/* set the reset address */
12441332
rv->PC = pc;
1245-
rv->insn_len = INSN_UNKNOWN;
12461333

12471334
/* set the default stack pointer */
12481335
rv->X[rv_reg_sp] = DEFAULT_STACK_ADDR;

src/riscv_private.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "breakpoint.h"
1111
#include "mini-gdbstub/include/gdbstub.h"
1212
#endif
13+
#include "decode.h"
1314
#include "riscv.h"
1415

1516
#define RV_NUM_REGS 32
@@ -96,6 +97,6 @@ struct riscv_t {
9697
uint32_t csr_mip;
9798
uint32_t csr_mbadaddr;
9899

99-
/* current instruction length */
100-
uint8_t insn_len;
100+
/* basic block */
101+
struct block_t block;
101102
};

0 commit comments

Comments
 (0)