FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

Rocket-ChipでMNISTのプログラムを動かす (1. コンパイルと Spikeによるシミュレーション)

Rocket-Chipでディープラーニング系のプログラムを動かしたいと思っている。

まずは、Rocket-Chipで通常のMNISTプログラムを移植して動かしていこう。 これまでに作ったHiFive1のMNISTのプログラムを移植して、まずはアクセラレータを使わずに動作させたい。

RISC-V toolchainでmallocなどの関数を使いたい

もともとHiFive1用に作ったプログラムはmallocが使われていたので、何かカラクリがあるはずだ。 このあたりは、Freedom-E-SDKに仕組みが隠されていた。

github.com

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には備わっている。

sircmpwn.github.io

-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を使っている。

github.com

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のコードは正しく動いているようだ。 よしよし。

f:id:msyksphinz:20180112003111p:plain
f:id:msyksphinz:20180112003102p:plain

関連記事