Instructions
Objective
Write a MIPS assignment program in assembly language to transform matrices.
Requirements and Specifications
### Part 1 -- Initialize Data Structure
**int initialize(char\* filename, Buffer\* buffer)**
This function takes two arguments -- a string *filename* and the address of a data structure *buffer* (as defined above). The function will read the content in *filename*, parse it and store the contents in *buffer*. The contents in *buffer* should be in the format defined for the data structure above. So, the first two elements should be the no. of rows and columns of a matrix and the remaining elements should be the integers of the matrix. One way to do this is to read the file one character at a time, and store them in the buffer as integers in appropriate positions.
If the file is read without any errors and the buffer is initialized properly, then the function should return 1 in *$v0*.
The function should return -1 in *$v0* if an error occurs during initialization. When this happens the *buffer* data structure should remain unchanged. You should assume the buffer contains all zeros before initialization. Initialization errors can occur due to the following reasons:
- File I/O error.
- The first two lines are not [1-10].
- The file has more than X lines (excluding the first two lines), where X is the no. of rows in the first line.
- The file has more than Y columns (excluding the first two lines), where Y is the no. of columns in the second line.
- Lines 3 and after have non-numeric characters.
- Numbers in lines 3 and after (except the last number) do not end with exactly one whitespace.
**Note that this function must handle newline characters in both Windows and UNIX-based systems**. On Windows, line endings are terminated with a combination of carriage return (*\r*) and newline (*\n*) characters, also referred to as CR/LF. On UNIX-based systems, line endings are just the newline character (*\n*).
### Part 2 -- Write Buffer To File
**void write_file(char\* filename, Buffer\* buffer)**
This function takes two arguments -- a string filename and the address of the buffer data structure (as defined above). It should write the data in *buffer* to the file in *filename*. The format of the file is the same as defined previously.
### Part 3 -- Rotate Clockwise By 90
**void rotate_clkws_90(Buffer\* buffer, char\* filename)**
This function takes two arguments -- the address of the *buffer* data structure and a string *filename*. It rotates the matrix in *buffer* clockwise by 90 degrees and writes it to *filename*.
### Part 4 -- Rotate Clockwise By 180
**void rotate_clkws_180(Buffer\* buffer, char\* filename)**
This function takes two arguments -- the address of the *buffer* data structure and a string *filename*. It rotates the matrix in *buffer* clockwise by 180 degrees and writes it to *filename*.
### Part 5 -- Rotate Clockwise By 270
**void rotate_clkws_270(Buffer\* buffer, char\* filename)**
This function takes two arguments -- the address of the *buffer* data structure and a string *filename*. It rotates the matrix in *buffer* clockwise by 270 degrees and writes it to *filename*.
### Part 6 -- Mirroring
**void mirror(Buffer\* buffer, char\* filename)**
This function takes two arguments -- the address of the *buffer* data structure and a string *filename*. It creates a mirror of the matrix in *buffer* writes it to *filename*. For example, consider the following matrix with 2 rows and 3 columns:
### Part 7 -- Duplicates
**(int, int) duplicate(Buffer\* buffer)**
This function takes the data structure *buffer* as an argument. Assume that the matrix in *buffer* contains only binary values 0 and 1. The function checks to see if the matrix has any duplicate rows. If a duplicate row exists in the matrix then the function returns 1 in *$v0* and the index (starting at 1) of the first duplicate row in *$v1*. If the matrix has no duplicate rows then the function returns -1 in *$v0* and 0 in *$v1*
Assume that buffer points to a valid Buffer struct. You do not need to validate the buffer.
Screenshots of output




Source Code
######### FULL NAME ##########
######### SBU ID ##########
######### NET ID ##########
######## DO NOT ADD A DATA SECTION ##########
######## DO NOT ADD A DATA SECTION ##########
######## DO NOT ADD A DATA SECTION ##########
.text
read_char:
addi $sp, $sp, -1 # allocate space in stack to read a char
li $v0, 14 # syscall to read a file
move $a1, $sp # read in stack
li $a2, 1 # read 1 char
syscall # read file
blt $v0, $0, rc_exit # if < 0, it's an error
beq $v0, $0, rc_exit # if = 0, return
lb $v0, 0($sp) # load read char
rc_exit:
addi $sp, $sp, 1 # restore stack
jr $ra # return
# read an integer from the file
# Receives: $a0 = file descriptor
# Returns: $v0 = integer, $v1 = next char if no errors, < 0 if error
read_integer:
addi $sp, $sp, -16 # allocate space on stack
sw $ra, 0($sp) # save registers on stack
sw $s0, 4($sp)
sw $s1, 8($sp)
sw $s2,12($sp)
move $s2, $a0 # save file descriptor
li $s1, 0 # number of digits
li $s0, 0 # start number in zero
ri_loop:
move $a0, $s2 # pass file descriptor
jal read_char # read a char
blt $v0, $0, ri_exit # if < 0, it's an error
beq $v0, $0, ri_exit # if = 0, return
li $t0, 48 # load ascii code for '0'
blt $v0, $t0, ri_exit # if not a digit, end
li $t0, 57 # load ascii code for '9'
bgt $v0, $t0, ri_exit # if not a digit, end
addi $v0, $v0, -48 # convert ascii to decimal digit
li $t0, 10
mul $s0, $s0, $t0 # multiply old number by 10
add $s0, $s0, $v0 # add digit
addi $s1, $s1, 1 # increment number of digits
j ri_loop # repeat loop
ri_exit:
bne $s1, $0, ri_ok # if at least a digit was read, it's ok
li $v0, -1 # else, it's an error
ri_ok:
move $v1, $v0 # set code to last char or error
move $v0, $s0 # return number
lw $s2,12($sp)
lw $s1, 8($sp)
lw $s0, 4($sp)
lw $ra, 0($sp)
addi $sp, $sp, 16 # restore stack
jr $ra
write_char:
addi $sp, $sp, -1 # allocate space in stack to write a char
sb $a1, 0($sp) # save char to write in stack
li $v0, 15 # syscall to write a file
move $a1, $sp # write from stack
li $a2, 1 # write 1 char
syscall # write file
addi $sp, $sp, 1 # restore stack
jr $ra # return
# write an integer to a file
# Receives: $a0 = file descriptor, $a1 = integer to write
# Returns: $v0 < 0 if error, number of chars written if success
write_integer:
addi $sp, $sp, -12 # allocate space on stack
sw $ra, 0($sp) # save registers on stack
sw $s0, 4($sp)
sw $s1, 8($sp)
# convert number to a string of chars
li $t0, 0 # insert a marker in the stack
addi $sp, $sp, -1 # push value to stack
sb $t0, 0($sp)
li $t1, 10 # load 10 for divisions
wi_conv_num:
div $a1, $t1 # divide number by 10
mflo $a1 # save quotient in a1
mfhi $t0 # load remainder in t0 [0-9]
addi $t0, $t0, 48 # convert digit to ascii
addi $sp, $sp, -1 # push digit to stack
sb $t0, 0($sp)
bne $a1, $0, wi_conv_num # repeat until number is zero
# save converted number in file
move $s0, $a0 # save file descriptor
li $s1, 0 # number of written chars is zero
wi_loop:
lb $a1, 0($sp) # load char to write
addi $sp, $sp, 1 # pop from stack
beq $a1, $0, wi_exit # if end of number, return
move $a0, $s0 # pass file descriptor
jal write_char # write a char
blt $v0, $0, wi_error # if < 0, it's an error
add $s1, $s1, $v0 # increment number of written chars
j wi_loop # repeat loop
wi_error:
li $s1, -1 # return error
wi_exit:
move $v0, $s1 # return number of chars written
lw $s1, 8($sp)
lw $s0, 4($sp)
lw $ra, 0($sp)
addi $sp, $sp, 12 # restore stack
jr $ra
.globl initialize
initialize:
addi $sp, $sp, -24 # allocate space on stack
sw $ra, 0($sp) # save registers on stack
sw $s0, 4($sp)
sw $s1, 8($sp)
sw $s2, 12($sp)
sw $s3, 16($sp)
sw $s4, 20($sp)
move $s0, $a1 # save buffer pointer in s0
li $v0, 13 # syscall to open a file
li $a1, 0 # open for reading
li $a2, 0 # mode = 0
syscall # open file
move $s1, $v0 # save file descriptor
blt $v0, $0, init_error # if < 0, there was an error
# read rows
move $a0, $s1 # pass file descriptor
jal read_integer # read integer
blt $v1, $0, init_error # if < 0, there was an error
move $s2, $v0 # save rows
blt $s2, 1, init_error # if rows < 1, it's an error
bgt $s2, 10, init_error # if rows > 10, it's an error
sw $s2, 0($s0) # save in buffer
beq $v1, 10, init_rd_cols # if ending char was a \n, read cols
bne $v1, 13, init_error # if not a \r, it's an error
# if \r, read the \n
move $a0, $s1 # pass file descriptor
jal read_char # read char
blt $v0, $0, init_error # if < 0, there was an error
bne $v0, 10, init_error # if not a \n, it's an error
init_rd_cols:
# read cols
move $a0, $s1 # pass file descriptor
jal read_integer # read integer
blt $v1, $0, init_error # if < 0, there was an error
move $s3, $v0 # save cols
blt $s3, 1, init_error # if cols < 1, it's an error
bgt $s3, 10, init_error # if cols > 10, it's an error
sw $s3, 4($s0) # save in buffer
beq $v1, 10, init_rd_mat # if ending char was a \n, read matrix
bne $v1, 13, init_error # if not a \r, it's an error
# if \r, read the \n
move $a0, $s1 # pass file descriptor
jal read_char # read char
blt $v0, $0, init_error # if < 0, there was an error
bne $v0, 10, init_error # if not a \n, it's an error
init_rd_mat:
add $s0, $s0, 8 # advance pointer to start of matrix
init_rows:
move $s4, $s3 # load number of columns
init_cols:
# read matrix number
move $a0, $s1 # pass file descriptor
jal read_integer # read integer
blt $v1, $0, init_error # if < 0, there was an error
sw $v0, 0($s0) # save in buffer
add $s0, $s0, 4 # advance pointer to next position in matrix
beq $s4, 1, init_nxt_col # if last val, skip test
bne $v1, 32, init_error # if not a space after number, it's an error
init_nxt_col:
addi $s4, $s4, -1 # decrement remaining cols
bne $s4, $0, init_cols # if not zero, repeat
beq $v1, 10, init_nxt_row # if \n space after number, read next row
bne $v1, 13, init_error # if not a \r, it's an error
# if \r, read the \n
move $a0, $s1 # pass file descriptor
jal read_char # read char
blt $v0, $0, init_error # if < 0, there was an error
bne $v0, 10, init_error # if not a \n, it's an error
init_nxt_row:
addi $s2, $s2, -1 # decrement remaining rows
bne $s2, $0, init_rows # if not zero, repeat
# read end of file
move $a0, $s1 # pass file descriptor
jal read_char # read char
blt $v0, $0, init_error # if < 0, there was an error
bne $v0, $0, init_error # if not end of file, it's an error
li $v0, 16 # system call for close file
move $a0, $s1 # file descriptor to close
syscall # close file
li $v0, 1 # return without error
j init_exit
init_error:
li $v0, -1 # return error code
init_exit:
lw $s4, 20($sp) # load register values from stack
lw $s3, 16($sp)
lw $s2, 12($sp)
lw $s1, 8($sp)
lw $s0, 4($sp)
lw $ra, 0($sp)
addi $sp, $sp, 24 # restore stack
jr $ra
.globl write_file
write_file:
addi $sp, $sp, -28 # allocate space on stack
sw $ra, 0($sp) # save registers on stack
sw $s0, 4($sp)
sw $s1, 8($sp)
sw $s2, 12($sp)
sw $s3, 16($sp)
sw $s4, 20($sp)
sw $s5, 24($sp)
move $s0, $a1 # save buffer pointer in s0
li $v0, 13 # syscall to open a file
li $a1, 1 # open for writing
li $a2, 0 # mode = 0
syscall # open file
move $s1, $v0 # save file descriptor
blt $v0, $0, wf_error # if < 0, there was an error li $s2, 0 # number of written chars = 0
# write rows
move $a0, $s1 # pass file descriptor
lw $a1, 0($s0) # load rows from buffer
jal write_integer # write integer
blt $v0, $0, wf_error # if < 0, there was an error
add $s2, $s2, $v0 # add written chars
# write a newline
move $a0, $s1 # pass file descriptor
li $a1, 13 # cr char
jal write_char # write char
blt $v0, $0, wf_error # if < 0, there was an error
add $s2, $s2, $v0 # add written chars
move $a0, $s1 # pass file descriptor
li $a1, 10 # newline char
jal write_char # write char
blt $v0, $0, wf_error # if < 0, there was an error
add $s2, $s2, $v0 # add written chars
# write cols
move $a0, $s1 # pass file descriptor
lw $a1, 4($s0) # load cols from buffer
jal write_integer # write integer
blt $v0, $0, wf_error # if < 0, there was an error
add $s2, $s2, $v0 # add written chars
# write a newline
move $a0, $s1 # pass file descriptor
li $a1, 13 # cr char
jal write_char # write char
blt $v0, $0, wf_error # if < 0, there was an error
add $s2, $s2, $v0 # add written chars
move $a0, $s1 # pass file descriptor
li $a1, 10 # newline char
jal write_char # write char
blt $v0, $0, wf_error # if < 0, there was an error
add $s2, $s2, $v0 # add written chars
lw $s3, 0($s0) # load rows
lw $s4, 4($s0) # load cols
add $s0, $s0, 8 # advance pointer to start of matrix
wf_rows:
move $s5, $s4 # load number of columns
wf_cols:
# write matrix number
move $a0, $s1 # pass file descriptor
lw $a1, 0($s0) # load value from buffer
add $s0, $s0, 4 # advance pointer to next position in matrix
jal write_integer # write integer
blt $v0, $0, wf_error # if < 0, there was an error
add $s2, $s2, $v0 # add written chars
beq $s5, 1, wf_nxt_col # if last val, skip space write
# write a space
move $a0, $s1 # pass file descriptor
li $a1, 32 # space char
jal write_char # write char
blt $v0, $0, wf_error # if < 0, there was an error
add $s2, $s2, $v0 # add written chars
wf_nxt_col:
addi $s5, $s5, -1 # decrement remaining cols
bne $s5, $0, wf_cols # if not zero, repeat
# write a newline
move $a0, $s1 # pass file descriptor
li $a1, 13 # newline char
jal write_char # write char
blt $v0, $0, wf_error # if < 0, there was an error
add $s2, $s2, $v0 # add written chars
move $a0, $s1 # pass file descriptor
li $a1, 10 # newline char
jal write_char # write char
blt $v0, $0, wf_error # if < 0, there was an error
add $s2, $s2, $v0 # add written chars
addi $s3, $s3, -1 # decrement remaining rows
bne $s3, $0, wf_rows # if not zero, repeat
li $v0, 16 # system call for close file
move $a0, $s1 # file descriptor to close
syscall # close file
move $v0, $s2 # return number of chars written
j wf_exit
wf_error:
li $v0, -1 # return error code
wf_exit:
lw $s5, 24($sp) # load register values from stack
lw $s4, 20($sp)
lw $s3, 16($sp)
lw $s2, 12($sp)
lw $s1, 8($sp)
lw $s0, 4($sp)
lw $ra, 0($sp)
addi $sp, $sp, 28 # restore stack
jr $ra
.globl rotate_clkws_90
rotate_clkws_90:
addi $sp, $sp, -4 # allocate space on stack
sw $ra, 0($sp) # save registers on stack
move $fp, $sp # point to current sp
lw $t0, 0($a0) # load rows
lw $t1, 4($a0) # load cols
mul $t2, $t0, $t1 # rows*cols
sll $t2, $t2, 2 # rows*cols*4
add $t2, $t2, 8 # add 2 words (rows, cols)
sub $sp, $sp, $t2 # allocate space in stack to save a new buffer
move $t2, $sp # point to buffer
sw $t1, 0($t2) # save cols as rows for rotated matrix
sw $t0, 4($t2) # save rows as cols for rotated matrix
sll $t3, $t0, 2 # rows*4 = line size for rotated matrix
# rotation
move $t4, $a0 # point to initial buffer
move $t7, $t0 # load rows
r90_rows:
move $t8, $t1 # load cols
addi $t5, $t7, -1 # (rows -1)
sll $t5, $t5, 2 # current (rows -1) * 4
add $t5, $t5, $t2 # address of mat[rows-1]
r90_cols:
lw $t6, 8($t4) # load value from initial buffer
sw $t6, 8($t5) # save value in end buffer
addi $t4, $t4, 4 # advance to next position
add $t5, $t5, $t3 # advance to next position
addi $t8, $t8, -1 # decrement remaining columns
bne $t8, $0, r90_cols # repeat loop while not zero
addi $t7, $t7, -1 # decrement remaining rows
bne $t7, $0, r90_rows # repeat loop while not zero
# write matrix
move $a0, $a1 # pass filename
move $a1, $sp # pass buffer in stack
jal write_file # write the file
move $sp, $fp # restore stack pointer
lw $ra, 0($sp)
addi $sp, $sp, 4 # restore stack
jr $ra
.globl rotate_clkws_180
rotate_clkws_180:
addi $sp, $sp, -4 # allocate space on stack
sw $ra, 0($sp) # save registers on stack
move $fp, $sp # point to current sp
lw $t0, 0($a0) # load rows
lw $t1, 4($a0) # load cols
mul $t2, $t0, $t1 # rows*cols
sll $t2, $t2, 2 # rows*cols*4
add $t2, $t2, 8 # add 2 words (rows, cols)
sub $sp, $sp, $t2 # allocate space in stack to save a new buffer
move $t2, $sp # point to buffer
sw $t0, 0($t2) # save rows for rotated matrix
sw $t1, 4($t2) # save cols for rotated matrix
addi $t3, $t0, -1 # (rows -1)
mul $t3, $t3, $t1 # (rows -1) * cols
addi $t5, $t1, -1 # (cols -1)
add $t5, $t5, $t3 #current (rows -1) * cols + (cols -1)
sll $t5, $t5, 2 # ((rows -1) * cols + (cols -1)) * 4
add $t5, $t5, $t2 # address of mat[rows-1][cols-1]
# rotation
move $t4, $a0 # point to initial buffer
move $t7, $t0 # load rows
r180_rows:
move $t8, $t1 # load cols
r180_cols:
lw $t6, 8($t4) # load value from initial buffer
sw $t6, 8($t5) # save value in end buffer
addi $t4, $t4, 4 # advance to next position
addi $t5, $t5, -4 # advance to next position
addi $t8, $t8, -1 # decrement remaining columns
bne $t8, $0, r180_cols # repeat loop while not zero
addi $t7, $t7, -1 # decrement remaining rows
bne $t7, $0, r180_rows # repeat loop while not zero # write matrix
move $a0, $a1 # pass filename
move $a1, $sp # pass buffer in stack
jal write_file # write the file
move $sp, $fp # restore stack pointer
lw $ra, 0($sp)
addi $sp, $sp, 4 # restore stack
jr $ra
.globl rotate_clkws_270
rotate_clkws_270:
addi $sp, $sp, -4 # allocate space on stack
sw $ra, 0($sp) # save registers on stack
move $fp, $sp # point to current sp
lw $t0, 0($a0) # load rows
lw $t1, 4($a0) # load cols
mul $t2, $t0, $t1 # rows*cols
sll $t2, $t2, 2 # rows*cols*4
add $t2, $t2, 8 # add 2 words (rows, cols)
sub $sp, $sp, $t2 # allocate space in stack to save a new buffer
sw $t1, 0($sp) # save cols as rows for rotated matrix
sw $t0, 4($sp) # save rows as cols for rotated matrix
addi $t2, $t1, -1 # (cols -1)
mul $t2, $t2, $t0 # current (cols -1) * rows
sll $t2, $t2, 2 # current (cols -1) * rows * 4
add $t2, $t2, $sp # address of mat[cols-1][0]
sll $t3, $t0, 2 # rows*4 = line size for rotated matrix
# rotation
move $t4, $a0 # point to initial buffer
move $t7, $t0 # load rows
r270_rows:
move $t8, $t1 # load cols
move $t5, $t2 # load current mat[cols -1][row] position
r270_cols:
lw $t6, 8($t4) # load value from initial buffer
sw $t6, 8($t5) # save value in end buffer
addi $t4, $t4, 4 # advance to next position
sub $t5, $t5, $t3 # advance to next position
addi $t8, $t8, -1 # decrement remaining columns
bne $t8, $0, r270_cols # repeat loop while not zero
addi $t2, $t2, 4 # advance to next col in rotated matrix
addi $t7, $t7, -1 # decrement row
bne $t7, $0, r270_rows # repeat loop while not zero
# write matrix
move $a0, $a1 # pass filename
move $a1, $sp # pass buffer in stack
jal write_file # write the file
move $sp, $fp # restore stack pointer
lw $ra, 0($sp)
addi $sp, $sp, 4 # restore stack
jr $ra
.globl mirror
mirror:
addi $sp, $sp, -4 # allocate space on stack
sw $ra, 0($sp) # save registers on stack
move $fp, $sp # point to current sp
lw $t0, 0($a0) # load rows
lw $t1, 4($a0) # load cols
mul $t2, $t0, $t1 # rows*cols
sll $t2, $t2, 2 # rows*cols*4
add $t2, $t2, 8 # add 2 words (rows, cols)
sub $sp, $sp, $t2 # allocate space in stack to save a new buffer
sw $t0, 0($sp) # save rows for rotated matrix
sw $t1, 4($sp) # save cols for rotated matrix
addi $t2, $t1, -1 # (cols -1)
sll $t2, $t2, 2 # (cols -1) * 4
add $t2, $t2, $sp # address of mat[0][cols-1]
sll $t3, $t1, 2 # cols * 4 = linesize
# mirroring
move $t4, $a0 # point to initial buffer
move $t7, $t0 # load rows
mirror_rows:
move $t8, $t1 # load cols
move $t5, $t2 # load current mat[row][cols -1] position
mirror_cols:
lw $t6, 8($t4) # load value from initial buffer
sw $t6, 8($t5) # save value in end buffer
addi $t4, $t4, 4 # advance to next position
addi $t5, $t5, -4 # advance to next position
addi $t8, $t8, -1 # decrement remaining columns
bne $t8, $0, mirror_cols # repeat loop while not zero
add $t2, $t2, $t3 # advance to next col in mirrored matrix
addi $t7, $t7, -1 # decrement row
bne $t7, $0, mirror_rows # repeat loop while not zero
# write matrix
move $a0, $a1 # pass filename
move $a1, $sp # pass buffer in stack
jal write_file # write the file
move $sp, $fp # restore stack pointer
lw $ra, 0($sp)
addi $sp, $sp, 4 # restore stack
jr $ra
.globl duplicate
duplicate:
addi $sp, $sp, -8 # allocate space on stack
sw $s0, 0($sp) # save registers on stack
sw $s1, 4($sp)
lw $t0, 0($a0) # load rows
lw $t1, 4($a0) # load cols
addi $t0, $t0, -1 # rows - 1
sll $t2, $t1, 2 # cols *4 = line size
move $t3, $a0 # point to initial buffer
li $t4, 0 # current rows
dup_findrow:
addi $t6, $t4, 1 # initial rows = curr row + 1
add $t5, $t3, $t2 # point to next row
j dup_cmp # jump to comparison
dup_rows:
move $t7, $t1 # load cols
move $s0, $t3 # save current row
move $s1, $t5 # save current row
dup_cols:
lw $t8, 8($t3) # load value from initial row
lw $t9, 8($t5) # load value from curr row
bne $t8, $t9, no_dup # if not equal, is not a duplicate
addi $t3, $t3, 4 # advance to next position
addi $t5, $t5, 4 # advance to next position
addi $t7, $t7, -1 # decrement remaining columns
bne $t7, $0, dup_cols # repeat loop while not zero
# it will end here if duplicate
li $v0, 1 # duplicate found
add $v1, $t6, 1 # return row index
j dup_exit
no_dup:
addi $t6, $t6, 1 # increment row
move $t3, $s0 # restart initial row
add $t5, $s1, $t2 # advance to next row
dup_cmp:
ble $t6, $t0, dup_rows # repeat loop while <= rows-1
add $t3, $t3, $t2 # advance to next row
addi $t4, $t4, 1 # increment row
blt $t4, $t0, dup_findrow # repeat loop while < rows-1
# it will end here if no duplicate
li $v0, -1 # no duplicate found
li $v1, 0 # return 0
dup_exit:
lw $s0, 0($sp)
lw $s1, 4($sp)
addi $sp, $sp, 8 # restore stack
jr $ra