#### Matrix Multiplication

For this assignment you will need to add a subprogram `mmult` to the code for the previous assignment. This subprogram takes two matrices as parameters and returns their matrix product. You will also need to add code to the main program to multiply two matrices and print out the product matrix.

#### Matrix Product

When you multiply two matrices M1 and M2 to form a product R, the entries of R are computed by summing products of entries of a row of M1 and a column of M2. This is illustrated below.

 R 10 13 28 40
 =
 M1 0 1 2 3 4 5
 ×
 M2 0 1 2 3 4 5

40 = 3 * 1 + 4 * 3 + 5 * 5

In this computation,

• The row index in M1 is the same as the row index in R.
• The column index in M2 is the same as the column index in R.
• For each product, the column index in M1 is the same as the row index in M2.

Consequently,

• The number of rows in R is the same as the number of rows in M1.
• The number of columns in R is the same as the number of columns in M2.
• Two matrices M1 and M2 can be multiplied only if they satisfy a compatibility condition: the number of columns of M1 equals the number of rows of M2.

#### The `mmult` Subprogram

The `mmult` subprogram should have two parameters: the addresses of two matrix descriptors. It should return the address of a new matrix descriptor that refers to the matrix product of the two parameter matrices.

The first thing to do in the subprogram is check the matrix descriptors to see if the two parameter matrices are compatible. If they are not, you can just return null (0).

If the parameter matrices are compatible then you need to call `mcreate` create a new matrix descriptor and matrix array for the result of the multiplication. Then you need to implement the assembly language equivalent of the following multiplication loop. In this pseudocode, M1 and M2 are the matrices to be multiplied and R is the result matrix created by `mcreate`.

```for (int r = 0; r < M1 row count; r++) {
for (int c = 0; c < M2 column count; c++) {
R[r][c] = 0
for (int k = 0; k < M1 column count; k++) {
R[r][c] += M1[r][k]*M2[k][c]
}
}
}```

The loop control variables r and c are row and column indices in R and M1 or M2. The innermost loop control variable is used as a column index in M1 and as a row index in M2.

#### Entry Access

For accessing entries in the matrices, you can do address computations using the following formula.

```address of M[r][c] = r*(row size of M) + c*(entry size of M)
+ base address of the entries array for M```

The row size of M is just the product of the column count of M and the entry size of M. For 4 byte entries the above formula becomes

```address of M[r][c] = (r*(column count of M) + c)*4
+ base address of the entries array for M```

If you have r, c, the column count, and the base address in registers then you can compute the entry address using a single additional register. You multiply r and the column count, putting the result into the additional register. Then add c into the register, and so on.

The additional register is being used as a scratch register. This way of using a register is appropriate when you do only need the register values in a short stretch of code. It also makes sense to use the same scratch register in two different stretches of code as long as it is not carrying data from one stretch to another.

Scratch registers can be very useful when you are running short of registers. This is an important consideration in this assignment.

#### Register Usage

I suggest that you make this assignment easier on yourself: carefully plan and document the use of registers before writing the code.

Since you have to use registers to do arithmetic, it makes sense to designate a register to be used as a temporary copy of the R[r][c] entry. To take advantage of sequential access into R you will also want a register for the entry address. Set the temporary copy register to 0 before the innermost loop and increment it by the product of the appropriate M1 and M2 entries inside the innermost loop. You only store its contents to R[r][c] (and increment the address register) after the innermost loop completes.

It is probably best to copy the data in the M1 and M2 descriptor structs into registers early in the `mmult` code rather than accessing the data through the structs each time you need it. The reason for this is that you will need to overwrite the \$a0 and \$a1 registers when you call `mcreate`.

After deciding what values you need in registers you will find that there are not enough \$t registers to get the job done. The best strategy is to use some \$s registers. They should be saved on the stack before they are used and restored before the subprogram returns.

#### The main Program

You can use the same main program as the previous assignment with a little bit of extra code. The extra code just calls `mmult` with the addresses of the static matrices `matrix2x3` and `matrix3x2` as parameters, then uses `mwrite` to print the product matrix. You should see the following result:

``` 10 13
28 40```

#### What to Turn in

Turn in both a copy of your program and a Mars session record. In this session, you will just run your main program. You will not need to enter any input.