1 / 32

マイクロプロセッサ

マイクロプロセッサ. 第 3 回. 命令:マシンの言葉(その2). 関根 優年. MIPS の命令形式( R フォーマット). MIPS 命令長は 32 ビット. R フォーマット (register). 6 ビット. 5 ビット. 5 ビット. 6 ビット. 5 ビット. 5 ビット. 各フィールドの説明. ・ op : 命令の基本操作 (opcode) ・ rs : 第1のソース・オペランドのレジスタ ・ rt : 第2のソース・オペランドのレジスタ ・ rd : 演算結果を収めるレジスタ

Download Presentation

マイクロプロセッサ

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. マイクロプロセッサ 第3回 命令:マシンの言葉(その2) 関根 優年

  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(メモリの番地数はこれよりも全然多い) 設計原則3 : 優れた設計には適度な妥協が必要である

  3. 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命令の符号化

  4. ここまでのMIPSのオペランド、命令 MIPS命令 命令形式 R形式 (算術命令) 6ビット 5ビット 5ビット 6ビット 5ビット 5ビット I形式 (データ転送・ 分岐命令) 16ビット 6ビット 5ビット 5ビット

  5. コンピュータ内での命令の表現 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ビット長)はいくつかのフィールドに分かれている

  6. コンピュータ演算の中心 ALU: Arithmetic Logic Unit rs rt 加減乗除 論理演算 ALU acm Acm: accumulator

  7. コンピュータ・ハードウェアのオペランド C言語とは異なり,MIPSコードではオペランドに変数指定ができない。 算術命令のオペランドはある特殊な記憶領域を用いる レジスタ(register) MIPSアーキテクチャでは、 レジスタ 1語(word) = 32ビット長 レジスタの数は32個 レジスタの数が無数でない理由は? 設計原則2 :  小さければ小さいほど高速になる。 b 算術 演算 (add) c レジスタ番号は0~31と書けるが、 MIPSでは、$記号の後に数字を使い表記する。 a 32個 Cプログラム中の変数に対応するレジスタ $s0, $s1, … コンパイル時に必要とされる一時レジスタ $t0, $t1, … add a,b,c レジスタ 32ビット

  8. メモリとレジスタ間のデータ転送 メモリ・ アドレス メモリ プロセッサ : : : : 3 2 1 0 算術 演算 アドレスは 配列の役目 メモリ[0]=1 メモリ[1]=1000 : : データ 転送命令 レジスタ  プロセッサ内にある 記憶データ量小 プロセッサの外にある 記憶データ量大 データ転送命令:    メモリとレジスタの間をデータを転送する命令 ロード命令: メモリからレジスタへデータを転送する命令 ストア命令: レジスタからメモリへデータを転送する命令

  9. メモリとレジスタの効率的使用 メモリ  レジスタアクセスより低速  記憶データ量大 レジスタ  高速アクセス 記憶データ量小 コンパイラ ー 頻繁に使用する変数をレジスタに         それ以外の変数をメモリ上におく レジスタのスピルアウト(あふれ出る) レジスタの代わりに、ロード命令、ストア命令 を用いて、メモリを変数記憶領域として使うこと ここまでのMIPS命令

  10. コンピュータハードウェア内での手続きのサポートコンピュータハードウェア内での手続きのサポート 手続き、サブルーチン(Cでいえば関数)はどうするのか? 手続きを行うときの手順 手続き終了後には、何も なかったように復帰可能とする 1.手続きからアクセスできる場所にパラメータを置く 2.手続きに制御を移す 3.手続きに必要なメモリ資源を入手する 4.必要なタスクを実行する 5. 呼び出し元のプログラムからアクセスできる   場所に結果を置く 6.制御を元の位置に戻す 呼び出し元のプログラム のメモリ領域 手続き用のレジスタ領域  パラメータ、結果などの保持 プロセッサ 算術 演算 手続きプログラム のメモリ領域 手続き用のメモリ領域確保 レジスタ

  11. 手続き読出しのためのレジスタ・命令 Cでいえば、 int func(int a,int b) // 引数 { : return xxx;// 返り値 } 手続き読み出しのためのレジスタ ・$a0~$a3 : 4個の引数レジスタ、パラメータを渡すために使用 ・$v0~$v1 : 2個の返り値レジスタ、結果の値を返すために使用 ・$ra : 1個の戻りアドレス・レジスタ、制御を元に戻すために使用 ①手続き用の引数を$a0~$a3に渡す ②手続きを開始する命令 : jal(jump and link)命令 手続きのアドレスにジャンプすると同時に、 次の命令のアドレスをレジスタ$raに保持する jal ProcedureAddress (PC+4をレジスタ$raに退避させる) PC(プログラムカウンタ)-現在実行中の命令アドレスが保持されるレジスタ ③手続き本体 ④手続きの返り値を$v0~$v1に渡す ⑤手続きを終了する jr $ra 次の命令アドレス(レジスタ$raに格納されている)へジャンプ

  12. もっと多くのレジスタを使用する場合 メモリにレジスタを スピルアウト(退避)  手続きのための引数、戻り値に必要とされる レジスタ数がそれぞれ4個,2個を超えたらば? スタック プッシュ(push)  スタックに  データを入れる スタックポインタ を1語分減少 メモリ New reg Old reg : : : : : レジスタ の書込 Old reg : : : : : スタックポインタ (退避先のメモリ アドレス位置) スタック 領域 ポップ(pop)  スタックに  データを出す スタックポインタ を1語分増加 スタックポインタを動かし、 レジスタを退避するデータ構造 : : : : : レジスタ の読出 MIPSアーキテクチャでは、スタック ポインタ専用のレジスタ$spがある

  13. 例題) 他の手続きを呼出さない手続きのコンパイル例題) 他の手続きを呼出さない手続きのコンパイル 例題) 次のC言語のステートメントを、MIPSコードに変換せよ int leaf_example (int g, int h, int i, int j){ int f; f = (g + h) - (i + j); return f; } なお、4,8,12といった定数を直接加算 または減算ができるとする 答) パラメータ変数 g, h, i, jは引数レジスタ$a0,$a1,$a2,$a3、fは$s0とする Leaf_example : sub$sp,$sp,12 # スタックに3語分のスペースをとる sw $t1,8($sp) # レジスタ$t1の値を退避 sw $t0,4($sp) # レジスタ$t0の値を退避 sw $s0,0($sp) # レジスタ$s0の値を退避 add $t0,$a0,$a1# g+hが$t0に記憶 add $t1,$a2,$a3 # i+jを$t1に記憶 sub $s0,$t1,$t2 # 変数fに$t0-$t1を記憶 add $v0,$s0,$zero #fを返す プッシュ操作 関数の中での計算 ポップ操作

  14. 例題) 他の手続きを呼出さない手続きのコンパイル-2例題) 他の手続きを呼出さない手続きのコンパイル-2 lw $s0,0($sp) # レジスタ$s0の値を復元 lw $t0,4($sp) # レジスタ$t0の値を復元 lw $t1,8($sp) # レジスタ$t1の値を復元 add $sp,$sp,12 # スタックから3語分のスペースを除く jr $ra # 呼び出し元のルーチンにジャンプして戻る ここで$t0~$t7は手続き時に破壊されてもよいとした

  15. 入れ子にされた手続き 手続き内に、他の手続きさらには自分自身がいる場合はどうする? まともにやると、   手続き用の引数レジスタ $a0~$a3   関数内で計算に用いられているレジスタ 戻りアドレスレジスタ $ra が競合してしまう。 手続きの呼び出し元 に復帰不能になる 保存されるべきほかの全てのレジスタ をスタック上にプッシュする 呼び出し側 : 呼び出し後に必要となる引数レジスタ$a0~$a3、一時レジスタ $t0~$t7があれば、プッシュ 被呼び出し側: 戻りアドレスレジスタ$ra及び被呼び出し方で使用する退避レジ           スタ$s0~$s7をプッシュ。 スタックポインタの$spを、スタック中に格納されるレジスタに設定 手続きから戻るときは、レジスタをメモリから復元し、スタック・ポインタを再調整する

  16. 例題) 入れ子状にリンクされた、再帰型手続きのコンパイル例題) 入れ子状にリンクされた、再帰型手続きのコンパイル 例題) 次の階乗計算のC言語のステートメントを、MIPSコードに変換せよ int fact (int n){ if(n < 1) return (1); else return (n*fact(n-1)); } 答) パラメータ変数nは引数レジスタ$a0に相当する fact : sub$sp,$sp,8 # スタックに2語分のスペースをとる sw $ra,4($sp) # 戻りアドレスの退避 sw $a0,0($sp) # 引数レジスタ$a0の退避 slt $t0,$a0,1 # n<1であるかをチェック beq $t0,$zero,L1 # n≧1であれば、L1に分岐 add $v0,$zero,1# $v0に1を返す. add $sp,$sp,8 # スタックを2語分のスペースを落とす jr $ra # 呼び出し元に戻る L1: sub $a0,$a0,1 # n=n-1 jal fact # 引数n-1を使ってfactを呼び出す lw $a0,0($sp) # 引数nの復元 lw $ra,4($sp) # 戻りアドレスを復元する add $sp,$sp,8 # スタックから2語分のスペースをおとす mul $v0,$a0,$v0 # n * fact(n - 1)を返す jr $ra # 呼び出し元に戻る プッシュ操作 ここで再帰 終了 ポップ操作 mul $s0,$s1,$s2 は乗算命令としている

  17. MIPSのレジスタ規約 レジスタ番号1は、アセンブラ用に予約($at) レジスタ番号26-27は、オペレーティングシステム用に予約($k0-$k1) 32個のレジスタ フレームポインタ($fp): 手続き用のデータ格納領域(手続きフレーム)のポインタ               手続き中にスタックポインタが変わる場合に有効 グローバルポインタ($gp): Cでいうグローバル変数(手続きの外で定義された                  変数)に相当するレジスタ

  18. 数値を超えて アルファベット文字 ー ASCIIコード(7bit)  (American Standard Code for Information Interchange) 文字は1バイト(8bit)単位で扱う byte転送用コマンド load byte : メモリから1バイト読込 lb $t0,0($sp) store byte : メモリに1バイト書込 sb $t0,0($sp) 文字列 : 文字が並んだもの 自然言語をほとんど 網羅できるユニコード(16ビット) などもある

  19. 例題) 文字列コピー手続きのコンパイル 例題) 文字列コピーを表すC言語のステートメントを、MIPSコードに変換せよ void strcpy (char x[], char y[]){ int i i = 0; while((x[i]=y[i])!=0) i=i+1; } ただし、文字列の終端には null文字があるとする。 答) 配列x,yのベースアドレスは引数レジスタ$a0,$a1, iは$s0とする。 strcpy : sub$sp,$sp,4 # スタックに1語分のスペースをとる sw $s0,0($sp) # レジスタ$s0の退避 add $s0,$zero,$zero # i=0 L1: add $t1,$a1,$s0 # y[i]のアドレスを$t1に(バイトなのでiのまま) lb $t2,0($t1) # y[i]の値を$t2に add $t3,$a0,$s0 # x[i]のアドレスを$t3に sb $t2,0($t3) # x[i]=y[i] add $s0,$s0,1 # i=i+1 bne $t2,$zero,L1# もし、y[i]がヌル文字(0)でなければL1へ lw $s0,0($sp) # $s0の前の値を復元する add $sp,$sp,4 # スタックから1語分のスペースをおとす jr $ra # 呼び出し元に戻る プッシュ操作 ポップ操作

  20. MIPSのその他のアドレシング方式 即値アドレシング方式 プログラム中において定数を使う演算が多い 例) 配列の次の要素を指すためのインデックス繰り上げ     ループの繰り返し回数のカウント     入れ子になった手続き呼出しにおけるスタック調整 全体の演算に対する割合 gcc(Cコンパイラ) 52% spice(回路シミュレータ) 69% これまでのMIPS命令では 例) $spに4を足す演算 lw $t0,Addrconstant($s0) # $t0=4 add $sp,$sp,$t0 # $sp=$sp+$t0 メモリから定数を取り出さずに、計算できるとよい 即値命令 :    オペランドの一つを定数とし、命令自体の中に定数を持つ

  21. 例題) アセンブリ言語の定数の機械語への翻訳例題) アセンブリ言語の定数の機械語への翻訳 例題) 次の加算の即値命令addi(add immediate)をMIPSの機械語命令 を記述せよ addi $sp,$sp,4 答) 上記の命令の機械語コードは以下のとおり op rs rt immediate 10進数 2進数 即値で表現できるのは16ビット set less than命令(immediate) slti $t0,$s2,10 # $s2<10のとき、$t0=1とする

  22. load upper immediate命令 設計原則4 : 一般的な場合は高速化せよ オペランドが定数である演算は多数 ⇒ メモリ読み出しなしでの即値演算 定数が16ビット以上の場合の対応 load upper immediate命令 定数の上位16ビットを格納する即値命令 lui $t0,255 の機械語 即値がレジスタの上位ビットにコピー lui $t0,255の実行後のレジスタ$t0の内容

  23. 例題) 32ビットの定数のロード 例題) 次の32ビットの定数をレジスタ$s0にロードするMIPSコードを記述せよ 0000 0000 0011 1101 0000 1001 0000 0000 答) 上位16ビットを$s0にロード lui $s0,61 (上位16ビット0000 0000 0011 1101は10進数で61) 下位16ビットを$s0に追加(実際には即値で加算) addi $s0,$s0,2304 (下位16ビット0000 1001 0000 0000は10進数で2304)

  24. 分岐とジャンプにおけるアドレシング j 10000 # 10000番地にジャンプ ジャンプ命令 6ビット 26ビット 226ビットのフィールドへ分岐可能  条件分岐 命令 bne $s0,$s1,Exit # $s0と$s1が等しくないときExitへ 6ビット 5ビット 5ビット 16ビット 216ビットのフィールドへ条件分岐可能  メモリ領域の拡大に伴い、プログラムが巨大化 PC相対アドレシング方式 分岐可能なアドレス領域を拡大する方法

  25. PC相対アドレシング方式 分岐先は、分岐命令の近くにあることが多い 現在の命令アドレス(プログラムカウンタ)位置を基準に分岐する 分岐先のアドレス=分岐命令中のレジスタ値+現在のプログラムカウンタ プログラムカウンタから±215語、相対的にアドレスを動かすことが可能 メモリ MIPSにおいても、条件分岐命令について PC相対アドレシング方式を採用 現在の プログラムカウンタ 分岐命令 ジャンプ命令(手続き呼び出しなど) PCの近くにジャンプするとは限らない   ⇒ 絶対値によるアドレシング この相対的なアドレス値 を分岐命令時に指定 分岐先の アドレス MIPSでは、 (PC+4)のアドレスを基準に相対アドレシング。 相対アドレス値は語数で表す(1語=4バイト)

  26. 例題) 機械語での分岐オフセットの表記 をコンパイルしたときの次のMIPSコード を機械語表現せよ 例題) while (save[i] == k) i = i + j; Loop: add $t1,$s3,$s3 # ここは前の例題で $s3 ← i add $t1,$t1,$t1 # 出ているので省略 add $t1,$t1,$s5# 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: ただし、ループの開始アドレスを80000とする 答) 80000 80004 ここが 条件分岐命令 80008 80012 80016 (PC+4)=80020 80020 に2語長つまり、 8足したアドレス (80028)へ分岐 80024 80028 分岐先のアドレス

  27. 例題) より遠くへの分岐 分岐先が216ビット以上にあるとき   ⇒ 分岐先への無条件分岐を挿入し、       挿入したジャンプ先に飛ばすかどうかを条件分岐する 例題) レジスタ$s0とレジスタ$s1が等しいときに分岐する以下の命令 beq $s0,$s1,L1 をもっと遠くへ分岐可能とする命令列に置換えよ 答) bne $s0,$s1,L2# $s0≠$s1の場合は、L2へ分岐 j L1 # $s0=$s1は、L1へ分岐 L2:

  28. MIPSのアドレシング・モードのまとめ(1) 1.即値アドレシング オペランドに命令中の定数を指定 2.レジスタアドレシング オペランドにレジスタを指定 3.ベース相対アドレシング 命令中の定数とレジスタの和で、オペランド が記憶されているメモリアドレスを指定 命令中の定数とPCの和で、オペランド が記憶されているメモリアドレスを指定 4.PC相対アドレシング 5.擬似直接アドレシング 命令中の26ビットとPCの上位ビットを 連結してジャンプアドレスを指定

  29. MIPSのアドレシング・モードのまとめ(2) 1.即値アドレシング 2.レジスタアドレシング レジスタ 3.ベース相対アドレシング メモリ Byte / Half Word / Word + 4.PC相対アドレシング メモリ Word +

  30. プログラムの起動 Cプログラム  配列とポインタ:  アセンブリコードでの両者の違いは? コンパイラ 例) 配列を0クリアする  アセンブリ言語プログラム  アセンブラ オブジェクト:機械語モジュール オブジェクト:ライブラリルーチン リンカ 実行ファイル:機械語プログラム ローダ  メモリ 

  31. 配列バージョンのclear clear1( int array[], int size ){ int i; for( i=0; i<size; i=i+1 ) array[i]=0; } arrayは$a0, sizeは$a1にiは$t0にあるとする # i($t0)に0($zero)をコピー : move $t0,$t1($t1を$t0にコピー) move $t0,$zero # i = 0 loop1: add $t1,$t0,$t0 # $t1=i*2 add $t1,$t1,$t1 # $t1=i*4 # array[i]のアドレス値を$t2に格納 add $t2,$a0,$t1 # $t2=array[i]のアドレス # メモリ領域(アドレス array[i])に、0を格納する sw $zero,0($t2) # array[i]=0 addi $t0,$t0,1 # i=i+1 # iとsizeの比較を行い、ループの終了判定を行う($t3が比較結果) slt $t3,$t0,$a1 # (i<size)なら$t3=1 bne $t3,$zero,loop1 # (i<size)ならloop1へ ループ内でiの繰り上げを計算し、毎回アドレスを計算しなおす

  32. ポインタバージョンのclear clear2( int *array, int size ){ int *p; for( p=&array[0]; p<&array[size]; p=p+1 ) *p=0; } arrayの開始アドレスは$a0, sizeは$a1にあり、pは$t0とする # pに置くアドレス値を$a0からコピー move $t0,$a0 # p=&array[0] # array[size]のアドレスを計算し、$t2に格納 add $t1,$a1,$a1 # $t1=size*2 add $t1,$t1,$t1 # $t1=size*4 add $t2,$a0,$t1 # $t2=array[size]のアドレス # 現在のアドレス($t0に格納)のメモリ値を0にする。 loop2: sw $zero,0($t0) # メモリ[p]=0 # $t0を4バイト(1語長)進ませる addi $t0,$t0,4 # p=p+4 # iとsizeの比較を行い、ループの終了判定を行う($t3が比較結果) slt $t3,$t0,$t2 # (p<&array[size])なら$t3=1 bne $t3,$zero,loop2 # (p<&array[size])ならloop2へ アドレスのポインタを直接繰り上げ ⇒ ループ内の命令数が7⇒4へ

More Related