コンピュータシステム概論 SPIM演習 第二回

コンピュータシステム概論
SPIM演習 第二回
(コンピュータシステム概論 2016 年度ホームページ URL
file:///home/course/csI/public_html/2016/welcome.html 学内)
以下の例題を行い、レポートを作成し、課題1~4は授業終了時に、課題5は次の授業の時に提出して下さい。
なお、今回の演習も xspim を使って行ないます。
xspim &
xspim の使用方法を忘れた人は、前回のハンドアウトを参照して下さい。
(pdf 版はシステム概論ホームページから辿れ
ます)
1.1. 例題1 オーバーフロー
リスト1のプログラムは 2147483647 (0x7fffffff) と 2 (0x2) を加えて結果を表示します。結果は 2147483649 に
なることが期待されますが、符号つき整数(int)の最大値は 2147483647(0x7fffffff)なので、2 を加えようとするとオー
バーフローが起こります。
(メッセージ欄に「Exception occurred at PC=0x00400034 Arithmetic overflow」と表示さ
れます)本当のコンピューターでオーバーフローが起こると,OS カーネル内の例外処理をするルーチンが実行されます
が、
xspimでは例外が起こったというメッセージが表示され
(consoleに
「Exception 12 [Arithmetic overflow] occurred
and ignored」
)
、演算結果が 0 になります(つまり ignore(無視)された)
。
.data
dataA: .word 0x7fffffff
dataB: .word 0x00000002
.text
main: lw
$t0, dataA
lw
$t1, dataB
add
$t2, $t0, $t1
# 2147483647
# 2
#$t0 + $t1 -> $t2
li
$v0, 1
move
$a0, $t2
syscall
jr
#print_int system call
$ra
リスト1
次に,7 行目の add を addu に変更して実行してみて下さい。 addu はオーバーフローを検出しない符号なし加算命令
です。今度は-2147483647(0x80000001)という間違った結果が表示されます。(この場合、符号なしとして計算結果は正
しいが、syscall は符号付きの表示なので負の数になってしまう)このように,オーバーフローが起こると正しい計算結
果が得られないということを知っておく必要があります。
1.2. 課題1(演習終了時に提出のこと)
リスト1のdataA の値を0x7ffffffe に変更した時、
表1を参考に色々な値を試して、
オーバーフローにならないdataB
の値の範囲を求めなさい。
(16進数で記述する事)
0x00000000
0
0x00000001
1
..
..
0x7ffffffe
2147483646
0x7fffffff
2147483647
0x80000000
-2147483648
0x80000001
..
-2147483647
..
0xfffffffe
-2
表1 16進表記の数とそれを符号付きと見なした時の対応する10進数
1
0xffffffff
-1
2.1. 例題2 論理演算
論理演算はプログラム中で次のような用途に良く利用されます(図 1)。
・ある特定のビットを 1 にするために,そのビットが 1 で他のビットが全て 0 になっている値で OR する(「ビッ
トを立てる」ともいいます)。
・ある特定のビットを 0 にするために,そのビットが 0 で他のビットが 1 になっている値で AND する(「ビットを
マスク」するともいいます)。
・ビットを反転するために,反転させたいビットがすべて 1 になっている値で Exclusive OR(排他的論理和)を
する。
図 1 論理演算によるビットの操作
この他にも、存在しない命令の代わりに論理演算が使われることもあります。例えば Load Immediate (li $t0,1)
は,MIPS には存在しない SPIM が拡張した命令ですが,SPIM 内部で自動的に OR Immediate (ori $t0,$zero,1)に変
換され、レジスタ0(全てのビットが0)と即値との OR をすることで(ある数と0との OR はその数自身になる)
、結果
的に即値の値をレジスタに格納しています。
リスト2のプログラムは,AND を使ってレジスタ$t1 の下位の 8 ビットをマスクし(0 にする),結果をレジスタ$t2 に
格納します。結果の確認は,レジスタ$t2 の値を直接見て下さい。
main:
.text
li
li
and
jr
$t0, 0xffffff00
$t1, 0x5656
$t2, $t1, $t0
$ra
リスト2
2.2. 課題2(演習終了時に提出のこと)
・リスト2の計算結果は何になるか?(16進数で答えよ)
・リスト2のプログラムの AND 命令を OR 命令に、また XOR 命令に変更したプログラムをそれぞれ作成し、それぞれ
の計算結果を示しなさい。
なお、2 進←→16 進の変換は,bc コマンド(最後のページの補足参照)やシステム概論の変換 Web ページ
(file:///home/course/csI/public_html/2016/conv.html,convns.html)が利用できます。
3.1 例題3 シフトによる乗算/除算
2n をかける,2n で割るという計算は,シフト命令を使って簡単に行なうことができます。
2, 4, 8, ・・・ はそれぞれ 2 進数にすると 10, 100, 1000,・・・ になります。ですから 2n をかける事は桁を上げる(左に
n ビットシフトする)ことになります。逆に右に n ビットシフトすることは 2n で割ることになります。
左シフトには sll(Shift Left Logical),右シフトには srl(Shift Right Logical)という命令を使います。ただし,
符号つき整数を割る(右シフト)場合は sra(Shift Right Arithmetic)を使います。以下のプログラムで,Logical Shift
(論理シフト)と Arithmetic Shift (算術シフト)の違いを確認してみて下さい。論理シフトは左から0がシフト桁数
分代入されますが、算術シフトでは左から符号(一番左端のビットの値)がシフト桁数分代入されます。
2
main:
.text
li
srl
sra
$t0, 0x8000ff00
$t1, $t0, 1
$t2, $t0, 1
#1 ビット右へ論理シフト
#1 ビット右へ算術シフト
sll
$t3, $t0, 2
#2 ビット左へ論理シフト
jr
$ra
リスト3
4.2 例題4 浮動小数点
リスト4のプログラムは浮動小数点演算(加算と乗算)を行っています。浮動小数点を扱うレジスタは今まで使って
来たレジスタと違いますので($t* ではなく $f*)、間違わないようにして下さい。また単精度と倍精度でも使用するレ
ジスタの番号が違います。詳しくは xspim のレジスタの画面の下半分にある Double Floating Point Registers と
Single Floating Point Registers の所をみてください。通常全部の浮動小数点レジスタは見えていませんが、レジス
タ表示域の下線の右端の黒い部分をドラッグすると見えるようになります。
このプログラムでは数値を単精度と倍精度の浮動小数点形式でそれぞれ定義し、それぞれで演算しています。定義さ
れた数値は前回の演習であったように Data Segments にあります。メモリには 32 ビット(1word)づつ格納されていま
す。倍精度は 64 ビットなので 2word(8 バイト)で表現されています。
数値計算の例などを含めて浮動小数点に関して教科書(上)174~199ページにありますので、計算方法を忘れ
た人は読んで下さい。
dataA:
dataB:
dataX:
dataY:
str:
main:
.data
.float 29.6875
.float 29.6875
.double 2.5e-1
.double -4.25
.asciiz " "
.text
l.s
$f8, dataA
l.s
$f16, dataB
add.s
$f24, $f8, $f16
l.d
$f2, dataX
l.d
$f4, dataY
mul.d
$f10, $f2, $f4
li
mov.s
syscall
li
la
syscall
li
mov.d
syscall
jr
#単精度の浮動小数点数値のロード
#単精度の浮動小数点数値の足し算
#倍精度の浮動小数点数値のロード
#倍精度の浮動小数点数値のかけ算
$v0, 2
$f12, $f24
# print_float system call
$v0, 4
$a0, str
# print_string system call
$v0, 3
$f12, $f10
# print_double system call
$ra
リスト4
4.1 課題4(演習終了時に提出のこと)
・短精度浮動小数点形式にて10進数 29.6875 はどのような値になるか16進数8桁で答えよ
・倍精度浮動小数点形式にて10進数 2.5e-1 はどのような値になるか16進数 16 桁で答えよ
・リスト4の2つの計算結果を10進と16進にて答えよ(16 進は自分で求めること、ハンドアウト第三回にある
10進の小数点数を16進で表示するプログラムや google の変換などが有効である。)
3
5. 課題5 総合(本課題については、次週の講義の際に提出してもよい)
教科書(上)170ページ(又はハンドアウト)の乗算アルゴリズム1を使って整数乗算プログラムを書いて下さい。
前回と同じようにプログラムとその説明ならびに実行結果をレポートにまとめて、次の授業の時に提出して下さい。
※ レ ポ ー ト の 書 き 方 は 、 シ ス テ ム 概 論 Web ペ ー ジ の 「 良 い レ ポ ー ト の 書 き 方
file:///home/course/csI/public_html/2016/spim/goodrpt.html (学内)
」を必ず参照して下さい。
なお、教科書では 64 ビットのレジスタを使用していますが,SPIM のレジスタの大きさは 32 ビットなので乗数,被乗
数を 16 ビットとします。また,負の値は扱わない(符号なし)ことにします。図2はプログラムのフローチャートです
(教科書に載っているものに修正を加えたものです)。
図2 乗算プログラムのフローチャート
乗数,被乗数は適当に決めて下さい。値が 16 ビットなのでリスト5のように.half という疑似命令を使ってメモリに
書き込みます。レジスタにこの値をロードする時には lh(Load Half word)を使います。もしくは li で16ビット以下
の値を直接ロードしても構いません。なお、出来れば最初は以下のヒントを見ずに挑戦してみましょう。
.data
dataA: .half 333
#被乗数
dataB: .half 200
#乗数
.text
main: lh
$t0,dataA
lh
$t1,dataB
main:
リスト5
.text
li
li
リスト6
4
$t0,333
$t1,200
ヒント:
・被乗数,乗数の他に繰り返し回数,積(結果)を格納するレジスタが必要です。
・step1: 教科書の図中の「乗数 0」というのは乗数の最下位ビットの意味です。最下位ビットだけが 1 である数と AND
をとると最下位ビットを取り出すことができます。
(図3)
図3 最下位ビットの取り出し
・step1.a: if (A) { B; } のように,
「条件 A を満たす時に B を実行」させたい場合は,
「条件 A を満たさない時に B
を実行しない」というふうに置き換えて考えるとよいでしょう。例えば,$t0 に乗数の最下位ビットを調べた結果(0
か 1)が入っていれば,以下のように書けます。
skip:
beq $t0, $zero, skip
被乗数を積レジスタに加え結果を積レジスタに入れる
被乗数レジスタを 1 ビット左にシフト
・step2: sll を使います。
・step3: srl を使います。
6. 補足
6.1 bc の使い方
bc(1)はコマンドラインの電卓です。四則演算,べき乗,進数変換などの計算をすることができます。自分が作成した
プログラムの計算結果が正しいかなどのチェックに使ってみましょう。
進数変換をするには,入力する基数(ibase)と出力する基数(obase)を設定します(任意の基数を指定できます)。以下
に実際の使用例を載せておきますので興味のある人は試してみて下さい。なお、実行例は bc の出力を下線にて示して
います。
(実際には下線は付きません)
% bc
obase=10
ibase=16
F0A0
61600
F0*3
720
ibase=A
obase=2
88
1011000
quit
%
<-<-<-<-<-<-<-<-<-<-<--
出力(表示)を 10 進数にする
入力を 16 進数にする
入力
出力(16 進数→10 進数)
入力(計算もできる)
出力
入力を 10 進数にする(注:現在の ibase で入力する)
出力(表示)を 2 進数にする
入力
出力(10 進数→2 進数)
終了
5
6.2 2進数、10進数、16進数の変換
・ Google による
Google で「0xff00 to decimal」
(16進→10進)などのように書けば変換をしてくれます。なお、decimal(10進)
の他、hex(16進)
、binary(2進)などがありますので必要に応じて変換して見て下さい。定数の表記は16進は 0x、
2進は 0b(例 0b101010)となります。なお、符号付きの数は残念ながら補数には変換されません。
・ ネット上のツール
符号付/なしの両方に対応しているものでは、以下のサイトなどが使いやすいでしょう。他にも沢山ありますから、
色々検索して使いやすい物を探して見て下さい。
http://hogehoge.tk/tool/number.html
・ 簡単な C プログラムによる表示
以下のような簡単なプログラムを書くと32ビットの補数表記の16進数を符号付の10進数として表示する事が可
能です。使いやすいように自分で工夫してみてください。なお、16進数で表示させたい場合の printf の書式は%x で
す。
#include<stdio.h>
main(){
int x = 0xff001122; /* 表示させたい値 */
printf(“%d¥n”,x);
}
6
(切り離して提出)
学籍番号:
氏名:
課題1
課題2
計算結果:
OR:
XOR:
課題4
2.5e-1
29.6875
10進
16進
10進
16進
感想
7