そろそろHiFive1ボードを活用しないと、、、
MNISTのデータは非常に巨大で、フラッシュなどに入れないとHiFive1のチップの中にはもちろん入らない。 まずはMNISTデータを小さくしてオブジェクトとして貼り付け、HiFive1のシリアルコンソールから出力するところから始めよう。
MNISTデータを小さくしてオブジェクトにする
前回も紹介したが、MNISTデータは巨大だし、組み込み向けボードはファイルI/Oという概念がないので、「ファイルを開いてロードする」という手法は使えない。 従って、ファイルは予めRISC-V互換のオブジェクトファイルに変換しておき、それを実行ファイルにリンクしておくということでデータを読み込む。
普通のやつらの下を行け: objcopy で実行ファイルにデータを埋め込む - bkブログ
まずは、train-images-idx3-ubyteのデータから先頭を切り取って小さくする。次に、objcopyを使ってこれをオブジェクトに変換するというわけだ。
train-images-idx3-ubyte.100.o: train-images-idx3-ubyte head -c 4000000 $< > $<.100 riscv64-unknown-elf-objcopy -I binary -O elf32-littleriscv -B riscv --rename-section .data=.rodata $<.100 $@ %-ubyte.o: %-ubyte $(OBJCOPY) -I binary -O elf32-littleriscv -B riscv --rename-section .data=.rodata $(notdir $<) $(notdir $@)
一応hexdumpでファイルの中身を確認してみる。
これがちゃんとオブジェクトファイルに変換されていればよい。
MNISTデータを埋め込んでシリアルコンソールに表示する
MNISTは以下のように埋め込んでいる。これを1文字ずつ変換してシリアルコンソールに表示する。write()
関数は、HiFive1のシリアルコンソールに出力させる。
const char* hex_enum[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"}; int main () { write (STDOUT_FILENO, message, strlen (message)); int len = _binary_train_images_idx3_ubyte_100_end - _binary_train_images_idx3_ubyte_100_start; int i; const int offset = 0x12; for (i = 0; i < len; i++) { char hex_value = _binary_train_images_idx3_ubyte_100_start[i+offset]; write (STDOUT_FILENO, hex_enum[(hex_value >> 4) & 0x0f], 2); write (STDOUT_FILENO, hex_enum[(hex_value >> 0) & 0x0f], 2); if ((i % 28) == 27) { write (STDOUT_FILENO, "\r\n", 2); } }
これで生成したバイナリファイルをHiFive1に流し込んで、実行してみる。
無事にMNISTのデータを表示させることができた。