bigmagic123 / d1-nezha-baremeta

riscv64 d1-nezha baremeta(Allwinner D1 riscv chip)
Apache License 2.0
74 stars 13 forks source link

A beginning of bare metal SDK? #3

Open taorye opened 2 years ago

taorye commented 2 years ago

About the source codes, I have tried to compile them and finally found that actually we do NOT need to include some header files like <stdio.h> <stdlib.h> on bare board. Also we can spend a little time to get the code easier to organize and reuse.I would like contribute if you could point me a direction.

bigmagic123 commented 2 years ago

Thanks for your advice,If you are interested in contributing code, You can refer to the link below:

https://github.com/bigmagic123/d1-nezha-baremeta/tree/main/src/d1_barematel_sdk

I want to do some separate routines for peripheral experiments on the development board. If you need SDK, you can add the successfully tested peripherals to the SDK, and finally you can make some demos

Using meson for project construction can be compiled on both Linux and window, which is convenient for development.

Looking forward to your suggestion for bare metal SDK!

taorye commented 2 years ago

The ddr was actually initialized after exec xfel ddr ddr2, furthermore the clk, gpio and uart0. So if we do nothing about configuration, we can also use them like uart0 below.

image

file main.c and link.ld are shown below:

typedef unsigned long uint64_t;
typedef unsigned int uint32_t;

typedef uint64_t virtual_addr_t;

static inline void write32(virtual_addr_t addr, uint32_t value) {
    *((volatile uint32_t *)(addr)) = value;
}

static inline uint32_t read32(virtual_addr_t addr) {
    return *((volatile uint32_t *)(addr));
}

static inline uint64_t counter(void)
{
    uint64_t cnt;
     __asm__ __volatile__("csrr %0, time\n" : "=r"(cnt) :: "memory");
    return cnt;
}

static inline void sdelay(unsigned long us)
{
    uint64_t t = counter() + us * 24;
    while(counter() <= t);
}

static void sys_uart_putc(char c)
{
    virtual_addr_t addr = 0x02500000;

    while((read32(addr + 0x7c) & (0x1 << 1)) == 0);
    write32(addr, c);
}

void _start(void)
{
    while(1){
        sys_uart_putc('h');
        sys_uart_putc('e');
        sys_uart_putc('l');
        sys_uart_putc('l');
        sys_uart_putc('o');
        sys_uart_putc('\r');
        sys_uart_putc('\n');
        sdelay(1000*1000);
    }
}
OUTPUT_FORMAT("elf64-littleriscv", "elf64-littleriscv", "elf64-littleriscv")
OUTPUT_ARCH(riscv)
ENTRY(_start)

STACK_SIZE = 0x100000;

MEMORY
{
    ram  : org = 0x40000000, len = 64M
}

SECTIONS
{
    .text :
    {
        PROVIDE(__image_start = .);
        PROVIDE(__text_start = .);
        main.o (.text*)
        *(.text*)
        PROVIDE(__text_end = .);
    } > ram

    .rodata ALIGN(8) :
    {
        PROVIDE(__rodata_start = .);
        *(.rodata*)
        *(.srodata*)
        PROVIDE(__rodata_end = .);
    } > ram

    .data ALIGN(8) :
    {
        PROVIDE(__data_start = .);
        PROVIDE(__global_pointer$ = . + 0x800);
        *(.sdata*)
        *(.data*)
        . = ALIGN(8);
        PROVIDE(__data_end = .);
        PROVIDE(__image_end = .);
    } > ram

    .bss ALIGN(8) (NOLOAD) :
    {
        PROVIDE(__bss_start = .);
        *(.bss*)
        *(.sbss*)
        . = ALIGN(8);
        PROVIDE(__bss_end = .);
    } > ram

    .stack ALIGN(16) (NOLOAD) :
    {
        PROVIDE(__stack_start = .);
        . += STACK_SIZE;
        . = ALIGN(16);
        PROVIDE(__stack_end = .);
    } > ram
}

I think these clocks and peripherals configured by xfel may cause interference and misunderstanding to the development program, because xfel does not reset them.

Is there a way for us to reset the board without losing the code data in the ddr after xfel write 0x40000000 image.bin, and then execute xfel exec 0x40000000 to simulate a normal reset boot.