15 points, Due Thursday, February 22
For this assignment you should modify your code for Programming Assignment 1 to read in two matrices, multiply them, and print out the result. You will need to add a subprogram mmult that performs the matrix multipication and modify the main program.
The matrix input and output should be done with the mread and mwrite subprograms that you wrote for Programming Assignment 1. The input should contain a simple concatenation of two matrices. The output should be the product matrix.
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 create a new matrix descriptor and matrix array for the result of the multipication. Then you need to implement the assembly language equivalent of the following multipication loop. In this pseudocode, M1 and M2 are the matrices to be multiplied and R is the result.
for (int i = 0; i < #rows in M1; i++) { for (int j = 0; j < #columns in M2; j++) { R[i][j] = 0.0 for (int k = 0; k < #columns in M1; k++) { R[i][j] += M1[i][k]*M2[k][j] } } }
Since you have to use registers to do arithmetic, it makes sense to designate a register to be used in place of R[i][j]. Set that register to 0.0 before the innermost loop, increment it by the product of the appropriate M1 and M2 entries inside the innermost loop, and store its contents to R[i][j] after the innermost loop.
For accessing entries in the matrices, you could do address computations using the following formula.
address of A[p][q] = base address of A + p*(row size of A) + q*(entry size of A)The row size of A is just the product of the number of columns of A and the entry size of A.
Although this gives the correct answer, it is more efficient to use a modification of sequential access. To do this, you set up registers initialized with the addresses of M1, M2, and R and increment or decrement them as needed at the end of each of the loops. The incrementing for R is easy: just add the entry size to its address register after the end of the innermost loop.
For M1, you will sometimes need to just increment by the entry size. At other times, you will need to decrement by the row size to restart a row. Depending on how you handle things, you may also need to increment by the row size to start a new row.
The incrementing and decrementing for M2 is the most complex since the algorithm acceses its entries by going down columns. At different times you will need to increment by the row size, decrement by the row size, or decrement by the entire array size.
Writing the code with this modified sequential access can result in the smallest and fastest code. However, you should take great care figuring out the increments and decrements. Errors will be difficult to debug. I recommend that you draw pictures to represent the increments and decrements visually. Then you will need to translate the visual moves into increment or decrement amounts. If you are visually oriented, this can be easier than converting indices to addresses directly.
The main program should first just invoke mread twice. Then it should check if the the matrices can be multiplied (number of columns in the second matrix = number of rows in the second matrix). If the matrices cannot be multiplied the program should just print out a message that the matrices are incompatible and then exit. If the matrices are compatible then the main program should invoke mmult passing the addresses of the input matrix descriptors read by mread. Then it should invoke mwrite passing the addresses of the matrix descriptor result from mmult.
You will need to demonstrate your program using xspim on the due date. At that time you should also turn in a copy of your code. Of course, it will be well commented if you want full credit.