In this section, we demonstrate how to build memory images (base_address = 0x80000000
) for simulation.
- clone
nexus-am
from github:
git clone https://github.com/OpenXiangShan/nexus-am.git
cd nexus-am
export AM_HOME=`pwd` # set AM_HOME
- enter tests or benchmark directory (using
apps/coremark
as an example):
cd apps/coremark
make ARCH=riscv64-xs
ls ./build # you will see .bin, .txt, *,elf
- use the ".bin" file as the memory image for RTL simulation
Here we use the DiffTest RTL-simulation framework as an example. NEMU and other designs should work similarly if the base address is 0x8000_0000.
$NOOP_HOME/build/emu -i ./build/coremark-riscv64-xs.bin
Some designs have a read-only bootrom for bring-up.
This section builds the bootrom (flash) image whose base address is 0x1000_0000.
We will be using riscv64-xs-flash
instead of riscv64-xs
to fix into the new address space.
Do NOT follow the steps in this section if you don't know what the bootrom means.
- enter benchmark directory (using
apps/coremark
as an example):
cd /apps/coremark
make ARCH=riscv64-xs-flash
ls ./build
-
you will find a ".bin" file, this is a benchmark image for flash
-
to add the flash image to simulation in DiffTest, you can use the
-F
option:
$NOOP_HOME/build/emu -F ./build/coremark-riscv64-xs-flash.bin
The driver consists of the following functions (implemented in am/src/xs/isa/riscv/mpe.c) :
-
_mpe_init(void (*entry)())
: register anentry
procedure that each processor will run into after initialization -
_ncpu()
: return the total number of processors -
_cpu()
: return the hartID of current processor (start from 0) -
_atomic_xchg(intptr_t *addr, intptr_t newval)
: atomic exchange function,replace the value in *addr with newval and return the original value -
_atomic_add(intptr_t *addr, intptr_t adder)
: atomic adding function,increment value in *addr with adder and return the original value -
_barrier()
: barrier function,wait until all processors arrive here
(For more atomic operations, You can implement it yourself using a similar format as _atomic_add)
A simple demo is provided in tests/amtest/src/tests/mp.c Here is the instruction to build and run
cd nexus-am
make ARCH=riscv64-xs-dual mainargs='m2'
# Here m means multi-processor demo, 2 means dual core
$(PATH_OF_DUALCORE_XS)/build/emu -i build/amtest-riscv64-xs-dual.bin --diff=$(PATH_OF_DUALCORE_XS)/ready-to-run/riscv64-nemu-interpreter-dual-so
The output should be like this:
My CPU ID is 0, nrCPU is 2
My CPU ID is 1, nrCPU is 2
sum = 193 atomic_sum = 200
Finalize CPU ID: 1
sum = 193 atomic_sum = 200
Finalize CPU ID: 0
Note that both sum
and atomic_sum
are incremented 100 times per CPU parallelly. However, atomic_sum
utilizes atomic primitive. Thus, we have sum
<= 200 && atomic_sum
== 200.
The major difference between RTL simulation with Verilator and FPGA of Xiangshan is that FPGA is using 16550 at 0x310b0000, while RTL simulation is using UARTLITE at 0x40600000. So we should change the serial devices when compiling for FPGA by
# Hello as an example
cd apps/hello
rm -rf $AM_HOME/am/build build # Macro definition is not yet added into dependency of Makefile, clean am.a manually
make ARCH=riscv64-xs CPPFLAGS=-DUART16550=1 # define UART16550
Then run build/hello-riscv64-xs.bin
on FPGA
Remember to rm -rf $AM_HOME/am/build build
if you want to switch back to uartlite.
compile_commands.json
can be used in many language servers to help completion.
# Hello as an example
rm -rf $AM_HOME/am/build apps/hello/build # A full rebuild to obtain full compile commands
bear -- make -C apps/hello ARCH=riscv64-xs
If you don't have bear on your machine, please search.