summaryrefslogtreecommitdiff
path: root/emulator/hart.c
diff options
context:
space:
mode:
Diffstat (limited to 'emulator/hart.c')
-rw-r--r--emulator/hart.c348
1 files changed, 125 insertions, 223 deletions
diff --git a/emulator/hart.c b/emulator/hart.c
index 297148b..efa0556 100644
--- a/emulator/hart.c
+++ b/emulator/hart.c
@@ -1,129 +1,106 @@
#include "emulator/hart.h"
+#include "emulator/bits.h"
+#include "emulator/instruction.h"
+#include "emulator/csr.h"
+
#include <stdio.h>
#include <inttypes.h>
#include <assert.h>
#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)
+#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 void handle_ecall(Hart* hart)
{
- const uint32_t mask = 1U << (size - 1);
- return (word ^ mask) - mask;
}
-static inline uint64_t sign_extend_64(uint64_t word, uint32_t size)
+static inline uint32_t load_size(Hart* hart, uint32_t address, uint32_t size)
{
- const uint64_t mask = 1ULL << (size - 1);
- return (word ^ mask) - mask;
+ if ((address & 0x80000000) == 0)
+ {
+ assert(address + size < hart->mem_size);
+ uint32_t value = 0;
+ memcpy(&value, hart->mem + address, size);
+ return value;
+ }
+
+ return 0;
}
-struct Instruction
+static uint32_t load_byte(Hart* hart, uint32_t address)
{
- uint8_t opcode;
- uint8_t rs1;
- uint8_t rs2;
- uint8_t rd;
- uint8_t funct3;
- uint8_t funct7;
- uint32_t imm;
-};
-typedef struct Instruction Instruction;
-
-static Instruction decode_r_type(uint32_t word)
+ return load_size(hart, address, 1);
+}
+
+static uint32_t load_half(Hart* hart, uint32_t address)
{
- Instruction instruction = {0};
- instruction.opcode = word & 0x7F;
- instruction.rd = (word >> 7) & 0x1F;
- instruction.funct3 = (word >> 12) & 0x07;
- instruction.rs1 = (word >> 15) & 0x1F;
- instruction.rs2 = (word >> 20) & 0x1F;
- instruction.funct7 = word >> 25;
- return instruction;
-};
-
-static Instruction decode_i_type(uint32_t word)
+ return load_size(hart, address, 2);
+}
+
+static uint32_t load_word(Hart* hart, uint32_t address)
{
- Instruction instruction = {0};
- instruction.opcode = word & 0x7F;
- instruction.rd = (word >> 7) & 0x1F;
- instruction.funct3 = (word >> 12) & 0x07;
- instruction.rs1 = (word >> 15) & 0x1F;
- instruction.imm = sign_extend(word >> 20, 12);
- return instruction;
-};
-
-static Instruction decode_s_type(uint32_t word)
+ return load_size(hart, address, 4);
+}
+
+static inline void store_size(Hart* hart, uint32_t address, uint32_t value, uint32_t size)
{
- Instruction instruction = {0};
- instruction.opcode = word & 0x7F;
- instruction.funct3 = (word >> 12) & 0x07;
- instruction.rs1 = (word >> 15) & 0x1F;
- instruction.rs2 = (word >> 20) & 0x1F;
- instruction.imm = sign_extend(((word >> 7) & 0x1F) | (word >> 25), 12);
- return instruction;
-};
-
-static Instruction decode_b_type(uint32_t word)
+ if ((address & 0x80000000) == 0)
+ {
+ assert(address + size < hart->mem_size);
+ memcpy(hart->mem + address, &value, size);
+ }
+ else if (address == 0x80000000)
+ {
+ fwrite(&value, 1, size, stdout);
+ }
+}
+
+static void store_byte(Hart* hart, uint32_t address, uint8_t value)
{
- Instruction instruction = decode_s_type(word);
- instruction.imm = ((instruction.imm << 11) & 0x800) | (instruction.imm & 0xfffff7ff);
- return instruction;
-};
+ store_size(hart, address, value, 1);
+}
-static Instruction decode_u_type(uint32_t word)
+static void store_half(Hart* hart, uint32_t address, uint16_t value)
{
- Instruction instruction = {0};
- instruction.opcode = word & 0x7F;
- instruction.rd = (word >> 7) & 0x1F;
- instruction.imm = word & 0xFFFFF000;
- return instruction;
-};
-
-static Instruction decode_j_type(uint32_t word)
+ store_size(hart, address, value, 2);
+}
+
+static void store_word(Hart* hart, uint32_t address, uint32_t value)
{
- Instruction instruction = {0};
- instruction.opcode = word & 0x7F;
- instruction.rd = (word >> 7) & 0x1F;
- instruction.imm = sign_extend(
- ((word & 0x80000000) >> 11) |
- ((word & 0x000FF000) >> 0) |
- ((word & 0x00100000) >> 9) |
- ((word & 0x7FE00000) >> 20), 21);
- return instruction;
+ store_size(hart, address, value, 4);
}
static void execute_op_imm(Hart* hart, uint32_t instruction)
@@ -338,62 +315,6 @@ static void execute_branch(Hart* hart, uint32_t instruction)
}
}
-static inline uint32_t load_size(Hart* hart, uint32_t address, uint32_t size)
-{
- if ((address & 0x80000000) == 0)
- {
- assert(address + size < hart->mem_size);
- uint32_t value = 0;
- memcpy(&value, hart->mem + address, size);
- return value;
- }
-
- return 0;
-}
-
-static uint32_t load_byte(Hart* hart, uint32_t address)
-{
- return load_size(hart, address, 1);
-}
-
-static uint32_t load_half(Hart* hart, uint32_t address)
-{
- return load_size(hart, address, 2);
-}
-
-static uint32_t load_word(Hart* hart, uint32_t address)
-{
- return load_size(hart, address, 4);
-}
-
-static inline void store_size(Hart* hart, uint32_t address, uint32_t value, uint32_t size)
-{
- if ((address & 0x80000000) == 0)
- {
- assert(address + size < hart->mem_size);
- memcpy(hart->mem + address, &value, size);
- }
- else if (address == 0x80000000)
- {
- fwrite(&value, 1, size, stdout);
- }
-}
-
-static void store_byte(Hart* hart, uint32_t address, uint8_t value)
-{
- store_size(hart, address, value, 1);
-}
-
-static void store_half(Hart* hart, uint32_t address, uint16_t value)
-{
- store_size(hart, address, value, 2);
-}
-
-static void store_word(Hart* hart, uint32_t address, uint32_t value)
-{
- store_size(hart, address, value, 4);
-}
-
static void execute_load(Hart* hart, uint32_t instruction)
{
const Instruction inst = decode_i_type(instruction);
@@ -462,43 +383,6 @@ 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);
@@ -528,32 +412,32 @@ static void execute_system(Hart* hart, uint32_t instruction)
}
break;
}
- case 1: // CRSRW
+ case 1: // CSRRW
{
- uint16_t crs_id = inst.imm & 0xFFF;
+ uint16_t csr_id = inst.imm & 0xFFF;
if (inst.rd == 0)
{
- crs_write(hart, crs_id, hart->regs[inst.rs1]);
+ csr_action(hart, csr_id, hart->regs[inst.rs1], CSR_W);
}
else
{
- hart->regs[inst.rd] = crs_read_write(hart, crs_id, hart->regs[inst.rs1]);
+ hart->regs[inst.rd] = csr_action(hart, csr_id, hart->regs[inst.rs1], CSR_RW);
}
break;
}
- case 2: // CRSRS
+ case 2: // CSRRS
{
- uint16_t crs_id = inst.imm & 0xFFF;
+ uint16_t csr_id = inst.imm & 0xFFF;
uint32_t value = 0;
if (inst.rs1 == 0)
{
- value = crs_read(hart, crs_id);
+ value = csr_action(hart, csr_id, 0, CSR_R);
}
else
{
- value = crs_read_set(hart, crs_id, hart->regs[inst.rs1]);
+ value = csr_action(hart, csr_id, hart->regs[inst.rs1], CSR_RS);
}
if (inst.rd != 0)
@@ -562,18 +446,18 @@ static void execute_system(Hart* hart, uint32_t instruction)
}
break;
}
- case 3: // CRSRC
+ case 3: // CSRRC
{
- uint16_t crs_id = inst.imm & 0xFFF;
+ uint16_t csr_id = inst.imm & 0xFFF;
uint32_t value = 0;
if (inst.rs1 == 0)
{
- value = crs_read(hart, crs_id);
+ value = csr_action(hart, csr_id, 0, CSR_R);
}
else
{
- value = crs_read_clear(hart, crs_id, hart->regs[inst.rs1]);
+ value = csr_action(hart, csr_id, hart->regs[inst.rs1], CSR_RC);
}
if (inst.rd != 0)
@@ -582,32 +466,32 @@ static void execute_system(Hart* hart, uint32_t instruction)
}
break;
}
- case 5: // CRSRWI
+ case 5: // CSRRWI
{
- uint16_t crs_id = inst.imm & 0xFFF;
+ uint16_t csr_id = inst.imm & 0xFFF;
if (inst.rd == 0)
{
- crs_write(hart, crs_id, inst.rs1);
+ csr_action(hart, csr_id, inst.rs1, CSR_W);
}
else
{
- hart->regs[inst.rd] = crs_read_write(hart, crs_id, inst.rs1);
+ hart->regs[inst.rd] = csr_action(hart, csr_id, inst.rs1, CSR_RW);
}
break;
}
- case 6: // CRSRSI
+ case 6: // CSRRSI
{
- uint16_t crs_id = inst.imm & 0xFFF;
+ uint16_t csr_id = inst.imm & 0xFFF;
uint32_t value = 0;
if (inst.rs1 == 0)
{
- value = crs_read(hart, crs_id);
+ value = csr_action(hart, csr_id, 0, CSR_R);
}
else
{
- value = crs_read_set(hart, crs_id, inst.rs1);
+ value = csr_action(hart, csr_id, inst.rs1, CSR_RS);
}
if (inst.rd != 0)
@@ -616,18 +500,18 @@ static void execute_system(Hart* hart, uint32_t instruction)
}
break;
}
- case 7: // CRSRCI
+ case 7: // CSRRCI
{
- uint16_t crs_id = inst.imm & 0xFFF;
+ uint16_t csr_id = inst.imm & 0xFFF;
uint32_t value = 0;
if (inst.rs1 == 0)
{
- value = crs_read(hart, crs_id);
+ value = csr_action(hart, csr_id, 0, CSR_R);
}
else
{
- value = crs_read_clear(hart, crs_id, inst.rs1);
+ value = csr_action(hart, csr_id, inst.rs1, CSR_RC);
}
if (inst.rd != 0)
@@ -644,6 +528,10 @@ static void execute_system(Hart* hart, uint32_t instruction)
void execute(Hart* hart, uint32_t instruction)
{
+ // @Todo Better time (same on all cores)
+ // @Todo Memory-map mtime and mtimecmp
+ hart->time = __rdtsc();
+
switch (instruction & 0x7f)
{
case 0x03:
@@ -721,16 +609,30 @@ void execute(Hart* hart, uint32_t instruction)
}
assert(hart->regs[0] == 0);
+
+ hart->instret += 1;
}
void execute_from(Hart* hart, uint32_t start_address)
{
hart->pc = start_address;
- hart->halted = false;
- while (!hart->halted)
+ while (true)
{
uint32_t instruction = load_word(hart, hart->pc);
execute(hart, instruction);
}
}
+
+void csr_init(Hart* hart);
+
+void hart_init(Hart* hart, uint32_t id, char* mem, uint32_t mem_size)
+{
+ memset(hart, 0, sizeof(Hart));
+ hart->hartid = id;
+ hart->priv = PRIV_M;
+ hart->mem = mem;
+ hart->mem_size = mem_size;
+
+ csr_init(hart);
+}