MIPS Any reason not to use li instead of lw for storing ints,floats,doubles? - mips

I see people using lw and li for the same purpose, of storing and manipulating numbers in registers. But which one is the most adequate, under what circumstances?
Thank you.

I see people using lw and li for the same purpose
They don't have the same purpose.
The purpose of lw is to load a word (32 bits) from memory into a register. For example:
.data
foo: .word 12345
.text
la $a0, foo # $a0 = address of foo
lw $t0, ($a0) # $t0 = 12345
The purpose of li is to load an immediate into a register. For example:
li $t0, 12345 # $t0 = 12345
Note that the MIPS instruction set doesn't actually include any li instruction. It's a pseudo-instruction implemented by the assembler, which will convert it into one or more actual instructions (e.g. a combination of lui and ori).

Related

MIPS - how to store char values into space

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.

MIPS: Is it possible to print the value that is inside storage that contains .word?

i am currently learning MIPS and i have a question about MIPS. As the question title, is it possible to print a value that is inside a storage that declared with ".word"
EX:
.data
var1: .word 3
.text
.globl main
main:
li $v0, 4
la $a0, var1
syscall
So is it possible for it to printed about the value 3 from var1?
Sure, just load the word from that address:
la $a0, var1
lw $a0, ($a0)
Or, if you wanted to, you could replace those two instructions with a single lw:
lw $a0, var1
Note that this is a pseudo-instruction, which the assembler will translate into 1 or more actual instructions. So you're not gaining anything at the machine code level, but your assembly code will be more compact.

Declaring integer values in MIPS

So I am writing an assembly program that has lots of constant integer values.
I know that in the .data section I can assign a label with a .word data type and type in my number. With this method I still have to load an address in main.
But in main, I could just simply use
li $t1, some_number
Are any one of these methods better than the other and why?
Generally I'd say using li is the better approach. You're avoiding adding a bunch of clutter in your .data section, and you will also get more efficient code in some cases.
Let's look at some examples:
.data
ten: .word 10
million: .word 1000000
.text
main:
lw $t0,ten
li $t1,10
lw $t2,million
li $t3,1000000
It's important to understand here that both lw and li are pseudo-instructions that get translated into one or more actual instructions. lw does exist in the MIPS instruction set, but this particular variant of it doesn't. li doesn't exist in the MIPS instruction set.
If we look at what SPIM generates for the first two instructions, we see:
[0x00400024] 0x3c011001 lui $1, 4097 ; 9: lw $t0,ten
[0x00400028] 0x8c280000 lw $8, 0($1)
[0x0040002c] 0x3409000a ori $9, $0, 10 ; 10: li $t1,10
So that's one additional instruction for the lw variant, as the address first has to be loaded into a register, and then the value is loaded from that address. This also means one additional (potentially slow) memory access (well, two if you count the instruction fetch).
Now let's look at the other two instructions, where the value to be loaded is too large to be encoded in a single instruction:
[0x00400030] 0x3c011001 lui $1, 4097 ; 11: lw $t2,million
[0x00400034] 0x8c2a0004 lw $10, 4($1)
[0x00400038] 0x3c01000f lui $1, 15 ; 12: li $t3,1000000
[0x0040003c] 0x342b4240 ori $11, $1, 16960
Here the immediate 1000000 is loaded using two instructions as (15 << 16) | 16960. So both variants require two instructions, but the li variant doesn't need to read from memory.
If you want to assign a meaningful name to a constant to avoid having magic numbers all over your code you can do so with =:
TEN = 10
li $t0, TEN # Expands to li $t0, 10
You could perhaps avoid loading the addresses for lw all the time by using $gp-relative addressing, but I feel that that's beyond the scope of this question.

MIPS How to branch to a 32-bit address?

I am trying to branch to an address:
bne $t0, $0, 0x7813a21c
However, this is incorrect because bne only allocates 16-bits to the immediate
How can I branch to a direct 32-bit address? Is there a way to branch from a value in a register?
You have to use JR to jump to an address stored in a register.
To preform this type of operation you will need a jump statement. You have to tell the code to jump control context to the exact line you wish to specify. This is example syntax: j offset Where in your address is the offset.
Here is a link that better reviews what you have to do. Check out the section on jump. These are the types of jump available. One of them is what you need: j offset, jal offset, jr $rs, jalr $rs
Here is the link:
http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/Mips/jump.html
Good luck
We can load 32-bit addresss to the register (e.g. $t1) in 2 steps:
Load the upper 16 bits by lui (Load Upper Immediate).
Load the lower 16 bits by ori (Or Immediate).
NOTE: It is work because lui fills the lower 16 bits with 0s, so bitwise OR load the lower 16 bits (n | 0 = n);
In code below if $t0 is equal to 0 we do skip jr instruction.
Or if $t0 is not equal to 0 we do not skip jr instruction (or we do jump).
beq $t0, $0, SKIP
# load 0x7813a21c to $t0
lui $t1, 0x7813 # load the upper 16 bits
# Now $t1 = 0x78130000
ori $t1, $1, 0xa21c # load the lower 16 bits
# Now $t1 = 0x7813A21C
jr $t1 # as #Matt Eckert said
SKIP:

the functions (procedures) in MIPS

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