Reputation: 47
I have to use Mips32 for a class and I'm having some trouble with I/O. The big problem is that I can't use syscalls because those will only work on an emulator and my professor wants to just use an assembler, therefore we're required to use printf and scanf. I tried writing a program to handle some very basic I/O. The idea is to prompt the user to input an integer, scan an integer, and the output the value that the user put in. So my program looks like this:
.abicalls
.option pic0
.data
.align 2
inputMessage:
.asciiz "Please input a positive integer: \0"
intFormat:
.asciiz "%d\0"
input:
.word 0
.text
.align 2
.globl main
.set nomips16
.ent main
.type main, @function # tells the symbol table that `main` is a function
c_print:
#Prints a format based on $a1
#$a1 = 0: prints input message
#$a1 = 1: prints integer in $a0
# The following two instructions are necessary becuase printf takes argument $a0 as the address of a format string
# and it takes $a1, $a2, etc... as the variables to be inserted based on that format string. So I need to move $a1
# to $a2 and $a0 to $a1 to make room for the for the string format in $a0
addi $a2, $a1, 0 # Move $a1 to $a2
addi $a1, $a0, 0 # Move $a0 to $a1
li $t0, 1 # Load 1 into $t0. This is used to compare $a2 (now the option) to see what we will print
beq $a2, $t0, print_o1 # If $a2 == 1 jump to print_o1, else it just goes to print_o0
print_o0:
la $a0, inputMessage # Load the address of the inputMessage string into $a0
j print_oEnd # Jump to print_oEnd
print_o1:
la $a0, intFormat # Load the address of the intFormat string into $a0
j print_oEnd # Jump to print_oEnd
print_oEnd:
# The following instruction is used to store the memory address so it is preserved when we return from printf
addi $s1, $ra, 0 # Put the return address into $s1
jal printf # Jump and Link to printf
addi $ra, $s1, 0 # Put the return address back into $ra
jr $ra # Jump back to the next instruction after we called c_print
c_scan:
la $a0, intFormat # Load the address of the intFormat string into $a0
la $a1, input # Load the address of the word called "input" into $a1
addi $s1, $ra, 0 # Preserve the return address in $s1
jal scanf # Jump and Link to scanf
addi $ra, $s1, 0 # Put the return address back into #ra
lw $v0, input # Load the word called "input" (now it's the user input integer) into $v0
jr $ra # Jump back to the next instruction after we called c_scan
main:
#==========================
li $a0, 0 # Load 0 into $a0 (serves no purpose since I'm loading 0 into $a1)
li $a1, 0 # Load 0 into $a1 (option 0 makes c_print just print a message, not the int in $a1)
jal c_print # Jump and Link to function c_print
jal c_scan # Jump and Link to function c_scan (takes no arguments)
addi $a0, $v0, 0 # c_scan stores the input into $v0, so put $v0 into $a0
li $a1, 1 # Load 1 into $a1 (option 1 makes c_print print the integer in $a0)
jal c_print # Jump and link to function c_print
#==========================
.end main
.size main, .-main
At the moment this program will output the inputMessage, but it will not output the integer that we scanned in. Also the program will not terminate, it will just wait for me to press ctrl-c. I know that there is a syscall to end the program, but do I need to do something like that here? Or should it just end on it's own? Is there a problem with how I terminate my strings? And do I need to preserve the return address before I jump and link to another label?
As you can see I have a lot of questions and not a lot of experience, so any help would be greatly appreciated. Thank you.
Upvotes: 0
Views: 913
Reputation: 58467
If you're running this on a real MIPS-based device, or an emulator that emulates branch delay slots, you may need to fill those slots in case the assembler you use doesn't do it for you. That is, insert a nop
after each branch instruction (there are better ways, but that's the easiest way).
I know that there is a syscall to end the program, but do I need to do something like that here?
Assuming that you're linking against libc
you could call the exit
function. A jr $ra
at the end of you main
routine might also work, as long as you save the value that $ra
had when entering main
and restore it before the jr
.
Is there a problem with how I terminate my strings?
.asciiz
means zero-terminated ASCII, so the '\0'
in your strings are redundant, but shouldn't cause any problems.
And do I need to preserve the return address before I jump and link to another label?
Whenever you have nested function calls you need to preserve the return address, since each jal
will modify $ra
.
Upvotes: 1