# INEL 4206 - Microprocessors
# University of Puerto Rico Mayaguez
#
# Program fills a two-dimensional array with a sequence of integer numbers
#
# Instructional Objectives
# + teach how to represent two-dimensional arrays
		.data
						# array in row major order
array:		.word	0			# array[0,0]		
		.word	1			# array[0,1]		
		.word	2			# array[0,2]		
		.word	3			# array[1,0]		
		.word	4			# array[1,1]
		.word	5			# array[1,2]
		.word	6			# array[2,0]
		.word	7			# array[2,1]
		.word	8			# array[2,2]
rows:		.word	3
cols:		.word	3
obsize:		.word	4
tab:		.asciiz	"\t"
newline:	.asciiz "\n"
finish:		.asciiz "Finished!\n"
filled:		.asciiz "Filled!\n"
		.globl	main
		.text
main:					# void main() {
	sub	$sp, $sp, 40		# Push main stack frame
	sw	$a0, 36($sp)		# Save argument registers
	sw	$a1, 32($sp)		# 
	sw	$a2, 28($sp)		# 
	sw	$a3, 24($sp)		
	sw	$ra, 20($sp)		# Save other registers as needed
	sw	$fp, 16($sp)		
	sw	$s0, 12($sp)		# Save callee saved registers ($sx)
	sw	$s1, 8($sp)		
	sw	$s2, 4($sp)		#
	sw	$s3, 0($sp)		# 
	addu	$fp, $sp, 36		# Establish frame pointer
					#   // Allocate registers for locals
	la	$t0, array
	move	$a0, $t0
	la	$t0, rows
	lw	$a1, 0($t0)
	la	$t0, cols
	lw	$a2, 0($t0)
	jal	pindex			#   pindex(array, rows, cols)


	la	$a0, finish
	li	$v0, 4			#
	syscall				#   printf("Finished!\n"); 
	
	la	$t0, array
	move	$a0, $t0
	la	$t0, rows
	lw	$a1, 0($t0)
	la	$t0, cols
	lw	$a2, 0($t0)
	jal	pmatrix			#   pmatrix(array, rows, cols)

	la	$a0, finish
	li	$v0, 4			#
	syscall				#   printf("Finished!\n"); 
	
	lw	$a0, 36($sp)		#   // restore caller's registers
	lw	$a1, 32($sp)		# 
	lw	$a2, 28($sp)		# 
	lw	$a3, 24($sp)		
	lw	$ra, 20($sp)		#   
	lw	$fp, 16($sp)		
	lw	$s0, 12($sp)		#   
	lw	$s1, 8($sp)		
	lw	$s2, 4($sp)		# 
	lw	$s3, 0($sp)		# 
	addu	$sp, $sp, 40		#   // pop stack frame
	jr	$ra			# }

# void pindex(int *a[], int rows, int cols)
# pindex - prints the indices of the matrix a by rows
pindex:	
	sub	$sp, $sp, 48		# Push main stack frame
	sw	$a0, 44($sp)		# Save argument registers
	sw	$a1, 40($sp)		# 
	sw	$a2, 36($sp)		# 
	sw	$a3, 32($sp)		
	sw	$ra, 28($sp)		# Save other registers as needed
	sw	$fp, 24($sp)		
	sw	$s0, 20($sp)		# Save callee saved registers ($sx)
	sw	$s1, 16($sp)		
	sw	$s2, 12($sp)		# 
	sw	$s3, 8($sp)		#
	sw	$s4, 4($sp)		# 
	sw	$s5, 0($sp)		#
	addu	$fp, $sp, 44		# Establish frame pointer
					# Allocate registers for locals
	move	$s0, $a0		#   array base address in $s0
	move	$s1, $a1		#   array rows in $s1
	move	$s4, $a1		#   array cols in $s4
	li	$s2, 0			#   loop index i in $s2
	li	$s2, 0			#   loop index j in $s5
	la	$t0, obsize		#   object size in $s3
	lw	$s3, 0($t0)		#   
	blez	$s1, endfor1		#   for(int i=0; i<length; i++) {
for1:	li	$s5, 0			#
	blez	$s4, endfor2		#     for(int j=0; j<length; j++) {
for2:					#
	move	$a0, $s2
	li	$v0, 1	
	syscall	

	la	$a0, tab
	li	$v0, 4
	syscall	

	move	$a0, $s5
	li	$v0, 1	
	syscall	
	
	la	$a0, newline
	li	$v0, 4
	syscall	

	addi	$s5, 1
	blt	$s5, $s4, for2		#   }
endfor2:	
	addi	$s2, 1
	blt	$s2, $s1, for1		#   }
endfor1:
	lw	$a0, 44($sp)		# Save argument registers
	lw	$a1, 40($sp)		#
	lw	$a2, 36($sp)		#
	lw	$a3, 32($sp)		#
	lw	$ra, 28($sp)		# Save other registers as needed
	lw	$fp, 24($sp)		#
	lw	$s0, 20($sp)		# Save callee saved registers ($sx)
	lw	$s1, 16($sp)		#
	lw	$s2, 12($sp)		# 
	lw	$s3, 8($sp)		#
	lw	$s4, 4($sp)		# 
	lw	$s5, 0($sp)		#
	addu	$sp, $sp, 48		# Establish frame pointer
	jr	$ra			#   return; 

# void pmatrix(int *a[], int rows, int cols)
# pmatrix - prints the contents of the matrix by rows
pmatrix:	
	sub	$sp, $sp, 48		# Push main stack frame
	sw	$a0, 44($sp)		# Save argument registers
	sw	$a1, 40($sp)		# 
	sw	$a2, 36($sp)		# 
	sw	$a3, 32($sp)		
	sw	$ra, 28($sp)		# Save other registers as needed
	sw	$fp, 24($sp)		
	sw	$s0, 20($sp)		# Save callee saved registers ($sx)
	sw	$s1, 16($sp)		
	sw	$s2, 12($sp)		# 
	sw	$s3, 8($sp)		#
	sw	$s4, 4($sp)		# 
	sw	$s5, 0($sp)		#
	addu	$fp, $sp, 44		# Establish frame pointer
					# Allocate registers for locals
	move	$s0, $a0		#   array base address in $s0
	move	$s1, $a1		#   array rows in $s1
	move	$s4, $a1		#   array cols in $s4
	li	$s2, 0			#   loop index i in $s2
	li	$s2, 0			#   loop index j in $s5
	la	$t0, obsize		#   object size in $s3
	lw	$s3, 0($t0)		#   
	blez	$s1, endfor3		#   for(int i=0; i<length; i++) {
for3:	li	$s5, 0			#
	blez	$s4, endfor4		#     for(int j=0; j<length; j++) {
for4:					#
	multu	$s3, $s4		#       // rowsize = objsize * cols
	mflo	$t0			#
	multu	$t0, $s2		#	
	mflo	$t0			#
	addu	$t0, $t0, $s0		#	// rowaddr = i*rowsize+baddr
	multu	$s3, $s5			#
	mflo	$t1			#	// offset = j * objsize
	addu	$t0, $t0, $t1		#	// celladdr = rowaddr + offset

	lw	$a0, 0($t0)		#
	li	$v0, 1			#
	syscall				#

	la	$a0, tab
	li	$v0, 4			#
	syscall				#   printf("\n"); 
	
	addi	$s5, 1			#
	blt	$s5, $s4, for4		#   }
endfor4:	
	la	$a0, newline
	li	$v0, 4			#
	syscall				#   printf("\n"); 
	addi	$s2, 1
	blt	$s2, $s1, for3		#   }
endfor3:
	lw	$a0, 44($sp)		# Save argument registers
	lw	$a1, 40($sp)		#
	lw	$a2, 36($sp)		#
	lw	$a3, 32($sp)		#
	lw	$ra, 28($sp)		# Save other registers as needed
	lw	$fp, 24($sp)		#
	lw	$s0, 20($sp)		# Save callee saved registers ($sx)
	lw	$s1, 16($sp)		#
	lw	$s2, 12($sp)		# 
	lw	$s3, 8($sp)		#
	lw	$s4, 4($sp)		# 
	lw	$s5, 0($sp)		#
	addu	$sp, $sp, 48		# Establish frame pointer
	jr	$ra			#   return; 
