クリーム色の背景、色付き表示、高コントラスト、大きな文字のほうが読みやすいですか?配色と文字を選ぶと、すべてのページに一度で反映されます。

無料レッスン

プロセッサの命令を読む(RISC-V)

このレッスンのあとで: 短い RISC-V のプログラムを読むことができる。

55分のレッスンコマンド10件コンパイラとアーキテクチャのラボ:gcc、flex、bison、RISC-V を1台の VM で

止まった検査装置の最後の1行

工場の検査装置が、ラインの途中で止まりました。装置が残した記録には、最後に実行した命令が1行だけあります。sw a1, 12(a0) です。

装置の中にソースコードはなく、あるのは命令だけです。命令が読めれば、止まったときにプログラムが何をしていたかが分かります。

このレッスンのゴール

メモ

短い RISC-V のプログラムを読むことができる。

キーワード

ことばいみれい
レジスタプロセッサの中の、小さくて速い記憶場所a0
即値命令の中に直接書かれた数93
ロードメモリの値をレジスタへ写す命令lw
ストアレジスタの値をメモリへ写す命令sw
分岐プログラムの別の場所へ飛ぶかもしれない命令bne
ラベルプログラムの1つの場所に付けた名前loop:

学生が入力するセルは、このプレビューでは空白です。

役目のある32個のレジスタ

64ビットの RISC-V のプロセッサには、64ビットのレジスタが32個あります。名前は x0 から x31 です。アセンブリでは、多くのレジスタをふだんの役目の名前で呼びます。

x0 は zero と呼び、いつ読んでも0です。書きこんでも捨てられます。a のレジスタは関数の入力と答えを運び、t のレジスタは一時的な値を持ちます。

例: このレッスンで会うレジスタ

番号名前ふだんの役目
x0zeroいつも0
x2spスタックの場所を指すスタックポインタ
x5 から x7t0 から t2一時的な値
x10、x11a0、a1関数の入力。答えは a0
x17a7ecall で Linux に頼むシステムコールの番号

学生が入力するセルは、このプレビューでは空白です。

アーキテクチャのフォルダへ移る

コマンド
cd ~/arch

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

命令の3つの形

ほとんどの命令は、まず答えを入れるレジスタを書き、次に入力がどこから来るかを書きます。

add a0, a0, t0 は、2つのレジスタを足します。addi t0, t0, 1 は、レジスタと即値を足します。li a0, 5 は別の形に見えますが、省略形です。小さい数なら、アセンブラは addi a0, zero, 5 と書きます。

ロードとストアがメモリに触れる

レジスタは少ないので、データはメモリに置きます。RISC-V の計算は、レジスタどうしでしか行いません。ロードはメモリからレジスタへ、ストアはレジスタからメモリへ値を写します。

lw a0, 12(a1) は、a1 の番地に12を足した場所から、4バイトを読みます。C の int は4バイトなので、表の4番目(0から数えて3番)は12バイト先です。

loop.c を RISC-V のアセンブリにする

コマンド
riscv64-linux-gnu-gcc -O2 -march=rv64gc -S loop.c

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

ロードとストアを行番号付きで探す

コマンド
grep -n -E 'lw|sw' loop.s

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

行ごとに足すループを見る

コマンド
grep -A 4 'L6:' loop.s

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

例: C と RISC-V を並べる

loop.c の CRISC-V働き
grid[r][c] = 1;sw a3,0(a5)1 を持つ a3 を、a5 の番地へ書く
sum = sum + grid[r][c];lw a4,0(a5)a5 の番地から4バイトを a4 へ読む
sum = sum + grid[r][c];add a3,a3,a4読んだ数を合計に足す。レジスタの中で
次の c へaddi a5,a5,4番地を int 1つ分、4バイト進める

学生が入力するセルは、このプレビューでは空白です。

よくある間違い

注意

「add は、メモリの数を直接足せる」と考える人が多くいます。RISC-V ではできません。メモリに触れるのはロードとストアだけです。値はロードし、レジスタの中で計算して、ストアで戻します。だから合計を出すには、まず lw、それから add が要ります。

分岐でループを作る

分岐は2つのレジスタを比べ、条件が合えば飛びます。beq は等しいときに、bne は等しくないときに飛びます。

loop: のようなラベルが、飛び先の名前です。次のプログラムは、8 を5回足します。t0 が回数を数え、a0 が合計を持ちます。bne t0, t1, loop は、t0 が5になるまで上へ戻ります。

RISC-V でループを書く

コマンド
printf '.globl _start\n_start:\n  li a0, 0\n  li t0, 0\n  li t1, 5\nloop:\n  addi a0, a0, 8\n  addi t0, t0, 1\n  bne t0, t1, loop\n  li a7, 93\n  ecall\n' > times.s

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

アセンブルする

コマンド
riscv64-linux-gnu-as times.s -o times.o

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

リンクする

コマンド
riscv64-linux-gnu-ld times.o -o times

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

エミュレータで実行する

コマンド
qemu-riscv64 ./times

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

合計を読む

コマンド
echo $?

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

省略形なしで読み戻す

コマンド
riscv64-linux-gnu-objdump -d -M no-aliases times

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

さらに挑戦

1 から 9 までの奇数の和を出す RISC-V のプログラムを書いてください。使うのは li、add、addi、bne だけです。t0 を 1 から始めて、2ずつ増やします。

まず自分のインタプリタで動かします。次に、times.s と同じように printf でファイルにし、ラボで組み立てて実行します。終了ステータスは 25 になるはずです。

このラボとソースについて: コンパイラとアーキテクチャのラボ:gcc、flex、bison、RISC-V を1台の VM で

授業で使いますか?このモジュールを学生に割り当てると、教員用ガイド、自動採点つきの課題、学生ごとのラボを使えます。