Skip to content

Commit 76a028a

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. Use hash table and block prediction to manage blocks efficiently. In decode stage, allocate a new block which contains up to 1024 instruction by default, decode the instruction into block until it is full or the latest instruction is a branch instruction and put it into the block map. In execution stage, emulator executes instructions in block. The number of instructions based on the member insn_num in struct block. In particular, when an exception/interrupt occurs, emulator will do the following steps: 1. Execute the exception/interrupt handler that resets a new program counter from the register mtvec and function emulate returns false. 2. Enter to the decode stage again, and create new block based on the new program counter. That is, emulator will stop executing old block and create the new one from new program counter.
1 parent 2aa7154 commit 76a028a

File tree

7 files changed

+368
-131
lines changed

7 files changed

+368
-131
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ OBJS := \
9898
utils.o \
9999
decode.o \
100100
emulate.o \
101+
riscv.o \
101102
io.o \
102103
elf.o \
103104
main.o \

src/decode.c

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*/
55

66
#include <assert.h>
7-
#include <stdio.h>
7+
#include <stdlib.h>
88

99
#include "decode.h"
1010

@@ -1653,19 +1653,18 @@ static inline bool op_cbnez(struct rv_insn_t *ir, const uint32_t insn)
16531653
#define op_cfsd OP_UNIMP
16541654

16551655
/* handler for all unimplemented opcodes */
1656-
static inline bool op_unimp(struct rv_insn_t *rv_insn UNUSED,
1657-
uint32_t insn UNUSED)
1656+
static inline bool op_unimp(struct rv_insn_t *ir UNUSED, uint32_t insn UNUSED)
16581657
{
16591658
return false;
16601659
}
16611660

16621661
/* RV32 decode handler type */
1663-
typedef bool (*decode_t)(struct rv_insn_t *rv_insn, uint32_t insn);
1662+
typedef bool (*decode_t)(struct rv_insn_t *ir, uint32_t insn);
16641663

16651664
/* decode RISC-V instruction */
1666-
bool rv_decode(struct rv_insn_t *ir, uint32_t insn, uint8_t *insn_len)
1665+
bool rv_decode(struct rv_insn_t *ir, uint32_t insn)
16671666
{
1668-
assert(ir && insn_len);
1667+
assert(ir);
16691668

16701669
#define OP_UNIMP op_unimp
16711670
#define OP(insn) op_##insn
@@ -1704,7 +1703,7 @@ bool rv_decode(struct rv_insn_t *ir, uint32_t insn, uint8_t *insn_len)
17041703
if ((insn & FC_OPCODE) != 3) {
17051704
insn &= 0x0000FFFF;
17061705
const uint16_t c_index = (insn & FC_FUNC3) >> 11 | (insn & FC_OPCODE);
1707-
*insn_len = INSN_16;
1706+
ir->insn_len = INSN_16;
17081707

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

17161715
/* standard uncompressed instruction */
17171716
const uint32_t index = (insn & INSN_6_2) >> 2;
1718-
*insn_len = INSN_32;
1717+
ir->insn_len = INSN_32;
17191718

17201719
/* decode instruction */
17211720
const decode_t op = rv_jump_table[index];
@@ -1725,3 +1724,30 @@ bool rv_decode(struct rv_insn_t *ir, uint32_t insn, uint8_t *insn_len)
17251724
#undef OP_UNIMP
17261725
#undef OP
17271726
}
1727+
1728+
/* sign extend a 16 bit value */
1729+
uint32_t sign_extend_h(const uint32_t x)
1730+
{
1731+
return (int32_t) ((int16_t) x);
1732+
}
1733+
1734+
/* sign extend an 8 bit value */
1735+
uint32_t sign_extend_b(const uint32_t x)
1736+
{
1737+
return (int32_t) ((int8_t) x);
1738+
}
1739+
1740+
/* clear all block in the block map */
1741+
void block_map_clear(struct block_map *map)
1742+
{
1743+
assert(map);
1744+
for (uint32_t i = 0; i < map->block_capacity; i++) {
1745+
struct block *block = map->map[i];
1746+
if (block) {
1747+
free(block->ir);
1748+
free(block);
1749+
map->map[i] = NULL;
1750+
}
1751+
}
1752+
map->size = 0;
1753+
}

src/decode.h

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,6 @@ enum {
219219
/* clang-format on */
220220

221221
enum {
222-
INSN_UNKNOWN = 0,
223222
INSN_16 = 2,
224223
INSN_32 = 4,
225224
};
@@ -236,21 +235,42 @@ struct rv_insn_t {
236235
#if RV32_HAS(EXT_C)
237236
uint8_t shamt;
238237
#endif
238+
239+
/* instruction length */
240+
uint8_t insn_len;
241+
};
242+
243+
/* translated basic block */
244+
struct block {
245+
/* number of instructions encompased */
246+
uint32_t insn_number;
247+
/* address range of the basic block */
248+
uint32_t pc_start, pc_end;
249+
/* maximum of instructions encompased */
250+
uint32_t insn_capacity;
251+
/* block predictoin */
252+
struct block *predict;
253+
/* memory blocks */
254+
struct rv_insn_t *ir;
255+
};
256+
257+
struct block_map {
258+
/* max number of entries in the block map */
259+
uint32_t block_capacity;
260+
/* number of entries currently in the map */
261+
uint32_t size;
262+
/* block map */
263+
struct block **map;
239264
};
240265

241266
/* sign extend a 16 bit value */
242-
static inline uint32_t sign_extend_h(const uint32_t x)
243-
{
244-
return (int32_t) ((int16_t) x);
245-
}
267+
uint32_t sign_extend_h(const uint32_t x);
246268

247269
/* sign extend an 8 bit value */
248-
static inline uint32_t sign_extend_b(const uint32_t x)
249-
{
250-
return (int32_t) ((int8_t) x);
251-
}
270+
uint32_t sign_extend_b(const uint32_t x);
271+
272+
/* clear all block in the block map */
273+
void block_map_clear(struct block_map *map);
252274

253275
/* 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);
276+
bool rv_decode(struct rv_insn_t *ir, const uint32_t insn);

0 commit comments

Comments
 (0)