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,

Consequently,

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.

Your TA may also ask you to demonstrate your program in lab.

References

Important sections from the following references are linked in through the "References" submenu.