| | 237 | |
| | 238 | 上の2番目のアセンブラソースファイルをエディタにカット&ペーストして、SPIM上で動作を確認してみてください。 |
| | 239 | レジスタをインクリメントしながらメモリにアクセスする方法を理解してください。 |
| | 240 | |
| | 241 | = 条件分岐 = |
| | 242 | 本演習で利用可能な命令の中で、条件分岐に利用できるのはbranch on equal命令だけです。 |
| | 243 | 例えば、C言語での以下の条件分岐は |
| | 244 | {{{ |
| | 245 | if( i == j) goto label |
| | 246 | : |
| | 247 | label: |
| | 248 | }}} |
| | 249 | 以下のbeq命令と同等です。 |
| | 250 | {{{ |
| | 251 | beq $i,$j,label |
| | 252 | }} |
| | 253 | |
| | 254 | == 大小比較 == |
| | 255 | 大小比較をするには、set on less than命令、あるいはset less than imm命令と、beq命令を組み合わせて実現します。 |
| | 256 | === C言語 === |
| | 257 | {{{ |
| | 258 | if(a > b) {サブプログラム1}else {サブプログラム2} |
| | 259 | }}} |
| | 260 | |
| | 261 | === MIPSアセンブリ === |
| | 262 | {{{ |
| | 263 | lw $8, a // $8 = a |
| | 264 | lw $9, b // $9 = b |
| | 265 | slt $8,$9,$8 // $8 = if ($9<$8) $8=1;else $8=0 |
| | 266 | beq $8,$0,label1 // if $8=0 then goto label1 |
| | 267 | {サブプログラム1に対応するアセンブラプログラム} |
| | 268 | goto label2 |
| | 269 | label1: |
| | 270 | {サブプログラム2に対応するアセンブラプログラム} |
| | 271 | label2: |
| | 272 | }}} |
| | 273 | |
| | 274 | 「 <=」による条件分岐をどのように実現するか、また、「if (条件1 || 条件2)」や「if (条件1 && 条件2)」をどのように実現するかは各自検討してください。 |
| | 275 | |
| | 276 | == while文 == |
| | 277 | === C言語 === |
| | 278 | {{{ |
| | 279 | while(条件){ サブプログラム} |
| | 280 | }}} |
| | 281 | |
| | 282 | === MIPSアセンブリ === |
| | 283 | {{{ |
| | 284 | label1: |
| | 285 | $a ← if (条件) 1 else 0 |
| | 286 | beq $a,$0,label2 |
| | 287 | (サブプログラムに対応するアセンブラプログラム) |
| | 288 | goto label1 |
| | 289 | }}} |
| | 290 | なお、条件が等式の場合は$aを用いず、直接beq命令で等式判定をします。 |
| | 291 | |
| | 292 | == for文 == |
| | 293 | {{{ |
| | 294 | for( i = init_value; i < terminate_value ;更新式){サブプログラム} |
| | 295 | }}} |
| | 296 | のようなfor文は、while文を使って |
| | 297 | {{{ |
| | 298 | i = init_value; |
| | 299 | while(i < terminate_value){ |
| | 300 | サブプログラム; |
| | 301 | 更新式} |
| | 302 | }}} |
| | 303 | と置き換えることができるので、while文のアセンブリプログラムを応用することで変換可能です。 |
| | 304 | このとき、iの値をレジスタに保持しておくと、iへのswやlw命令を省略でき、 |
| | 305 | 高速化が行えますが、繰り返しの中で自由に使えるレジスタが減ってしまいます。 |
| | 306 | 多重ループの場合は、内部の繰り返しに優先してfor文の制御変数(今の場合i)をレジスタに割り付けるといいでしょう。 |
| | 307 | この場合繰り返しの最後に、レジスタの値をメモリに書き戻さないと、正しい最適化とはなりません. |
| | 308 | |
| | 309 | = 例題3 アセンブラでのループ S=Σi=1..ni = |
| | 310 | この例題では、1からnまでを単純に加算するプログラムを扱います。 |
| | 311 | == C言語 == |
| | 312 | {{{ |
| | 313 | main() |
| | 314 | { |
| | 315 | int i = 0; |
| | 316 | int n = 15; |
| | 317 | int s = 0; |
| | 318 | while( i != n ) { |
| | 319 | i++; |
| | 320 | s += i; |
| | 321 | } |
| | 322 | } |
| | 323 | }}} |
| | 324 | 総和演算のような処理は処理はwhile文を用いることによって記述できます。 |
| | 325 | |
| | 326 | === MIPSアセンブリ === |
| | 327 | アセンブラでは、分岐命令と比較命令を用いてループを実現します。メモリの初期状態を以下のように仮定しましょう。 |
| | 328 | |
| | 329 | || アドレス || データ || |
| | 330 | || n || 15 || |
| | 331 | || s || 結果の格納 || |
| | 332 | |
| | 333 | このコードをアセンブラに変換します。 |
| | 334 | ループ変数 i を$8、n の値が入っているレジスタを$9とすると、ループの部分は次のように書けます。 |
| | 335 | {{{ |
| | 336 | or $8, $0, $0 # i = 0 |
| | 337 | loop: beq $8, $9, loopend # i == n なら loopend へ飛ぶ |
| | 338 | addi $8, $8, 1 # i++ |
| | 339 | |
| | 340 | ・・・・ループの中身・・・・・ |
| | 341 | |
| | 342 | j loop |
| | 343 | loopend: |
| | 344 | }}} |
| | 345 | |
| | 346 | 例題のソースファイル全体は次のようになります。 |
| | 347 | {{{ |
| | 348 | .data |
| | 349 | n: .word 15 |
| | 350 | s: .word 0 |
| | 351 | .text |
| | 352 | main: or $8, $0, $0 # i = 0 |
| | 353 | lw $9, n # nの値をロード |
| | 354 | or $10, $0, $0 # s = 0 |
| | 355 | |
| | 356 | loop: beq $8, $9, loopend # i == n なら loopend へ |
| | 357 | addi $8, $8, 1 # i++ |
| | 358 | add $10, $10, $8 # s += i |
| | 359 | j loop |
| | 360 | |
| | 361 | loopend: sw $10, s # sの値をストア |
| | 362 | |
| | 363 | exit: j exit |
| | 364 | }}} |
| | 365 | |
| | 366 | = 課題2 配列の総和計算 = |
| | 367 | メモリ上に並んだN要素からなる配列の総和を求めるプログラムを作成し、SPIMシミュレータで動作確認を行ってください。 |
| | 368 | プログラムの先頭部分(配列データ)には下のコードを使用してください。 |
| | 369 | {{{ |
| | 370 | .data |
| | 371 | N: .word 10 # The length of Array |
| | 372 | A: .word 8 # A[0] = 8 |
| | 373 | .word 4 # A[1] = 4 |
| | 374 | .word 7 |
| | 375 | .word 12 |
| | 376 | .word 13 |
| | 377 | .word 19 |
| | 378 | .word 23 |
| | 379 | .word 43 |
| | 380 | .word 56 # A[8] = 56 |
| | 381 | .word 32 # A[9] = 32 |
| | 382 | S: .word 0 |
| | 383 | .text |
| | 384 | main: |
| | 385 | }}} |
| | 386 | |
| | 387 | = 課題3 配列のコピー = |
| | 388 | メモリ上に並んだN要素からなる配列Aの内容を別の配列Bにコピーするプログラムを作成し、シミュレータで動作確認を行ってください。 |
| | 389 | プログラムの先頭部分には、下のコードを使用して下さい。 |
| | 390 | {{{ |
| | 391 | .data |
| | 392 | N: .word 10 # The length of Array |
| | 393 | A: .word 8 # A[0] = 8 |
| | 394 | .word 4 # A[1] = 4 |
| | 395 | .word 7 |
| | 396 | .word 12 |
| | 397 | .word 13 |
| | 398 | .word 19 |
| | 399 | .word 23 |
| | 400 | .word 43 |
| | 401 | .word 56 # A[8] = 56 |
| | 402 | .word 32 # A[9] = 32 |
| | 403 | B: .space 40 # 配列B の格納先 大きさは40バイト |
| | 404 | .text |
| | 405 | main: |
| | 406 | }}} |
| | 407 | |
| | 408 | |
| | 409 | |
| | 410 | |
| | 411 | |