340 likes | 557 Views
マイクロプロセッサ. 第 2 回. 命令:コンピュータの言葉(その1) アセンブラ と 機械語. 関根 優年 田向 権. 本年度の授業計画. 教科書および参考資料. パターソン&ヘネシー コンピュータの構成と設計 (上) ハードウェアとソフトウェアのインタフェイス 第 3 版 第 2 章 「命令:コンピュータの言葉」 “ SPIM” A MIPS32 Simulator 関根研究室の授業用ページから移動 「農工大 関根研究室」で検索 トップページからマイクロプロセッサのページへ..
E N D
マイクロプロセッサ 第2回 命令:コンピュータの言葉(その1) アセンブラ と 機械語 関根 優年 田向 権
教科書および参考資料 • パターソン&ヘネシー コンピュータの構成と設計 (上) ハードウェアとソフトウェアのインタフェイス 第3版 第2章 「命令:コンピュータの言葉」 • “SPIM” A MIPS32 Simulator 関根研究室の授業用ページから移動 「農工大 関根研究室」で検索 トップページからマイクロプロセッサのページへ. 上記ページの指示に従いSPIMシミュレータをインストールしておくこと
MIPSアセンブリ言語について • MIPSアセンブリ言語は,教科書にまとめられている.常に開いて参考にすること. 第3版:81,82ページ,および, 教科書最初の緑色の折込ページ • レジスタ,メモリ,メモリアドレスを常に意識 • 慣れるまではノートに作図しながら考える • メモリロード・ストア,条件分岐さえ理解できれば大丈夫 • C言語に自信の無い人は必ず復習を! • 本授業は,プログラミングの基礎知識があることを前提として進めます
命令・命令セット 命令(instruction) : コンピュータ言語の言葉 命令セット(instruction set) : コンピュータの語彙 命令列 ⇒ 機械語によるプログラムのコーディングが必要 (アセンブリ言語) 本講義では MIPS Computer社の命令セット を用いて説明する。 MIPS Computer社の命令セットは 東芝,NEC,日立, 任天堂(Nintendo64), ソニー(Play station,PS2, PSP), シリコングラフィクス などで用いられている
コンピュータ・ハードウェアの演算 コンピュータでは算術演算が不可欠 以下ではMIPSの命令セット 加算命令 add a, b, c 2つの変数b,cを加えて、その和をaに収める 例えば、変数b,c,d,eの和を変数aに格納する add a, b, c# bとcの和をaに格納 add a, a, d# 結果として、bとcとdの和をaに格納 add a, a, e# 結果として、bとcとdとeの和をaに格納 # : この記号の右側はコメント領域。コンピュータはコメントを無視 アセンブリ言語では、1行に1命令(複数行にまたがる命令は×)
コンピュータ演算の中心 ALU: Arithmetic Logic Unit rs rt 加減乗除 論理演算 ALU acm Acm: accumulator
MIPSの命令セットの単純性 add a, b, c 命令 オペランド1, オペランド2, オペランド3 全ての命令が必要とするオペランドの数を必ず3つにする ⇒ ハードウェアの制御構造を単純化できる オペランド数が命令によって違うと、ハードウェアが複雑になる 設計原則1 : 単純性は規則性につながる (p.46) 加算、減算のMIPS命令
例題) C ⇒ MIPSコードへのコンパイル 答) 例題) 次のC言語のステートメントを、 MIPSコードに変換せよ add a, b, c sub d, a, e a = b + c; d = a – e; 例題) 次のC言語のステートメントを、 MIPSコードに変換せよ f = (g + h) – (i + j); 答) 括弧内の演算結果をテンポラリの変数t0, t1に格納する add t0, g, h# 一時変数t0にg+hを記憶 add t1, i, j # 一時変数t1にi+jを記憶 sub f,t0,t1 # 変数fにt0-t1を記憶
コンピュータ・ハードウェアのオペランド C言語とは異なり,MIPSコードではオペランドに変数指定ができない。 算術命令のオペランドはある特殊な記憶領域を用いる レジスタ(register) MIPSアーキテクチャでは、 レジスタ 1語(word) = 32ビット長 レジスタの数は32個 レジスタの数が無数でない理由は? 設計原則2 : (p.48) 小さければ小さいほど高速になる b 算術 演算 (add) c レジスタ番号は0~31と書けるが、 MIPSでは、$記号の後に数字を使い表記する。 a 32個 Cプログラム中の変数に対応するレジスタ $s0, $s1, … コンパイル時に必要とされる一時レジスタ $t0, $t1, … add a,b,c レジスタ 32ビット
例題)レジスタを使用したCの代入文のコンパイル例題)レジスタを使用したCの代入文のコンパイル 例題) 次のC言語のステートメントを、 MIPSコードに変換せよ f = (g + h) – (i + j); ただし、変数f,g,h,i,jはそれぞれ レジスタ$s0,$s1,$s2,$s3,$s4に格納されるとする。 答) 括弧内の演算結果をテンポラリレジスタ$t0,$t1に格納する add $t0,$s1,$s2# 一時レジスタ$t0に$s1+$s2を記憶 add $t1,$s3,$s4 # 一時レジスタ$t1に$s3+$s4を記憶 sub $s0,$t0,$t1 # レジスタ$s0 (f)に$t0-$t1を記憶
メモリの使用 変数がたくさんある ⇒ レジスタの数が足りない メモリの使用 入力 記憶(メモリ) 制御 キーボード マウス など プログラム本体及び プログラムが必要と するデータ格納領域 オーバーフロー データバス 出力 ディスプレイ など プロセッサ(=制御+データバス) プログラムの命令により動く 数値演算、条件分岐、入出力データ送出
メモリとレジスタ間のデータ転送 メモリ・ アドレス メモリ プロセッサ : : : : 3 2 1 0 算術 演算 アドレスは 配列の役目 メモリ[0]=1 メモリ[1]=1000 : : データ 転送命令 レジスタ プロセッサ内にある 記憶データ量小 プロセッサの外にある 記憶データ量大 データ転送命令: メモリとレジスタの間をデータを転送する命令 ロード命令: メモリからレジスタへデータを転送する命令 ストア命令: レジスタからメモリへデータを転送する命令
MIPSの実際のメモリ・アドレス 多くのプログラムは、8ビットのバイト(byte)が大きな役目を持つ ⇒ メモリアドレスもバイト単位で表す ビッグエンディアン方式 リトルエンディアン方式 語(32ビット)アドレスは、4バイト中 の最後のアドレスとする 語(32ビット)アドレスは、4バイト中 の先頭アドレスとする メモリ・ アドレス (語アドレス) メモリ メモリ・ アドレス (語アドレス) メモリ 8bit 8bit 8bit 8bit 8bit 8bit 8bit 8bit 0 4 8 12 : : : : 0 4 8 12 : : : : MIPSはこっち
配列の場合 メモリの 開始アドレス 配列 A メモリ・ アドレス メモリ : : : xxa xxb xxc xxd : : : : : 0 1 2 3 : : xxa データ 転送命令 rs rt ALU acm レジスタ A[0]=1 A[1]=1000 :
例題) オペランドがメモリ中にある代入文のコンパイル例題) オペランドがメモリ中にある代入文のコンパイル 例題) 100語からなる配列Aについて、次のCのステートメントを MIPSコードに変換せよ。 g = h + A[8]; ただし、変数g,hはそれぞれレジスタ$s1,$s2、配列の 開始アドレス(ベースアドレス)はレジスタ$s3に割り付けられている。 答) メモリから配列の要素A[8]をテンポラリレジスタ$t0に格納する ここで、A[8]の語アドレスは$s3 + 8x4であるので、次のロード命令を行う。 lw $t0,32($s3)# 一時レジスタ$t0にA[8]を記憶 あとは加算命令 add $s1,$t0,$s2# gにA[8]+hを記憶 ロード命令 lw $t0,32($s3) メモリアドレス $s3+32の情報を、レジスタ$t0へロード
例題) ロード、ストアがある代入文のコンパイル例題) ロード、ストアがある代入文のコンパイル 例題) 100語からなる配列Aについて、次のCのステートメントを MIPSコードに変換せよ。 A[12] = h + A[8]; ただし、変数hはそれぞれレジスタ$s2、配列の 開始アドレス(ベースアドレス)はレジスタ$s3に割り付けられている。 答) メモリから配列の要素A[8]をテンポラリレジスタ$t0に格納する lw $t0,32($s3)# 一時レジスタ$t0にA[8]を記憶 加算した結果をテンポラリレジスタ$t0に格納する add $t0,$t0,$s2# レジスタ$t0に$t0+$s2を記憶 メモリの配列の要素A[12]にテンポラリレジスタ$t0を格納する sw $t0,48($s3)# 一時レジスタ$t0をA[12]を記憶 ストア命令 sw $t0,32($s3) メモリアドレス $s3+48に、レジスタ$t0の値をストア
例題)配列インデックスに変数を用いたコードのコンパイル例題)配列インデックスに変数を用いたコードのコンパイル 例題) 100語からなる配列Aについて、次のCのステートメントを MIPSコードに変換せよ。 g = h + A[i]; ただし、変数g,h,iはそれぞれレジスタ$s1,$s2,$s4、配列の 開始アドレス(ベースアドレス)はレジスタ$s3に割り付けられている。 答) A[i]のアドレス$s3 + 4×i = $s3 + 4×$s4を$t0に格納 add $t0,$s4,$s4# $t0にiの2倍の値を記憶 add $t0,$t0,$t0# $t0にiの4倍の値を記憶 add $t0,$s3,$t0# $s3 + 4*iを$t0に記憶 $t0に格納されたメモリアドレスの値 (A[i]) を$t0にロードする lw $t0,0($t0)# $t0にA[i]を記憶 add $s1,$t0,$s2# gにA[i]+hを記憶
メモリとレジスタの効率的使用 メモリ レジスタアクセスより低速 記憶データ量大 レジスタ 高速アクセス 記憶データ量小 コンパイラ ー 頻繁に使用する変数をレジスタに それ以外の変数をメモリ上におく レジスタのスピルアウト(あふれ出る) レジスタの代わりに、ロード命令、ストア命令 を用いて、メモリを変数記憶領域として使うこと ここまでのMIPS命令
コンピュータ内での命令の表現 MIPSアセンブリ言語命令のマシン命令への翻訳 例題) 次のMIPSコードを2進数のマシン命令に変換せよ add $t0, $s1, $s2 答) 10進数による表現は次のようなものである 演算の 種類 (add) 演算の 種類 (add) 第2オペランド レジスタ番号 $s2=18 第3オペランド レジスタ番号 $t0=8 第1オペランド レジスタ番号 $s1=17 使われて いない レジスタ番号と$s0,$s1, …, $t0,$t1の対応 $s0,$s1,…,=レジスタ16、レジスタ17, … $t0,$t1,…,=レジスタ8,レジスタ9, … 2進数による表現は次のようなものである(機械語、マシンコード) 6ビット 5ビット 5ビット 6ビット 5ビット 5ビット 命令(32ビット長)はいくつかのフィールドに分かれている
r進数表現について r進数表現 各桁のとるR種類の値は、 次の集合LRの要素 LR = {0,1,…,R-1} 正の整数Xに対するn桁のR進数 (xn-1 xn-2 … x1 x0 )R xi ∈ LR は次の関係が成立する。 X = xn-1Rn-1+xn-2Rn-2+…+ x1R+ x0 2進数の場合 正の整数Xに対するn桁の2進数 (xn-1 xn-2 … x1 x0 )2 xi ∈ L2 ( = {0,1}) X = xn-12n-1+xn-22n-2+…+ x12+ x0 各桁をビット(bit:binary digit) 最上位桁をMSB(Most Significant Bit) 最下位桁をLSB(Least Significant Bit)と呼ぶ 16進数はメモリ番地などのデータを表す ために、2進数の代わりによく用いられる
MIPSの命令形式(Rフォーマット) MIPS命令長は32ビット Rフォーマット(register) 6ビット 5ビット 5ビット 6ビット 5ビット 5ビット 各フィールドの説明 ・op : 命令の基本操作(opcode) ・rs : 第1のソース・オペランドのレジスタ ・rt: 第2のソース・オペランドのレジスタ ・rd : 演算結果を収めるレジスタ ・shamt : シフト量(後で説明、ここまでは0) ・funct : 機能、命令操作フィールドのバリエーション 上で示したフィールドよりも長いフィールドに対応する必要がある場合あり 例) ロード命令(lw)-5ビットでは32(メモリの番地数はこれよりも全然多い) 設計原則4 : 優れた設計には適度な妥協が必要である
MIPSの命令形式(Iフォーマット) データ転送用の命令形式 Iフォーマット(indirect) 16ビット 6ビット 5ビット 5ビット addressの範囲は、±32,768バイト(215 、すなわち8192語) 例) lw $t0, 32($s3) op=35, rs=19, rt=8, address=32 MIPS命令の符号化
例題) MIPSアセンブリ言語の機械語の翻訳 例題) Cステートメント A[300]=h+A[300]; のコンパイル結果は次のように与えられる。(Aのベースは$t1,hは$s2に割付) lw $t0,1200($t1) add $t0,$s2,$t0 sw $t0,1200($t1) このMIPSのマシンコードはどうなるか? 答) 10進法記述だと 2進法記述だと
条件判定用の命令 入力データと計算によって得られた値に基づいて、別の命令を行う 条件判定・分岐能力が必要 プログラミング言語での条件判定 ① if文を用いる ② goto文とラベル文を用いる MIPSの条件分岐命令の例 beq register1,register2,L1 register1とregister2が等しければ、L1というラベルの 付いたステートメントへプログラム分岐する(branch if equal) bne register1,register2,L1 register1とregister2が等しくないとき、L1というラベルの 付いたステートメントへプログラム分岐する(branch if not equal) gotoの付随するif文に類似している
例題) if文の条件分岐へのコンパイル 例題) 次のCコードをコンパイルしたときのMIPSコードを示せ if(i==j) goto L1; f = g + h; L1: f = f - i; 変数f,g,h,i,jはそれぞれレジスタ$s0~$s4に割り付けられている。 答) ラベルL1は後で定義するとして、iとjの条件判定MIPSコードは beq $s3,$s4,L1# i=jならL1に分岐 add $s0,$s1,$s2# f=g+h プログラム内蔵方式のコンピュータではメモリにプログラムが格納される L1 :sub $s0,$s0,$s3# f=f-i(常に実行される) ラベルL1は減算命令が格納されたメモリアドレス ラベルを用いることにより、分岐先のアドレス計算を プログラムにする必要がない。
例題) if-then-else文の条件分岐へのコンパイル例題) if-then-else文の条件分岐へのコンパイル 例題) 次のCコードをコンパイルしたときのMIPSコードを示せ if(i==j) f = g + h; else f = g - h; 変数f,g,h,i,jはそれぞれレジスタ$s0~$s4に割り付けられている。 答) if文中のすぐ後のコードを飛び越す方が効率的(ラベルElseは後で定義) bne $s3,$s4,Else# i≠jならElseに分岐 add $s0,$s1,$s2# f=g+h ここで無条件分岐(if文の最後まで分岐)する必要がある j Exit# ラベルExitへジャンプ else以降のコードは以下の通り Else: sub $s0,$s1,$s2# f=g-h(i=jならスキップ) Exit: 無条件分岐命令 j Label# ラベルLabelへジャンプ
例題)変数の配列インデックスを伴うループのコンパイル例題)変数の配列インデックスを伴うループのコンパイル 例題) 次のCコードをコンパイルしたときのMIPSコードを示せ Loop : g = g + A[i]; i = i + j; if(i!=h) goto Loop; Aは100個の要素からなる配列とし、そのベースは$s5、変数 g,h,i,jはそれぞれレジスタ$s1~$s4に割り付けられている。 答) Loop : add $t1,$s3,$s3 # ここは前の例題で add $t1,$t1,$t1 # 出ているので省略 add $t1,$t1,$s5# lw $t0,0($t1) # ここまででA[i]をt0に格納 add $s1,$t0,$s1 # g=g+A[i] add $s3,$s3,$s4 # i=i+j 基本ブロック 最後の命令で条件分岐 bne $s3,$s2,Loop# i≠hならLoopへ
例題) whileループのコンパイル 例題) 次のCコードをコンパイルしたときのMIPSコードを示せ while (save[i] == k) i = i + j; 配列saveのベースは$s6、変数i,j,kは それぞれレジスタ$s3~$s5に割り付けられている。 答) Loop: add $t1,$s3,$s3 # ここは前の例題で add $t1,$t1,$t1 # 出ているので省略 add $t1,$t1,$s6# lw $t0,0($t1) #save[i]をt0に格納 bne $t0,$s5,Exit # save[i]≠kでExitへ add $s3,$s3,$s4 # i=i+j j Loop # Loopへ Exit: save[i]とkの比較による条件分岐 無条件分岐
大小を用いた条件判定 レジスタの値の大小比較結果を出す命令(set on less than) slt $t0,$s3,$s4 レジスタ$s3の値がレジスタ$s4の値よりも小さいとき、 レジスタ$t0の値を1, それ以外では0に設定する。 slt命令と条件分岐命令を組み合わせることで、大小の条件判定が可能 例題) 変数a(レジスタ$s0が割付)が変数b(レジスタ$s1が割付)よりも 小さいことを判定し、真であればラベルLessへ分岐するコードを示せ 答) 変数aと変数bの大小比較 slt $t0,$s0,$s1 # aとbの大小比較結果を$t0へ bne $t0,$zero,Less #a<bではないことが成立しないなら、 # つまり、a<bであればLessへ分岐 $zero: レジスタ0に対応。常に値が0とする
case文/switch文 case / switch文 一つの変数の値に基づき、いくつかの処理から一つ選択 スイッチの実現方法 ① if-then-else構文をいくつもつなげた形での条件判定 ② それぞれの場合の処理のアドレスを表にして、インデックス に従い該当処理へジャンプする ジャンプアドレス表 - 分岐する処理のアドレスの表 MIPSでは②の手法をサポート ⇒ ジャンプレジスタ(jr)命令 レジスタ中に指定されているアドレスに無条件にジャンプする命令 例題) 次のCコードをコンパイルしたときのMIPSコードを示せ switch (k) {case 0: f=i+j; break; case 1: f=g+h; break; case 2: f=g-h; break; case 3: f=i-j; break;} ここでf~kは$s0~$s5,$t2には値2に設定されている
例題の答)ジャンプアドレス表を使用してのswitch文のコンパイル例題の答)ジャンプアドレス表を使用してのswitch文のコンパイル まず,kが0~3の値かどうかをチェック 答) slt $t3,$s5,$zero # k<0かチェック bne $t3,$zero,Exit #k<0であればExitへ slt $t3,$s5,$t2 # k<4かチェック beq $t3,$zero,Exit #k≧4であればExitへ switch変数のkを使用して、ジャンプアドレス表のインデックス を定める。 add $t1,$s5,$s5 # 2*kを$t1に add $t1,$t1,$t1 # 4*kを$t1に ここで、メモリ中の4つの連続する語にラベルL0,L1,L2,L3 に対応するアドレスが保持され、開始アドレスの値が$t4に あるとする。
例題の答)ジャンプアドレス表を使用してのswitch文のコンパイルーII例題の答)ジャンプアドレス表を使用してのswitch文のコンパイルーII add $t1,$t1,$t4 # Jumptable[k]のアドレスを$t1に lw $t0,0($t1) # Jumptable[k]の値を$t0に レジスタ$t0の値に基づき無条件ジャンプ(ジャンプレジスタ命令) jr $t0 # レジスタ$t0に基づいてジャンプ switch文のラベル L0: add $s0,$s3,$s4 #k=0であれば、i+jをfに代入 j Exit # このケースの終了 L1: add $s0,$s1,$s2 #k=1であれば、g+hをfに代入 j Exit # このケースの終了 L2: sub $s0,$s1,$s2 #k=2であれば、g-hをfに代入 j Exit # このケースの終了 L3: sub $s0,$s3,$s4 #k=3であれば、i-jをfに代入 Exit:
ここまでのMIPSのオペランド、命令 MIPS命令 命令形式 R形式 (算術命令) 6ビット 5ビット 5ビット 6ビット 5ビット 5ビット I形式 (データ転送・ 分岐命令) 16ビット 6ビット 5ビット 5ビット