	.globl	main
main:					# main is always a global label
	subu	$sp, $sp, 48		# frame is 32 bytes long
	sw 	$ra, 20($sp)		# save return address
	sw	$s1, 24($sp)		# save $s1
	sw	$s2, 28($sp)		# save $s2
	sw	$s3, 32($sp)		# save $s3
	sw	$s4, 36($sp)		# save $s4
	sw	$s5, 40($sp)		# save $s5
	sw	$s6, 44($sp)		# save $s6

	.data
msg1:		.asciiz "Enter an integer: "
msg2:		.asciiz "Sum of the greatest two is "
int1:		.asciiz "xxxxxxxxxxx\n"
int2:		.asciiz "xxxxxxxxxxx\n"
int3:		.asciiz "xxxxxxxxxxx\n"
result: 	.asciiz "xxxxxxxxxxx\n"

	.text
	la	$a0, msg1		# load msg1 into $a0
	jal	puts			# call puts

	la	$a0, int1		# load int1 into #a0
	jal	gets			# call gets

	la	$a0, int1		# load int1 into $a0
	jal	atoi			# call atoi

	move	$s1, $v0		# store first int in $s1


	la	$a0, msg1		# load msg1 into $a0
	jal 	puts

	la	$a0, int2		# load int2 into #a0
	jal	gets			# call gets

	la	$a0, int2		# load int2 into $a0
	jal	atoi			# call atoi

	move	$s2, $v0		# store second int in $s2


	la	$a0, msg1		# load msg1 into $a0
	jal	puts

	la	$a0, int3		# load int3 into #a0
	jal	gets			# call gets

	la	$a0, int3		# load int3 into $a0
	jal	atoi			# call atoi

	move	$s3, $v0		# store third int in $s3	

		
	slt	$s5, $s1, $s2		# $s1 < $s2 ?
	beq	$s5, $0, test2		# if not, goto test2	
	slt	$s5, $s3, $s1		# $s3 < $s1 ?
	beq	$s5, $0, test1		# if not, goto test1
	add	$s6, $s1, $s2		# $s1 and $s2 are greatest ints
	j 	end			# end tests
test1:
	add	$s6, $s3, $s2		# $s3 and $s2 are greatest ints
	j 	end			# end tests
test2:
	slt	$s5, $s3, $s2		# $s3 < $s2 ?
	beq	$s5, $0, test3		# if not, goto test3
	add	$s6, $s2, $s1		# $s2 and $s1 are greatest ints
	j	end			# end tests
test3:	
	add	$s6, $s3, $s1  		# $s3 and $s1 are greatest ints

end:
	la	$a0, msg2		# load msg2
	jal 	puts			# call puts

	la	$a0, result		# load result into $a0
	add	$a1, $0, $s6		# pass $s6 into a1
	jal	itoa			# call itoa

	la	$a0, result		# load result into $a0
	jal 	puts			# call puts


	lw	$ra, 20($sp)		# restore return address	
	lw	$s1, 24($sp)		# restore $s1
	lw	$s2, 28($sp)		# restore $s2
	lw	$s3, 32($sp)		# restore $s3
	lw	$s4, 36($sp)		# restore $s4
	lw	$s5, 40($sp)		# restore $s5
	lw	$s6, 44($sp)		# restore $s6
	addiu	$sp, $sp, 48		# pop the stack frame
	jr	$ra

# *********************************************************************
# ITOA
# *********************************************************************
itoa:
	subu 	$sp, $sp, 40		# frame is 40 bytes long
	sw	$ra, 20($sp)		# save return address
	
	.data
buf:		.asciiz "xxxxxxxxxxx"

	.text
	
	li	$t0, 10			# $t0 = 10
	la	$t1, buf		# load address of buf into $t1
	addi	$t2, $0, 1		# counts the number of characters
					# stored in the buffer

loop1:
 	divu	$a1, $t0		# divide by 10
	mfhi	$t3			# remainder in $t3
	add	$t4, $0, $0		# initialize $t4 = 0
	addi	$t4, $t3, 48		# convert to character
	sb	$t4, 0($t1)		# store character in buffer 
	sub	$a1, $a1, $t3		# subtract remainder
	beq	$a1, $0, loop2		# end loop if equal to zero
	addi	$t1, $t1, 1		# increment iterator
	addi	$t2, $t2, 1		# increment counter
	divu	$a1, $t0		# divide by 10
	mflo	$a1
	j	loop1			# continue loop2	 	

loop2:
	beq	$t2, $0, end1		# if count == 0, end
	lb	$t5, 0($t1)		# load character from buf
	sb	$t5, 0($a0)		# store character into 
					# allocated string				
	addi	$t2, $t2, -1		# decrement count
	addi	$t1, $t1, -1		# derement iterator
	addi	$a0, $a0, 1		# increment string pointer
	j	loop2			# continue loop

end1:
	sb	$0, 0($a0)		# store null character

	lw	$ra, 20($sp)		# restore return address
	addiu	$sp, $sp, 40		# pop stack frame
	jr	$ra			# return to caller

# *******************************************************************
# ATOI
# *******************************************************************
atoi:
	subu 	$sp, $sp, 40		# frame is 40 bytes long
	sw	$ra, 20($sp)		# save return address

	add	$v0, $0, $0		# v0 contains the return value
					# its value is initially zero
	
	add	$t0, $a0, $0		# $t0 iterates the string
	add	$t1, $0, $0		# counts the number of characters
					# in the string
	addi	$t3, $0, 10		# $t3 stores the value 10 
	li	$t4, 1			# temp value	

rm_space:
	lb	$t2, 0($t0)		# load character into $t2
	add	$t5, $0, $t2		# copy character into $t5
	addi	$t5, $t5, -32		# test if character is space
	bne	$t5, $0, loop3		# not a space, get digits
	add	$t0, $t0, 1		# increment iterator	
	j	rm_space		# loop until all spaces are removed 
	
loop3:	
	lb	$t2, 0($t0)		# load character into $t2
	beq	$t2, $0, endloop3	# end loop if character is zero
	addi	$t2, $t2, -48		# test if not digit
	slti	$t5, $t2, 10		# $t2 < 10 ??
	beq	$t5, $0, endloop3	# not a digit, so end loop
	slt	$t5, $t2, $0		# $t2 < 0 ??		
	bne	$t5, $0, endloop3	# not a digit, so end loop  	

	add	$t0, $t0, 1		# increment iterator
	add	$t1, $t1, 1		# increment count
	j 	loop3			# continue loop

endloop3:
	addi	$t0, $t0, -1		# t0 points to last character now 

loop4:
	beq	$t1, $0, end2		# if count == 0, end loop 

	lb	$t2, 0($t0)		# load character
	addi	$t2, $t2, -48		# subtract 48 to get int value
	mult	$t2, $t4		# multiply by appropriate power	
	mflo	$t2			# store quotient in $t2
	add	$v0, $v0, $t2		# add value to $v0	

	mult	$t4, $t3		# multiply power by 10
	mflo	$t4			# store qoutient in $t4
	addi	$t0, $t0, -1		# decrement iterator
	addi	$t1, $t1, -1		# decrement count

	j 	loop4			# continue loop		

end2:
	lw	$ra, 20($sp)		# restore return address
	addiu	$sp, $sp, 40		# pop stack frame
	jr	$ra			# return to caller

# *****************************************************************
# PUTS
# *****************************************************************
puts:
	subu 	$sp, $sp, 40		# frame is 40 bytes long
	sw	$ra, 20($sp)		# save return address
	
	.data
tx_ctrl:	.word	0xffff0008	# address of the memory mapped
					# Transmitter Control Register

tx_data:	.word	0xffff000c	# address of the memory mapped
					# Transmitter Data Register

	.text
	
	lw	$t0, tx_data		# load tx_data into $t0
	li	$t1, 0			# t1 counts the number of characters
					# printed

loop5:	
	lb	$t4, 0($a0)
	beq	$t4, $0, end3		# if $a0 is the null character end loop	

tx_wait1:
	lw	$t2, tx_ctrl		# load tx_ctrl into $t2

	lw	$t5, 0($t2)
	andi	$t5, $t5, 1		# test if transmitter is ready
	beq	$t5, $0, tx_wait1	# not ready - keep waiting

	lb	$t8, 0($a0)		# load character into $t8
	sb	$t8, 0($t0)		# store character from $t8
					# into tx_data
	
	addi	$t1, $t1, 1		# increment count
	add	$a0, $a0, 1		# increment pointer

	j	loop5			# loop back

end3:
	lw	$t2, tx_ctrl		# load tx_ctrl into $t2

	lw	$t5, 0($t2)
	andi	$t5, $t5, 1		# test if transmitter is ready
	beq	$t5, $0, end3		# not ready - keep waiting

	li	$t9, 13			# print CR
	sb	$t9, 0($t0)

end4:
	lw	$t2, tx_ctrl		# load tx_ctrl into $t2

	lw	$t5, 0($t2)
	andi	$t5, $t5, 1		# test if transmitter is ready
	beq	$t5, $0, end4		# not ready - keep waiting

	move	$v0, $t1		# return count to caller

	lw	$ra, 20($sp)		# restore return address
	addiu	$sp, $sp, 40		# pop stack frame
	jr	$ra			# return to caller
			
# *************************************************************************
# GETS
# *************************************************************************
gets:
	subu 	$sp, $sp, 40		# frame is 40 bytes long
	sw	$ra, 20($sp)		# save return address
	
	.data
rx_ctrl:	.word	0xffff0000	# address of the memory mapped
					# Receiver Control Register	

rx_data:	.word	0xffff0004	# address of the memory mapped
					# Receiver Data Register
	.text
	add	$t7, $0, $a0		# store address of string
		
	lw 	$t1, rx_data		# load rx_data into $t1
	lw	$t3, tx_data		# load tx_data into $t3

rx_wait:
	lw	$t0, rx_ctrl		# load rx_ctrl into $t0 

	lw	$t4, 0($t0)		
	andi	$t4, $t4, 1		# test if receiver is ready
	beq	$t4, $0, rx_wait	# not ready - keep waiting
	
	lw	$t4, 0($t1)		# get the character from 
					# rx_data into $t4
	
	add 	$t6, $0, $t4		
	addi 	$t6, $t6, -10		# test for new line
	beq 	$t6, $0, end5		# stop input

tx_wait2:
	lw	$t2, tx_ctrl		# load tx_ctrl into $t2

	lw	$t5, 0($t2)
	andi	$t5, $t5, 1		# test if transmitter is ready
	beq	$t5, $0, tx_wait2	# not ready - keep waiting

	sw	$t4, 0($t3)		# store character from $t4
					# into tx_data

	sb	$t4, 0($a0)		# store character into string
	addi	$a0, $a0, 1		# increment $a0 

	j	rx_wait			# wait for another character

end5:
	sb	$0, 0($a0)		# store terminating null into string

end6:
	lw	$t2, tx_ctrl		# load tx_ctrl into $t2

	lw	$t5, 0($t2)
	andi	$t5, $t5, 1		# test if transmitter is ready
	beq	$t5, $0, end6		# not ready - keep waiting

	li	$t9, 13			# print CR
	lw	$t0, tx_data		# load tx_data into $t0
	sb	$t9, 0($t0)

end7:
	lw	$t2, tx_ctrl		# load tx_ctrl into $t2

	lw	$t5, 0($t2)
	andi	$t5, $t5, 1		# test if transmitter is ready
	beq	$t5, $0, end7		# not ready - keep waiting
	
	
	add	$v0, $0, $t7		# return address of string

	lw	$ra, 20($sp)		# restore return address
	addiu	$sp, $sp, 40		# pop stack frame
	jr	$ra			# return to caller
