4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

RISC-V RV32I CPU ASFRV32Iの解説

Last updated at Posted at 2021-04-24

ASFRV32I

ASFRV32Iは1ファイル189行のVerilogで実装したシングルサイクルのRISC-V RV32IのCPUです。RISC-V Unpriviledged ISA 20191213 に準拠しています。

この記事ではASFRV32Iの使い方を説明していきます。ASFRV32Iの設計と実装の詳細は別の記事を参照してください。

ASFRV32Iの動かし方

Icarus verlogでシミュレーションできます。Linuxなら大抵のディストリビューションでバイナリが用意されていると思います。Windows版もあります。

ダウンロード

gitでダウンロードしてください。

$ git clone https://github.com/asfdrwe/ASFRV32I.git

論理合成

Icarus verlogで論理合成します。

iverilog -o RV32I RV32I.v RV32I_test.v

シミュレーション実行

test.hexを読み込んで実行します。

./RV32I

プログラム(test.hex)の書き方

ASFRV32Iのメモリは命令データ兼用で4KBです。1行が8bit16進数のテキスト形式のtest.hexを読み込み実行します。RISC-Vバイナリを実行するためにはこのテキスト形式に変換する必要があります。

ハンドアセンブルの場合

RV32Iは4バイト固定長です。ASFRV32Iではリトルエンディアンで書きます。
lui x1, 0x20000(x1レジスタの上位20bitに0x20000を代入し下位12bitに0x000を代入)ならば機械語は

0b_0010_0000_0000_0000_0000_00001_0110111(2進数)
0x_20_00_00_B7(16進数)

なのでtest.hexは次のようになります。

B7
00
00
20

gcc

RISC-Vのツールチェイン を取得してビルドしてください。

ファイル取得

$ git clone https://github.com/riscv/riscv-gnu-toolchain
$ cd riscv-gnu-toolchain
$ git submodule update --init --recursive

ビルドしてパスを通します。

$ ./configure --prefix=/opt/riscv
$ make linux
$ make install
$ export PATH=/opt/riscv/bin:$PATH

ASFRV32IはOSなしのベアメタルです。ASFRV32Iはプログラムを0番地から実行するので下記のlink.ldのようなリンカスクリプトで実行コード(.textセクション)を0番地に配置しています。

link.ld

OUTPUT_ARCH( "riscv" )
ENTRY(_start)

SECTIONS
{
. = 0x00000000;
.text.init : { *(.text.init) }
. = ALIGN(0x0100);
.tohost : { *(.tohost) }
. = ALIGN(0x0100);
.text : { *(.text) }
. = ALIGN(0x0100);
.data : { *(.data) }
.bss : { *(.bss) }
_end = .;
}
アセンブリ

アセンブリで記述する場合は次のように実装します。_startをエントリポイントとして0番地に配置され_startからプログラムが実行されます。
test.S

.globl _start

_start:
lui x1, 0x50000
addi x1, x1, 0xca
_loop:
jal x2, _loop

.data
      .align 4
testdata:
      .dword 41

コンパイルは次のように行います。

$ riscv64-unknown-elf-gcc -o test.bin test.S -march=rv32g -mabi=ilp32 -nostdlib -nostartfiles -T ./link.ld
バイナリの変換

elf形式のバイナリを1行8bit16進数のテキストファイルに変換します。freedom-bin2hex.py をダウンロードしてください。実行にはpythonが必要です。

objcopyでbinaryをダンプしてfreedom-bin2hex.pyで1行8bit16進数のテキストファイルに変換します。

$ riscv64-unknown-elf-objcopy -O binary test test.bin
$ python freedom-bin2hex.py -w 8 test.bin test.hex
c言語

ベアメタルなのでint main()は使えません。printf等も使えません。スタックポインタを設定するスタートアップルーチンがないとサブルーチンの呼び出しができないので、0x0800をスタックに設定したstart.Sをスタートアップルーチンとします。start.Sは_mainをエントリポイントとしています。

start.S

.globl _start

_start:
li sp, 0x0800
jal _main
j

Cでのコード例
test2.c

void _main()
{
static int a, b, c;
a = 1;
b = 2;
c = 1 + 2;
int d, e, f, h;
d = 10;
e = 15;
f = e - d;
h = a - 10;
return;
}

コンパイルは次のようにstart.Sも一緒にアセンブル&リンクして-nostdlib -nostartfilesを指定してください。

ASFRV32Iでは未対応命令はNOP扱いなので掛け算等はNOPになるはずです(未確認)。
-march=rv32iを指定してlibgccをリンクすれば掛け算もRV32Iの範囲でなんとかしてくれるとは思いますが確認していません。

$ riscv64-unknown-elf-gcc -o test2.bin start.S test2.c -march=rv32g -mabi=ilp32 -nostdlib -nostartfiles -T ./link.ld

バイナリからtest.hexへの変換はアセンブリのときと同じです。

$ riscv64-unknown-elf-objcopy test2 -O binary test2.bin
$ freedom-bin2hex.py -w 8 test2.bin test.hex

riscv-tests

riscv-tests を使うことでRV32Iに正しく準拠しているか確認できます。

ファイル取得

$ git clone https://github.com/riscv/riscv-tests
$ cd riscv-tests
$ git submodule update --init --recursive
$ autoconf

ASFRV32Iはメモリが4KBで割り込みやCSR関係を実装していないので、0番地から実行するように修正しCSR命令と割り込み関連を削除します。

risc-testsのトップディレクトリで riscv-tests.patch を当ててください。

$ patch -p1 < ASFRV32Iの場所/riscv-tests.patch

hex形式にしたものとコンパイル後に逆アセンブルしたもの(*.dump)をtest以下に用意してあります。ASFRV32Iではecallが0番地への無条件分岐なのことに気をつけて動作確認してみてください。

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?