rsnikhil / Learn_Bluespec_and_RISCV_Design

Textbook and full source codes to learn basics of RISC-V pipelined CPU design using the Bluespec Hardware Design Language(s)
MIT License
54 stars 7 forks source link

Startup code linking & FPGA synthesis #2

Open sang-jun-kim opened 4 months ago

sang-jun-kim commented 4 months ago

Hello, thank you for your great tutorial and examples of RISC-V CPU implementation using bluespec language.

I am currently trying to run some tests with Fife pipelined CPU however, it seems there is only two tests that I can run for now (hello world, rv32ui add).

According to your description in Build_and_Run_Guide it seems that you have linked a "startup code" to generate test programs from source code. I would like to ask what kind of startup code you have used or would there be a way for me to make my own version of startup code to make more test programs?

Also, it seems the hello world source code uses stdio.h library which to me seems impossible to run on verilator environment since the implemented RISCV CPU won't run actual kernels with C libraries. Would it be related to the startup code that was used?

Finally, I am very interested in FPGA synthesis using AWS EC2 F1 instance. I would like to as when the documentation for running on FPGA would be possible.

Thank you very much for your time

rsnikhil commented 4 months ago

I am currently trying to run some tests with Fife pipelined CPU however, it seems there is only two tests that I can run for now (hello world, rv32ui add).

Yes, those are the only two tests I have provided in the repository.

According to your description in Build_and_Run_Guide it seems that you have linked a "startup code" to generate test programs from source code. I would like to ask what kind of startup code you have used or would there be a way for me to make my own version of startup code to make more test programs?

Yes.

The file: Code/Tools/Hello_World_Example_Code/hello.RV32.bare.objdump is a disassembly of the "Hello World!" ELF file.

In that file, in addtion to the code for the Hello World routine itself (label 'main' at PC address 80002190), there is a lot of other code, corresponding to the "startup" code and emulation of routines in stdio, stdlib etc.

Also, it seems the hello world source code uses stdio.h library which to me seems impossible to run on verilator environment since the implemented RISCV CPU won't run actual kernels with C libraries. Would it be related to the startup code that was used?

I run these on Verilator all the time. The RISC-C CPU will run actual kernels with C libraries, except that these are not the usual C libraries one uses under Linux. Instead, they implement the C library calls with alternate code that runs on bare-metal hardware. Specifically, the 'printf()' routing used by Hello World ultimately writes characters to a particular set of memory addresses representing a UART (serial character I/O). This is all the extra code you see in the obj dump disassembly of Hello World.

In Fife/Drum, the shared testbench (in src_Top/ directory) implements a memory model and a UART model (using imported C code). When Fife or Drum writes to the UART, the characters are routed to this UART model, which then prints them on the terminal.

I will try to put together some notes/examples so you can reproduce the ELF builds, and also build ELFs for other C and ASM programs. It's not difficult; I just need to organize it and document it a bit.

Finally, I am very interested in FPGA synthesis using AWS EC2 F1 instance. I would like to as when the documentation for running on FPGA would be possible.

I have all the components in place (and have it running for some predecessors of Drum and Fife), but need to do some system integration to bring in Fife and Drum. I hope to get to this some time in August.

grahamrow commented 3 weeks ago

Greetings, I've been having lots of fun playing with the Drum core and ran into a similar roadblock. I've been using a custom preamble and linker script to try to get this working and can get the code to run but not to exit properly. After returning from main in the c program below the simulation starts looking off into the void:

ERROR: c_mem_req(): wild address for CLIENT_IMEM
    Mem request I_36 LOAD 4B addr:00000000
ERROR: c_mem_req(): wild address for CLIENT_IMEM
    Mem request I_37 LOAD 4B addr:00000000
ERROR: c_mem_req(): wild address for CLIENT_IMEM
    Mem request I_38 LOAD 4B addr:00000000
etc. etc. etc. 

Right now I'm compiling with riscv64-unknown-elf-gcc -march=rv32i -mabi=ilp32 -nostdlib -nodefaultlibs -O0 -Wl,--gc-sections -Wl,-T,riscv32i.ld crt0.s example.c -o example to produce an executable. For crt0.s i have

.section .init, "ax"
.globl _start
_start:
    .cfi_startproc
    .cfi_undefined ra
    .option push
    .option norelax
    la  gp, __global_pointer$
    .option pop
    la sp, __stack_top
    add s0, sp, zero
    jal zero, main
    .cfi_endproc
    .end

for example.c something like

int doubler(int a) {
    return a+a;
}
int main() {
    int a = 4;
    int b = doubler(a) + a;
    return 0;
}

for riscv32i.ld I have

...
MEMORY
{
  RAM (rwx) : ORIGIN = 0x80000000, LENGTH = 0x10000000
}
...
ENTRY(_start)
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x0000)); . = SEGMENT_START("text-segment", 0x0000) + SIZEOF_HEADERS;
PROVIDE(__stack_top = ORIGIN(RAM) + LENGTH(RAM) );
...

Looking at some of the examples from riscv-tests like rv32ui-p-add it looks like I'm probably missing some setup and teardown, e.g. TEST_PASS runs:

80000670 <pass>:
80000670:   0ff0000f            fence
80000674:   00100193            li  gp,1
80000678:   05d00893            li  a7,93
8000067c:   00000513            li  a0,0
80000680:   00000073            ecall
80000684:   c0001073            unimp

at the end, while some setup I'm not grokking seems to happen in the section that gets jumped to immediate from the _start entry point. In all it would indeed be very helpful to have a better idea of how to compile for execution on Drum/Fife. Thanks again for the repos, they are a terrific resource!