diff --git a/.gitmodules b/.gitmodules index e4ce605..7e43040 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,4 +4,4 @@ branch = dev [submodule "diffu"] path = diffu - url = https://git.xinyang.life/xin/diffu.git + url = git@github.com:xinyangli/diffu.git diff --git a/abstract-machine/CMakeLists.txt b/abstract-machine/CMakeLists.txt index 659bb84..b6e660c 100644 --- a/abstract-machine/CMakeLists.txt +++ b/abstract-machine/CMakeLists.txt @@ -76,7 +76,8 @@ target_include_directories( INTERFACE $ $ $) -target_compile_definitions(am_interface INTERFACE ARCH_H=) +target_compile_definitions(am_interface INTERFACE ARCH_H= + "__ISA__=\"${ISA}\"") file(GLOB_RECURSE AM_HEADERS "${CMAKE_SOURCE_DIR}/am/include/*.h") target_sources( am_interface diff --git a/abstract-machine/am/include/arch/riscv.h b/abstract-machine/am/include/arch/riscv.h index 9709050..cb6ecc1 100644 --- a/abstract-machine/am/include/arch/riscv.h +++ b/abstract-machine/am/include/arch/riscv.h @@ -1,5 +1,6 @@ #ifndef ARCH_H__ #define ARCH_H__ +#include #ifdef __riscv_e #define NR_REGS 16 @@ -9,10 +10,13 @@ struct Context { // TODO: fix the order of these members to match trap.S - uintptr_t mepc, mcause, gpr[NR_REGS], mstatus; + uintptr_t gpr[NR_REGS]; + uintptr_t mcause, mstatus, mepc; void *pdir; }; +enum Cause { CauseEnvironmentCallFromMMode = 11 }; + #ifdef __riscv_e #define GPR1 gpr[15] // a5 #else diff --git a/abstract-machine/am/src/platform/nemu/trm.c b/abstract-machine/am/src/platform/nemu/trm.c index c4287c5..5d08a48 100644 --- a/abstract-machine/am/src/platform/nemu/trm.c +++ b/abstract-machine/am/src/platform/nemu/trm.c @@ -6,7 +6,7 @@ int main(const char *args); Area heap = RANGE(&_heap_start, PMEM_END); #ifndef MAINARGS -#define MAINARGS "5" +#define MAINARGS "i" #endif static const char mainargs[] = MAINARGS; diff --git a/abstract-machine/am/src/riscv/nemu/cte.c b/abstract-machine/am/src/riscv/nemu/cte.c index 77a357c..12a9d32 100644 --- a/abstract-machine/am/src/riscv/nemu/cte.c +++ b/abstract-machine/am/src/riscv/nemu/cte.c @@ -1,14 +1,20 @@ +#include "arch/riscv.h" #include -#include #include +#include -static Context* (*user_handler)(Event, Context*) = NULL; +static Context *(*user_handler)(Event, Context *) = NULL; -Context* __am_irq_handle(Context *c) { +Context *__am_irq_handle(Context *c) { if (user_handler) { Event ev = {0}; switch (c->mcause) { - default: ev.event = EVENT_ERROR; break; + case CauseEnvironmentCallFromMMode: + ev.event = EVENT_YIELD; + break; + default: + ev.event = EVENT_ERROR; + break; } c = user_handler(ev, c); @@ -20,7 +26,7 @@ Context* __am_irq_handle(Context *c) { extern void __am_asm_trap(void); -bool cte_init(Context*(*handler)(Event, Context*)) { +bool cte_init(Context *(*handler)(Event, Context *)) { // initialize exception entry asm volatile("csrw mtvec, %0" : : "r"(__am_asm_trap)); @@ -42,9 +48,6 @@ void yield() { #endif } -bool ienabled() { - return false; -} +bool ienabled() { return false; } -void iset(bool enable) { -} +void iset(bool enable) {} diff --git a/abstract-machine/default.nix b/abstract-machine/default.nix index ef21cf2..4e3fb1c 100644 --- a/abstract-machine/default.nix +++ b/abstract-machine/default.nix @@ -15,6 +15,9 @@ stdenv.mkDerivation { (lib.cmakeFeature "ISA" isa) ] ++ map (p: (lib.cmakeBool "__PLATFORM_${lib.strings.toUpper p}__" true)) platform; + cmakeBuildType = "Debug"; + dontStrip = true; + nativeBuildInputs = [ cmake ]; diff --git a/am-kernels b/am-kernels index 02b38e7..8c4ea04 160000 --- a/am-kernels +++ b/am-kernels @@ -1 +1 @@ -Subproject commit 02b38e7b44f673f808abcb3bf9464811f8c58d4b +Subproject commit 8c4ea046225e2dce599dc36aeef6c4c857996d00 diff --git a/nemu/.gitignore b/nemu/.gitignore index 36e223b..5bea786 100644 --- a/nemu/.gitignore +++ b/nemu/.gitignore @@ -9,6 +9,7 @@ build/ .envrc .metals/ .vscode/ +.zed/ compile_commands.json ### C ### diff --git a/nemu/include/utils.h b/nemu/include/utils.h index f974584..43c30ad 100644 --- a/nemu/include/utils.h +++ b/nemu/include/utils.h @@ -20,7 +20,14 @@ // ----------- state ----------- -enum { NEMU_RUNNING, NEMU_STOP, NEMU_END, NEMU_ABORT, NEMU_QUIT }; +enum { + NEMU_RUNNING, + NEMU_GDB_INTERRUPT, + NEMU_STOP, + NEMU_END, + NEMU_ABORT, + NEMU_QUIT +}; typedef struct { int state; @@ -36,42 +43,41 @@ uint64_t get_time(); // ----------- log ----------- -#define ANSI_FG_BLACK "\33[1;30m" -#define ANSI_FG_RED "\33[1;31m" -#define ANSI_FG_GREEN "\33[1;32m" -#define ANSI_FG_YELLOW "\33[1;33m" -#define ANSI_FG_BLUE "\33[1;34m" +#define ANSI_FG_BLACK "\33[1;30m" +#define ANSI_FG_RED "\33[1;31m" +#define ANSI_FG_GREEN "\33[1;32m" +#define ANSI_FG_YELLOW "\33[1;33m" +#define ANSI_FG_BLUE "\33[1;34m" #define ANSI_FG_MAGENTA "\33[1;35m" -#define ANSI_FG_CYAN "\33[1;36m" -#define ANSI_FG_WHITE "\33[1;37m" -#define ANSI_BG_BLACK "\33[1;40m" -#define ANSI_BG_RED "\33[1;41m" -#define ANSI_BG_GREEN "\33[1;42m" -#define ANSI_BG_YELLOW "\33[1;43m" -#define ANSI_BG_BLUE "\33[1;44m" +#define ANSI_FG_CYAN "\33[1;36m" +#define ANSI_FG_WHITE "\33[1;37m" +#define ANSI_BG_BLACK "\33[1;40m" +#define ANSI_BG_RED "\33[1;41m" +#define ANSI_BG_GREEN "\33[1;42m" +#define ANSI_BG_YELLOW "\33[1;43m" +#define ANSI_BG_BLUE "\33[1;44m" #define ANSI_BG_MAGENTA "\33[1;35m" -#define ANSI_BG_CYAN "\33[1;46m" -#define ANSI_BG_WHITE "\33[1;47m" -#define ANSI_NONE "\33[0m" +#define ANSI_BG_CYAN "\33[1;46m" +#define ANSI_BG_WHITE "\33[1;47m" +#define ANSI_NONE "\33[0m" #define ANSI_FMT(str, fmt) fmt str ANSI_NONE -#define log_write(...) IFDEF(CONFIG_TARGET_NATIVE_ELF, \ - do { \ - extern FILE* log_fp; \ - extern bool log_enable(); \ - if (log_enable()) { \ - fprintf(log_fp, __VA_ARGS__); \ - fflush(log_fp); \ - } \ - } while (0) \ -) +#define log_write(...) \ + IFDEF( \ + CONFIG_TARGET_NATIVE_ELF, do { \ + extern FILE *log_fp; \ + extern bool log_enable(); \ + if (log_enable()) { \ + fprintf(log_fp, __VA_ARGS__); \ + fflush(log_fp); \ + } \ + } while (0)) -#define _Log(...) \ - do { \ - printf(__VA_ARGS__); \ - log_write(__VA_ARGS__); \ +#define _Log(...) \ + do { \ + printf(__VA_ARGS__); \ + log_write(__VA_ARGS__); \ } while (0) - #endif diff --git a/nemu/src/device/keyboard.c b/nemu/src/device/keyboard.c index da699b5..2ae5d17 100644 --- a/nemu/src/device/keyboard.c +++ b/nemu/src/device/keyboard.c @@ -13,7 +13,10 @@ * See the Mulan PSL v2 for more details. ***************************************************************************************/ +#include +#include #include +#include #include #define KEYDOWN_MASK 0x8000 @@ -22,28 +25,27 @@ #include // Note that this is not the standard -#define NEMU_KEYS(f) \ - f(ESCAPE) f(F1) f(F2) f(F3) f(F4) f(F5) f(F6) f(F7) f(F8) f(F9) f(F10) f(F11) f(F12) \ -f(GRAVE) f(1) f(2) f(3) f(4) f(5) f(6) f(7) f(8) f(9) f(0) f(MINUS) f(EQUALS) f(BACKSPACE) \ -f(TAB) f(Q) f(W) f(E) f(R) f(T) f(Y) f(U) f(I) f(O) f(P) f(LEFTBRACKET) f(RIGHTBRACKET) f(BACKSLASH) \ -f(CAPSLOCK) f(A) f(S) f(D) f(F) f(G) f(H) f(J) f(K) f(L) f(SEMICOLON) f(APOSTROPHE) f(RETURN) \ -f(LSHIFT) f(Z) f(X) f(C) f(V) f(B) f(N) f(M) f(COMMA) f(PERIOD) f(SLASH) f(RSHIFT) \ -f(LCTRL) f(APPLICATION) f(LALT) f(SPACE) f(RALT) f(RCTRL) \ -f(UP) f(DOWN) f(LEFT) f(RIGHT) f(INSERT) f(DELETE) f(HOME) f(END) f(PAGEUP) f(PAGEDOWN) +#define NEMU_KEYS(f) \ + f(ESCAPE) f(F1) f(F2) f(F3) f(F4) f(F5) f(F6) f(F7) f(F8) f(F9) f(F10) \ + f(F11) f(F12) f(GRAVE) f(1) f(2) f(3) f(4) f(5) f(6) f(7) f(8) f(9) f(0) \ + f(MINUS) f(EQUALS) f(BACKSPACE) f(TAB) f(Q) f(W) f(E) f(R) f(T) f(Y) \ + f(U) f(I) f(O) f(P) f(LEFTBRACKET) f(RIGHTBRACKET) f(BACKSLASH) \ + f(CAPSLOCK) f(A) f(S) f(D) f(F) f(G) f(H) f(J) f(K) f(L) \ + f(SEMICOLON) f(APOSTROPHE) f(RETURN) f(LSHIFT) f(Z) f(X) \ + f(C) f(V) f(B) f(N) f(M) f(COMMA) f(PERIOD) f(SLASH) \ + f(RSHIFT) f(LCTRL) f(APPLICATION) f(LALT) \ + f(SPACE) f(RALT) f(RCTRL) f(UP) f(DOWN) \ + f(LEFT) f(RIGHT) f(INSERT) f(DELETE) \ + f(HOME) f(END) f(PAGEUP) f(PAGEDOWN) -#define NEMU_KEY_NAME(k) NEMU_KEY_ ## k, +#define NEMU_KEY_NAME(k) NEMU_KEY_##k, -enum { - NEMU_KEY_NONE = 0, - MAP(NEMU_KEYS, NEMU_KEY_NAME) -}; +enum { NEMU_KEY_NONE = 0, MAP(NEMU_KEYS, NEMU_KEY_NAME) }; -#define SDL_KEYMAP(k) keymap[SDL_SCANCODE_ ## k] = NEMU_KEY_ ## k; +#define SDL_KEYMAP(k) keymap[SDL_SCANCODE_##k] = NEMU_KEY_##k; static uint32_t keymap[256] = {}; -static void init_keymap() { - MAP(NEMU_KEYS, SDL_KEYMAP) -} +static void init_keymap() { MAP(NEMU_KEYS, SDL_KEYMAP) } #define KEY_QUEUE_LEN 1024 static int key_queue[KEY_QUEUE_LEN] = {}; @@ -92,9 +94,11 @@ void init_i8042() { i8042_data_port_base = (uint32_t *)new_space(4); i8042_data_port_base[0] = NEMU_KEY_NONE; #ifdef CONFIG_HAS_PORT_IO - add_pio_map ("keyboard", CONFIG_I8042_DATA_PORT, i8042_data_port_base, 4, i8042_data_io_handler); + add_pio_map("keyboard", CONFIG_I8042_DATA_PORT, i8042_data_port_base, 4, + i8042_data_io_handler); #else - add_mmio_map("keyboard", CONFIG_I8042_DATA_MMIO, i8042_data_port_base, 4, i8042_data_io_handler); + add_mmio_map("keyboard", CONFIG_I8042_DATA_MMIO, i8042_data_port_base, 4, + i8042_data_io_handler); #endif IFNDEF(CONFIG_TARGET_AM, init_keymap()); } diff --git a/nemu/src/device/serial.c b/nemu/src/device/serial.c index ad437e8..dba02f6 100644 --- a/nemu/src/device/serial.c +++ b/nemu/src/device/serial.c @@ -16,6 +16,7 @@ #include #include #include +#include #include /* http://en.wikibooks.org/wiki/Serial_Programming/8250_UART_Programming */ diff --git a/nemu/src/device/timer.c b/nemu/src/device/timer.c index 23c2d49..886ecd6 100644 --- a/nemu/src/device/timer.c +++ b/nemu/src/device/timer.c @@ -16,6 +16,7 @@ #include #include #include +#include #include static uint32_t *rtc_port_base = NULL; diff --git a/nemu/src/isa/riscv32/csr.c b/nemu/src/isa/riscv32/csr.c new file mode 100644 index 0000000..5b9a298 --- /dev/null +++ b/nemu/src/isa/riscv32/csr.c @@ -0,0 +1,18 @@ +#include + +void init_csr(csr_t csr) { memset(csr, 0, sizeof(word_t)); } + +void write_csr(csr_t csr, csr_addr_t csrnum, word_t value) { + switch (csrnum) { + default: + csr[csrnum] = value; + } +} + +word_t read_csr(csr_t csr, csr_addr_t csrnum) { + switch (csrnum) { + // TODO: Implement csr read checks + default: + return csr[csrnum]; + } +} diff --git a/nemu/src/isa/riscv32/include/isa-def.h b/nemu/src/isa/riscv32/include/isa-def.h index 524cb4e..e3f514a 100644 --- a/nemu/src/isa/riscv32/include/isa-def.h +++ b/nemu/src/isa/riscv32/include/isa-def.h @@ -18,9 +18,13 @@ #include +#define CSR_SIZE (0x1000) + +typedef word_t csr_t[CSR_SIZE]; + typedef struct { word_t gpr[MUXDEF(CONFIG_RVE, 16, 32)]; - // word_t csr[MUXDEF(CONFIG_RVE, )] + csr_t csr; vaddr_t pc; } MUXDEF(CONFIG_RV64, riscv64_CPU_state, riscv32_CPU_state); diff --git a/nemu/src/isa/riscv32/inst.c b/nemu/src/isa/riscv32/inst.c index dc65f47..75a5fa2 100644 --- a/nemu/src/isa/riscv32/inst.c +++ b/nemu/src/isa/riscv32/inst.c @@ -13,6 +13,7 @@ * See the Mulan PSL v2 for more details. ***************************************************************************************/ +#include "isa.h" #include "local-include/reg.h" #include "macro.h" #include "types.h" @@ -20,6 +21,7 @@ #include #include #include +#include #include #include @@ -33,6 +35,8 @@ enum { TYPE_S, TYPE_B, TYPE_J, + TYPE_CSR, + TYPE_CSRI, TYPE_N, // none }; @@ -66,6 +70,14 @@ enum { *imm = SEXT(BITS(i, 31, 31), 1) << 20 | BITS(i, 30, 21) << 1 | \ BITS(i, 20, 20) << 11 | BITS(i, 19, 12) << 12; \ } while (0) +#define csr() \ + do { \ + *src2 = BITS(i, 31, 20); \ + } while (0) +#define uimm() \ + do { \ + *imm = BITS(i, 19, 15); \ + } while (0) static void decode_operand(Decode *s, int *rd, word_t *src1, word_t *src2, word_t *imm, int type) { @@ -98,6 +110,14 @@ static void decode_operand(Decode *s, int *rd, word_t *src1, word_t *src2, src2R(); immB(); break; + case TYPE_CSR: + src1R(); + csr(); + break; + case TYPE_CSRI: + csr(); + uimm(); + break; } } @@ -249,6 +269,44 @@ static int decode_exec(Decode *s) { INSTPAT("0000001 ????? ????? 111 ????? 01100 11", remu, R, R(rd) = src1 % src2); + // "Previledge" + // -- CSR instructions + INSTPAT( + "??????? ????? ????? 001 ????? 11100 11", csrrw, CSR, do { + R(rd) = read_csr(cpu.csr, src2); + write_csr(cpu.csr, src2, src1); + } while (0);); + INSTPAT( + "??????? ????? ????? 010 ????? 11100 11", csrrs, CSR, do { + R(rd) = read_csr(cpu.csr, src2); + set_csr_bits(cpu.csr, src2, src1); + } while (0);); + INSTPAT( + "??????? ????? ????? 011 ????? 11100 11", csrrc, CSR, do { + R(rd) = read_csr(cpu.csr, src2); + clear_csr_bits(cpu.csr, src2, src1); + } while (0);); + INSTPAT( + "??????? ????? ????? 101 ????? 11100 11", csrrwi, CSRI, do { + R(rd) = read_csr(cpu.csr, src2); + write_csr(cpu.csr, src2, imm); + } while (0);); + INSTPAT( + "??????? ????? ????? 110 ????? 11100 11", csrrsi, CSRI, do { + R(rd) = read_csr(cpu.csr, src2); + set_csr_bits(cpu.csr, src2, imm); + } while (0);); + INSTPAT( + "??????? ????? ????? 111 ????? 11100 11", csrrci, CSRI, do { + R(rd) = read_csr(cpu.csr, src2); + clear_csr_bits(cpu.csr, src2, imm); + } while (0);); + // -- Machine level + INSTPAT("0000000 00000 00000 000 00000 11100 11", ecall, N, + s->dnpc = isa_raise_intr(CauseEnvironmentCallFromMMode, cpu.pc)); + INSTPAT("0011000 00010 00000 000 00000 11100 11", mret, N, + s->dnpc = read_csr(cpu.csr, MEPC)); + INSTPAT("??????? ????? ????? ??? ????? ????? ??", inv, N, INV(s->pc)); INSTPAT_END(); diff --git a/nemu/src/isa/riscv32/local-include/csr.h b/nemu/src/isa/riscv32/local-include/csr.h new file mode 100644 index 0000000..9dfca1c --- /dev/null +++ b/nemu/src/isa/riscv32/local-include/csr.h @@ -0,0 +1,29 @@ +#ifndef __NEMU_CSR_H__ +#define __NEMU_CSR_H__ +#include +#include + +#define MSTATUS 0x300 +#define MISA 0x301 +#define MIE 0x304 +#define MTVEC 0x305 +#define MEPC 0x341 +#define MCAUSE 0x342 + +enum { CauseEnvironmentCallFromMMode = 11 }; + +typedef uint16_t csr_addr_t; + +void init_csr(csr_t csr); + +/* macro for setting and clearing csr bits */ +#define set_csr_bits(csr, reg, mask) \ + write_csr(csr, reg, read_csr(csr, reg) | (mask)) + +#define clear_csr_bits(csr, reg, mask) \ + write_csr(csr, reg, read_csr(csr, reg) & ~(mask)) + +void write_csr(csr_t csr, csr_addr_t csrnum, word_t value); +word_t read_csr(csr_t csr, csr_addr_t csrnum); + +#endif // __NEMU_CSR_H__ diff --git a/nemu/src/isa/riscv32/reg.c b/nemu/src/isa/riscv32/reg.c index fe96b86..b76282c 100644 --- a/nemu/src/isa/riscv32/reg.c +++ b/nemu/src/isa/riscv32/reg.c @@ -14,6 +14,7 @@ ***************************************************************************************/ #include "local-include/reg.h" +#include "csr.h" #include "macro.h" #include #include @@ -51,11 +52,13 @@ word_t isa_reg_str2val(const char *s, bool *success) { } int isa_read_reg(void *args, int regno, size_t *reg_value) { - if (regno > 32) { + if (regno > 33) { return EFAULT; } - if (regno == 32) { + if (regno == 33) { + *reg_value = cpu.csr[MTVEC]; + } else if (regno == 32) { *reg_value = cpu.pc; } else { *reg_value = cpu.gpr[regno]; @@ -64,11 +67,13 @@ int isa_read_reg(void *args, int regno, size_t *reg_value) { } int isa_write_reg(void *args, int regno, size_t data) { - if (regno > 32) { + if (regno > 33) { return EFAULT; } - if (regno == 32) { + if (regno == 33) { + cpu.csr[MTVEC] = data; + } else if (regno == 32) { cpu.pc = data; } else { cpu.gpr[regno] = data; @@ -76,6 +81,6 @@ int isa_write_reg(void *args, int regno, size_t data) { return 0; } -__EXPORT arch_info_t isa_arch_info = {.reg_num = 32, +__EXPORT arch_info_t isa_arch_info = {.reg_num = 33, .reg_byte = MUXDEF(CONFIG_RV64, 8, 4), .target_desc = TARGET_RV32}; diff --git a/nemu/src/isa/riscv32/system/intr.c b/nemu/src/isa/riscv32/system/intr.c index 3619b59..4fc8c35 100644 --- a/nemu/src/isa/riscv32/system/intr.c +++ b/nemu/src/isa/riscv32/system/intr.c @@ -13,16 +13,14 @@ * See the Mulan PSL v2 for more details. ***************************************************************************************/ +#include #include word_t isa_raise_intr(word_t NO, vaddr_t epc) { - /* TODO: Trigger an interrupt/exception with ``NO''. - * Then return the address of the interrupt/exception vector. - */ + write_csr(cpu.csr, MEPC, epc); + write_csr(cpu.csr, MCAUSE, NO); - return 0; + return read_csr(cpu.csr, MTVEC); } -word_t isa_query_intr() { - return INTR_EMPTY; -} +word_t isa_query_intr() { return INTR_EMPTY; } diff --git a/nemu/src/monitor/gdbstub.cc b/nemu/src/monitor/gdbstub.cc index 5905ef4..5963b72 100644 --- a/nemu/src/monitor/gdbstub.cc +++ b/nemu/src/monitor/gdbstub.cc @@ -59,6 +59,11 @@ static void nemu_is_stopped(gdb_action_t *act, breakpoint_t *stopped_at) { } break; + case NEMU_GDB_INTERRUPT: + act->reason = gdb_action_t::ACT_BREAKPOINT; + act->data = cpu.pc; + break; + default: act->reason = gdb_action_t::ACT_SHUTDOWN; act->data = nemu_state.halt_ret; @@ -103,7 +108,7 @@ __EXPORT bool nemu_del_bp(void *args, size_t addr, bp_type_t type) { } __EXPORT void nemu_on_interrupt(void *args) { - // fputs("Not implemented", stderr); + nemu_state.state = NEMU_GDB_INTERRUPT; } __EXPORT int nemu_read_reg(void *args, int regno, size_t *data) { @@ -121,7 +126,8 @@ static struct target_ops nemu_gdbstub_ops = {.cont = nemu_cont, .write_mem = nemu_write_mem, .set_bp = nemu_set_bp, .del_bp = nemu_del_bp, - .on_interrupt = NULL}; + .on_interrupt = nemu_on_interrupt, + .monitor = NULL}; static DbgState *pdbg; static gdbstub_t gdbstub_priv; const char SOCKET_ADDR[] = "/tmp/gdbstub-nemu.sock"; @@ -152,7 +158,7 @@ __EXPORT void nemu_init(void *args) { int gdbstub_loop() { if (!gdbstub_init(&gdbstub_priv, &nemu_gdbstub_ops, - (arch_info_t)isa_arch_info, SOCKET_ADDR)) { + (arch_info_t)isa_arch_info, NULL, SOCKET_ADDR)) { return EINVAL; } printf("Waiting for gdb connection at %s", SOCKET_ADDR);