diff --git a/.gitignore b/.gitignore index 2f31ace..84c3ed2 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ _* *~ build/ !.gitignore +.vscode \ No newline at end of file diff --git a/am/include/arch/riscv64-mycpu.h b/am/include/arch/riscv64-mycpu.h new file mode 100644 index 0000000..5c75646 --- /dev/null +++ b/am/include/arch/riscv64-mycpu.h @@ -0,0 +1,16 @@ +#ifndef ARCH_H__ +#define ARCH_H__ + +struct Context { + // TODO: fix the order of these members to match trap.S + uintptr_t epc, cause, gpr[32], status; +}; + +#define GPR1 gpr[0] +#define GPR2 gpr[0] +#define GPR3 gpr[0] +#define GPR4 gpr[0] +#define GPRx gpr[0] + +#endif + diff --git a/am/src/mycpu/cte.c b/am/src/mycpu/cte.c new file mode 100644 index 0000000..b94083f --- /dev/null +++ b/am/src/mycpu/cte.c @@ -0,0 +1,45 @@ +#include +#include + +static Context* (*user_handler)(Event, Context*) = NULL; + +Context* __am_irq_handle(Context *c) { + if (user_handler) { + Event ev = {0}; + switch (c->cause) { + default: ev.event = EVENT_ERROR; break; + } + + c = user_handler(ev, c); + assert(c != NULL); + } + + return c; +} + +extern void __am_asm_trap(void); + +bool cte_init(Context*(*handler)(Event, Context*)) { + // initialize exception entry + asm volatile("csrw mtvec, %0" : : "r"(__am_asm_trap)); + + // register event handler + user_handler = handler; + + return true; +} + +Context *kcontext(Area kstack, void (*entry)(void *), void *arg) { + return NULL; +} + +void yield() { + asm volatile("li a7, -1; ecall"); +} + +bool ienabled() { + return false; +} + +void iset(bool enable) { +} diff --git a/am/src/mycpu/input.c b/am/src/mycpu/input.c new file mode 100644 index 0000000..0460fa4 --- /dev/null +++ b/am/src/mycpu/input.c @@ -0,0 +1,6 @@ +#include + +void __am_input_keybrd(AM_INPUT_KEYBRD_T *kbd) { + kbd->keydown = 0; + kbd->keycode = AM_KEY_NONE; +} diff --git a/am/src/mycpu/ioe.c b/am/src/mycpu/ioe.c new file mode 100644 index 0000000..97a306d --- /dev/null +++ b/am/src/mycpu/ioe.c @@ -0,0 +1,33 @@ +#include +#include + +void __am_timer_init(); + +void __am_timer_rtc(AM_TIMER_RTC_T *); +void __am_timer_uptime(AM_TIMER_UPTIME_T *); +void __am_input_keybrd(AM_INPUT_KEYBRD_T *); +void __am_timer_rtc(AM_TIMER_RTC_T *); + +static void __am_timer_config(AM_TIMER_CONFIG_T *cfg) { cfg->present = true; cfg->has_rtc = true; } +static void __am_input_config(AM_INPUT_CONFIG_T *cfg) { cfg->present = true; } + +typedef void (*handler_t)(void *buf); +static void *lut[128] = { + [AM_TIMER_CONFIG] = __am_timer_config, + [AM_TIMER_RTC ] = __am_timer_rtc, + [AM_TIMER_UPTIME] = __am_timer_uptime, + [AM_INPUT_CONFIG] = __am_input_config, + [AM_INPUT_KEYBRD] = __am_input_keybrd, +}; + +static void fail(void *buf) { panic("access nonexist register"); } + +bool ioe_init() { + for (int i = 0; i < LENGTH(lut); i++) + if (!lut[i]) lut[i] = fail; + __am_timer_init(); + return true; +} + +void ioe_read (int reg, void *buf) { ((handler_t)lut[reg])(buf); } +void ioe_write(int reg, void *buf) { ((handler_t)lut[reg])(buf); } diff --git a/am/src/mycpu/libgcc/div.S b/am/src/mycpu/libgcc/div.S new file mode 100644 index 0000000..0d394d2 --- /dev/null +++ b/am/src/mycpu/libgcc/div.S @@ -0,0 +1,140 @@ +#define FUNC_TYPE(X) .type X,@function +#define FUNC_SIZE(X) .size X,.-X + +#define FUNC_BEGIN(X) \ + .globl X; \ + FUNC_TYPE (X); \ +X: + +#define FUNC_END(X) \ + FUNC_SIZE(X) + +#define FUNC_ALIAS(X,Y) \ + .globl X; \ + X = Y + + +#define __riscv_xlen 64 + + .text + .align 2 + +#if __riscv_xlen == 32 +/* Our RV64 64-bit routines are equivalent to our RV32 32-bit routines. */ +# define __udivdi3 __udivsi3 +# define __umoddi3 __umodsi3 +# define __divdi3 __divsi3 +# define __moddi3 __modsi3 +#else +FUNC_BEGIN (__udivsi3) + /* Compute __udivdi3(a0 << 32, a1 << 32); cast result to uint32_t. */ + sll a0, a0, 32 + sll a1, a1, 32 + move t0, ra + jal __udivdi3 + sext.w a0, a0 + jr t0 +FUNC_END (__udivsi3) + +FUNC_BEGIN (__umodsi3) + /* Compute __udivdi3((uint32_t)a0, (uint32_t)a1); cast a1 to uint32_t. */ + sll a0, a0, 32 + sll a1, a1, 32 + srl a0, a0, 32 + srl a1, a1, 32 + move t0, ra + jal __udivdi3 + sext.w a0, a1 + jr t0 +FUNC_END (__umodsi3) + +FUNC_ALIAS (__modsi3, __moddi3) + +FUNC_BEGIN( __divsi3) + /* Check for special case of INT_MIN/-1. Otherwise, fall into __divdi3. */ + li t0, -1 + beq a1, t0, .L20 +#endif + +FUNC_BEGIN (__divdi3) + bltz a0, .L10 + bltz a1, .L11 + /* Since the quotient is positive, fall into __udivdi3. */ + +FUNC_BEGIN (__udivdi3) + mv a2, a1 + mv a1, a0 + li a0, -1 + beqz a2, .L5 + li a3, 1 + bgeu a2, a1, .L2 +.L1: + blez a2, .L2 + slli a2, a2, 1 + slli a3, a3, 1 + bgtu a1, a2, .L1 +.L2: + li a0, 0 +.L3: + bltu a1, a2, .L4 + sub a1, a1, a2 + or a0, a0, a3 +.L4: + srli a3, a3, 1 + srli a2, a2, 1 + bnez a3, .L3 +.L5: + ret +FUNC_END (__udivdi3) + +FUNC_BEGIN (__umoddi3) + /* Call __udivdi3(a0, a1), then return the remainder, which is in a1. */ + move t0, ra + jal __udivdi3 + move a0, a1 + jr t0 +FUNC_END (__umoddi3) + + /* Handle negative arguments to __divdi3. */ +.L10: + neg a0, a0 + /* Zero is handled as a negative so that the result will not be inverted. */ + bgtz a1, .L12 /* Compute __udivdi3(-a0, a1), then negate the result. */ + + neg a1, a1 + j __udivdi3 /* Compute __udivdi3(-a0, -a1). */ +.L11: /* Compute __udivdi3(a0, -a1), then negate the result. */ + neg a1, a1 +.L12: + move t0, ra + jal __udivdi3 + neg a0, a0 + jr t0 +FUNC_END (__divdi3) + +FUNC_BEGIN (__moddi3) + move t0, ra + bltz a1, .L31 + bltz a0, .L32 +.L30: + jal __udivdi3 /* The dividend is not negative. */ + move a0, a1 + jr t0 +.L31: + neg a1, a1 + bgez a0, .L30 +.L32: + neg a0, a0 + jal __udivdi3 /* The dividend is hella negative. */ + neg a0, a1 + jr t0 +FUNC_END (__moddi3) + +#if __riscv_xlen == 64 + /* continuation of __divsi3 */ +.L20: + sll t0, t0, 31 + bne a0, t0, __divdi3 + ret +FUNC_END (__divsi3) +#endif diff --git a/am/src/mycpu/libgcc/muldi3.S b/am/src/mycpu/libgcc/muldi3.S new file mode 100644 index 0000000..c9e131d --- /dev/null +++ b/am/src/mycpu/libgcc/muldi3.S @@ -0,0 +1,25 @@ +#define FUNC_TYPE(X) .type X,@function +#define FUNC_SIZE(X) .size X,.-X + +#define FUNC_BEGIN(X) \ + .globl X; \ + FUNC_TYPE (X); \ +X: + +#define FUNC_END(X) \ + FUNC_SIZE(X) + + +FUNC_BEGIN (__muldi3) + mv a2, a0 + li a0, 0 +.L1: + andi a3, a1, 1 + beqz a3, .L2 + add a0, a0, a2 +.L2: + srli a1, a1, 1 + slli a2, a2, 1 + bnez a1, .L1 + ret +FUNC_END (__muldi3) \ No newline at end of file diff --git a/am/src/mycpu/mpe.c b/am/src/mycpu/mpe.c new file mode 100644 index 0000000..6715aa2 --- /dev/null +++ b/am/src/mycpu/mpe.c @@ -0,0 +1,17 @@ +#include + +bool mpe_init(void (*entry)()) { + return false; +} + +int cpu_count() { + return 1; +} + +int cpu_current() { + return 0; +} + +int atomic_xchg(int *addr, int newval) { + return 0; +} diff --git a/am/src/mycpu/start.S b/am/src/mycpu/start.S new file mode 100644 index 0000000..3e56e5c --- /dev/null +++ b/am/src/mycpu/start.S @@ -0,0 +1,8 @@ +.section entry, "ax" +.globl _start +.type _start, @function + +_start: + mv s0, zero + la sp, _stack_pointer + jal _trm_init diff --git a/am/src/mycpu/timer.c b/am/src/mycpu/timer.c new file mode 100644 index 0000000..6ea0ffa --- /dev/null +++ b/am/src/mycpu/timer.c @@ -0,0 +1,17 @@ +#include + +void __am_timer_init() { +} + +void __am_timer_uptime(AM_TIMER_UPTIME_T *uptime) { + uptime->us = 0; +} + +void __am_timer_rtc(AM_TIMER_RTC_T *rtc) { + rtc->second = 0; + rtc->minute = 0; + rtc->hour = 0; + rtc->day = 0; + rtc->month = 0; + rtc->year = 1900; +} diff --git a/am/src/mycpu/trap.S b/am/src/mycpu/trap.S new file mode 100644 index 0000000..bc64c53 --- /dev/null +++ b/am/src/mycpu/trap.S @@ -0,0 +1,51 @@ + +#define concat_temp(x, y) x ## y +#define concat(x, y) concat_temp(x, y) +#define MAP(c, f) c(f) + +#define REGS(f) \ + f( 1) f( 3) f( 4) f( 5) f( 6) f( 7) f( 8) f( 9) \ +f(10) f(11) f(12) f(13) f(14) f(15) f(16) f(17) f(18) f(19) \ +f(20) f(21) f(22) f(23) f(24) f(25) f(26) f(27) f(28) f(29) \ +f(30) f(31) + +#define PUSH(n) sd concat(x, n), (n * 8)(sp); +#define POP(n) ld concat(x, n), (n * 8)(sp); + +#define CONTEXT_SIZE ((32 + 3) * 8) +#define OFFSET_SP ( 2 * 8) +#define OFFSET_CAUSE (32 * 8) +#define OFFSET_STATUS (33 * 8) +#define OFFSET_EPC (34 * 8) + +.globl __am_asm_trap +__am_asm_trap: + addi sp, sp, -CONTEXT_SIZE + + MAP(REGS, PUSH) + + mv t0, sp + addi t0, t0, CONTEXT_SIZE + sd t0, OFFSET_SP(sp) + + csrr t0, mcause + csrr t1, mstatus + csrr t2, mepc + + sd t0, OFFSET_CAUSE(sp) + sd t1, OFFSET_STATUS(sp) + sd t2, OFFSET_EPC(sp) + + mv a0, sp + jal __am_irq_handle + + ld t1, OFFSET_STATUS(sp) + ld t2, OFFSET_EPC(sp) + csrw mstatus, t1 + csrw mepc, t2 + + MAP(REGS, POP) + + addi sp, sp, CONTEXT_SIZE + + mret diff --git a/am/src/mycpu/trm.c b/am/src/mycpu/trm.c new file mode 100644 index 0000000..0efe6e7 --- /dev/null +++ b/am/src/mycpu/trm.c @@ -0,0 +1,27 @@ +#include +#include + +extern char _heap_start; +int main(const char *args); + +extern char _pmem_start; +#define PMEM_SIZE (128 * 1024 * 1024) +#define PMEM_END ((uintptr_t)&_pmem_start + PMEM_SIZE) + +Area heap = RANGE(&_heap_start, PMEM_END); +#ifndef MAINARGS +#define MAINARGS "" +#endif +static const char mainargs[] = MAINARGS; + +void putch(char ch) { +} + +void halt(int code) { + while (1); +} + +void _trm_init() { + int ret = main(mainargs); + halt(ret); +} diff --git a/am/src/mycpu/vme.c b/am/src/mycpu/vme.c new file mode 100644 index 0000000..5134154 --- /dev/null +++ b/am/src/mycpu/vme.c @@ -0,0 +1,18 @@ +#include + +bool vme_init(void* (*pgalloc_f)(int), void (*pgfree_f)(void*)) { + return false; +} + +void protect(AddrSpace *as) { +} + +void unprotect(AddrSpace *as) { +} + +void map(AddrSpace *as, void *va, void *pa, int prot) { +} + +Context *ucontext(AddrSpace *as, Area kstack, void *entry) { + return NULL; +} diff --git a/klib/src/int64.c b/klib/src/int64.c index b3b2876..51401f8 100644 --- a/klib/src/int64.c +++ b/klib/src/int64.c @@ -705,3 +705,25 @@ COMPILER_RT_ABI si_int __ctzsi2(si_int a) { // } return r + ((2 - (x >> 1)) & -((x & 1) == 0)); } + +typedef int si_int; +typedef long long di_int; +typedef unsigned su_int; +#define CHAR_BIT __CHAR_BIT__ + + +si_int __ctzdi2(di_int a) { + dwords x; + x.all = a; + const si_int f = -(x.s.low == 0); + return __ctzsi2((x.s.high & f) | (x.s.low & ~f)) + + (f & ((si_int)(sizeof(si_int) * CHAR_BIT))); +} + +si_int __clzdi2(di_int a) { + dwords x; + x.all = a; + const si_int f = -(x.s.high == 0); + return __clzsi2((x.s.high & ~f) | (x.s.low & f)) + + (f & ((si_int)(sizeof(si_int) * CHAR_BIT))); +} diff --git a/scripts/riscv64-mycpu.mk b/scripts/riscv64-mycpu.mk new file mode 100644 index 0000000..92a553f --- /dev/null +++ b/scripts/riscv64-mycpu.mk @@ -0,0 +1,28 @@ +CROSS_COMPILE := riscv64-linux-gnu- +COMMON_FLAGS := -fno-pic -march=rv64ifd -mcmodel=medany +CFLAGS += $(COMMON_FLAGS) -static +ASFLAGS += $(COMMON_FLAGS) -O0 +LDFLAGS += -melf64lriscv + +AM_SRCS := mycpu/start.S \ + mycpu/trm.c \ + mycpu/libgcc/muldi3.S \ + mycpu/libgcc/div.S \ + mycpu/ioe.c \ + mycpu/timer.c \ + mycpu/input.c \ + mycpu/cte.c \ + mycpu/trap.S \ + mycpu/vme.c \ + mycpu/mpe.c + +CFLAGS += -fdata-sections -ffunction-sections +LDFLAGS += -T $(AM_HOME)/scripts/platform/nemu.ld --defsym=_pmem_start=0x80000000 --defsym=_entry_offset=0x0 +LDFLAGS += --gc-sections -e _start +CFLAGS += -DMAINARGS=\"$(mainargs)\" +.PHONY: $(AM_HOME)/am/src/mycpu/trm.c + +image: $(IMAGE).elf + @$(OBJDUMP) -d $(IMAGE).elf > $(IMAGE).txt + @echo + OBJCOPY "->" $(IMAGE_REL).bin + @$(OBJCOPY) -S --set-section-flags .bss=alloc,contents -O binary $(IMAGE).elf $(IMAGE).bin