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
Related
I tried to store a char in to a space x
.data
x: .space 1
.text
.globl main
main:
lb $t0, '*'
sb $t0, x
lb $a0, x
li $v0, 11
syscall
jr $ra
it shows "Bad address in data/stack"
but it works perfectly when i use int
.data
x: .space 4
.text
.globl main
main:
li $t0, 6
sw $t0, x
lw $a0, x
li $v0, 1
syscall
jr $ra
Whats the difference between them? Why the int one works but the char one does not?
Judging by the system calls you're using, you're running this in a simulator like SPIM or MARS. The simulator showed you what the problem is:
Runtime exception at 0x00400000: address out of range 0x0000002a
And at address 0x00400000 in the code window you can see lb $8,0x0000002a($0).
So you're trying to load a byte from address 0x2a (0x2a happens to be the ASCII code for '*').
Indeed, if you look up LB in the instruction set reference from MIPS, you'll see:
LB rt, offset(base)
Description: rt ← memory[base+offset]
Obviously this is not the instruction you want for loading the constant value '*'. For that you should be using the li pseudo-instruction (or addi or ori).
TL;DR: You're tring to use a memory load instruction to load an immediate constant. Don't ignore the information that the simulator is giving you.
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
This code is part of a much bigger program that worked just fine. Then I realized the assignment would be tested in -bare mode. As soon as I tried running it in -bare mode my print_string syscalls went from working fine to not printing anything and I have no idea why.
Running this gives me no errors it just doesn't print anything
(also are the 2 or $0,$0,$0 necessary at the end?)
.globl main
.data
v: .space 2
w: .space 2
x: .space 2
y: .space 2
z: .space 2
inputPrompt: .asciiz "Input mathmatical expression: "
.text
main: #main block used to read in all the necessary data
lui $a0, 0x1001
#prompt for expression
addi $v0, $0, 4
addi $a0, $a0, 10
syscall
or $0,$0,$0
jr $ra
or $0,$0,$0
This is the problem:
lui $a0, 0x1001
If you look at the addresses in the DATA/STACK viewer in SPIM, you'll see that when you're in bare mode the DATA section starts at 0x10000000 instead of 0x10010000. So you should change that lui to lui $a0, 0x1000.
are the 2 or $0,$0,$0 necessary
Bare mode implies that branch delay slots are simulated. So you should fill any branch delay slots with instructions that are safe to execute there. That could be NOPs, or more meaningful instructions if you manage to reorganize your code. For example, if you had:
ori $a0,$0,1
jal foo
you could've changed that into:
jal foo
ori $a0,$0,1 # will be executed in the delay slot
Note that syscall doesn't have any delay slot. From MIPS32™ Architecture For Programmers
Volume II: The MIPS32™ Instruction Set:
Format: SYSCALL
Description:
A system call exception occurs, immediately and unconditionally transferring control to the exception handler
I have this program I just wrote:
countzeroes:
li $v0, 0 # count = 0
li $t0, 0 # int i = 0
li $v1, 1 # compare bit = 1
cz_loop:
bge $t0, 32, cz_exit # exit loop if i >= 32
andi $t1, $a0, 1 # bit = arg0 & 1
beq $t1, $v1, cz_skip # skip if bit = 1
addi $v0, $v0, 1 # adds 1 to count
cz_skip:
srl $a0, $a0, 1 # shifts input right by 1
add $t0, $t0, 1 # i++
j cz_loop
cz_exit:
jr $ra
Pretty simple, just computes the number of zeroes in a 32 bit word. I was wondering how the program knows how to return $v0 at the end? I know v0 and v1 are return registers, but I was wondering if those two are always returned. If not, how does the program know to return v0?
In addition, I know jr $ra jumps to the return address- but what does that mean?
Thanks for your help.
"how the program knows how to return $v0 at the end?"
It doesn't know, you're writing the "return" value in $v0, in fact you could return the "result or return values" in any available register such as the temporals, it's just a convention to use the $v0 register to return values (in MIPS).
"I was wondering if those two are always returned"
Remember that in any subroutine in your program you always have access to all registers, so there's not "restriction" about what register store values that can be semantically called "return values", so I could easily create a method that returns 3 numbers in $t0, $t1, $t2 but that's my choice, you can return values in the stack also, there are a lot of possibilities, and this depends and lays down on the good programming practices and also the calling conventions, here you can find the MIPS calling convention: https://courses.cs.washington.edu/courses/cse410/09sp/examples/MIPSCallingConventionsSummary.pdf
" jr $ra jumps to the return address- but what does that mean?"
The program is executed instruction by instruction(the program has an instruction pointer aka program counter), when you call a subroutine the address of the next instruction is being stored in the $ra register, then when you make jr $ra, the program execution returns to that address (the instruction pointer gets the value of $ra).
In MIPS there are three different jumps you'll see. j, jr & jal.
j: it is considered an unconditional jump. Simply just do:
j function
jr:aka jump to register. Exactly as the name sounds you jump to register. This is when you have a register already saved somewhere in your program you want to jump back to. It will usually look like so:
jr $ra
$ra being the register which had been previously set aside before your jal (see below) which will jump the program back to that address.
jal: aka Jump and link copies the address of the next instruction into the register and then jumps to the address label. In other words, both jal and jr are used in conjunction with each other mainly for going to functions which are usually placed after the exit calls.
Ex:
main:
#program
jal function
#continue with program
function:
#
#do something
#
jr $ra
Also, most helpful site when I started learning: http://logos.cs.uic.edu/366/notes/mips%20quick%20tutorial.htm
Some other quick hints that I wish someone told me when I started:
Always start with "main:"
Be wary of the difference between high/low registers in multiplying
and dividing integers
Always keep track of your registers because with so many $s and $t
and $f and $p and $a and $v registers working at one time things can
get messy very quickly.
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