From f95a85de0082010e4af83e26e99299d601bb48d6 Mon Sep 17 00:00:00 2001 From: Steven Le Rouzic Date: Mon, 13 May 2024 00:04:44 +0200 Subject: Some work on CSR --- emulator/hart.c | 348 ++++++++++++++++++++------------------------------------ 1 file changed, 125 insertions(+), 223 deletions(-) (limited to 'emulator/hart.c') 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 #include #include #include #include -#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); +} -- cgit