持っていないプロセッサ用のプログラム
スマートフォン、ノートパソコン、サーバーは、それぞれ違うプロセッサを使っています。プロセッサは、自分の命令しか分かりません。RISC-V は、だれでも作ってよい公開の設計です。このマシンは RISC-V ではありませんが、エミュレータを使えば RISC-V のプログラムを動かせます。
このレッスンが終わると
メモ
短い RISC-V のプログラムを、アセンブリから終了ステータスまでたどることができる。
キーワード
- プロセッサ:コンピュータの中で命令を実行する部分。
- 命令:プロセッサができる小さな1歩。足し算など。
- レジスタ:プロセッサの中にある、ごく小さく速い記憶場所。
- エミュレータ:別のプロセッサのようにふるまうプログラム。
- 終了ステータス:プログラムが終わるときに返す数。
- キャッシュ:最近使ったものを置いておく、小さく速いメモリ。
ウォームアップ:すでに知っていること
メモ
頭の中で答えてみましょう。1. コンパイラはソースコードを何に変えますか。2. 機械語をつないで1つのプログラムにするのは、どの段階ですか。3. アセンブリとは何ですか。今日は、人が書いたアセンブリを読みます。
はじめる前に
メモ
このレッスンの上にあるバーのラボを起動を押してください。このラボは、あなた専用の Ubuntu のマシンまるごとです。コンテナよりも、立ち上がるまで少し時間がかかります。実行ボタンを押すと、コマンドが順番にマシンのターミナルへ入力されます。「マシンはまだ起動中です」と出たら、数秒待ってからもう一度押してください。自分で入力と書かれたところでは、プログラムがあなたの入力を待ちます。バーのターミナルを開くを押して、自分で打ち込みます。
RISC-V のプログラムを1行ずつ
add.s には命令が5つあります。li はレジスタに数を入れます。a0 に 2、a1 に 3 です。add は2つを足し、答えを a0 に入れます。li a7, 93 はプログラムを終わらせる Linux のシステムコールを選び、ecall がそれを呼びます。Linux は a0 の数を終了ステータスにします。
cd ~/archここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
cat add.sここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
チェック
ヒント
add a0, a0, a1 の後、a0 には何が入っていますか。答え: 5。2 と 3 の和です。
組み立てて、エミュレータで動かす
アセンブラが言葉を機械語に変え、リンカがプログラムにします。file は、これが RISC-V 用だと示します。このプロセッサでは動かせないので、qemu-riscv64 が RISC-V の命令を1つずつ実行します。何も表示されません。echo $? が、プログラムの残した終了ステータス 5 を表示します。
riscv64-linux-gnu-as add.s -o add.oここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
riscv64-linux-gnu-ld add.o -o addここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
file addここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
qemu-riscv64 ./addここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
echo $?ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
よくある間違い
注意
echo $? はプログラムが最後に表示したものを出す、と考える人がよくいます。実際に出すのは終了ステータスで、プログラムが終わるときに返す 0 から 255 までの数です。2 と 3 を 200 と 100 に変えて組み立て直すと、答えは 44 になります。300 は入りきらず、0 に戻って数え直すからです。
命令は数である
objdump -d は、プロセッサから見たプログラムを表示します。各行は、アドレス、16進数で書いた命令、言葉で書いた命令の順です。どの数も16進数で8けたです。ここにある命令は、どれも32ビットだからです。ecall は 00000073 です。
riscv64-linux-gnu-objdump -d addここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
キャッシュがメモリを速く見せる
loop.c は、1600万個の数の表を2回足し合わせます。行ごとに進むと、次の数はメモリ上で前の数のすぐ隣にあり、キャッシュがもう読み込んでいます。列ごとに進むと、次の数は 16 KB 先にあるので、プロセッサはほぼ毎回メモリを待ちます。合計はどちらも 16777216 ですが、時間は違います。列ごとのほうが何倍もかかります。
gcc -O2 -o loop loop.cここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
./loopここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
自分で入力:プロセッサが進むのを見る
ターミナルで gdb ./loop と打ちます。break main、続けて run と打つと、プログラムは main の最初で止まります。info registers pc と打つと、次の命令のアドレスであるプログラムカウンタ(pc)が見えます。stepi で命令を1つだけ実行し、もう一度 pc を見てください。先へ進んでいます。最後に quit、続けて y と打ちます。
最後のチェック
ヒント
前を見ないで答えましょう。1. レジスタとは何ですか。2. このマシンで RISC-V のプログラムを動かすコマンドはどれですか。3. echo $? は何を表示しますか。4. 行ごとのほうが速いのはなぜですか。答え: プロセッサの中の、ごく小さく速い記憶場所。qemu-riscv64。直前のコマンドの終了ステータス。次の数がもうキャッシュにあるから。
先生へ
ヒント
このレッスンは VM ラボで行います。学生はそれぞれ自分の Ubuntu マシンを持ち、実行ボタンはそのターミナルに入力して、表示された結果を見せます。学習のポイント:1. プロセッサは、レジスタを使う命令を実行する。2. アセンブラとリンカがアセンブリをプログラムにし、エミュレータがそれを別のプロセッサ用に動かす。3. 直前に読んだ場所の近くのメモリは、キャッシュのおかげで速い。よくある間違い:終了ステータスを、プログラムの表示だと思ってしまう。準備するもの:ラボとブラウザ。ヒント:./loop の前に、どちらが速いか、どれくらい違うかをクラスに予想させてください。このラボには検査がなく、採点もしません。成績が必要なら、独自の提出物を出してください。