diff --git a/include/device/alarm.h b/include/device/alarm.h new file mode 100644 index 0000000000000000000000000000000000000000..c360463f6d9c8854c5d2525aae0a99eef13483ae --- /dev/null +++ b/include/device/alarm.h @@ -0,0 +1,6 @@ +#ifndef __ALARM_H__ +#define __ALARM_H__ + +void add_alarm_handle(void *h); + +#endif diff --git a/src/device/alram.c b/src/device/alram.c new file mode 100644 index 0000000000000000000000000000000000000000..f41767532d326b53cdd66b9c1364488f70e72531 --- /dev/null +++ b/src/device/alram.c @@ -0,0 +1,40 @@ +#include "common.h" + +#include +#include + +#define TIMER_HZ 100 +#define MAX_HANDLER 8 + +typedef void (*alarm_handler_t) (void); +static alarm_handler_t handler[MAX_HANDLER] = {}; +static int idx = 0; +static struct itimerval it = {}; + +void add_alarm_handle(void *h) { + assert(idx < MAX_HANDLER); + handler[idx ++] = h; +} + +static void alarm_sig_handler(int signum) { + int i; + for (i = 0; i < idx; i ++) { + handler[i](); + } + + int ret = setitimer(ITIMER_VIRTUAL, &it, NULL); + Assert(ret == 0, "Can not set timer"); +} + +void init_alarm(void) { + struct sigaction s; + memset(&s, 0, sizeof(s)); + s.sa_handler = alarm_sig_handler; + int ret = sigaction(SIGVTALRM, &s, NULL); + Assert(ret == 0, "Can not set signal handler"); + + it.it_value.tv_sec = 0; + it.it_value.tv_usec = 1000000 / TIMER_HZ; + ret = setitimer(ITIMER_VIRTUAL, &it, NULL); + Assert(ret == 0, "Can not set timer"); +} diff --git a/src/device/device.c b/src/device/device.c index b02d06c39b8b42ef67f93b877b512d30aa5e227b..f28c8c993c6e3b9225d8b64231a28d99cd892c2e 100644 --- a/src/device/device.c +++ b/src/device/device.c @@ -2,31 +2,21 @@ #ifdef HAS_IOE -#include -#include +#include "device/alarm.h" #include -#define TIMER_HZ 100 -#define VGA_HZ 50 - -static struct itimerval it = {}; -static int device_update_flag = false; - +void init_alarm(); void init_serial(); void init_timer(); void init_vga(); void init_i8042(); -void timer_intr(); void send_key(uint8_t, bool); -static void timer_sig_handler(int signum) { - timer_intr(); +static int device_update_flag = false; +static void set_device_update_flag() { device_update_flag = true; - - int ret = setitimer(ITIMER_VIRTUAL, &it, NULL); - Assert(ret == 0, "Can not set timer"); } void device_update() { @@ -39,19 +29,19 @@ void device_update() { while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_QUIT: { - void monitor_statistic(); - monitor_statistic(); - exit(0); - } + void monitor_statistic(); + monitor_statistic(); + exit(0); + } // If a key was pressed case SDL_KEYDOWN: case SDL_KEYUP: { - uint8_t k = event.key.keysym.scancode; - bool is_keydown = (event.key.type == SDL_KEYDOWN); - send_key(k, is_keydown); - break; - } + uint8_t k = event.key.keysym.scancode; + bool is_keydown = (event.key.type == SDL_KEYDOWN); + send_key(k, is_keydown); + break; + } default: break; } } @@ -68,16 +58,8 @@ void init_device() { init_vga(); init_i8042(); - struct sigaction s; - memset(&s, 0, sizeof(s)); - s.sa_handler = timer_sig_handler; - int ret = sigaction(SIGVTALRM, &s, NULL); - Assert(ret == 0, "Can not set signal handler"); - - it.it_value.tv_sec = 0; - it.it_value.tv_usec = 1000000 / TIMER_HZ; - ret = setitimer(ITIMER_VIRTUAL, &it, NULL); - Assert(ret == 0, "Can not set timer"); + add_alarm_handle(set_device_update_flag); + init_alarm(); } #else diff --git a/src/device/serial.c b/src/device/serial.c index 3f4acf4413bedc1fd0b7a6b39ece406c921fb8b6..6e032b5aa8aa8b7feef30549f882ec9c4270ae6e 100644 --- a/src/device/serial.c +++ b/src/device/serial.c @@ -16,10 +16,7 @@ static void serial_ch_io_handler(uint32_t offset, int len, bool is_write) { char c = serial_ch_base[0]; /* We bind the serial port with the host stdout in NEMU. */ - putc(c, stdout); - if (c == '\n') { - fflush(stdout); - } + putc(c, stderr); } void init_serial() { diff --git a/src/device/timer.c b/src/device/timer.c index 2997ea4f0304a42731f1aee34d93cbbfead572da..183a8ba07abc728f1c0ae10f30fc61971db34048 100644 --- a/src/device/timer.c +++ b/src/device/timer.c @@ -1,20 +1,14 @@ #include "device/map.h" +#include "device/alarm.h" #include "monitor/monitor.h" #include #define RTC_PORT 0x48 // Note that this is not the standard #define RTC_MMIO 0xa1000048 -void timer_intr() { - if (nemu_state.state == NEMU_RUNNING) { - extern void dev_raise_intr(void); - dev_raise_intr(); - } -} - static uint32_t *rtc_port_base = NULL; -void rtc_io_handler(uint32_t offset, int len, bool is_write) { +static void rtc_io_handler(uint32_t offset, int len, bool is_write) { assert(offset == 0 || offset == 8 || offset == 12); if (!is_write) { struct timeval now; @@ -27,8 +21,16 @@ void rtc_io_handler(uint32_t offset, int len, bool is_write) { } } +static void timer_intr() { + if (nemu_state.state == NEMU_RUNNING) { + extern void dev_raise_intr(void); + dev_raise_intr(); + } +} + void init_timer() { rtc_port_base = (void*)new_space(16); add_pio_map("rtc", RTC_PORT, (void *)rtc_port_base, 16, rtc_io_handler); add_mmio_map("rtc", RTC_MMIO, (void *)rtc_port_base, 16, rtc_io_handler); + add_alarm_handle(timer_intr); } diff --git a/src/device/vga.c b/src/device/vga.c index b72d037adec48ce685b35624b960549aceacd7b7..c2526c059bd8bd3e71067a42f78ff4cc6b7fc336 100644 --- a/src/device/vga.c +++ b/src/device/vga.c @@ -23,7 +23,7 @@ static SDL_Texture *texture = NULL; static uint32_t (*vmem) [SCREEN_W] = NULL; static uint32_t *screensize_port_base = NULL; -void update_screen() { +static inline void update_screen() { SDL_UpdateTexture(texture, NULL, vmem, SCREEN_W * sizeof(vmem[0][0])); SDL_RenderClear(renderer); SDL_RenderCopy(renderer, texture, NULL, NULL); diff --git a/src/isa/riscv64/clint.c b/src/isa/riscv64/clint.c new file mode 100644 index 0000000000000000000000000000000000000000..c6a8fe624af2302aeaf0b7d72d5e8c583a8bebd9 --- /dev/null +++ b/src/isa/riscv64/clint.c @@ -0,0 +1,25 @@ +#include "monitor/monitor.h" +#include "device/alarm.h" +#include "device/map.h" + +#define CLINT_MMIO 0x2000000 +#define CLINT_MTIMECMP (0x4000 / sizeof(clint_base[0])) +#define CLINT_MTIME (0xBFF8 / sizeof(clint_base[0])) + +static uint64_t *clint_base = NULL; + +void clint_intr(void) { + if (nemu_state.state == NEMU_RUNNING) { + clint_base[CLINT_MTIME] += 0x800; + } +} + +bool clint_query_intr(void) { + return clint_base[CLINT_MTIME] >= clint_base[CLINT_MTIMECMP]; +} + +void init_clint(void) { + clint_base = (void *)new_space(0x10000); + add_mmio_map("clint", CLINT_MMIO, (void *)clint_base, 0x10000, NULL); + add_alarm_handle(clint_intr); +} diff --git a/src/isa/riscv64/csr.h b/src/isa/riscv64/csr.h index 9628a75bce4e69edf758de885a7dec8145a58d83..e12144fcc5fd5329fb53f607dcf9658c4d04b575 100644 --- a/src/isa/riscv64/csr.h +++ b/src/isa/riscv64/csr.h @@ -5,7 +5,7 @@ #define CSRS(f) \ f(mstatus , 0x300) f(mtvec , 0x305) f(mepc , 0x341) f(mcause , 0x342) \ - f(satp , 0x180) + f(mie , 0x304) f(satp , 0x180) #define CSR_STRUCT_START(name) \ typedef union { \ @@ -45,6 +45,21 @@ CSR_STRUCT_END(mcause) CSR_STRUCT_START(mepc) CSR_STRUCT_END(mepc) +CSR_STRUCT_START(mie) + uint64_t usie : 1; + uint64_t ssie : 1; + uint64_t hsie : 1; + uint64_t msie : 1; + uint64_t utie : 1; + uint64_t stie : 1; + uint64_t htie : 1; + uint64_t mtie : 1; + uint64_t ueie : 1; + uint64_t seie : 1; + uint64_t heie : 1; + uint64_t meie : 1; +CSR_STRUCT_END(mie) + #define CSRS_DECL(name, val) extern concat(name, _t)* const name; MAP(CSRS, CSRS_DECL) diff --git a/src/isa/riscv64/decode.c b/src/isa/riscv64/decode.c index bd4a810a0cc0cf2b89930b84e3bc56d1f0264007..fedec1ab5fb97e51cc6b4d73e9d04e4e3beed65f 100644 --- a/src/isa/riscv64/decode.c +++ b/src/isa/riscv64/decode.c @@ -92,6 +92,12 @@ make_DHelper(csr) { decode_op_r(id_dest, decinfo.isa.instr.rd, false); } +make_DHelper(csri) { + decode_op_i(id_src, decinfo.isa.instr.rs1, true); + decode_op_i(id_src2, decinfo.isa.instr.csr, true); + decode_op_r(id_dest, decinfo.isa.instr.rd, false); +} + // RVC #define creg2reg(creg) (creg + 8) diff --git a/src/isa/riscv64/exec/all-instr.h b/src/isa/riscv64/exec/all-instr.h index f760251188d7b48c80eb8a3b2d868971c0d704fa..1b5e3963e0e106cb390cffbdb56cf79ea5761977 100644 --- a/src/isa/riscv64/exec/all-instr.h +++ b/src/isa/riscv64/exec/all-instr.h @@ -28,6 +28,7 @@ make_EHelper(nemu_trap); make_EHelper(csrrw); make_EHelper(csrrs); +make_EHelper(csrrc); make_EHelper(priv); make_EHelper(mul); diff --git a/src/isa/riscv64/exec/exec.c b/src/isa/riscv64/exec/exec.c index 6ba82bdc30540290b1b5e2027e5d0689f025f722..157f34bac4e49a365578b966afa30f9d99ebecad 100644 --- a/src/isa/riscv64/exec/exec.c +++ b/src/isa/riscv64/exec/exec.c @@ -59,7 +59,7 @@ static make_EHelper(op32) { static make_EHelper(system) { static OpcodeEntry table [8] = { - EX(priv), IDEX(csr, csrrw), IDEX(csr, csrrs), EMPTY, EMPTY, EMPTY, EMPTY, EMPTY + EX(priv), IDEX(csr, csrrw), IDEX(csr, csrrs), EMPTY, EMPTY, EMPTY, IDEX(csri, csrrs), IDEX(csri, csrrc) }; idex(pc, &table[decinfo.isa.instr.funct3]); } diff --git a/src/isa/riscv64/exec/system.c b/src/isa/riscv64/exec/system.c index 87e6b0df8882848aa8c9da580e159d7a5ce03c48..764433e1fae0297da8e214a5b386c3e1969d24c8 100644 --- a/src/isa/riscv64/exec/system.c +++ b/src/isa/riscv64/exec/system.c @@ -24,7 +24,17 @@ make_EHelper(csrrs) { print_asm_template3("csrrs"); } -extern void raise_intr(uint32_t NO, vaddr_t epc); +make_EHelper(csrrc) { + rtlreg_t *csr = csr_decode_wrapper(id_src2->val); + + rtl_sr(id_dest->reg, csr, 8); + rtl_not(&s0, &id_src->val); + rtl_and(csr, csr, &s0); + + print_asm_template3("csrrc"); +} + +extern void raise_intr(word_t NO, vaddr_t epc); make_EHelper(priv) { uint32_t type = decinfo.isa.instr.csr; diff --git a/src/isa/riscv64/include/isa/decode.h b/src/isa/riscv64/include/isa/decode.h index dbe640a87ba960d76fc11b9b2dbc83ec33650a17..f5bdfb8af88ac5b3aac7df19001129b8fd25ed14 100644 --- a/src/isa/riscv64/include/isa/decode.h +++ b/src/isa/riscv64/include/isa/decode.h @@ -110,6 +110,7 @@ make_DHelper(B); make_DHelper(ld); make_DHelper(st); make_DHelper(csr); +make_DHelper(csri); make_DHelper(CR); make_DHelper(CB); diff --git a/src/isa/riscv64/init.c b/src/isa/riscv64/init.c index d8ca5a30eacd15d3201bfdfef3ad986c02f50682..2b8925dea781ad189d4ae52043042e0a8ca8b63d 100644 --- a/src/isa/riscv64/init.c +++ b/src/isa/riscv64/init.c @@ -11,10 +11,14 @@ const uint32_t isa_default_img [] = { }; const long isa_default_img_size = sizeof(isa_default_img); +void init_clint(void); + void init_isa(void) { cpu.gpr[0]._64 = 0; cpu.pc = PC_START; mstatus->val = 0x000c0100; register_pmem(0x80000000u); + + init_clint(); } diff --git a/src/isa/riscv64/intr.c b/src/isa/riscv64/intr.c index 288bff55533c238deab6b433645bc7101dd27591..b6feec80d0279a691eb61e76f7c0d7cd7d2c489f 100644 --- a/src/isa/riscv64/intr.c +++ b/src/isa/riscv64/intr.c @@ -1,7 +1,9 @@ #include "rtl/rtl.h" #include "csr.h" -void raise_intr(uint32_t NO, vaddr_t epc) { +#define INTR_BIT (1ULL << 63) + +void raise_intr(word_t NO, vaddr_t epc) { /* TODO: Trigger an interrupt/exception with ``NO''. * That is, use ``NO'' to index the IDT. */ @@ -15,11 +17,18 @@ void raise_intr(uint32_t NO, vaddr_t epc) { } bool isa_query_intr(void) { - if (cpu.INTR && mstatus->mie) { - cpu.INTR = false; - // machine external interrupt - raise_intr(0x8000000b, cpu.pc); - return true; + extern bool clint_query_intr(void); + if (mstatus->mie) { + //if (cpu.INTR) { + // cpu.INTR = false; + // // machine external interrupt + // raise_intr(0xb | INTR_BIT, cpu.pc); + //} + if (clint_query_intr() && mie->mtie) { + // machine timer interrupt + raise_intr(0x7 | INTR_BIT, cpu.pc); + return true; + } } return false; }