Skip to content

Commit da35767

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 da35767

File tree

7 files changed

+352
-123
lines changed

7 files changed

+352
-123
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: 6 additions & 8 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

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

16551654
/* handler for all unimplemented opcodes */
1656-
static inline bool op_unimp(struct rv_insn_t *rv_insn UNUSED,
1657-
uint32_t insn UNUSED)
1655+
static inline bool op_unimp(struct rv_insn_t *ir UNUSED, uint32_t insn UNUSED)
16581656
{
16591657
return false;
16601658
}
16611659

16621660
/* RV32 decode handler type */
1663-
typedef bool (*decode_t)(struct rv_insn_t *rv_insn, uint32_t insn);
1661+
typedef bool (*decode_t)(struct rv_insn_t *ir, uint32_t insn);
16641662

16651663
/* decode RISC-V instruction */
1666-
bool rv_decode(struct rv_insn_t *ir, uint32_t insn, uint8_t *insn_len)
1664+
bool rv_decode(struct rv_insn_t *ir, uint32_t insn)
16671665
{
1668-
assert(ir && insn_len);
1666+
assert(ir);
16691667

16701668
#define OP_UNIMP op_unimp
16711669
#define OP(insn) op_##insn
@@ -1704,7 +1702,7 @@ bool rv_decode(struct rv_insn_t *ir, uint32_t insn, uint8_t *insn_len)
17041702
if ((insn & FC_OPCODE) != 3) {
17051703
insn &= 0x0000FFFF;
17061704
const uint16_t c_index = (insn & FC_FUNC3) >> 11 | (insn & FC_OPCODE);
1707-
*insn_len = INSN_16;
1705+
ir->insn_len = INSN_16;
17081706

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

17161714
/* standard uncompressed instruction */
17171715
const uint32_t index = (insn & INSN_6_2) >> 2;
1718-
*insn_len = INSN_32;
1716+
ir->insn_len = INSN_32;
17191717

17201718
/* decode instruction */
17211719
const decode_t op = rv_jump_table[index];

src/decode.h

Lines changed: 43 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,20 @@ static inline uint32_t sign_extend_b(const uint32_t x)
250276
return (int32_t) ((int8_t) x);
251277
}
252278

279+
/* clear all block in the block map */
280+
static inline void block_map_clear(struct block_map *map)
281+
{
282+
assert(map);
283+
for (uint32_t i = 0; i < map->block_capacity; i++) {
284+
struct block *block = map->map[i];
285+
if (block) {
286+
free(block->ir);
287+
free(block);
288+
map->map[i] = NULL;
289+
}
290+
}
291+
map->size = 0;
292+
}
293+
253294
/* 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);
295+
bool rv_decode(struct rv_insn_t *ir, const uint32_t insn);

0 commit comments

Comments
 (0)