FPGA開発日記

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

MicroPython試行(2. RISC-V移植環境の調査)

MicroPythonは一つの題材なのだけれども、いろんなアプリケーションを移植してRISC-Vで動作させれば、少しはアプリケーションのことが分かるようなるかもしれない。

MicroPythonを題材にして、RISC-Vのソフトウェア実行環境とか、そのあたりについて勉強していこう。

MicroPython のアーキテクチャ移植における変更点

アーキテクチャの変更点においては、 py/nlr[ARCH].c にまとめてある。ここに今回はpy/nlrriscv32.cを作成した。

また、コンパイル時にターゲットアーキテクチャを決めるためのGCCのdefine文として、__riscvを使用した。これらのターゲットの定義defineは、以下で調査することが出来る。

riscv32-unknown-elf-cpp -dM /dev/null  | sort
...
#define __WINT_TYPE__ unsigned int
#define __WINT_WIDTH__ 32
#define __has_include(STR) __has_include__(STR)
#define __has_include_next(STR) __has_include_next__(STR)
#define __riscv 1
#define __riscv_atomic 1
#define __riscv_cmodel_medlow 1
#define __riscv_div 1
#define __riscv_float_abi_soft 1
#define __riscv_mul 1
#define __riscv_muldiv 1
#define __riscv_xlen 32
  • py/nlrriscv32.c (抜粋)
#include "py/mpstate.h"

#if !MICROPY_NLR_SETJMP && defined(__riscv)

#undef nlr_push

unsigned int nlr_push(nlr_buf_t *nlr) {

    __asm volatile (
    "sw  x2,  8 (x10) \n" // save regs...
    "sw  x8,  12(x10) \n"
    "sw  x9,  16(x10) \n"
...

とりあえず、 nlr_push()nlr_jump() の2つをいろいろ調べて移植してみた。が、まだちゃんと動作していない。

make clean && make
spike pk build/firmware.elf

z  00000000 ra 00026664 sp 7fbe5d20 gp 000601a8
tp 00000000 t0 000451f8 t1 00040000 t2 00000000
s0 0005dbd0 s1 00000000 a0 00000001 a1 00000000
a2 00000000 a3 00000000 a4 00060648 a5 7fbe5d30
a6 0000000f a7 7fbe5c64 s2 00000000 s3 00000000
s4 00000000 s5 00000000 s6 00000000 s7 00000000
s8 00000000 s9 00000000 sA 00000000 sB 00000000
t3 00000000 t4 00000000 t5 00000000 t6 00000000
pc 00026664 va 00000000 insn       00000000 sr 80046020
An illegal instruction was executed!

Environment Modulesを使ってRISC-Vのツール群を整理する環境構築

RISC-Vのツール群、主にコンパイラツールは32bitと64bitのものが存在する。それぞれにライブラリが定義されており、別々にディレクトリを用意してインストールするのが良いと思われる。

ビルドスクリプトも別々に用意されている。

riscv-tools/build.sh # 64bit用 riscv-tools/build-rv32ima.sh # 32bit用

これらのツール群のパスを設定するために、いちいちスクリプトを変更するのは面倒だ。これをかんりするために、Environment Modulesを使ってパスとライブラリを管理しよう。

modules.sourceforge.net

RISC-Vのツール群で設定する必要があるのは、

の設定が必要だ。${HOME}/modules/riscv/ディレクトリに riscv32, riscv64 ファイルを作り、環境変数 MODULEPATH=${HOME}/modules を設定する。

  • ${HOME}/modules/riscv/riscv32
#%Module1.0
##
proc ModulesHelp { } {
    puts stderr "RISC-V 32-bit Toolchain\n"
}

module-whatis   "RISC-V 32-bit Toolchain"

# append pathes
setenv       RISCV           $::env(HOME)/riscv32/
prepend-path PATH            $::env(HOME)/riscv32/bin/
prepend-path LD_LIBRARY_PATH $::env(HOME)/riscv32/lib/
  • ${HOME}/modules/riscv/riscv64
#%Module1.0
##
proc ModulesHelp { } {
    puts stderr "RISC-V 64-bit Toolchain\n"
}

module-whatis   "RISC-V 64-bit Toolchain"

# append pathes
setenv       RISCV           $::env(HOME)/riscv64/
prepend-path PATH            $::env(HOME)/riscv64/bin
prepend-path LD_LIBRARY_PATH $::env(HOME)/riscv64/lib

module avail で、ツール群の存在を確認する。

module avail

------------------------- /home/msyksphinz/modules/ ---------------------------------------
riscv/riscv32 riscv/riscv64

例えば、32bitツール群をロードしてみよう。

$ module load riscv/riscv32
$ printenv RISCV
/home/msyksphinz/riscv32/
$ which riscv32-unknown-elf-gcc
/home/msyksphinz/riscv32/bin//riscv32-unknown-elf-gcc
$ which riscv64-unknown-elf-gcc

次に、64bitツール群をロードしてみる。

$ module load riscv/riscv64
$ printenv RISCV
/home/msyksphinz/riscv64/
$ which riscv32-unknown-elf-gcc
$ which riscv64-unknown-elf-gcc
/home/msyksphinz/riscv64/bin/riscv64-unknown-elf-gcc

ちゃんと設定できた!

MicroPython試行(1. ダウンロードとビルド → RISC-Vツールチェインでコンパイルするとどうなる?)

ちょっとやりたいことがあって、MicroPythonをダウンロードしてビルドした。

github.com

sudo apt install -y libffi-dev
git clone https://github.com/micropython/micropython.git
cd micropython/
git submodule update --init
make axtls
make

なるほど、MicroPython、それなりにでっかい。

size -A ./micropython
./micropython  :
section                size      addr
.interp                  28   4194872
.note.ABI-tag            32   4194900
.note.gnu.build-id       36   4194932
.gnu.hash               380   4194968
.dynsym                3864   4195352
.dynstr                1586   4199216
.gnu.version            322   4200802
.gnu.version_r          208   4201128
.rela.dyn               312   4201336
.rela.plt              3144   4201648
.init                    26   4204792
.plt                   2112   4204832
.plt.got                  8   4206944
.text                234112   4206960
.fini                     9   4441072
.rodata               76929   4441088
.eh_frame_hdr         11740   4518020
.eh_frame             57748   4529760
.init_array               8   6688208
.fini_array               8   6688216
.jcr                      8   6688224
.dynamic                528   6688232
.got                      8   6688760
.got.plt               1072   6688768
.data                  4288   6689856
.bss                   2464   6694144
.comment                 52         0
Total                401032

なるほど、次に、QEMU-ARMでは?

cd ../qemu-arm
make
...
CC ../../lib/libm/sf_ldexp.c
CC ../../lib/libm/asinfacosf.c
CC ../../lib/libm/atanf.c
CC ../../lib/libm/atan2f.c
CC ../../lib/utils/sys_stdio_mphal.c
CC main.c
/opt/Xilinx/SDK/2017.1/gnu/aarch32/lin/gcc-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/6.2.1/../../../../arm-none-eabi/bin/ld: -lc_nano が見つかりません
collect2: error: ld returned 1 exit status

あれ、Xilinxのツール使ってしまった。ってか-lc_nanoって何だろう?

先に進む。RISC-V用のビルドディレクトリを作ってみる。

cd ../
cp qemu-arm qemu-riscv -r
cd qemu-riscv
make

うーん、途中で失敗した。

CC ../../py/emitinlinextensa.c
CC ../../py/formatfloat.c
CC ../../py/parsenumbase.c
CC ../../py/parsenum.c
CC ../../py/emitglue.c
CC ../../py/persistentcode.c
CC ../../py/runtime.c
CC ../../py/runtime_utils.c
CC ../../py/scheduler.c
CC ../../py/nativeglue.c
../../py/nativeglue.c:158:5: error: 'nlr_push' undeclared here (not in a function)
     nlr_push,
     ^~~~~~~~
../../py/nativeglue.c:159:5: error: 'nlr_pop' undeclared here (not in a function)
     nlr_pop,
     ^~~~~~~
../../py/mkrules.mk:47: ターゲット 'build/py/nativeglue.o' のレシピで失敗しました
make: *** [build/py/nativeglue.o] エラー 1

ちょっと先は長そうだ。

ソフトウェアデザイン11月号を購入。「なぜ,コンピュータは割り算が下手なのか!?」

スーパー台風により本屋に行けないので、ネットでPDF版を購入。 お目当ては猫、、、ではなくて第2特集の「なぜ,コンピュータは割り算が下手なのか!?」

内容は割と普通だった。せいぜい命令のレイテンシ計ってみたくらい。 ハードウェア屋さんだと割と常識でガッカリするかもしれない。

ソフトウェア屋さんで、プログラムの美しさとか言って除算とか剰余とかめっちゃ使っている方は、読んでみると如何? まあ内容は基本情報技術者程度だとは思いますが。。。

Halide to FPGA試行(1. HalideのコンパイルとCPU上でのテストパタン試行)

Pixel2 → Pixel Visual Core → Halideあたりを調べていたら、ちょうどFixstarsからHalide to FPGAという環境がリリースされた。

www.fixstars.com

ターゲットがZedBoardだし、お、ちょうど面白そうと思って早速中身を見てみた。

最初は、CPUでのテスト環境を試行してみる。

  • CPU上での開発: Halide to FPGA

CPU上での開発 – Halide to FPGA

HalideのビルドからLLVMのビルドまで一応フルスクラッチで作ってみた。

github.com

最初にLLVMをインストールしておく必要がある。これも一応フルスクラッチ

svn co https://llvm.org/svn/llvm-project/llvm/branches/release_39 llvm3.9
svn co https://llvm.org/svn/llvm-project/cfe/branches/release_39 llvm3.9/tools/clang
cd llvm3.9
mkdir build
cd build
cmake -DLLVM_ENABLE_TERMINFO=OFF -DLLVM_TARGETS_TO_BUILD="X86;ARM;NVPTX;AArch64;Mips;PowerPC" -DLLVM_ENABLE_ASSERTIONS=ON -DCMAKE_BUILD_TYPE=Release ..
make -j4

環境変数を通しておく。

export LLVM_CONFIG=/home/msyksphinz/work/software/llvm3.9/build/bin/llvm-config
export CLANG=/home/msyksphinz/work/software/llvm3.9/build/bin/clang

次にHalideのビルドを行う。

Halideのリビジョンは最新のTagに合わせておかないとどうもコンパイルが成功しそうにない。そんなもんなの?

git clone https://github.com/halide/Halide.git
cd Halide
git checkout release_2017_05_03
make -j4

こちらも環境変数を通しておく。

export HALIDE_ROOT=/home/msyksphinz/work/software/Halide

Halide To FPGAの環境をチェックアウトしてくる。

git clone git@github.com:fixstars/Halide-elements.git
cd Halide-elements
cd src/convolution
make

これで一応ビルドは出来たので、convolution_testを実行してみた。

./convolution_test
Success!

まあここまでは良いのだけど、問題はFPGAのイメージだ。とりあえずポータルサイトに行ってみたのだが、イメージがダウンロードできない。 なんかそもそもポータルページに不具合があるのか、何度もログインしても勝手にログアウトされてしまう。何だこりゃ?

ポータルサイトが安定するまでちょっと作業は放置しよう。

プログラミング言語Rustに入門中(2. 哲学者の食事)

Rust入門中の2回目。ってか間が空くのが長いな!

食事する哲学者

完全な写経中だけど、ちゃんと理解して自力でRustのコードが書ける日は来るのだろうか?

しかも私の環境では全然並列実行出来ていない感があるのだけど、大丈夫なのかしらん?

f:id:msyksphinz:20171021025334p:plain

use std::thread;
use std::time::Duration;
use std::sync::{Mutex, Arc};

struct Philosopher {
    name: String,
    left: usize,
    right: usize,
}

impl Philosopher {
    fn new(name: &str, left: usize, right: usize) -> Philosopher {
        Philosopher {
            name: name.to_string(),
            left: left,
            right: right,
        }
    }

    fn eat(&self, table: &Table) {
        let _left = table.forks[self.left].lock().unwrap();
        thread::sleep(Duration::from_millis(150));
        let _right = table.forks[self.right].lock().unwrap();
        
        println!("{} is eating.", self.name);

        thread::sleep(Duration::from_millis(1000));

        println!("{} is done eating.", self.name);
    }
}

struct Table {
    forks: Vec<Mutex<()>>,
}


fn main () {
    let table = Arc::new(Table { forks: vec![
        Mutex::new(()),
        Mutex::new(()),
        Mutex::new(()),
        Mutex::new(()),
        Mutex::new(()),
    ]});

    let philosophers = vec![
        Philosopher::new("Judith Butler", 0, 1),
        Philosopher::new("Gilles Deleuze", 1, 2),
        Philosopher::new("Karl Marx", 2, 3),
        Philosopher::new("Emma Goldman", 3, 4),
        Philosopher::new("Michel Foucault", 0, 4),
    ];

    let handles: Vec<_> = philosophers.into_iter().map(|p| {
        let table = table.clone();
        
        thread::spawn(move || {
            p.eat(&table);
        })
    }).collect();
    
    for h in handles {
        h.join().unwrap();
    }
}

UCBのRISC-V FPGAシミュレーション加速環境 "MIDAS"を試行する(1)

CARRVで発表された、UCBのRISC-V FPGAシミュレーション環境 MIDASのリポジトリがあったので、実験してみた。

試してみたのは以下のディレクトリ。

github.com

まずは一応全部ダウンロードした。riscv-fesvrを最新に更新しないと動作しないようなので、riscv-fesvrを更新する。

git clone https://github.com/ucb-bar/midas-top-release.git
cd midas-top
./setup.sh

しかしこのリポジトリまだきちんと管理されていないのか、サブリポジトリのダウンロードができないので少し変更した。

diff --git a/.gitmodules b/.gitmodules
index 1e1dad0..9b1170d 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,24 +1,24 @@
 [submodule "rocket-chip"]
        path = rocket-chip
-       url = git@github.com:ucb-bar/rocket-chip.git
+       url = https://github.com/ucb-bar/rocket-chip.git
 [submodule "midas"]
        path = midas
-       url = git@github.com:ucb-bar/midas-release.git
+       url = https://github.com/ucb-bar/midas-release.git
 [submodule "firrtl"]
        path = firrtl
-       url = git@github.com:ucb-bar/firrtl.git
+       url = https://github.com/ucb-bar/firrtl.git
 [submodule "chisel"]
        path = chisel
-       url = git@github.com:ucb-bar/chisel3.git
+       url = https://github.com/ucb-bar/chisel3.git
 [submodule "riscv-boom"]
        path = boom
-       url = git@github.com:ucb-bar/riscv-boom.git
+       url = https://github.com/ucb-bar/riscv-boom.git
 [submodule "midas-zynq"]
        path = platforms/zynq
-       url = git@github.com:ucb-bar/midas-zynq.git
+       url = https://github.com/ucb-bar/midas-zynq.git
 [submodule "fesvr"]
        path = riscv-fesvr
-       url = git@github.com:riscv/riscv-fesvr.git
+       url = https://github.com/riscv/riscv-fesvr.git

あとはriscv-fesvrのリポジトリ更新を行っておく。

cd riscv-fesvr
./configure --prefix=/home/msyksphinz/riscv64/
make
make install

make verilogの実行結果

f:id:msyksphinz:20171018231301p:plain

make run-bmark-testsの実行結果

f:id:msyksphinz:20171019003603p:plain

なぜか1本目でシミュレーションが止まるね。原因が良く分からないけど、とりあえずMakefileを改造する。

 $(output_dir)/%.out: $(output_dir)/% $(EMUL)
        cd $(dir $($(EMUL))) && \
        ./$(notdir $($(EMUL))) $< +sample=$<.sample +max-cycles=$(timeout_cycles) $(SW_SIM_ARGS) \
-       $(disasm) $@ && [ $$PIPESTATUS -eq 0 ]
+       $(disasm) $@

make bitstream BOARD=zedboardの実行結果。Vivadoで確認してみる。

f:id:msyksphinz:20171019020332p:plain