am: add riscv64-rocket
This commit is contained in:
parent
b458a3ad58
commit
73596f368c
|
@ -7,6 +7,10 @@ ifeq ($(ISA), mips32)
|
|||
CROSS_COMPILE = mips-linux-gnu-
|
||||
endif
|
||||
|
||||
ifeq ($(ISA), riscv64)
|
||||
CROSS_COMPILE = riscv64-unknown-linux-gnu-
|
||||
endif
|
||||
|
||||
AS = $(CROSS_COMPILE)gcc
|
||||
CC = $(CROSS_COMPILE)gcc
|
||||
CXX = $(CROSS_COMPILE)g++
|
||||
|
@ -28,6 +32,12 @@ CXXFLAGS += $(CFLAGS_COMMON) -ffreestanding -fno-rtti -fno-exceptions
|
|||
ASFLAGS += -march=mips32 -EL -mno-check-zero-division -O0 -mno-abicalls -fno-pic -fno-delayed-branch
|
||||
endif
|
||||
|
||||
ifeq ($(ISA), riscv64)
|
||||
CFLAGS_COMMON = -fno-pic -static -mcmodel=medany -fno-delete-null-pointer-checks -mabi=lp64 -march=rv64imac
|
||||
CFLAGS += $(CFLAGS_COMMON)
|
||||
CXXFLAGS += $(CFLAGS_COMMON) -ffreestanding -fno-rtti -fno-exceptions
|
||||
endif
|
||||
|
||||
ifeq ($(ISA), x86)
|
||||
CFLAGS += -m32 -fno-pic -fno-builtin -fno-stack-protector -fno-omit-frame-pointer -march=i386
|
||||
CXXFLAGS += -m32 -fno-pic -fno-builtin -fno-stack-protector -fno-omit-frame-pointer -march=i386 -ffreestanding -fno-rtti -fno-exceptions
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
# RISCV64-rocket
|
|
@ -0,0 +1,4 @@
|
|||
start.o: start.S
|
||||
riscv64-unknown-linux-gnu-gcc -mabi=lp64 -march=rv64imac -I$(AM_HOME)/am/arch/riscv64-rocket/include -fno-pic -ffunction-sections -MMD -c start.S -o start.o
|
||||
|
||||
-include start.d
|
|
@ -0,0 +1,15 @@
|
|||
.section entry, "ax"
|
||||
.globl _start
|
||||
.type _start, @function
|
||||
|
||||
.extern fdt
|
||||
|
||||
_start:
|
||||
la sp, stack_end
|
||||
la t0, fdt
|
||||
sw x11, (t0)
|
||||
tail _trm_init
|
||||
|
||||
stack:
|
||||
.skip 0x4000
|
||||
stack_end:
|
|
@ -0,0 +1,10 @@
|
|||
#!/bin/bash
|
||||
|
||||
DIR=${AM_HOME}/am/arch/riscv64-rocket/img
|
||||
DEST=$1
|
||||
shift
|
||||
|
||||
bash -c "cd $DIR/boot && make"
|
||||
|
||||
riscv64-unknown-linux-gnu-ld --gc-sections -T $DIR/loader.ld -e _start -o $DEST $DIR/boot/start.o --start-group $@ --end-group
|
||||
riscv64-unknown-linux-gnu-objdump -d $DEST > $DEST.txt
|
|
@ -0,0 +1,22 @@
|
|||
SECTIONS {
|
||||
. = 0x80000000;
|
||||
entry : { *(entry) }
|
||||
.text : {
|
||||
*(.text*)
|
||||
}
|
||||
.rodata : {
|
||||
*(.rodata*)
|
||||
}
|
||||
etext = .;
|
||||
_etext = .;
|
||||
.data : {
|
||||
*(.data*)
|
||||
}
|
||||
edata = .;
|
||||
_edata = .;
|
||||
.bss : {
|
||||
*(.bss*)
|
||||
}
|
||||
end = .;
|
||||
_end = .;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
|
||||
echo "Run with rocketchip project"
|
|
@ -0,0 +1,14 @@
|
|||
#ifndef __ARCH_H__
|
||||
#define __ARCH_H__
|
||||
|
||||
struct _RegSet {
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef __RISCV64_ROCKET__
|
||||
#define __RISCV64_ROCKET__
|
||||
|
||||
#define MAX_HARTS 2
|
||||
|
||||
#endif
|
|
@ -0,0 +1,123 @@
|
|||
#include <klib.h>
|
||||
#include "fdt.h"
|
||||
#include "riscv64-rocket.h"
|
||||
|
||||
static inline uint32_t bswap(uint32_t x)
|
||||
{
|
||||
uint32_t y = (x & 0x00FF00FF) << 8 | (x & 0xFF00FF00) >> 8;
|
||||
uint32_t z = (y & 0x0000FFFF) << 16 | (y & 0xFFFF0000) >> 16;
|
||||
return z;
|
||||
}
|
||||
|
||||
static uint32_t *fdt_scan_helper(
|
||||
uint32_t *lex,
|
||||
const char *strings,
|
||||
struct fdt_scan_node *node,
|
||||
const struct fdt_cb *cb)
|
||||
{
|
||||
struct fdt_scan_node child;
|
||||
struct fdt_scan_prop prop;
|
||||
int last = 0;
|
||||
|
||||
child.parent = node;
|
||||
// these are the default cell counts, as per the FDT spec
|
||||
child.address_cells = 2;
|
||||
child.size_cells = 1;
|
||||
prop.node = node;
|
||||
|
||||
while (1) {
|
||||
switch (bswap(lex[0])) {
|
||||
case FDT_NOP: {
|
||||
lex += 1;
|
||||
break;
|
||||
}
|
||||
case FDT_PROP: {
|
||||
assert (!last);
|
||||
prop.name = strings + bswap(lex[2]);
|
||||
prop.len = bswap(lex[1]);
|
||||
prop.value = lex + 3;
|
||||
if (node && !strcmp(prop.name, "#address-cells")) { node->address_cells = bswap(lex[3]); }
|
||||
if (node && !strcmp(prop.name, "#size-cells")) { node->size_cells = bswap(lex[3]); }
|
||||
lex += 3 + (prop.len+3)/4;
|
||||
cb->prop(&prop, cb->extra);
|
||||
break;
|
||||
}
|
||||
case FDT_BEGIN_NODE: {
|
||||
uint32_t *lex_next;
|
||||
if (!last && node && cb->done) cb->done(node, cb->extra);
|
||||
last = 1;
|
||||
child.name = (const char *)(lex+1);
|
||||
if (cb->open) cb->open(&child, cb->extra);
|
||||
lex_next = fdt_scan_helper(
|
||||
lex + 2 + strlen(child.name)/4,
|
||||
strings, &child, cb);
|
||||
if (cb->close && cb->close(&child, cb->extra) == -1)
|
||||
while (lex != lex_next) *lex++ = bswap(FDT_NOP);
|
||||
lex = lex_next;
|
||||
break;
|
||||
}
|
||||
case FDT_END_NODE: {
|
||||
if (!last && node && cb->done) cb->done(node, cb->extra);
|
||||
return lex + 1;
|
||||
}
|
||||
default: { // FDT_END
|
||||
if (!last && node && cb->done) cb->done(node, cb->extra);
|
||||
return lex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fdt_scan(uintptr_t fdt, const struct fdt_cb *cb)
|
||||
{
|
||||
struct fdt_header *header = (struct fdt_header *)fdt;
|
||||
|
||||
// Only process FDT that we understand
|
||||
if (bswap(header->magic) != FDT_MAGIC ||
|
||||
bswap(header->last_comp_version) > FDT_VERSION) return;
|
||||
|
||||
const char *strings = (const char *)(fdt + bswap(header->off_dt_strings));
|
||||
uint32_t *lex = (uint32_t *)(fdt + bswap(header->off_dt_struct));
|
||||
|
||||
fdt_scan_helper(lex, strings, 0, cb);
|
||||
}
|
||||
|
||||
uint32_t fdt_size(uintptr_t fdt)
|
||||
{
|
||||
struct fdt_header *header = (struct fdt_header *)fdt;
|
||||
|
||||
// Only process FDT that we understand
|
||||
if (bswap(header->magic) != FDT_MAGIC ||
|
||||
bswap(header->last_comp_version) > FDT_VERSION) return 0;
|
||||
return bswap(header->totalsize);
|
||||
}
|
||||
|
||||
const uint32_t *fdt_get_address(const struct fdt_scan_node *node, const uint32_t *value, uint64_t *result)
|
||||
{
|
||||
*result = 0;
|
||||
for (int cells = node->address_cells; cells > 0; --cells)
|
||||
*result = (*result << 32) + bswap(*value++);
|
||||
return value;
|
||||
}
|
||||
|
||||
const uint32_t *fdt_get_size(const struct fdt_scan_node *node, const uint32_t *value, uint64_t *result)
|
||||
{
|
||||
*result = 0;
|
||||
for (int cells = node->size_cells; cells > 0; --cells)
|
||||
*result = (*result << 32) + bswap(*value++);
|
||||
return value;
|
||||
}
|
||||
|
||||
int fdt_string_list_index(const struct fdt_scan_prop *prop, const char *str)
|
||||
{
|
||||
const char *list = (const char *)prop->value;
|
||||
const char *end = list + prop->len;
|
||||
int index = 0;
|
||||
while (end - list > 0) {
|
||||
if (!strcmp(list, str)) return index;
|
||||
++index;
|
||||
list += strlen(list) + 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
#ifndef FDT_H
|
||||
#define FDT_H
|
||||
|
||||
#define FDT_MAGIC 0xd00dfeed
|
||||
#define FDT_VERSION 17
|
||||
|
||||
struct fdt_header {
|
||||
uint32_t magic;
|
||||
uint32_t totalsize;
|
||||
uint32_t off_dt_struct;
|
||||
uint32_t off_dt_strings;
|
||||
uint32_t off_mem_rsvmap;
|
||||
uint32_t version;
|
||||
uint32_t last_comp_version; /* <= 17 */
|
||||
uint32_t boot_cpuid_phys;
|
||||
uint32_t size_dt_strings;
|
||||
uint32_t size_dt_struct;
|
||||
};
|
||||
|
||||
#define FDT_BEGIN_NODE 1
|
||||
#define FDT_END_NODE 2
|
||||
#define FDT_PROP 3
|
||||
#define FDT_NOP 4
|
||||
#define FDT_END 9
|
||||
|
||||
struct fdt_scan_node {
|
||||
const struct fdt_scan_node *parent;
|
||||
const char *name;
|
||||
int address_cells;
|
||||
int size_cells;
|
||||
};
|
||||
|
||||
struct fdt_scan_prop {
|
||||
const struct fdt_scan_node *node;
|
||||
const char *name;
|
||||
uint32_t *value;
|
||||
int len; // in bytes of value
|
||||
};
|
||||
|
||||
struct fdt_cb {
|
||||
void (*open)(const struct fdt_scan_node *node, void *extra);
|
||||
void (*prop)(const struct fdt_scan_prop *prop, void *extra);
|
||||
void (*done)(const struct fdt_scan_node *node, void *extra); // last property was seen
|
||||
int (*close)(const struct fdt_scan_node *node, void *extra); // -1 => delete the node + children
|
||||
void *extra;
|
||||
};
|
||||
|
||||
// Scan the contents of FDT
|
||||
void fdt_scan(uintptr_t fdt, const struct fdt_cb *cb);
|
||||
uint32_t fdt_size(uintptr_t fdt);
|
||||
|
||||
// Extract fields
|
||||
const uint32_t *fdt_get_address(const struct fdt_scan_node *node, const uint32_t *base, uint64_t *value);
|
||||
const uint32_t *fdt_get_size(const struct fdt_scan_node *node, const uint32_t *base, uint64_t *value);
|
||||
int fdt_string_list_index(const struct fdt_scan_prop *prop, const char *str); // -1 if not found
|
||||
|
||||
// Setup memory+clint+plic
|
||||
void query_mem(uintptr_t fdt);
|
||||
void query_harts(uintptr_t fdt);
|
||||
void query_plic(uintptr_t fdt);
|
||||
void query_clint(uintptr_t fdt);
|
||||
|
||||
// Remove information from FDT
|
||||
void filter_harts(uintptr_t fdt, unsigned long hart_mask);
|
||||
void filter_plic(uintptr_t fdt);
|
||||
void filter_compat(uintptr_t fdt, const char *compat);
|
||||
|
||||
// The hartids of available harts
|
||||
extern uint64_t hart_mask;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,36 @@
|
|||
#include <am.h>
|
||||
|
||||
void _ioe_init() {
|
||||
}
|
||||
|
||||
// -------------------- cycles and uptime --------------------
|
||||
|
||||
static unsigned long riscv64_time = 0;
|
||||
|
||||
unsigned long _uptime(){
|
||||
return riscv64_time ++;
|
||||
}
|
||||
|
||||
// -------------------- video --------------------
|
||||
|
||||
|
||||
_Screen _screen = {
|
||||
.width = 0,
|
||||
.height = 0,
|
||||
};
|
||||
|
||||
void _draw_p(int x, int y, uint32_t p) {
|
||||
}
|
||||
|
||||
void _draw_sync() {
|
||||
}
|
||||
|
||||
// -------------------- keyboard --------------------
|
||||
|
||||
static inline int upevent(int e) { return e; }
|
||||
static inline int downevent(int e) { return e | 0x8000; }
|
||||
|
||||
int _read_key(){
|
||||
return _KEY_NONE;
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
#include <am.h>
|
||||
#include <klib.h>
|
||||
#include "fdt.h"
|
||||
|
||||
uintptr_t fdt = 0;
|
||||
static uintptr_t mem_size = 0;
|
||||
|
||||
extern char _end;
|
||||
extern int main();
|
||||
extern void uart_init(uintptr_t fdt);
|
||||
extern void uart_send(uint8_t data);
|
||||
|
||||
_Area _heap = {
|
||||
.start = &_end,
|
||||
};
|
||||
|
||||
//////////////////////////////////////////// MEMORY SCAN /////////////////////////////////////////
|
||||
|
||||
struct mem_scan {
|
||||
int memory;
|
||||
const uint32_t *reg_value;
|
||||
int reg_len;
|
||||
};
|
||||
|
||||
static void mem_open(const struct fdt_scan_node *node, void *extra)
|
||||
{
|
||||
struct mem_scan *scan = (struct mem_scan *)extra;
|
||||
memset(scan, 0, sizeof(*scan));
|
||||
}
|
||||
|
||||
static void mem_prop(const struct fdt_scan_prop *prop, void *extra)
|
||||
{
|
||||
struct mem_scan *scan = (struct mem_scan *)extra;
|
||||
if (!strcmp(prop->name, "device_type") && !strcmp((const char*)prop->value, "memory")) {
|
||||
scan->memory = 1;
|
||||
} else if (!strcmp(prop->name, "reg")) {
|
||||
scan->reg_value = prop->value;
|
||||
scan->reg_len = prop->len;
|
||||
}
|
||||
}
|
||||
|
||||
static void mem_done(const struct fdt_scan_node *node, void *extra)
|
||||
{
|
||||
struct mem_scan *scan = (struct mem_scan *)extra;
|
||||
const uint32_t *value = scan->reg_value;
|
||||
const uint32_t *end = value + scan->reg_len/4;
|
||||
uintptr_t self = (uintptr_t)mem_done;
|
||||
|
||||
if (!scan->memory) return;
|
||||
assert (scan->reg_value && scan->reg_len % 4 == 0);
|
||||
|
||||
while (end - value > 0) {
|
||||
uint64_t base, size;
|
||||
value = fdt_get_address(node->parent, value, &base);
|
||||
value = fdt_get_size (node->parent, value, &size);
|
||||
if (base <= self && self <= base + size) { mem_size = size; }
|
||||
}
|
||||
assert (end == value);
|
||||
}
|
||||
|
||||
void query_mem(uintptr_t fdt)
|
||||
{
|
||||
struct fdt_cb cb;
|
||||
struct mem_scan scan;
|
||||
|
||||
memset(&cb, 0, sizeof(cb));
|
||||
cb.open = mem_open;
|
||||
cb.prop = mem_prop;
|
||||
cb.done = mem_done;
|
||||
cb.extra = &scan;
|
||||
|
||||
mem_size = 0;
|
||||
fdt_scan(fdt, &cb);
|
||||
assert (mem_size > 0);
|
||||
}
|
||||
|
||||
void _putc(char ch) {
|
||||
uart_send(ch);
|
||||
}
|
||||
|
||||
static void puts(const char *s) {
|
||||
for (const char *p = s; *p; p ++) {
|
||||
_putc(*p);
|
||||
}
|
||||
}
|
||||
|
||||
void _halt(int code) {
|
||||
puts("Exited (");
|
||||
if (code == 0) _putc('0');
|
||||
else {
|
||||
char buf[10], *p = buf + 9;
|
||||
for (*p = 0; code; code /= 10) {
|
||||
*(-- p) = '0' + code % 10;
|
||||
}
|
||||
puts(p);
|
||||
}
|
||||
puts(").\n");
|
||||
|
||||
while (1);
|
||||
}
|
||||
|
||||
void _trm_init() {
|
||||
uart_init(fdt);
|
||||
|
||||
query_mem(fdt);
|
||||
_heap.end = (void *)0x80000000 + mem_size;
|
||||
|
||||
int ret = main();
|
||||
_halt(ret);
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
#include <klib.h>
|
||||
#include "fdt.h"
|
||||
|
||||
volatile uint8_t* uart_base_ptr;
|
||||
|
||||
#define UART_RX_FIFO_REG 0
|
||||
#define UART_TX_FIFO_REG 0x4
|
||||
#define UART_STAT_REG 0x8
|
||||
#define UART_CTRL_REG 0xc
|
||||
|
||||
void uart_send(uint8_t data) {
|
||||
// wait until THR empty
|
||||
while((*(uart_base_ptr + UART_STAT_REG) & 0x08));
|
||||
*(uart_base_ptr + UART_TX_FIFO_REG) = data;
|
||||
}
|
||||
|
||||
void uart_send_string(const char *str) {
|
||||
while(*str != 0) {
|
||||
uart_send(*(str++));
|
||||
}
|
||||
}
|
||||
|
||||
void uart_send_buf(const char *buf, const int32_t len) {
|
||||
int32_t i;
|
||||
for(i=0; i<len; i++) {
|
||||
uart_send(buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int uart_recv() {
|
||||
// check whether RBR has data
|
||||
if(! (*(uart_base_ptr + UART_STAT_REG) & 0x01u)) {
|
||||
return -1;
|
||||
}
|
||||
return *(uart_base_ptr + UART_RX_FIFO_REG);
|
||||
}
|
||||
|
||||
// IRQ triggered read
|
||||
uint8_t uart_read_irq() {
|
||||
return *(uart_base_ptr + UART_RX_FIFO_REG);
|
||||
}
|
||||
|
||||
// check uart IRQ for read
|
||||
uint8_t uart_check_read_irq() {
|
||||
return (*(uart_base_ptr + UART_STAT_REG) & 0x01u);
|
||||
}
|
||||
|
||||
// enable uart read IRQ
|
||||
void uart_enable_read_irq() {
|
||||
*(uart_base_ptr + UART_CTRL_REG) = 0x0010u;
|
||||
}
|
||||
|
||||
// disable uart read IRQ
|
||||
void uart_disable_read_irq() {
|
||||
*(uart_base_ptr + UART_CTRL_REG) = 0x0000u;
|
||||
}
|
||||
|
||||
struct uart_scan
|
||||
{
|
||||
int compat;
|
||||
uint64_t reg;
|
||||
};
|
||||
|
||||
static void uart_open(const struct fdt_scan_node *node, void *extra)
|
||||
{
|
||||
struct uart_scan *scan = (struct uart_scan *)extra;
|
||||
memset(scan, 0, sizeof(*scan));
|
||||
}
|
||||
|
||||
static void uart_prop(const struct fdt_scan_prop *prop, void *extra)
|
||||
{
|
||||
struct uart_scan *scan = (struct uart_scan *)extra;
|
||||
if (!strcmp(prop->name, "compatible") && !strcmp((const char*)prop->value, "sifive,uart0")) {
|
||||
scan->compat = 1;
|
||||
} else if (!strcmp(prop->name, "reg")) {
|
||||
fdt_get_address(prop->node->parent, prop->value, &scan->reg);
|
||||
}
|
||||
}
|
||||
|
||||
static void uart_done(const struct fdt_scan_node *node, void *extra)
|
||||
{
|
||||
struct uart_scan *scan = (struct uart_scan *)extra;
|
||||
if (!scan->compat || !scan->reg || uart_base_ptr) return;
|
||||
|
||||
// Enable Rx/Tx channels
|
||||
uart_base_ptr = (void*)scan->reg;
|
||||
}
|
||||
|
||||
void uart_init(uintptr_t fdt)
|
||||
{
|
||||
struct fdt_cb cb;
|
||||
struct uart_scan scan;
|
||||
|
||||
memset(&cb, 0, sizeof(cb));
|
||||
cb.open = uart_open;
|
||||
cb.prop = uart_prop;
|
||||
cb.done = uart_done;
|
||||
cb.extra = &scan;
|
||||
|
||||
fdt_scan(fdt, &cb);
|
||||
|
||||
if(!uart_base_ptr) {
|
||||
//uart_base_ptr = (void *)0x60000000;
|
||||
return;
|
||||
}
|
||||
/*
|
||||
|
||||
uart_base_ptr += read_const_csr(mhartid) * 0x10000;
|
||||
*/
|
||||
|
||||
// reset the receive FIFO and transmit FIFO
|
||||
*(uart_base_ptr + UART_CTRL_REG) = 0x3;
|
||||
}
|
Loading…
Reference in New Issue