Rocket-Chipでディープラーニング系のプログラムを動かしたいと思っている。
まずは、Rocket-Chipで通常のMNISTプログラムを移植して動かしていこう。 これまでに作ったHiFive1のMNISTのプログラムを移植して、まずはアクセラレータを使わずに動作させたい。
RISC-V toolchainでmallocなどの関数を使いたい
もともとHiFive1用に作ったプログラムはmalloc
が使われていたので、何かカラクリがあるはずだ。
このあたりは、Freedom-E-SDKに仕組みが隠されていた。
- bsp/libwrap/stdlib/malloc.c
void* __wrap_malloc(unsigned long sz) { extern void* sbrk(long); void* res = sbrk(sz); if ((long)res == -1) return 0; return res; } void __wrap_free(void* ptr) { }
- bsp/libwrap/sys/sbrk.c
void *__wrap_sbrk(ptrdiff_t incr) { extern char _end[]; extern char _heap_end[]; static char *curbrk = _end; if ((curbrk + incr < _end) || (curbrk + incr > _heap_end)) return NULL - 1; curbrk += incr; return curbrk - incr; }
これらのコードは、真面目にmalloc
を使う代わりに、mallocを疑似的にまねる簡略的なコードだ。
malloc
が複数定義されていても、wrapperを使って上書きするようなオプションがgccには備わっている。
-Wl,--wrap=malloc -Wl,--wrap=free -Wl,--wrap=open -Wl,--wrap=lseek -Wl,--wrap=read -Wl,--wrap=write -Wl,--wrap=fstat -Wl,--wrap=stat -Wl,--wrap=close -Wl,--wrap=link -Wl,--wrap=unlink -Wl,--wrap=execve -Wl,--wrap=fork -Wl,--wrap=getpid -Wl,--wrap=kill -Wl,--wrap=wait -Wl,--wrap=isatty -Wl,--wrap=times -Wl,--wrap=sbrk -Wl,--wrap=_exit
これで、これまでに作ったMNISTのプログラムをコンパイルし直した。
16bitの半精度浮動小数点はlibfixmath
を使っている。
train_twolayernet_fix16: train_twolayernet_fix16.c syscalls.c crt.S wh1_init.o wh0_init.o wb0_init.o wb1_init.o sbrk.o malloc.o t10k-labels-idx1-ubyte.o t10k-images-idx3-ubyte.o riscv64-unknown-elf-gcc \ -mabi=lp64 \ -DPREALLOCATE=1 \ -mcmodel=medany \ -std=gnu99 \ -O2 \ -ffast-math \ -fno-common \ -fno-builtin-printf \ -static \ -nostartfiles \ -nostdlib \ -T ./test.ld \ -o $@ \ $^ \ -lfixmath -L. \ -Wl,--wrap=malloc \ -Wl,--wrap=sbrk \ -Wl,--wrap=free
SpikeでMNISTコードをシミュレーション
次にRTLシミュレーションを実行する前に、Spikeでシミュレーションをして動作を確認しておこう。
msyksphinz@msyksphinz-VirtualBox:~/work/training/risc-v/mnist$ spike train_twolayernet_fix16 === TestNetwork === === start === Correct = 185 Time = 0000000000000000 - 0000000000000000
rdcycle
などのレジスタはSpikeで動かないみたいなので、ここは省略している。200個の画像をテストして185個正解しているので、MNISTのコードは正しく動いているようだ。
よしよし。