See below.
convert uses $s0 as a character pointer
because $a0 might be changed by conChar.
You might think that it would be a good idea to look inside
conChar to see if, in fact, it actually changes $a0.
But this is a violation of modularity.
It is much better to have a calling convention, and to follow it,
than to make modules depend critically on each other's quirks.
For example, conChar doesn't actually alter $a0.
At least not now,
but later on, conChar might be changed.
Then you (or the unfortunate programmer that inherited your program) would have to
look everywhere conChar was used to see what assumptions were
made.
# convert -- convert a line to all capitals
#
# on entry:
# $a0 -- address of input buffer
# $a1 -- length of input buffer
#
# register use:
# $s0 -- pointer into character buffer
#
# on exit:
# no return values
.text
.globl convert
convert:
sub $sp,$sp,4 # push the return address
sw $ra,($sp)
sub $sp,$sp,4 # push $s0
sw $s0,($sp)
# for ( p=buffer; *p!=0; p++ )
move $s0,$a0 # p=buffer
cloop: lbu $a0,($s0) # get a char from the string
beqz $a0,endC # exit if null byte
# argument a0: char to convert
jal conChar # convert character
sb $v0,($s0) # put converted char into string
addu $s0,$s0,1 # p++
b cloop
endC:
lw $s0,($sp) # pop $s0
add $sp,$sp,4
lw $ra,($sp) # pop return address
add $sp,$sp,4
jr $ra # return to caller