| | 1 | トップ:http://galaxy.u-aizu.ac.jp/note/wiki/CAEX2016 |
| | 2 | |
| | 3 | = 課題4:乗算の実装 = |
| | 4 | 第4版教科書上巻p.210の「3.3 乗算」をよく読んで、乗算をおこなうプログラムを作ってください。 |
| | 5 | 乗数A、被乗数B、積Cは32ビットです。求める乗算結果は64ビットではなく、下位の32ビットだけで十分です。 |
| | 6 | つまり、乗数と被乗数は最大16ビットまでを仮定してください。 |
| | 7 | |
| | 8 | 今後演習で設計するHDLでは、シフト命令をサポートしていませんので、以下のような工夫が必要になります。 |
| | 9 | |
| | 10 | == 左シフト == |
| | 11 | 1ビット左シフトは2倍することと同等なので加算命令によって実現できます。 |
| | 12 | |
| | 13 | シフト命令を使う場合: |
| | 14 | {{{ |
| | 15 | sll $8,$9,1 |
| | 16 | }}} |
| | 17 | |
| | 18 | 加算命令の場合: |
| | 19 | {{{ |
| | 20 | add $8,$9,$9 |
| | 21 | }}} |
| | 22 | |
| | 23 | ここで気をつけなければならないのは、加算によるオーバーフローです。 |
| | 24 | 最上位ビットが1である数を2倍すると(正確には同じ数を足し合わせると)、 |
| | 25 | 最上位ビットで桁上がりを生じるため、add 命令ではオーバーフロー例外が発生します。 |
| | 26 | xspimでは、このためプログラムが停止するので、 左シフトするための加算はaddではなく、 |
| | 27 | オーバーフローを無視するadduを使用してください。 |
| | 28 | |
| | 29 | 一方、演習の後半で設計するプロセッサはオーバーフローをチェックしませんので、 |
| | 30 | 回路シミュレーション時はadduをaddに戻す必要があります。 |
| | 31 | 詳しいことは、該当回の際に説明します。なお、今回作成するプログラムはadduを利用したものを保存しておくこと。 |
| | 32 | |
| | 33 | == 右シフト == |
| | 34 | 1ビット右シフトを他の命令で単純に実現することは困難です。 |
| | 35 | そこで今回は乗算アルゴリズムとハードウエアの直列バージョン(教科書上巻p.212)に |
| | 36 | あるアルゴリズムを、左シフトのみを使うように修正して乗算を実現します。 |
| | 37 | |
| | 38 | [[Image(http://galaxy.u-aizu.ac.jp/note/raw-attachment/wiki/Ex02%E8%AA%B2%E9%A1%8C2015/mult_chart.gif)]] |
| | 39 | |
| | 40 | 乗算で使われる右シフトは、ビットを下位から順に調べることだけが目的なので、 |
| | 41 | 左シフトを使って同等の機能を実現することができます。 |
| | 42 | |
| | 43 | 下のように、右シフトの結果と定数1とのandをとる代わりに、 |
| | 44 | 初期値として1をレジスタに入れておき、これを左シフトしたものとand をとるようにします。 |
| | 45 | |
| | 46 | シフト命令を使う場合: |
| | 47 | {{{ |
| | 48 | srl $8,$8,1 |
| | 49 | andi $9,$8,1 |
| | 50 | }}} |
| | 51 | |
| | 52 | 加算命令の場合: |
| | 53 | {{{ |
| | 54 | addi $10,$0,1 # $10に1を代入(前処理) |
| | 55 | : |
| | 56 | addu $10,$10,$10 # 左シフト。通常でslr命令だった部分に相当 |
| | 57 | and $9,$8,$10 # 通常でandi命令だった部分に相当 |
| | 58 | }}} |
| | 59 | |
| | 60 | この様にして各ビットが1か0かを調べられます。 |
| | 61 | |
| | 62 | [[Image(http://galaxy.u-aizu.ac.jp/note/raw-attachment/wiki/Ex02%E8%AA%B2%E9%A1%8C2015/shift_ex.gif)]] |
| | 63 | |
| | 64 | シフト命令を使う方法(上)だと結果は 0…01(32ビット) か 00…0(32ビット)の2通りだけですが、 |
| | 65 | 加算命令を使用した方法(下)だと、そのビットが0のときは 00…0 ですが、そのビットが1だった場合、 |
| | 66 | その結果もそれが何桁目かによって、結果を左にシフトしています。 |
| | 67 | ですから、結果が0であるか否かで条件分岐をすることになります。 |
| | 68 | |
| | 69 | == 初期化部分 == |
| | 70 | {{{ |
| | 71 | .data |
| | 72 | A: .word 13 |
| | 73 | B: .word 37 |
| | 74 | C: .word 0 |
| | 75 | |
| | 76 | ... 必要な変数の領域を追加する .... |
| | 77 | .text |
| | 78 | main: ... プログラムを書く .... |
| | 79 | |
| | 80 | |
| | 81 | exit: j exit |
| | 82 | }}} |
| | 83 | |
| | 84 | 作成ファイル名は「ex02_p4.s」としてください。 |
| | 85 | |
| | 86 | = 課題5:行列積 = |
| | 87 | 以下のC言語で書かれた行列乗算のプログラムを参考にして、行列積C = A x Bを計算するプログラムを作ってください。 |
| | 88 | |
| | 89 | == 行列A == |
| | 90 | {{{ |
| | 91 | 0 1 0 0 |
| | 92 | 2 0 0 0 |
| | 93 | 0 0 0 3 |
| | 94 | 0 0 4 0 |
| | 95 | }}} |
| | 96 | |
| | 97 | == 行列B == |
| | 98 | {{{ |
| | 99 | 1 2 3 4 |
| | 100 | 5 6 7 8 |
| | 101 | 9 10 11 12 |
| | 102 | 13 14 15 16 |
| | 103 | }}} |
| | 104 | |
| | 105 | |
| | 106 | == テンプレート == |
| | 107 | 作成ファイル名は「ex02_p5.s」としてください。 |
| | 108 | |
| | 109 | {{{ |
| | 110 | .data |
| | 111 | A: .word 0 |
| | 112 | .word 1 |
| | 113 | .word 0 |
| | 114 | .word 0 |
| | 115 | ... 配列Aの要素を書く .... |
| | 116 | |
| | 117 | B: .word 1 |
| | 118 | .word 2 |
| | 119 | .word 3 |
| | 120 | .word 4 |
| | 121 | ... 配列Bの要素を書く .... |
| | 122 | |
| | 123 | C: .space 64 ## 結果行列の保存用 |
| | 124 | |
| | 125 | ... 必要な変数の領域を追加する .... |
| | 126 | .text |
| | 127 | main: |
| | 128 | exit: j exit |
| | 129 | }}} |
| | 130 | |
| | 131 | == C言語バージョン == |
| | 132 | {{{ |
| | 133 | |
| | 134 | #include <stdio.h> |
| | 135 | main() |
| | 136 | { |
| | 137 | static int mat1[4][4] = { |
| | 138 | { 1, 0, 0, 0 }, |
| | 139 | { 0, 1, 0, 0 }, |
| | 140 | { 0, 0, 1, 0 }, |
| | 141 | { 0, 0, 0, 1 }, |
| | 142 | }; |
| | 143 | static int mat2[4][4] = { |
| | 144 | { 1, 2, 3, 4 }, |
| | 145 | { 5, 6, 7, 8 }, |
| | 146 | { 9, 10, 11, 12 }, |
| | 147 | { 13, 14, 15, 16 }, |
| | 148 | }; |
| | 149 | static int result[4][4]; |
| | 150 | |
| | 151 | int i, j, k; |
| | 152 | int s; |
| | 153 | int m1, m2; |
| | 154 | |
| | 155 | /* 行列の乗算 */ |
| | 156 | for( i = 0; i < 4; i++ ) { |
| | 157 | for( j = 0; j < 4; j++ ) { |
| | 158 | s = 0; |
| | 159 | for( k = 0; k < 4; k++ ) { |
| | 160 | mask = 1; |
| | 161 | m1 = mat1[i][k]; /* 被乗数 */ |
| | 162 | m2 = mat2[k][j]; /* 乗数 */ |
| | 163 | s += m1 * m2 |
| | 164 | } |
| | 165 | result[i][j] = s; |
| | 166 | } |
| | 167 | } |
| | 168 | |
| | 169 | /* 結果の表示 */ |
| | 170 | for( i = 0; i < 4; i++ ) { |
| | 171 | for( j = 0; j < 4; j++ ) { |
| | 172 | printf("%3d", result[i][j]); |
| | 173 | } |
| | 174 | printf("\n"); |
| | 175 | } |
| | 176 | } |
| | 177 | }}} |