I've been trying to learn how to program with Assembly MIPS32 on Mars.
I got a question though, i want to make a function (i don't know if that is how its called) that returns an integer.
Basically i would like to make a method that asks the user to insert a number and add that number with another one that was previously requested
This is what i came up with but i don't know how to return the value to $s2
New:
la $a0, prompt2 # Print string "Input: "
li $v0,4
syscall
li $v0,5 #Read int x
syscall
jr $ra
Add:
j New
add $s1, $s1, $s2 #add Int $s1 and $s2 and save them to $s1
j loop
if anyone has any suggestions or fixes please respond.
Thanks in advance
It is common on MIPS processors to use $v0 for function return values. Of course, you're free to come up with any calling convention you want for your own functions, but unless you have a very good reason not to I'd say stick with $v0 for return values.
Also, to call a function you'd typically use jal, because that's what sets up the $ra register so that you later can return with jr $ra.
If you don't already have it, I suggest that you download MIPS32™ Architecture For Programmers Volume II: The MIPS32™ Instruction Set and read up on how jal and jr work (or any other instruction that you feel that you don't fully understand).
So the code you described in your question could look something like:
New:
la $a0, prompt2 # Print string "Input: "
li $v0,4
syscall
li $v0,5 #Read int x
syscall
# The result of syscall 5 is in $v0
jr $ra
Add:
jal New
add $s1, $s1, $v0 # add the value we just read to $s1
j loop
Related
I have a mini bank program written that goes calls multiple functions inside the subrouting deposit, this is the subroutine
deposit:
addi $sp, $sp, -8 #save space on stack
addi $s3, $0, 1 #trigger s3
sw $s3, 0($sp)
sw $ra, 4($sp)
.....
jal AsciiConvert #convert ascii of deposited amount to integer
beq $v0, $0, Err_ACC #if no value to be deposited was inputed print error message
beq $t0, $0, deposit_checking #if check exists returns a 0
beq $t0, 1, deposit_saving #if check exists returns a 1
jal printarray
lw $s3, 0($sp)
lw $ra, 4($sp) # reload $ra so we can return to caller
addi $sp, $sp, 8 # restore $sp, freeing the allocated space
jr $ra
deposit_checking:
... arithmetic operations...
jr $ra
the ascii convert subroutine:
AsciiConvert:
...normal arithemtics...
j ConvertOP
ConvertOP:
lb $s0, 0($a1)
beq $s0, $0, endConvert #end at null terminating
beq $s0,32,endConvert #if found a space
addi $s0, $s0, -48 #convert to int
mul $s2, $s1, 10 #multiply sum by 10
add $s2, $s2, $s0 #sum = sum + previous number
add $s1, $s2, $0 #s1 holds previous value
addi $a1, $a1, 1 #increment adress
add $v0, $s2, $0 #store the number in the return adress
j ConvertOP
endConvert:
jr $ra
When I go into deposit, I jal AsciiConvert and then I go into the deposit_Checking subroutine, however the return address of that deposit_Checking returns me back to the line of jal AsciiConvert and not to the line where I called the deposit_Checking subroutine, leading to an infinite loop between Ascii convert subroutine and deposit_Checking subroutine...can someone please help me?
deposit_checking looks like a subroutine, and you identify it as a subroutine in your post, but, we don't enter subroutines with beq instruction, you're supposed to use jal to call a subroutine.
In machine code, the return address, $ra for MIPS, is effectively a parameter to the subroutine — it tells the subroutine where to resume execution in the caller, where to return to. There are several ways to set the $ra register with a meaningful return address, though of course jal is by far the most common way.
beq transfers control of the processor to the target label (when eq is true) by changing the program counter (pc) though does not provide a (new) $ra value.
By not setting $ra to a new value, its old value is retained. Since the $ra register was last set by the jal AsciiConvert, the jr $ra for the other function goes back there, none the wiser that this was not the right call — as it is the caller's job to set that parameter properly.
And while some instruction sets allow calling on a condition, we wouldn't necessarily want all beqs to capture a return address, because then any function that used beq would have to concern itself with preserving $ra.
Let's also note that these behaviors are all visible during debugging. jr $ra, for example will transfer control to whatever machine instruction is addressed by the value in the $ra register. When you first enter a subroutine/function, there should be a proper return address parameter provided in $ra register, and by the time you get to the end of the function with its final instruction jr $ra, if the value in the $ra register's value has changed from entry, then it won't go back to where it was called from — so we'd be looking for somewhere in between that changes $ra, without restoring it back.
I have this function:
makenode:
li $v0, 9 #allocate memory
li $a0, 8 #8 bytes
syscall #$v0 <---- address
move $s1, $v0 #$s1 = address of first node
sw $t4, 0($s1) #$t4 is a string
sw $s2, 4($s1) #copy address of 2nd node
#into first node
Can it be done like this? That 4($s1) points to $2 even though it hasn't been created yet?
and since this is a function (which will be called again), how do I make it that it will work on the next run? Do I increment $s1 so it now represents $s2?
I'd like to pass a character as an argument to a function in MIPS. Do I do this by storing the character into register $a0, use jal to move to the function, then extract what's in $a0 into a separate register using lw?
If someone could give me an example of passing an argument or two in MIPS, I'd really appreciate it. I've found a lot of info on the MIPS calling conventions, but not any simple and succinct examples.
No need to use lw which is for extracting words from memory. You can simply use $a0 in the sub-routine.
Take a look at this example of a "print-char" function:
.text
main:
#save $ra on stack
addi $sp $sp -4
sw $fp 0($sp)
move $fp $sp
addi $sp $sp -4
sw $ra -4($fp)
#call sub-routine
addi $a0 $zero 'A'
jal printchar
#restore and shrink stack
lw $ra -4($fp)
lw $fp 0($fp)
addi $sp $sp 8
jr $ra
#prints a char and then a new line
printchar:
#call print-char syscall
addi $v0 $zero 11
syscall
addi $a0 $zero 10
syscall
jr $ra
As demonstrated, you the value of the $a0 register is just used in the sub-routine as it returns the value that it was given before the jal.
Also demonstrated is proper expansion and shrinking of the stack as is necessary for calling a sub-routing. As you will notice, the sub-routine does not perform this operation as it does not call a sub-routine and there-fore does not need to save the $ra. Stack manipulations would also be required in the sub-routine if it were to use an $s register as the MIPS calling convention specifies these as callee saved.
a very easy way to go about it would be to load the argument in a temp register and then just use:
move $a0,$t0
this way the argument stored in the temp register will be given as an argument
As far as I know, program counter, $PC is hidden from users. It isn't one of the 32 registers.
I want to do the following, instead of using jal
$ra <= PC + 4
j my_function
# instead of jal my_function
Is is possible to do this? I know JAIL is a macro.
How can I jump to a function without using JAL and able to return to the next instruction of the caller? Thanks.
Thanks!
One supported method of "discovering" the PC in code is to use JAL
with a zero offset (to jump/link to the next instruction), then read
the PC out of R31.
Attempt:
..statements before jump...
jal $0
addi $t3, $ra, 4
..statements when function returns..
I end up in infinite loop.
Doing a JAL to find out the PC is quite useless since you can use that JAL to do the jump... One way to do it is using LA pseudo-instruction, something like:
la $ra, current
addiu $ra, $ra, 8
current:
j example
nop
return:
j return
nop
example:
jr $ra
nop
I'm new in MIPS language and I don't understand how the functions (procedures) in the MIPS assembly language work. Here are but I will specify my problem :
What does:
jal
jr
$ra
mean in mips language and the important thing
How can we use them when we want to create a function or (procedure)?
Firstly, you might want to check this quick MIPS reference. It really helped me.
Secondly, to explain jal, jr and $ra. What jal <label> does is jump to the label label and store the program counter (think of it as the address of the current instruction) in the $ra register. Now, when you want to return from label to where you initially were, you just use jr $ra.
Here's an example:
.text
main:
li $t0, 1
jal procedure # call procedure
li $v0, 10
syscall
procedure:
li $t0, 3
jr $ra # return
You will notice when running this in a SPIM emulator that the value left in $t0 is 3, the one loaded in the so-called procedure.
Hope this helps.
1.the first two are instructions,the third it's kind of special register
jal=jump and link (Address of following instruction put in $ra,and jump to target address)
jr=jump to specify register
$ra=return address
we often use the instruction like this ...
jr $ra (Copy $ra to program counter)
it means return(jump) to the address saved in $ra .
2.
Here's an example function (procedure) in C
int main(){
x=addthem(a,b);
}
int addthem(int a, int b){
return a+b;
}
function in MIPS
.text
main: #assume value a is already in $t0, b in $t1
add $a0,$0,$t0 # it's the same function as move the value
add $a1,$0,$t1
jal addthem # call procedure
add $t3,$0,$v0 # move the return value from $v0 to where we want
syscall
addthem:
addi $sp,$sp,-4 # Moving Stack pointer
sw $t0, 0($sp) # Store previous value
add $t0,$a0,$a1 # Procedure Body
add $v0,$0,$t0 # Result
lw $t0, 0($sp) # Load previous value
addi $sp,$sp,4 # Moving Stack pointer
jr $ra # return (Copy $ra to PC)
You will want to read the System V Application Binary Interface, MIPS RISC Processor Supplement. This describes the conventions used for calling functions, in particular how the stack is managed and parameters are exchanged (there is no hardware stack in MIPS, everything is a matter of software conventions, and the ABI defines those conventions).
The document above assumes some basic knowledge of what MIPS instructions do, so you will also need the MIPS32 Architecture for Programmers, in particular volume II (instruction set), which describes the detailed effect of each instruction. But, do yourself a favor, download and read volume I (introduction) first.
The jal instruction is the "jump and link" opcode. It jumps at the target address (which is the address of the first opcode of the called procedure) while saving the current instruction pointer into the link register, which is register 31 (to be precise, it saves in register 31 the value x+8, where x is the address of the jal opcode itself).
jal: aka jump and link against any function name will redirect you to the required function.
jr $ra: It returns the value from a function that was called.
main function:
.data
x: .word 3 # initializing x to be 3
y: .word 5 # initializing y to be 5
answer: .word 0 # intialzing answer to be 0
prompt: .asciiz "Add X to Y: " # console prompt for final answer
.text
.globl main
.ent main
main:
lw $a0, x # pass arguments to function $a0 - x, $a1 - y
lw $a1, y
jal adds # adds function is called
sw $v0, answer # answer from the returned value
la $a0, prompt # displaying prompt on the console
li $v0, 4
syscall
lw $a0, answer # displaying final answer on the console
li $v0, 1
syscall
li $v0, 10 # end program
syscall
.end main
adds function:
.globl adds
.ent adds
adds: # adds function
li $v0, 0
add $v0, $a0, $a1 # adding arguments to the callee
jr $ra # return
.end adds