Skip to content

Commit 177d998

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 177d998

File tree

7 files changed

+412
-184
lines changed

7 files changed

+412
-184
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: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
*/
55

66
#include <assert.h>
7-
#include <stdio.h>
87

98
#include "decode.h"
109

@@ -1663,9 +1662,9 @@ static inline bool op_unimp(struct rv_insn_t *rv_insn UNUSED,
16631662
typedef bool (*decode_t)(struct rv_insn_t *rv_insn, 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];

src/decode.h

Lines changed: 91 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include <stdbool.h>
99
#include <stdint.h>
10+
#include <stdlib.h>
1011

1112
enum {
1213
/* RV32I Base Instruction Set */
@@ -219,7 +220,6 @@ enum {
219220
/* clang-format on */
220221

221222
enum {
222-
INSN_UNKNOWN = 0,
223223
INSN_16 = 2,
224224
INSN_32 = 4,
225225
};
@@ -236,6 +236,32 @@ 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+
/* translated basic block */
245+
struct block {
246+
/* number of instructions encompased */
247+
uint32_t insn_number;
248+
/* address range of the basic block */
249+
uint32_t pc_start, pc_end;
250+
/* maximum of instructions encompased */
251+
uint32_t insn_capacity;
252+
/* block predictoin */
253+
struct block *predict;
254+
/* memory blocks */
255+
struct rv_insn_t *ir;
256+
};
257+
258+
struct block_map {
259+
/* max number of entries in the block map */
260+
uint32_t block_capacity;
261+
/* number of entries currently in the map */
262+
uint32_t size;
263+
/* block map */
264+
struct block **map;
239265
};
240266

241267
/* sign extend a 16 bit value */
@@ -250,7 +276,68 @@ static inline uint32_t sign_extend_b(const uint32_t x)
250276
return (int32_t) ((int8_t) x);
251277
}
252278

279+
/* hash function is used when mapping address into the block map */
280+
static inline uint32_t hash(size_t k)
281+
{
282+
k ^= k << 21;
283+
k ^= k >> 17;
284+
#if (SIZE_MAX > 0xFFFFFFFF)
285+
k ^= k >> 35;
286+
k ^= k >> 51;
287+
#endif
288+
return k;
289+
}
290+
291+
/* allocate a basic block */
292+
static inline struct block *block_alloc(const uint8_t bits)
293+
{
294+
struct block *block = malloc(sizeof(struct block));
295+
block->insn_capacity = 1 << bits;
296+
block->insn_number = 0;
297+
block->predict = NULL;
298+
block->ir = malloc(block->insn_capacity * sizeof(struct rv_insn_t));
299+
return block;
300+
}
301+
302+
/* insert a block into block map */
303+
static inline void block_insert(struct block_map *map, struct block *block)
304+
{
305+
assert(map && block);
306+
const uint32_t mask = map->block_capacity - 1;
307+
uint32_t index = hash(block->pc_start);
308+
309+
/* insert into the block map */
310+
for (;; index++) {
311+
if (!map->map[index & mask]) {
312+
map->map[index & mask] = block;
313+
break;
314+
}
315+
}
316+
map->size++;
317+
}
318+
319+
/* initialize the block map */
320+
static inline void block_map_init(struct block_map *map, const uint8_t bits)
321+
{
322+
map->block_capacity = 1 << bits;
323+
map->size = 0;
324+
map->map = calloc(map->block_capacity, sizeof(struct block *));
325+
}
326+
327+
/* clear all block in the block map */
328+
static inline void block_map_clear(struct block_map *map)
329+
{
330+
assert(map);
331+
for (uint32_t i = 0; i < map->block_capacity; i++) {
332+
struct block *block = map->map[i];
333+
if (block) {
334+
free(block->ir);
335+
free(block);
336+
map->map[i] = NULL;
337+
}
338+
}
339+
map->size = 0;
340+
}
341+
253342
/* 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);
343+
bool rv_decode(struct rv_insn_t *rv_insn, const uint32_t insn);

0 commit comments

Comments
 (0)