chipsalliance / VeeRwolf

FuseSoC-based SoC for VeeR EH1 and EL2
268 stars 61 forks source link

Which are the steps to run baremetal c routines? #48

Closed kuoyaoming93 closed 2 years ago

kuoyaoming93 commented 2 years ago

Hi all,

I am trying to run baremetal C programs with SweRVolf running on Nexys A7. I don't use Zephyr OS because I would like to do some specific experiments.

At first, I made blinky.c based on blinky.S in this repo. However, I have some issues to run the code. There are three files: crt.s, blinky.c, link.ld

crt.s

.section .text.init
.global _start
_start:

        #li t0, 0x59555555
        #csrw 0x7c0, t0

        la sp, STACK

        call main

blinky.c

#include <stdint.h>

#define GPIO_BASE 0x80001010

volatile uint32_t* const port_led     = (uint32_t*) GPIO_BASE;

void main()
{
    uint32_t i=0;

    while(1){
        *port_led |= (1<<3);   // led-on
        for(i=0;i<100000;i++);
        *port_led &= ~(1<<3);  // led-off
        for(i=0;i<100000;i++);
    }
}

link.ld

OUTPUT_ARCH( "riscv" )
ENTRY(_start)

SECTIONS {
    . = 0;
  .text   : { *(.text*) }
  .data  :  { *(.*data) STACK = ALIGN(16) + 0x2000;}
  .bss : { *(.bss) }
}

To compile and generate the .elf file:

riscv64-unknown-elf-gcc -S -nostartfiles -nostdlib -march=rv32im -mabi=ilp32 -O3 -fomit-frame-pointer -fPIC -no-pie -Tlink.ld blink.c -o blink.s -lc

riscv64-unknown-elf-gcc -nostartfiles -nostdlib -march=rv32im -mabi=ilp32 -O3 -fomit-frame-pointer -fPIC -no-pie -Tlink.ld -oblinky.elf blink.s crt0.s -lc

I am able to turn on the leds, but when I try to do the "blinky" with the for loop, the led has a strange behaviour and doesn't blink as expected. The intensity of the led is very low in comparison with the blinky.S example.

On the other hand, I don't know if the STACK is well defined in linkerscript and crt0.s. These files are based on the files in SweRV-EL2 repo. For example, the following code:

#include <stdint.h>

#define GPIO_BASE   0x80001010
#define SWITCH_BASE 0x80001012

volatile uint32_t* const port_led     = (uint32_t*) GPIO_BASE;
volatile uint32_t* const port_sw      = (uint32_t*) SWITCH_BASE;

void delay()
{
    uint32_t i=0;
    for(i=0;i<100000;i++);
}

void main()
{
    int i=0;
    while(1){

        *port_led |= (1);   // led-on
        delay();
        *port_led &= ~(1);  // led-off
        delay();
    }
}

If the delay is defined in another function, the task doesn't work. Definitely I have something wrong in the stack definition.

If there is an example with every step that I should follow is highly appreciated. I would like to run benchmaks in C (baremetal) using this SoC, because I already have tests running on the SweRV-EL2 core running on Verilator and I would like to adapt it.

Thanks in advance, Yao-Ming

kuoyaoming93 commented 2 years ago

I made a objdump of the .elf

00000000 <main>:
   0:   fe010113            addi    sp,sp,-32
   4:   00112e23            sw  ra,28(sp)
   8:   00012623            sw  zero,12(sp)
   c:   800017b7            lui a5,0x80001
  10:   01078793            addi    a5,a5,16 # 80001010 <STACK+0x7fffef70>
  14:   0007a703            lw  a4,0(a5)
  18:   800017b7            lui a5,0x80001
  1c:   01078793            addi    a5,a5,16 # 80001010 <STACK+0x7fffef70>
  20:   00176713            ori a4,a4,1
  24:   00e7a023            sw  a4,0(a5)
  28:   028000ef            jal ra,50 <delay>
  2c:   800017b7            lui a5,0x80001
  30:   01078793            addi    a5,a5,16 # 80001010 <STACK+0x7fffef70>
  34:   0007a703            lw  a4,0(a5)
  38:   800017b7            lui a5,0x80001
  3c:   01078793            addi    a5,a5,16 # 80001010 <STACK+0x7fffef70>
  40:   ffe77713            andi    a4,a4,-2
  44:   00e7a023            sw  a4,0(a5)
  48:   008000ef            jal ra,50 <delay>
  4c:   fc1ff06f            j   c <main+0xc>

00000050 <delay>:
  50:   ff010113            addi    sp,sp,-16
  54:   00012623            sw  zero,12(sp)
  58:   00012623            sw  zero,12(sp)
  5c:   0100006f            j   6c <delay+0x1c>
  60:   00c12783            lw  a5,12(sp)
  64:   00178793            addi    a5,a5,1
  68:   00f12623            sw  a5,12(sp)
  6c:   00c12703            lw  a4,12(sp)
  70:   000187b7            lui a5,0x18
  74:   69f78793            addi    a5,a5,1695 # 1869f <STACK+0x165ff>
  78:   fee7f4e3            bgeu    a5,a4,60 <delay+0x10>
  7c:   00000013            nop
  80:   01010113            addi    sp,sp,16
  84:   00008067            ret

00000088 <_start>:
  88:   00000117            auipc   sp,0x0
  8c:   01812103            lw  sp,24(sp) # a0 <_GLOBAL_OFFSET_TABLE_+0x4>
  90:   f71ff0ef            jal ra,0 <main>

And noticed that 0x88 is the start of the program, and not 0x00. I was running from 0x00 using telnet... Only changed the compile order (crt0.s first), and solved the problem.

Finally, I think the stack pointer is well configured because I can make function calls.