# fun fact(x:int):int = 
#  if (x) < 1 then 1
#    else  (x * fact(x-1) )
# in
#  let a = fact(10) in
#	printint a
#

	.data 
NL:	.asciiz	"\n"



	.text 




main:
	addi 	$sp,	$sp,	-4	# push initial stack frame
	sw 	$ra,	0($sp)		# save return address
	jal 	init			# initialize allocator
	li 	$v0,	10		# move factorial argument into place
	move 	$a0,	$v0
	jal 	_fact			# run fact function
	move 	$v1,	$v0		# save result of fact
	li 	$v0,	1		# set up system call to print result
	move 	$a0,	$v1
	syscall 
	li 	$v0,	4		# set up system call to print newline
	la 	$a0,	NL
	syscall 
	lw 	$ra,	0($sp)		# retrieve saved return address
	addi 	$sp,	$sp,	4	# pop initial stack frame
	jr 	$ra			# end simulation



_fact:					# argument arrives in $a0
	addi 	$sp,	$sp,	-8	# allocate activation record
	sw 	$ra,	4($sp)		# save return address
	sw 	$s0,	0($sp)		# callee save register $s0
	move 	$s0,	$a0		# move argument to $s0
	li 	$v0,	1		# load 1 
	bge 	$s0,	$v0,	L2	# if 1 > x then jump to L2 else fall to L1
 


L1:
	li 	$v0,	1		# answer is 1
	j 	L3			# jump to L3



L2:
	li 	$v0,	1		# load 1
	sub	$v0,	$s0,	$v0	# subtract from x
	move 	$a0,	$v0		# move x to arg position for recursive call
	jal 	_fact
	move 	$v0,	$v0		# very superfluous move instruction!
	mulo	$v0,	$s0,	$v0	# multiply result of fact by x
	move 	$v0,	$v0		# very superfluous move instruction!



L3:					# returning from function
	move 	$v0,	$v0		# very superfluous move instruction!
	lw 	$ra,	4($sp)		# retrieve return address
	lw 	$s0,	0($sp)		# retrieve callee save register
	addi 	$sp,	$sp,	8	# pop fact's stack frame
	jr 	$ra			# return



alloc:					# allocate data
	addi 	$sp,	$sp,	-4
	sw 	$ra,	0($sp)
	move 	$v0,	$s7
	add	$s7,	$s7,	$a0
	lw 	$ra,	0($sp)
	addi 	$sp,	$sp,	4
	jr 	$ra



init:					# initialize heap/gc
	addi 	$sp,	$sp,	-4
	sw 	$ra,	0($sp)
	li 	$v0,	9
	li 	$a0,	32000
	syscall 
	move 	$s7,	$v0
	lw 	$ra,	0($sp)
	addi 	$sp,	$sp,	4
	jr 	$ra

