I have this code :
void test(int x)
{
cout<<x;
double y=x+4.0;
cout<<y;
}
void main ()
{
test(7); // call the test in main
}
In MIPS :
after I put the value of parameter x in 0($fp) in stack and jump to test :
lw $a0,0($fp) // load value of x and print it
li $v0,1
syscall
lw $t1,0($fp)
sw $t1,0($sp) // put the value of x in stack and point it by $sp
li.d $f0,4.0
s.d $f0,4($sp) // put the value 4.0 in stack and point it by $sp
l.d $f0,0($sp)
l.d $f2,4($sp)
add.d $f4,$f0,$f2
s.d $f4,8($sp) // put the result of add
l.d $f12,8($sp) // print the value of y
li $v0,3
syscall
My problem is the result of y in QTSPIM is 4 .... the problem because I load an integer value in a double register ... How I can solve this problem ???
You need to load the integer value into an fp register and then convert it to floating point format. You have an 8-byte load (which will load the 4 bytes of your value, plus the following 4 bytes, whatever they happen to be), so you probably want to change that, and then do a cvt:
l.w $f0,0($fp)
cvt.d.w $f0,$f0
Related
I have a piece of code in MIPS I am failing to understand. Namely the register convention using the "read" linux syscall:
...
move a0,zero #a0 = 0
move a1,s0 #a1 = some adress in memory
li v0,4003 #v0 = 4003 = SYSCALL READ
syscall
bnez a3, label #What is in a3??
li v1,1
bne v0,v1
...
Now I get understand it as
char buffer;
int v0 = read(0, &buffer, 1);
????
What I do not get at all is what is the meaning of reg a3 in this context? v0 is the return value of read, but a3 should be parameter and not ret value. Is it errno?
It's a boolean indicating whether or not there was an error:
On a few architectures, a register is used as a boolean (0
indicating no error, and -1 indicating an error) to signal
that the system call failed.
Arch/ABI Instruction System Ret Ret Error
call # val val2
-------------------------------------------------------------
mips syscall v0 v0 v1 a3
source
I have translated this C program into MIPS assembly code.
So, here I want to know:
Have I done something wrong?
If my assembly code is correct, can I do it more precisely by reducing the
number of instructions. I have used 14 instructions here
Here is my approach for converting this C program
This is my MIPS assembly code
#s0 = res
main:
addi $a0 , $0 , 27
addi $a1 , $0 , 3
jal division # call function
add $s0 , $v0 , $0 # res = returned value
division:
addi $t0 , $0 , 0 # $t0 = 0
addi $s0 , $0 , 0 # $s0 = val and val = 0
add $s1 , $0 , $a0 # $s1 = i and i = 27
loop:
slt $t1 , $s1 , $t0 # checking if i>0
bne $t1 , $0 , break # if $t1 = 0 then break
addi $s0 , $s0 , 1 # else val = val + 1
sub $s1 , $s1 , $a1 # i = i - y
add $v0 , $s0 , $0 # put return value in $v0
j loop
break:
jr $ra # return to caller
This is the high level C program
int main(){
int res;
res = division (27, 3);
}
int division(int x, int y)
{
int i;
int val = 0;
for (i = x; i>0; i = i-y){
val = val + 1;
}
return val;
}
Errors:
The relation is negated incorrectly. You have translated it as
for ( i = x; i >= 0; i -= y )
So, it will loop one time more than you want (when the integer division is exact). You are aware that loop condition test requires negation for the if-goto-label style of assembly:
if ( ! (i > 0) ) goto break;
However ! (i > 0) is i <= 0 where you have i < 0.
You don't properly terminate the program when the main is finished, so it will accidentally fall into the divide subroutine. The solution is to add an exit syscall to the main.
Suggestions:
The register usage is excessive, and using fewer registers will also decrease the number of instructions required. Further, using the $s registers without preserving their original values is a violation of the calling convention. However, the best solution is to simply avoid using them in that function — just use $a0 and $a1 directly instead of copying them elsewhere.
(It is ok to use s registers in main without preserving their original values, b/c main is at the top of the call chain — it has no caller — by contrast we might consider division as a general purpose function that could be called from any caller, and so should follow the calling convention.)
We not only want to minimize the instructions, but also the number of instructions in the loop. You're doing the work of "return val" by copying $s0 into $v0, but every time in the loop whereas only once is necessary, so that is better left for after the loop. Even better still, simply use $v0 for the counter (val) in the first place.
The slt instruction has an equivalent slti that is handy when comparing to a constant. With slti, no need to load a constant 0 into $t0 register. If you did need a constant 0 in a register, there is always the $0 register as well.
The MIPS instruction set has relational branch instructions that compare with zero, so you can branch on register <= 0 (or < 0) directly without slt/slti.
Currently I'm studying for my computer organization midterm, and I'm trying to fully understand the stack pointer and the stack. I know these following facts that surround the concept:
It follows the first in last out principle
And adding something to the stack takes a two step process:
addi $sp, $sp, -4
sw $s0, 0($sp)
What I think is stopping me from fully understanding is that I can't come up with a relevant, self apparent situation where I would need and/or want to keep track of data with a stack pointer.
Could someone elaborate on the concept as a whole and give me some useful code examples?
An important use of stack is nesting subroutine calls.
Each subroutine may have a set of variables local to that subroutine. These variables can be conveniently stored on a stack in a stack frame. Some calling conventions pass arguments on the stack as well.
Using subroutines also means you have to keep track of the caller, that is the return address.
Some architectures have a dedicated stack for this purpose, while others implicitly use the "normal" stack. MIPS by default only uses a register, but in non-leaf functions (ie. functions that call other functions) that return address is overwritten. Hence you have to save the original value, typically on the stack among your local variables. The calling conventions may also declare that some register values must be preserved across function calls, you can similarly save and restore them using the stack.
Suppose you have this C fragment:
extern void foo();
extern int bar();
int baz()
{
int x = bar();
foo();
return x;
}
MIPS assembly may then look like:
addiu $sp, $sp, -8 # allocate 2 words on the stack
sw $ra, 4($sp) # save $ra in the upper one
jal bar # this overwrites $ra
sw $v0, ($sp) # save returned value (x)
jal foo # this overwrites $ra and possibly $v0
lw $v0, ($sp) # reload x so we can return it
lw $ra, 4($sp) # reload $ra so we can return to caller
addiu $sp, $sp, 8 # restore $sp, freeing the allocated space
jr $ra # return
The MIPS calling convention requires first four function parameters to be in registers a0 through a3 and the rest, if there are more, on the stack. What's more, it also requires the function caller to allocate four slots on the stack for the first four parameters, despite those being passed in the registers.
So, if you want to access parameter five (and further parameters), you need to use sp. If the function in turn calls other functions and uses its parameters after the calls, it will need to store a0 through a3 in those four slots on the stack to avoid them being lost/overwritten. Again, you use sp to write these registers to the stack.
If your function has local variables and can't keep all of them in registers (like when it can't keep a0 through a3 when it calls other functions), it will have to use the on-stack space for those local variables, which again necessitates the use of sp.
For example, if you had this:
int tst5(int x1, int x2, int x3, int x4, int x5)
{
return x1 + x2 + x3 + x4 + x5;
}
its disassembly would be something like:
tst5:
lw $2,16($sp) # r2 = x5; 4 slots are skipped
addu $4,$4,$5 # x1 += x2
addu $4,$4,$6 # x1 += x3
addu $4,$4,$7 # x1 += x4
j $31 # return
addu $2,$4,$2 # r2 += x1
See, sp is used to access x5.
And then if you have code something like this:
int binary(int a, int b)
{
return a + b;
}
void stk(void)
{
binary(binary(binary(1, 2), binary(3, 4)), binary(binary(5, 6), binary(7, 8)));
}
this is what it looks in disassembly after compilation:
binary:
j $31 # return
addu $2,$4,$5 # r2 = a + b
stk:
subu $sp,$sp,32 # allocate space for local vars & 4 slots
li $4,0x00000001 # 1
li $5,0x00000002 # 2
sw $31,24($sp) # store return address on stack
sw $17,20($sp) # preserve r17 on stack
jal binary # call binary(1,2)
sw $16,16($sp) # preserve r16 on stack
li $4,0x00000003 # 3
li $5,0x00000004 # 4
jal binary # call binary(3,4)
move $16,$2 # r16 = binary(1,2)
move $4,$16 # r4 = binary(1,2)
jal binary # call binary(binary(1,2), binary(3,4))
move $5,$2 # r5 = binary(3,4)
li $4,0x00000005 # 5
li $5,0x00000006 # 6
jal binary # call binary(5,6)
move $17,$2 # r17 = binary(binary(1,2), binary(3,4))
li $4,0x00000007 # 7
li $5,0x00000008 # 8
jal binary # call binary(7,8)
move $16,$2 # r16 = binary(5,6)
move $4,$16 # r4 = binary(5,6)
jal binary # call binary(binary(5,6), binary(7,8))
move $5,$2 # r5 = binary(7,8)
move $4,$17 # r4 = binary(binary(1,2), binary(3,4))
jal binary # call binary(binary(binary(1,2), binary(3,4)), binary(binary(5,6), binary(7,8)))
move $5,$2 # r5 = binary(binary(5,6), binary(7,8))
lw $31,24($sp) # restore return address from stack
lw $17,20($sp) # restore r17 from stack
lw $16,16($sp) # restore r16 from stack
addu $sp,$sp,32 # remove local vars and 4 slots
j $31 # return
nop
I hope I've annotated the code without making mistakes.
So, note that the compiler chooses to use r16 and r17 in the function but preserves them on the stack. Since the function calls another one, it also needs to preserve its return address on the stack instead of simply keeping it in r31.
PS Remember that all branch/jump instructions on MIPS effectively execute the immediately following instruction before actually transferring control to a new location. This might be confusing.
I am trying to store a integer that i am reading from the user into a array, however when i try to store it into my array my data becomes unaligned.
This first block of code is where i initialize all the data. (Under the 1. is where i am trying to store the integer )
'#Constants
P_INT = 1 #Syscall to print integer(value)
P_STRING = 4 #Syscall to print a string(addr)
P_CHAR = 11 #Syscall to print a char(char)
R_INT = 5 #Syscall to read a integer(none)
EXIT = 10 #Exit program(none)
'#Data
.data
newline:
.asciiz "\n"
'#Space for the bored.
1.
board_rep:
.space 578
'#The current node to be read in
cur_node:
.word 0
'#Size of the bored
size:
.space 4
'#Plus sign
plus:
.asciiz "+"
'#dash
dash:
.asciiz "-"
Right here is where it becomes unaligned (the sw right after 2.) . The strange thing is that i am doing the exact same thing later (in the third code block) except that i am storing it in the size array.
'#Grabs user input for the bored and stores it
get_board_rep:
li $v0,R_INT '#Read next node and store it
syscall
2.
sw $v0,0($s1)
addi $s1,$s1,4 ' #Increment next node addr
lw $a0,0($s1)
j prnt_node
At the store word (under the 3. ) it stores the read in integer fine.
la $s0, size ' #Store the variable addr's
la $s1, board_rep
li $v0,R_INT ' #Get user input(size of bored)
syscall
3.
sw $v0,0($s0) ' #Store the size of bored
jal get_board_rep
I thought maybe the array was too large but i changed it to 4 (the same size that the other array that worked). But it still was unaligned.
Thanks in advance . This is a project and i know some people don't like helping with stuff like this. But i have done my homework and i cannot find a answer anywhere.
That doesn't look aligned to me, and if i'm wrong try explicitly aligning it anyway.
Let's say I have $t0, and I'd like to divide its integer contents by two, and store it in $t1.
My gut says: srl $t1, $t0, 2
... but wouldn't that be a problem if... say... the right-most bit was 1? Or does it all come out in the wash because the right-most bit (if positive) makes $t0 an odd number, which becomes even when divided?
Teach me, O wise ones...
Use instruction sra: Shift right arithmetic !!
sra $t1, $t0, 1
Divides the content of $t0 by the first power of 2.
Description: Shifts a register value
right by the shift amount (shamt) and
places the value in the destination
register. The sign bit is shifted in.
Operation: $d = $t >> h;
advance_pc (4);
Syntax: sra $d, $t, h
Encoding:
0000 00-- ---t tttt dddd dhhh hh00
0011
Why is this important? Check this simple program that divides an integer number (program's input) by 2.
#include <stdio.h>
/*
* div divides by 2 using sra
* udiv divides by 2 using srl
*/
int div(int n);//implemented in mips assembly.
int udiv(int n);
int main(int argc,char** argv){
if (argc==1) return 0;
int a = atoi(argv[1]);
printf("div:%d udiv:%d\n",div(a),udiv(a));
return 1;
}
//file div.S
#include <mips/regdef.h>
//int div(int n)
.globl div
.text
.align 2
.ent div
div:
sra v0,a0,1
jr ra //Returns value in v0 register.
.end div
//int udiv(int n)
.globl udiv
.text
.align 2
.ent udiv
udiv:
srl v0,a0,1
jr ra //Returns value in v0 register.
.end udiv
Compile
root#:/tmp#gcc -c div.S
root#:/tmp#gcc -c main.c
root#:/tmp#gcc div.0 main.o -o test
Test drives:
root#:~# ./test 2
div:1 udiv:1
root#:~# ./test 4
div:2 udiv:2
root#:~# ./test 8
div:4 udiv:4
root#:~# ./test 16
div:8 udiv:8
root#:~# ./test -2
div:-1 udiv:2147483647
root#:~# ./test -4
div:-2 udiv:2147483646
root#:~# ./test -8
div:-4 udiv:2147483644
root#:~# ./test -16
div:-8 udiv:2147483640
root#:~#
See what happens? The srl instruction is shifting the sign bit
-2 = 0xfffffffe
if we shift one bit to the right, we get 0x7fffffff
0x7ffffffff = 2147483647
Of course this is not a problem when the number is a positive integer, because the sign bit is 0.
To do unsigned integer division, thats right. This only works for unsigned integers and if you don't care about the fractional part.
You will want to use a shift amount of 1, not 2:
srl $t1, $t0, 1
If you use 2, you will end up dividing by 4. In general, shifting right by x divides by 2x.
If you are concerned about "rounding" and you want to round up, you can just increment by 1 before doing the logical (unsigned) shift.
And other have stated it previously but you only shift by 1 to divide by 2. A right shift by N bits divides by 2^N.
To use rounding (rounding up at 0.5 or greater) with shift values of N other than 1, just add 1<<(N-1) prior to the shift.