add riscv32-nemu
This commit is contained in:
parent
c9544eab37
commit
0f0b9b9f42
|
@ -7,6 +7,10 @@ ifeq ($(ISA), mips32)
|
|||
CROSS_COMPILE = mips-linux-gnu-
|
||||
endif
|
||||
|
||||
ifeq ($(ISA), riscv32)
|
||||
CROSS_COMPILE = riscv-none-embed-
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM), navy)
|
||||
NAVY_LIBS = libndl libos libc
|
||||
INC_DIR += $(addsuffix /include/, $(addprefix $(NAVY_HOME)/libs/, $(NAVY_LIBS)))
|
||||
|
@ -45,6 +49,11 @@ CFLAGS_COMMON += -m32 -fno-pic -fno-omit-frame-pointer -march=i386 -mstringop-st
|
|||
ASFLAGS += -m32
|
||||
endif
|
||||
|
||||
ifeq ($(ISA), riscv32)
|
||||
CFLAGS_COMMON += -fno-pic -static -march=rv32im -mabi=ilp32
|
||||
ASFLAGS += -march=rv32im -mabi=ilp32 -O0 -fno-pic
|
||||
endif
|
||||
|
||||
ifeq ($(ISA), am_native)
|
||||
CFLAGS_COMMON += -fno-omit-frame-pointer -fno-reorder-functions
|
||||
endif
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
# RISCV32-NEMU
|
|
@ -0,0 +1,4 @@
|
|||
start.o: start.S
|
||||
riscv-none-embed-gcc -I$(AM_HOME)/am/arch/riscv32-nemu/include -march=rv32im -mabi=ilp32 -fno-pic -MMD -c start.S -o start.o
|
||||
|
||||
-include start.d
|
|
@ -0,0 +1,7 @@
|
|||
.globl _start
|
||||
.type _start, function
|
||||
|
||||
_start:
|
||||
mv s0, zero
|
||||
la sp, _stack_pointer
|
||||
jal _trm_init
|
|
@ -0,0 +1,13 @@
|
|||
#!/bin/bash
|
||||
|
||||
DIR=${AM_HOME}/am/arch/riscv32-nemu/img
|
||||
DEST=$1
|
||||
shift
|
||||
CROSS_COMPILE=riscv-none-embed-
|
||||
|
||||
make -C $DIR/boot -s
|
||||
|
||||
${CROSS_COMPILE}ld --gc-sections -melf32lriscv -T $DIR/loader.ld -e _start -o $DEST $DIR/boot/start.o --start-group $@ --end-group
|
||||
${CROSS_COMPILE}objdump -d $DEST > $DEST.txt
|
||||
|
||||
${CROSS_COMPILE}objcopy -S --set-section-flags .bss=alloc,contents -O binary $DEST $DEST.bin
|
|
@ -0,0 +1,29 @@
|
|||
SECTIONS {
|
||||
. = 0x80100000;
|
||||
.text : {
|
||||
*(.text)
|
||||
}
|
||||
etext = .;
|
||||
_etext = .;
|
||||
.rodata : {
|
||||
*(.rodata*)
|
||||
}
|
||||
.data : {
|
||||
*(.data)
|
||||
}
|
||||
edata = .;
|
||||
_data = .;
|
||||
.bss : {
|
||||
_bss_start = .;
|
||||
*(.bss*)
|
||||
*(.sbss*)
|
||||
*(.scommon)
|
||||
}
|
||||
_stack_top = ALIGN(4096);
|
||||
. = _stack_top + 0x8000;
|
||||
_stack_pointer = .;
|
||||
end = .;
|
||||
_end = .;
|
||||
_heap_start = ALIGN(4096);
|
||||
_heap_end = 0x88000000;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
|
||||
make -C $NEMU_HOME ISA=riscv32 run ARGS="-b -l `dirname $1`/nemu-log.txt $1.bin"
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef __ARCH_H__
|
||||
#define __ARCH_H__
|
||||
|
||||
#include <am.h>
|
||||
|
||||
#define PMEM_SIZE (128 * 1024 * 1024)
|
||||
#define PGSIZE 4096
|
||||
|
||||
struct _Context {
|
||||
struct _Protect *prot;
|
||||
uint32_t gpr[31];
|
||||
};
|
||||
|
||||
#define GPR1 //gpr[3]
|
||||
#define GPR2 //gpr[4]
|
||||
#define GPR3 //gpr[5]
|
||||
#define GPR4 //gpr[6]
|
||||
#define GPRx //gpr[1]
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,44 @@
|
|||
#ifndef __RISCV32_H__
|
||||
#define __RISCV32_H__
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#include <arch.h>
|
||||
|
||||
#define MMIO_OFFSET(addr) (addr)
|
||||
|
||||
static inline uint8_t inb(uintptr_t addr) { return *(volatile uint8_t *)MMIO_OFFSET(addr); }
|
||||
static inline uint16_t inw(uintptr_t addr) { return *(volatile uint16_t *)MMIO_OFFSET(addr); }
|
||||
static inline uint32_t inl(uintptr_t addr) { return *(volatile uint32_t *)MMIO_OFFSET(addr); }
|
||||
|
||||
static inline void outb(uintptr_t addr, uint8_t data) { *(volatile uint8_t *)MMIO_OFFSET(addr) = data; }
|
||||
static inline void outw(uintptr_t addr, uint16_t data) { *(volatile uint16_t *)MMIO_OFFSET(addr) = data; }
|
||||
static inline void outl(uintptr_t addr, uint32_t data) { *(volatile uint32_t *)MMIO_OFFSET(addr) = data; }
|
||||
|
||||
#define PTE_V 0x2
|
||||
#define PTE_D 0x4
|
||||
|
||||
// Page directory and page table constants
|
||||
#define NR_PDE 1024 // # directory entries per page directory
|
||||
#define NR_PTE 1024 // # PTEs per page table
|
||||
#define PGSHFT 12 // log2(PGSIZE)
|
||||
#define PTXSHFT 12 // Offset of PTX in a linear address
|
||||
#define PDXSHFT 22 // Offset of PDX in a linear address
|
||||
|
||||
// +--------10------+-------10-------+---------12----------+
|
||||
// | Page Directory | Page Table | Offset within Page |
|
||||
// | Index | Index | |
|
||||
// +----------------+----------------+---------------------+
|
||||
// \--- PDX(va) --/ \--- PTX(va) --/\------ OFF(va) ------/
|
||||
typedef uint32_t PTE;
|
||||
typedef uint32_t PDE;
|
||||
#define PDX(va) (((uint32_t)(va) >> PDXSHFT) & 0x3ff)
|
||||
#define PTX(va) (((uint32_t)(va) >> PTXSHFT) & 0x3ff)
|
||||
#define OFF(va) ((uint32_t)(va) & 0xfff)
|
||||
|
||||
// Address in page table or page directory entry
|
||||
#define PTE_ADDR(pte) ((uint32_t)(pte) & ~0xfff)
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,19 @@
|
|||
#include <am.h>
|
||||
#include <riscv32.h>
|
||||
#include <amdev.h>
|
||||
|
||||
#define KBD_DATA_MMIO 0x4060
|
||||
#define KEYDOWN_MASK 0x8000
|
||||
|
||||
size_t input_read(uintptr_t reg, void *buf, size_t size) {
|
||||
switch (reg) {
|
||||
case _DEVREG_INPUT_KBD: {
|
||||
_KbdReg *kbd = (_KbdReg *)buf;
|
||||
int k = inl(KBD_DATA_MMIO);
|
||||
kbd->keydown = (k & KEYDOWN_MASK ? 1 : 0);
|
||||
kbd->keycode = k & ~KEYDOWN_MASK;
|
||||
return sizeof(_KbdReg);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
#include <am.h>
|
||||
#include <riscv32.h>
|
||||
#include <amdev.h>
|
||||
|
||||
#define RTC_MMIO 0x4048 // Note that this is not standard
|
||||
static unsigned long boot_time;
|
||||
|
||||
size_t timer_read(uintptr_t reg, void *buf, size_t size) {
|
||||
switch (reg) {
|
||||
case _DEVREG_TIMER_UPTIME: {
|
||||
_UptimeReg *uptime = (_UptimeReg *)buf;
|
||||
uptime->hi = 0;
|
||||
uptime->lo = inl(RTC_MMIO) - boot_time;
|
||||
return sizeof(_UptimeReg);
|
||||
}
|
||||
case _DEVREG_TIMER_DATE: {
|
||||
_RTCReg *rtc = (_RTCReg *)buf;
|
||||
rtc->second = 0;
|
||||
rtc->minute = 0;
|
||||
rtc->hour = 0;
|
||||
rtc->day = 0;
|
||||
rtc->month = 0;
|
||||
rtc->year = 2018;
|
||||
return sizeof(_RTCReg);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void timer_init() {
|
||||
boot_time = inl(RTC_MMIO);
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
#include <am.h>
|
||||
#include <riscv32.h>
|
||||
#include <amdev.h>
|
||||
#include <klib.h>
|
||||
|
||||
#define SCREEN_MMIO 0x4100
|
||||
static int W, H;
|
||||
static uint32_t* const fb = (uint32_t *)MMIO_OFFSET(0x40000);
|
||||
|
||||
size_t video_read(uintptr_t reg, void *buf, size_t size) {
|
||||
switch (reg) {
|
||||
case _DEVREG_VIDEO_INFO: {
|
||||
_VideoInfoReg *info = (_VideoInfoReg *)buf;
|
||||
info->width = W;
|
||||
info->height = H;
|
||||
return sizeof(_VideoInfoReg);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t video_write(uintptr_t reg, void *buf, size_t size) {
|
||||
switch (reg) {
|
||||
case _DEVREG_VIDEO_FBCTL: {
|
||||
_FBCtlReg *ctl = (_FBCtlReg *)buf;
|
||||
int x = ctl->x, y = ctl->y, w = ctl->w, h = ctl->h;
|
||||
uint32_t *pixels = ctl->pixels;
|
||||
int len = sizeof(uint32_t) * ( (x + w >= W) ? W - x : w );
|
||||
uint32_t *p_fb = &fb[y * W + x];
|
||||
int j;
|
||||
|
||||
for (j = 0; j < h; j ++) {
|
||||
if (y + j < H) { memcpy(p_fb, pixels, len); }
|
||||
else { break; }
|
||||
p_fb += W;
|
||||
pixels += w;
|
||||
}
|
||||
|
||||
if (ctl->sync) {
|
||||
// do nothing, hardware syncs.
|
||||
}
|
||||
return size;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vga_init() {
|
||||
uint32_t data = inl(SCREEN_MMIO);
|
||||
W = data >> 16;
|
||||
H = data & 0xffff;
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
#include <am.h>
|
||||
#include <amdev.h>
|
||||
#include <klib.h>
|
||||
|
||||
static inline size_t no_read(uintptr_t reg, void *buf, size_t size) {
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline size_t no_write(uintptr_t reg, void *buf, size_t size) {
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vga_init();
|
||||
void timer_init();
|
||||
|
||||
int _ioe_init() {
|
||||
vga_init();
|
||||
timer_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t timer_read(uintptr_t reg, void *buf, size_t size);
|
||||
size_t video_read(uintptr_t reg, void *buf, size_t size);
|
||||
size_t video_write(uintptr_t reg, void *buf, size_t size);
|
||||
size_t input_read(uintptr_t reg, void *buf, size_t size);
|
||||
|
||||
|
||||
static _Device nemu_dev[] = {
|
||||
{_DEV_TIMER, "NEMU Timer", timer_read, no_write},
|
||||
{_DEV_INPUT, "NEMU Keyboard Controller", input_read, no_write},
|
||||
{_DEV_VIDEO, "NEMU VGA Controller", video_read, video_write},
|
||||
};
|
||||
|
||||
#define NR_DEV (sizeof(nemu_dev) / sizeof(nemu_dev[0]))
|
||||
|
||||
_Device *_device(int n) {
|
||||
n --;
|
||||
return (n >= 0 && (unsigned int)n < NR_DEV) ? &nemu_dev[n] : NULL;
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
#include <am.h>
|
||||
#include <riscv32.h>
|
||||
|
||||
// Define this macro after serial has been implemented
|
||||
#define HAS_SERIAL
|
||||
|
||||
#define SERIAL_PORT 0x43f8
|
||||
|
||||
extern char _heap_start;
|
||||
extern char _heap_end;
|
||||
extern int main();
|
||||
|
||||
_Area _heap = {
|
||||
.start = &_heap_start,
|
||||
.end = &_heap_end,
|
||||
};
|
||||
|
||||
void _putc(char ch) {
|
||||
#ifdef HAS_SERIAL
|
||||
outb(SERIAL_PORT, ch);
|
||||
#endif
|
||||
}
|
||||
|
||||
void _halt(int code) {
|
||||
__asm__ volatile("mv a0, %0; .word 0x0000006b" : :"r"(code));
|
||||
|
||||
// should not reach here
|
||||
while (1);
|
||||
}
|
||||
|
||||
void _trm_init() {
|
||||
int ret = main();
|
||||
_halt(ret);
|
||||
}
|
Loading…
Reference in New Issue