wiki:Ex03_CA_2021

Version 1 (modified by nakasato, 5 years ago) (diff)

--

トップ:http://galaxy.u-aizu.ac.jp/note/wiki/CAEX2021

今回の課題: サブルーチンを使ったプログラム

以下の2つのプログラムの説明とソースコード、実行結果をまとめてレポートを提出すること。

課題3では、 課題1の命令表に掲載されている 命令に加え、サブルーチンを実装すために、jal (jump and link)命令と jr (jump register) 命令を使用してください。

課題3−1:行列積

以下のC言語で書かれた行列乗算のプログラムを参考にして、行列積C = A x Bを計算するプログラムを作ってください。

  1. 課題2で作成した乗算のプログラムを以下のようにサブルーチン化し、メインプログラムから呼び出して使うこと。
  2. サブルーチンのラベルは「MUL」にする。
  3. 引数は$a0と$a1を介して引き渡す。
  4. このサブルーチンでは結果は$v0に保持する。
  5. メインプログラムでは、計算結果$v0を使って行列積を計算する。

行列A

0  1  0  0
2  0  0  0 
0  0  0  3
0  0  4  0

行列B

1  2  3  4
5  6  7  8 
9 10 11 12
13 14 15 16

初期化部分

        .data 
A:      .word 0 
        .word 1 
        .word 0 
        .word 0 
    ... 配列Aの要素を書く .... 

B:      .word 1 
        .word 2 
        .word 3 
        .word 4 
    ... 配列Bの要素を書く .... 

C:      .space 64 ## 結果行列の保存用

       ... 必要な変数の領域を追加する ....
        .text 
main: 
exit:   j exit

C言語バージョン

#include <stdio.h>
main()
{
  static int mat1[4][4] = {
    { 1, 0, 0, 0 },
    { 0, 1, 0, 0 },
    { 0, 0, 1, 0 },
    { 0, 0, 0, 1 },
  };
  static int mat2[4][4] = {
    {  1,  2,  3,  4 },
    {  5,  6,  7,  8 },
    {  9, 10, 11, 12 },
    { 13, 14, 15, 16 },
  };
  static int result[4][4];

  int  i, j, k;
  int  s;
  int  m1, m2;

  /* 行列の乗算 */
  for( i = 0; i < 4; i++ ) {
    for( j = 0; j < 4; j++ ) {
      s = 0;
      for( k = 0; k < 4; k++ ) {
	mask = 1;
	m1 = mat1[i][k];  /* 被乗数 */
	m2 = mat2[k][j];  /* 乗数 */
        s += m1 * m2
      }
      result[i][j] = s;
    }
  }

  /* 結果の表示 */
  for( i = 0; i < 4; i++ ) {
    for( j = 0; j < 4; j++ ) {
      printf("%3d", result[i][j]); 
    }
    printf("\n");
  }
}

課題3−2:再帰的手続き

教科書第5版上巻p.99にある階乗を計算する再帰的手続きをもとに、スタックレジスタ($sp)の使いかたを理解します。 メインプログラムは、ラベルmainからはじまり、$a0にNをセットして手続きfactを呼び出します。 Nは要素数を指定し、結果はFNに格納します。

この手続きは自分自身を呼び出すので、$a0と$raレジスタをスタックに保持する必要があります。

        .data 
N:      .word 5 
FN:     .word 0 

.text 
main:   lw $a0, N         # $a0(= N) = 10 
        jal fact          # $v0 = fact($a0) 
        sw $v0 FN         # FN = $v0 
        exit: j exit 

fact:   addi $sp, $sp, -8 
        sw $ra, 4($sp) 
        sw $a0, 0($sp) 

        slti $t0, $a0,1   # $t1 = ($a0 < 1) 1:0 
        beq $t0, $0, L1   # if $t1 = 0 then L1 

        addi $v0,$0,1     # $v0 = 1 
        addi $sp,$sp,8    # $sp = $sp + 8 
        jr $ra            # return FN = 1 

L1:     addi $a0,$a0,-1 
        jal fact          # fact($a0 - 1) 
        lw $a0, 0($sp) 
        lw $ra, 4($sp) 
        addi $sp,$sp,8 
        mul $v0,$a0,$v0 
        jr $ra

このプログラムをシミュレータで実行し、サブルーチン"fact"の動作を確認した上で、 課題3-1で作成した積を計算するサブルーチンを、スタックを使って引数をやり取りするように変更したうえで、 このプログラムの"mul"命令の呼び出し部分を置き換えて、全体を完成させてください。

N = 5、8の時に、正しく階乗が計算できていることの動作を確認しなさい。 特に、スタックポインタ($sp)について理解すること。

Ex03のレポート

課題3-1, 3-2についてついて、プログラムの説明を書き、ソースファイルを添付してレポートを提出してください。 プログラムの細かな説明は、ソースファイルにコメントの形で埋め込んでも構いません。 xspimに表示される実行後のメモリの値をウィンドウ画像ダンプ等で取得し、乗算結果の部分を丸で囲むなどして強調した上でレポートに含めてください。