First off, what hardware and/or emulator is this for (PS2, SPIM, MARS, MIPSsym, etc.)? Keep in mind that, if this is for actual MIPS hardware and not SPIM, then you have to take the branch and load delay slots into account (unless the assembler is doing that for you automatically, but even then it's something you need to be aware of).
Second, where is it hanging? Does the program do anything unusual before it hangs?
Third, were you aware that you syscall twice in a row in play_short?
And some advice: if your assembler allows them (I know that MARS doesn't), you might find it worthwhile to define equates which name the various system calls, as well as for the standard stack offsets. Here are the ones for SPIM which I have used in the past, based on those provided by my old assembly language professor:
################################################################################
#stack offsets
fp.ra = 4
fp.a0 = 8
fp.a1 = 12
fp.a2 = 16
fp.a3 = 20
fp.s0 = -4
fp.s1 = -8
fp.s2 = -12
################################################################################
#System calls
print_int = 01 #$a0 = integer
print_float = 02 #$f12 = float
print_double= 03 #$f12 = double
print_string= 04 #$a0 = string
read_int = 05 #returns integer in $v0
read_float = 06 #returns float in $f0
read_double = 07 #returns double in $f0
read_string = 08 #$a0 = buffer, $a1 = length
malloc = 09 #$a0 = size of request returns pointer in $v0
Exit = 10
print_char = 11 #$a0 = char
read_char = 12 #returns char (in $v0)
open = 13 #$a0 = filename (string), $a1 =flags, $a2 = mode 0=read 1= wr 2=rw 8=append
# returns file descriptor (in $v0)
read = 14 #$a0 = file descriptor, $a1 = buffer, $a2 = length
# returns num chars read (in $v0 )
write = 15 #$a0 = file descriptor, $a1 = buffer,$a2 = length
# returns num chars written (in $v0 )
close = 16 #$a0 = file descriptor
exit2 = 17 #$a0 = result
################################################################################ You will probably need to adjust them somewhat, but it looks to me as if at least the syscall to exit to the OS is the same, so to use that as an example:
li $v0, exit #returning control to OS
syscall The stack offset would be used in function calls, for instances where a call function then calls another in turn, and you need to save the function's activation record on the stack.
addi $sp, $sp -8 # set aside stack space for the frame pointer and the return address
sw $fp, 0($sp) # store the old frame pointer
addi $fp, $sp, 0 # set the frame pointer - in this case to the SP, but not always
sw $ra, fp.ra($fp) # store the return address to the standard offset