HiFive1ボードはRISC-Vが動作する(おそらく世界で唯一商用の?)プロセッサボードである。このHiFive1ボードの仕様は以下のようになっている。
- Microcontroller: SiFive Freedom E310 (FE310)
- SiFive E31 Coreplex
- 32bit RV32IMAC (整数演算のみ、乗除算ハードウェア回路付属、コンパクト命令付属)
- Speed: 320+ MHz
- Performance: 1.61 DMIPs/MHz, 2.73 Coremark/MHz
- Memory: 16 KB Instruction Cache, 16 KB Data Scratchpad
- Other Features: Hardware Multiply/Divide, Debug Module, Flexible Clock Generation with on-chip oscillators and PLLs
- SPI Controllers/HW CS Pins: 1/3
- External Interrupt Pins: 19
- External Wakeup Pins: 1
- Flash Memory: 128 Mbit Off-Chip (ISSI SPI Flash)
というわけで、フラッシュメモリが128Mbitも付属しているのが大きいと個人的に思っている。ここにどうにかして学習データを流し込んで、機械学習のプログラムを動作させたいのだ。
train_twolayernet (MNIST向け機械学習ネットワーク (16bit 固定小数点版))のコンパイル
自作したMNIST動作用の機械学習ネットワークは、固定小数点ライブラリlibfixmathを使うようになっている。
libfixmathをRISC-V向けにコンパイルするためには、オリジナルのlibfixmathに対して以下の変更を加えている。
diff --git a/libfixmath/Makefile b/libfixmath/Makefile index b284590..27cceb9 100644 --- a/libfixmath/Makefile +++ b/libfixmath/Makefile @@ -4,14 +4,19 @@ LIB = SRC = . INC = +TARGET=/home/msyksphinz/work/freedom-e-sdk/work/build/riscv-gnu-toolchain/riscv64-unknown-elf/prefix/bin/riscv64-unknown-elf- + #Compiler settings -CPP = gcc -CC = gcc -AS = gcc -LD = gcc -AR = ar -CPP_FLAGS = -O2 $(INC) -Wall -Wextra -c -CC_FLAGS = -O2 $(INC) -Wall -Wextra -c +CPP = $(TARGET)gcc +CC = $(TARGET)gcc +AS = $(TARGET)gcc +LD = $(TARGET)gcc +AR = $(TARGET)ar + +DEFINES += FIXMATH_NO_CACHE + +CPP_FLAGS = -O2 $(INC) -Wall -Wextra -c -std=gnu11 -O3 -g -g -march=rv32imac -mabi=ilp32 -mcmodel=medany $(addprefix -D, $(DEFINES)) +CC_FLAGS = -O2 $(INC) -Wall -Wextra -c -std=gnu11 -O3 -g -g -march=rv32imac -mabi=ilp32 -mcmodel=medany $(addprefix -D, $(DEFINES)) AS_FLAGS = $(CC_FLAGS) -D_ASSEMBLER_ LD_FLAGS = -Wall
MNISTの訓練データをRISC-Vバイナリに直接埋め込む方法
HiFive1にはファイルシステムも入っていないしOSも動かないので、これまで使っていたread/write系の関数は動作しない。これを補うために、あらかじめトレーニングデータをRISC-Vの形式に変換して、リンク時に埋め込むという作業が必要になる。
これはバイナリをオブジェクトファイルに変換する必要がある。これにはobjcopyコマンドを使用する。
普通のやつらの下を行け: objcopy で実行ファイルにデータを埋め込む - bkブログ
上記を使用して、トレーニングファイルを以下のようにMakefileを使ってオブジェクトファイルに変換を行った。
%-ubyte.o: %-ubyte $(OBJCOPY) -I binary -O elf32-littleriscv -B riscv --rename-section .data=.rodata $(notdir $<) $(notdir $@)
これをコンパイルすると、デフォルトではファイルの大きさが大きすぎてセクションに入らないので、以下のエラーが出る。
/home/msyksphinz/work/freedom-e-sdk/work/build/riscv-gnu-toolchain/riscv64-unknown-elf/prefix/lib/gcc/riscv64-unknown-elf/7.1.1/../../../../riscv64-unknown-elf/bin/ld: train_twolayernet セク ション `.data' は領域 `ram' 内に入りません /home/msyksphinz/work/freedom-e-sdk/work/build/riscv-gnu-toolchain/riscv64-unknown-elf/prefix/lib/gcc/riscv64-unknown-elf/7.1.1/../../../../riscv64-unknown-elf/bin/ld: section .stack VMA [0000000080003800,0000000080003fff] overlaps section .data VMA [0000000080000000,0000000083468297] /home/msyksphinz/work/freedom-e-sdk/work/build/riscv-gnu-toolchain/riscv64-unknown-elf/prefix/lib/gcc/riscv64-unknown-elf/7.1.1/../../../../riscv64-unknown-elf/bin/ld: 領域 `ram' が 0 バイト 溢れました
objdump -h
でセクションを確認すると、.data
が非常に大きいことが分かる。
software/train_twolayernet/train-images-idx3-ubyte.o: ファイル形式 elf32-littleriscv セクション: 索引名 サイズ VMA LMA File off Algn 0 .data 02cdc610 00000000 00000000 00000034 2**0 CONTENTS, ALLOC, LOAD, DATA
.data
セクションはflash.ldsによって以下のように定義されている。
- ./bsp/env/freedom-e300-hifive1/flash.lds
MEMORY { flash (rxai!w) : ORIGIN = 0x20400000, LENGTH = 512M ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = 16K }
.data
セクションはram
に配置されており、16Kしかない。イメージデータをどうにかしてflashデータにコピーするしかない。これには、あらかじめobjcopyコマンドでrename-sectionを指定する。
%-ubyte.o: %-ubyte $(OBJCOPY) -I binary -O elf32-littleriscv -B riscv --rename-section .data=.rodata $(notdir $<) $(notdir $@)
これで、すべての学習データがflashセクションに移動した。
software/train_twolayernet/train_twolayernet: ファイル形式 elf32-littleriscv セクション: 索引名 サイズ VMA LMA File off Algn 0 .init 0000007e 20400000 20400000 00001000 2**0 CONTENTS, ALLOC, LOAD, READONLY, CODE 1 .text 0000dfca 20400080 20400080 00001080 2**2 CONTENTS, ALLOC, LOAD, READONLY, CODE 2 .rodata 034685dc 2040e050 2040e050 0000f050 2**3 CONTENTS, ALLOC, LOAD, DATA 3 .eh_frame 00000068 2387662c 2387662c 0347762c 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 4 .lalign 00000000 23876694 23876694 034789f8 2**0 CONTENTS 5 .dalign 00000000 80000000 80000000 034789f8 2**0 CONTENTS 6 .data 000009f8 80000000 23876694 03478000 2**3 CONTENTS, ALLOC, LOAD, DATA 7 .bss 00000040 800009f8 800009f8 00000000 2**2 ALLOC 8 .stack 00000800 80003800 80003800 00000000 2**0 ALLOC 9 .debug_frame 00001258 00000000 00000000 034789f8 2**2 CONTENTS, READONLY, DEBUGGING 10 .debug_info 00010107 00000000 00000000 03479c50 2**0 CONTENTS, READONLY, DEBUGGING 11 .debug_abbrev 00003dbe 00000000 00000000 03489d57 2**0 CONTENTS, READONLY, DEBUGGING 12 .debug_loc 000158a5 00000000 00000000 0348db15 2**0 CONTENTS, READONLY, DEBUGGING 13 .debug_aranges 000004c0 00000000 00000000 034a33c0 2**3 CONTENTS, READONLY, DEBUGGING 14 .debug_ranges 00001ff8 00000000 00000000 034a3880 2**0 CONTENTS, READONLY, DEBUGGING 15 .debug_line 00008d84 00000000 00000000 034a5878 2**0 CONTENTS, READONLY, DEBUGGING 16 .debug_str 000023a6 00000000 00000000 034ae5fc 2**0 CONTENTS, READONLY, DEBUGGING 17 .comment 0000001a 00000000 00000000 034b09a2 2**0 CONTENTS, READONLY
ここまでで一応バイナリを作成することができたのだが、アップロード時にHiFive1でエラーが出ている。これは解析する必要があるなあ。
$ sudo make upload PROGRAM=hello [sudo] msyksphinz のパスワード: work/build/openocd/prefix/bin/openocd -f bsp/env/freedom-e300-hifive1/openocd.cfg & \ /home/msyksphinz/work/freedom-e-sdk/work/build/riscv-gnu-toolchain/riscv64-unknown-elf/prefix/bin/riscv64-unknown-elf-gdb software/hello/hello --batch -ex "set remotetimeout 240" -ex "target extended-remote localhost:3333" -ex "monitor reset halt" -ex "monitor flash protect 0 64 last off" -ex "load" -ex "monitor resume" -ex "monitor shutdown" -ex "quit" && \ echo "Successfully uploaded 'hello' to freedom-e300-hifive1." Open On-Chip Debugger 0.10.0-dev (2017-07-17-09:46) Licensed under GNU GPL v2 For bug reports, read http://openocd.org/doc/doxygen/bugs.html adapter speed: 10000 kHz Info : auto-selecting first available session transport "jtag". To override use 'transport select <transport>'. Info : ftdi: if you experience problems at higher adapter clocks, try the command "ftdi_tdo_sample_edge falling" Info : clock speed 10000 kHz Info : JTAG tap: riscv.cpu tap/device found: 0x10e31913 (mfg: 0x489 (<unknown>), part: 0x0e31, ver: 0x1) Info : Examined RISCV core; XLEN=32, misa=0x40001105 Error: couldn't bind gdb to socket: Address already in use