| | 1 | トップ:http://galaxy.u-aizu.ac.jp/note/wiki/CAEX2016 |
| | 2 | |
| | 3 | = swap手続き = |
| | 4 | 第4版教科書上巻p.137の「2.13 Cプログラムの包括的な例題解説」にあるswap手続き(関数)を |
| | 5 | 本演習で利用可能な命令で実装したプログラムを示します。 |
| | 6 | 教科書の該当分をよく読んで、C言語とMIPS命令との対応を理解すること。 |
| | 7 | |
| | 8 | == C言語 == |
| | 9 | {{{ |
| | 10 | void swap(int v[], int k) |
| | 11 | { |
| | 12 | int temp; |
| | 13 | temp = v[k]; |
| | 14 | v[k] = v[k+1]; |
| | 15 | v[k+1] = temp; |
| | 16 | } |
| | 17 | }}} |
| | 18 | |
| | 19 | == アセンブリプログラム == |
| | 20 | {{{ |
| | 21 | swap: addi $t1, $a1, 0 |
| | 22 | add $t1, $t1, $t1 |
| | 23 | add $t1, $t1, $t1 |
| | 24 | add $t1, $a0, $t1 |
| | 25 | lw $t0, 0($t1) |
| | 26 | lw $t2, 4($t1) |
| | 27 | sw $t2, 0($t1) |
| | 28 | sw $t0, 4($t1) |
| | 29 | jr $ra |
| | 30 | }}} |
| | 31 | |
| | 32 | 引数の受け渡しは$a0と$a1のレジスタを使います。 |
| | 33 | ここでは、$a0でswapされる整列させる配列の先頭アドレスを、$a1でswapする箇所の配列の添え字(k)を受け渡します。 |
| | 34 | |
| | 35 | シフト命令は利用できないので、add命令の組み合わせで「k*4」を実現しています。 |
| | 36 | |
| | 37 | == 練習課題1 == |
| | 38 | 以下のテンプレートと組み合わせて、swap関数の動作を確認すること。 |
| | 39 | |
| | 40 | {{{ |
| | 41 | .data |
| | 42 | k: .word 3 |
| | 43 | A: .word 32 |
| | 44 | .word 422 |
| | 45 | .word 83 |
| | 46 | .word 2 |
| | 47 | .word 92 |
| | 48 | .word 32 |
| | 49 | .word 97 |
| | 50 | .word 22 |
| | 51 | .word 4 |
| | 52 | .word 86 |
| | 53 | |
| | 54 | .text |
| | 55 | main: la $a0, A |
| | 56 | lw $a1, k |
| | 57 | jal swap |
| | 58 | exit: j exit |
| | 59 | }}} |
| | 60 | |
| | 61 | = ソート手続き = |
| | 62 | 教科書に従い、swap関数を使って単純なソートプログラムの動作を確認します。 |
| | 63 | |
| | 64 | {{{ |
| | 65 | .data |
| | 66 | N: .word 3 |
| | 67 | A: .word 32 |
| | 68 | .word 422 |
| | 69 | .word 83 |
| | 70 | .word 2 |
| | 71 | .word 92 |
| | 72 | .word 32 |
| | 73 | .word 97 |
| | 74 | .word 22 |
| | 75 | .word 4 |
| | 76 | .word 86 |
| | 77 | |
| | 78 | .text |
| | 79 | main: la $a0, A |
| | 80 | lw $a1, N |
| | 81 | jal sort |
| | 82 | exit: j exit |
| | 83 | |
| | 84 | sort: addi $sp, $sp, -20 |
| | 85 | sw $ra, 16($sp) |
| | 86 | sw $s3, 12($sp) |
| | 87 | sw $s2, 8($sp) |
| | 88 | sw $s1, 4($sp) |
| | 89 | sw $s0, 0($sp) |
| | 90 | |
| | 91 | or $s2, $0, $a0 #move $s2, $a0 |
| | 92 | or $s3, $0, $a1 #move $s3, $a1 |
| | 93 | |
| | 94 | or $s0,$0,$0 # $s0(= i) = 0 |
| | 95 | |
| | 96 | for1tst: slt $t0,$s0,$s3 # $t0 = (i < N) 1:0 |
| | 97 | beq $t0,$0,exit1 # if $t0 == 0 then exit1 |
| | 98 | addi $s1, $s0, -1 # j = i - 1 |
| | 99 | |
| | 100 | for2tst: slti $t0, $s1, 0 # $t0 = (j < 0) 1:0 |
| | 101 | beq $t0, $0, cont #bne $t0, $0, exit2 変更点2 |
| | 102 | j exit2 |
| | 103 | |
| | 104 | cont: or $t1, $s1, $0 # $t1 = j * 4 |
| | 105 | add $t1, $t1, $t1 #変更点3 |
| | 106 | add $t1, $t1, $t1 |
| | 107 | |
| | 108 | add $t2, $s2, $t1 # $t2 = &(A[j]) |
| | 109 | lw $t3, 0($t2) # $t3 = A[j] |
| | 110 | lw $t4, 4($t2) # $t4 = A[j+1] |
| | 111 | |
| | 112 | slt $t0, $t4, $t3 # $t0 = (A[j]< A[j+1]) 1:0 |
| | 113 | beq $t0, $0, exit2 # if $t0 == 0 then exit2 |
| | 114 | or $a0, $s2, $0 # $a0 = $s2(&A) |
| | 115 | or $a1, $s1, $0 # $a1 = $s1(j) |
| | 116 | jal swap |
| | 117 | |
| | 118 | addi $s1, $s1, -1 # j = j - 1 |
| | 119 | j for2tst |
| | 120 | |
| | 121 | exit2: addi $s0, $s0, 1 # i = i + 1 |
| | 122 | j for1tst |
| | 123 | |
| | 124 | exit1: lw $s0, 0($sp) |
| | 125 | lw $s1, 4($sp) |
| | 126 | lw $s2, 8($sp) |
| | 127 | lw $s3, 12($sp) |
| | 128 | lw $ra, 16($sp) |
| | 129 | addi $sp, $sp, 20 |
| | 130 | jr $ra |
| | 131 | }}} |
| | 132 | |
| | 133 | sort関数の、引数の受け渡しは$a0と$a1のレジスタを使います。 |
| | 134 | ここでは、$a0に整列させる配列の先頭アドレスを、$a1にNをそれぞれセットしています。 |
| | 135 | |
| | 136 | 教科書のプログラムとの変更点は以下のところです。 |
| | 137 | * move命令をor命令に置換 |
| | 138 | * bne命令をbeqとj命令の組み合わせに置換 |
| | 139 | * sll命令をadd命令の組み合わせに置換 |
| | 140 | |
| | 141 | $spは明示的に初期化されていませんが、xspimによって自動的に設定されます。 |
| | 142 | |
| | 143 | == 練習課題2 == |
| | 144 | swap関数と組み合わせて、N = 3の時に正しく動作することを確認すること。 |
| | 145 | また、変数Nが10の場合に正しい結果が得られることを確認すること。 |
| | 146 | |
| | 147 | = 課題6:手続きを用いた行列の積アルゴリズム = |
| | 148 | 第2回演習で作成した、行列の積を求めるプログラムのうち、2つの整数の積を求める部分を手続き呼び出しに置き換えなさい。 |
| | 149 | 1. 手続きのラベルは「MUL」にする。 |
| | 150 | 1. 引数は$a0と$a1を介して引き渡す。 |
| | 151 | 1. この手続きでは結果は$v0に保持する。 |
| | 152 | 1. メインプログラムでは、計算結果$v0を使って行列積を計算する。 |
| | 153 | |
| | 154 | ファイル名は「ex03_p6.s」としてください。 |
| | 155 | |
| | 156 | = 再帰手続き呼び出し = |
| | 157 | 第4版教科書上巻p.105にある階乗を計算する再帰的手続きをもとに、スタックレジスタ($sp)の使いかたを理解します。 |
| | 158 | メインプログラムは、ラベルmainからはじまり、$a0にNをセットして手続きfactを呼び出します。 |
| | 159 | Nは要素数を指定し、結果はFNに格納します。 |
| | 160 | |
| | 161 | この手続きは自分自身を呼び出すので、$a0と$raレジスタをスタックに保持する必要があります。 |
| | 162 | |
| | 163 | {{{ |
| | 164 | .data |
| | 165 | N: .word 5 |
| | 166 | FN: .word 0 |
| | 167 | |
| | 168 | .text |
| | 169 | main: lw $a0, N # $a0(= N) = 10 |
| | 170 | jal fact # $v0 = fact($a0) |
| | 171 | sw $v0 FN # FN = $v0 |
| | 172 | exit: j exit |
| | 173 | |
| | 174 | fact: addi $sp, $sp, -8 |
| | 175 | sw $ra, 4($sp) |
| | 176 | sw $a0, 0($sp) |
| | 177 | |
| | 178 | slti $t0, $a0,1 # $t1 = ($a0 < 1) 1:0 |
| | 179 | beq $t0, $0, L1 # if $t1 = 0 then L1 |
| | 180 | |
| | 181 | addi $v0,$0,1 # $v0 = 1 |
| | 182 | addi $sp,$sp,8 # $sp = $sp + 8 |
| | 183 | jr $ra # return FN = 1 |
| | 184 | |
| | 185 | L1: addi $a0,$a0,-1 |
| | 186 | jal fact # fact($a0 - 1) |
| | 187 | lw $a0, 0($sp) |
| | 188 | lw $ra, 4($sp) |
| | 189 | addi $sp,$sp,8 |
| | 190 | mul $v0,$a0,$v0 |
| | 191 | jr $ra |
| | 192 | }}} |
| | 193 | |
| | 194 | == 練習課題3 == |
| | 195 | N = 5、8の時に、正しく階乗が計算できていることの動作を確認しなさい。特に、スタックポインタ($sp)について理解すること。 |
| | 196 | |
| | 197 | = 課題7:手続きを用いたプログラムの作成 = |
| | 198 | 下記の機能を実現する手続きを作成し、実行を確認してください。 |
| | 199 | 作成するプログラムでは、main関数から、作成した関数(手続き)を呼び出し、動作を確認する部分も含めること。 |
| | 200 | |
| | 201 | == 16bit整数a, b, cを引数とし d = a*b + cを計算する関数: int mac(int a, int b, int c) == |
| | 202 | 以下のパターンについて動作確認をすること。 |
| | 203 | {{{ |
| | 204 | (a, b, c) = (11, 21, 0) |
| | 205 | (a, b, c) = (11, 21, 6) |
| | 206 | (a, b, c) = (3333, 4444, 5555) |
| | 207 | }}} |
| | 208 | |
| | 209 | ファイル名は「ex03_p7a.s」としてください。 |
| | 210 | |
| | 211 | == 16bit整数aをn bit左シフトする関数: int left_shift(int a, int n) == |
| | 212 | 動作確認は”0x1”を1, 4, 7, 15 bitシフトした結果を確認すること。シフト命令を使ってはいけない。 |
| | 213 | |
| | 214 | ファイル名は「ex03_p7b.s」としてください。 |