From 822fd8616cf3d960cb2df1d2f25452ef57ea854b Mon Sep 17 00:00:00 2001 From: Steven Le Rouzic Date: Sun, 12 May 2024 14:26:38 +0200 Subject: Zicrs --- build.bat | 4 -- emulator/hart.c | 216 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- emulator/hart.h | 5 +- main.asm | 5 +- 4 files changed, 210 insertions(+), 20 deletions(-) diff --git a/build.bat b/build.bat index d7c7ea7..ff0b0d8 100644 --- a/build.bat +++ b/build.bat @@ -4,15 +4,11 @@ SET BUILD_OPTS= -std=c11 -D_CRT_SECURE_NO_WARNINGS -I. IF NOT EXIST build mkdir build -echo emulator.lib clang emulator/lib.c -o build/emulator.lib %BUILD_OPTS% -fuse-ld=llvm-lib -echo emulator.exe clang emulator/main.c build/emulator.lib -o build/emulator.exe %BUILD_OPTS% -echo hart_test.exe clang emulator/hart_test.c build/emulator.lib -o build/hart_test.exe %BUILD_OPTS% -echo main.bin clang --target=riscv32 -march=rv32i -e _main -nostdlib main.asm -o build/main.bin 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 #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) { 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 +#include 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); - diff --git a/main.asm b/main.asm index 2d41e48..3ae0850 100644 --- a/main.asm +++ b/main.asm @@ -13,10 +13,13 @@ l1: ret _main: + csrr a0, mhartid + la a0, my_str call print -halt: j halt + li a0, 0 + ecall .section .rodata my_str: .string "Hello, world!\n" -- cgit