kubo39's blog

ただの雑記です。

D言語でRISC-Vシミュレータ上でハローワールドする

D言語でもRISC-Vやりたいんだが…? ← できた。そういう話です。

準備

LDCのバージョンは以下のもの。自前ビルドしてる人はRISC-V向けにしてることと、RISC-VはLLVM 9.0.0以降で公式にサポートされていることに注意されたい。

$ ldc2 --version | head -2
LDC - the LLVM D compiler (1.21.0):
  based on DMD v2.091.1 and LLVM 10.0.0
$ ldc2 --version | grep RISC-V
    riscv32    - 32-bit RISC-V
    riscv64    - 64-bit RISC-V

RISC-VのGCCツールチェーンをダウンロードしてPATHの通るところにおく必要がある。 ここではてきとうにgccというディレクトリを作ってそこに展開してる。 バージョンはちょっと古いものを使って試したが、もっと新しいやつもってきても大丈夫だと思われる。

$ mkdir -p gcc
$ curl -L https://static.dev.sifive.com/dev-tools/riscv64-unknown-elf-gcc-8.1.0-2018.12.0-x86_64-linux-ubuntu14.tar.gz | tar --strip-components=1 -C gcc -xz

シミュレータ環境としてこのへんを用意しておく。

やる

ソースコードはこんな感じだよ。

extern (C):

// version(CRuntime_Musl) とか定義してもいい。
int printf(scope const char* format, scope const ...);

int main()
{
    printf("Hello, World!\n");
    return 0;
}

コンパイルオプションはRISC-V 64向けだと以下のようにする。 -mattrの指定は整数乗除算(+m),アトミック命令(+a),16bit圧縮命令(+c)を指定。というかこれ以外だとgccのリンクの時にこけるんだよな。。新しいので試したほうがいいかもしれない。 あとLLVM 10だとCPUタイプをgeneric-rv64指定したときにrvcヒント命令(+rvc-hints)もついてくるけど、今回だと多分関係ない(はず)。

$ ldc2 --mtriple=riscv64-unknown-none-elf -mcpu=generic-rv64 \
  -mattr=+m,+a,+c -betterC -c hello.d
$ riscv64-unknown-elf-gcc -march=rv64imac -mabi=lp64 -o hello hello.o

シミュレータ上で動かす。

$ spike pk hello
bbl loader
Hello, World!
$

おまけ(読まなくてもいいやつ)

-mcpu=generic-rv64 指定ないとgenericというRISC-Vターゲットには存在しないCPUタイプ指定してくるのでこれが必須。upstreamのLDCではすでに修正されている。 あとLDCは--gcc指定でリンク処理するCコンパイラ指定できるんだけど、ArmとMIPS以外の環境だと勝手に-m32/-m64を付けてくるので上記のようにリンクは別コマンドでやる必要がある。 これもパッチはもうできててたぶんそのうち取り込まれる。

一応RISC-V 32版でのコンパイル方法ものせておくけど、spikeがバグってんのか--isa指定いろいろ試してもだめだった。(ここはほんとに読まなくていいとこ)

$ ldc2 --mtriple=riscv32-unknown-none-elf -mcpu=generic-rv32 \
  -mattr=+m,+a,+c -betterC -c hello.d
$ riscv64-unknown-elf-gcc -march=rv32imac -mabi=ilp32 -o hello hello.o