diff options
Diffstat (limited to 'emulator')
-rw-r--r-- | emulator/hart.c | 216 | ||||
-rw-r--r-- | emulator/hart.h | 5 |
2 files changed, 206 insertions, 15 deletions
diff --git a/emulator/hart.c b/emulator/hart.c index cfca837..db43cd1 100644 --- a/emulator/hart.c +++ b/emulator/hart.c @@ -6,6 +6,39 @@ #include <stdbool.h>
#include <string.h>
+#define REG_ZERO 0
+#define REG_RA 1
+#define REG_SP 2
+#define REG_GP 3
+#define REG_TP 4
+#define REG_T0 5
+#define REG_T1 6
+#define REG_T2 7
+#define REG_S0 8
+#define REG_S1 9
+#define REG_A0 10
+#define REG_A1 11
+#define REG_A2 12
+#define REG_A3 13
+#define REG_A4 14
+#define REG_A5 15
+#define REG_A6 16
+#define REG_A7 17
+#define REG_S2 18
+#define REG_S3 19
+#define REG_S4 20
+#define REG_S5 21
+#define REG_S6 22
+#define REG_S7 23
+#define REG_S8 24
+#define REG_S9 25
+#define REG_S10 26
+#define REG_S11 27
+#define REG_T3 28
+#define REG_T4 29
+#define REG_T5 30
+#define REG_T6 31
+
static inline uint32_t sign_extend(uint32_t word, uint32_t size)
{
const uint32_t mask = 1U << (size - 1);
@@ -327,28 +360,183 @@ static void execute_misc_mem(Hart* hart, uint32_t instruction) }
}
+static void handle_ecall(Hart* hart)
+{
+ if (hart->regs[REG_A0] == 0)
+ {
+ hart->halted = true;
+ }
+}
+
+static uint32_t crs_read(Hart* hart, uint16_t id)
+{
+ // @Todo
+ return 0;
+}
+
+static void crs_write(Hart* hart, uint16_t id, uint32_t new_value)
+{
+ // @Todo
+}
+
+static uint32_t crs_read_write(Hart* hart, uint16_t id, uint32_t new_value)
+{
+ // @Todo
+ return 0;
+}
+
+static uint32_t crs_read_clear(Hart* hart, uint16_t id, uint32_t mask)
+{
+ // @Todo
+ return 0;
+}
+
+static uint32_t crs_read_set(Hart* hart, uint16_t id, uint32_t mask)
+{
+ // @Todo
+ return 0;
+}
+
static void execute_system(Hart* hart, uint32_t instruction)
{
const Instruction inst = decode_i_type(instruction);
-
- if (inst.funct3 == 0 && inst.rs1 == 0 && inst.rd == 0)
+
+ switch (inst.funct3)
{
- if (inst.imm == 0)
+ case 0:
{
- // ECALL
+ if (inst.rs1 == 0 && inst.rd == 0)
+ {
+ if (inst.imm == 0)
+ {
+ handle_ecall(hart);
+ }
+ else if (inst.imm == 1)
+ {
+ // EBREAK
+ }
+ else
+ {
+ assert(!"Unhandled SYSTEM/PRIV instruction");
+ }
+ }
+ else
+ {
+ assert(!"Unhandled SYSTEM/PRIV instruction");
+ }
+ break;
}
- else if (inst.imm == 1)
+ case 1: // CRSRW
{
- // EBREAK
+ uint16_t crs_id = inst.imm & 0xFFF;
+
+ if (inst.rd == 0)
+ {
+ crs_write(hart, crs_id, hart->regs[inst.rs1]);
+ }
+ else
+ {
+ hart->regs[inst.rd] = crs_read_write(hart, crs_id, hart->regs[inst.rs1]);
+ }
+ break;
}
- else
+ case 2: // CRSRS
{
- assert(!"Unhandled SYSTEM/PRIV instruction");
+ uint16_t crs_id = inst.imm & 0xFFF;
+ uint32_t value = 0;
+
+ if (inst.rs1 == 0)
+ {
+ value = crs_read(hart, crs_id);
+ }
+ else
+ {
+ value = crs_read_set(hart, crs_id, hart->regs[inst.rs1]);
+ }
+
+ if (inst.rd != 0)
+ {
+ hart->regs[inst.rd] = value;
+ }
+ break;
}
- }
- else
- {
- assert(!"Unhandled SYSTEM instruction");
+ case 3: // CRSRC
+ {
+ uint16_t crs_id = inst.imm & 0xFFF;
+ uint32_t value = 0;
+
+ if (inst.rs1 == 0)
+ {
+ value = crs_read(hart, crs_id);
+ }
+ else
+ {
+ value = crs_read_clear(hart, crs_id, hart->regs[inst.rs1]);
+ }
+
+ if (inst.rd != 0)
+ {
+ hart->regs[inst.rd] = value;
+ }
+ break;
+ }
+ case 5: // CRSRWI
+ {
+ uint16_t crs_id = inst.imm & 0xFFF;
+
+ if (inst.rd == 0)
+ {
+ crs_write(hart, crs_id, inst.rs1);
+ }
+ else
+ {
+ hart->regs[inst.rd] = crs_read_write(hart, crs_id, inst.rs1);
+ }
+ break;
+ }
+ case 6: // CRSRSI
+ {
+ uint16_t crs_id = inst.imm & 0xFFF;
+ uint32_t value = 0;
+
+ if (inst.rs1 == 0)
+ {
+ value = crs_read(hart, crs_id);
+ }
+ else
+ {
+ value = crs_read_set(hart, crs_id, inst.rs1);
+ }
+
+ if (inst.rd != 0)
+ {
+ hart->regs[inst.rd] = value;
+ }
+ break;
+ }
+ case 7: // CRSRCI
+ {
+ uint16_t crs_id = inst.imm & 0xFFF;
+ uint32_t value = 0;
+
+ if (inst.rs1 == 0)
+ {
+ value = crs_read(hart, crs_id);
+ }
+ else
+ {
+ value = crs_read_clear(hart, crs_id, inst.rs1);
+ }
+
+ if (inst.rd != 0)
+ {
+ hart->regs[inst.rd] = value;
+ }
+ break;
+ }
+ default:
+ assert(!"Unhandled SYSTEM instruction");
+ break;
}
}
@@ -436,11 +624,11 @@ void execute(Hart* hart, uint32_t instruction) void execute_from(Hart* hart, uint32_t start_address)
{
hart->pc = start_address;
+ hart->halted = false;
- while (true)
+ while (!hart->halted)
{
uint32_t instruction = load_word(hart, hart->pc);
execute(hart, instruction);
}
}
-
diff --git a/emulator/hart.h b/emulator/hart.h index 5e9d451..8e04d19 100644 --- a/emulator/hart.h +++ b/emulator/hart.h @@ -1,16 +1,19 @@ #pragma once
#include <stdint.h>
+#include <stdbool.h>
struct Hart
{
uint32_t pc;
uint32_t regs[32];
+
char* mem;
uint32_t mem_size;
+
+ bool halted;
};
typedef struct Hart Hart;
void execute(Hart* hart, uint32_t instruction);
void execute_from(Hart* hart, uint32_t start_address);
-
|