Could someone help walk me through what some lines in this MIPs code are doing?
The C code is B[8] = A[i - j] with i = $s3, j = $s4, &A[] = $s6, and &B[] = $s7
The MIPs code is as follows...
sub $t0, $s3, $s4 # i - j
sll $t0, $t0, 2 #Gets the offset of 8 for B[]
add $t0, $s6, $t0 #Goes to the offset in B[] ?
lw $t1, 0($t0) #????
sw $t1, 32($s7) #????
I get a bit lost once it gets to the last 3 lines.
Why is it 0($t0) and 32($s7)? Or just why 0 and 32?
sll $t0, $t0, 2 // This multiplies (i-j) * 4, not 8. Because the indexes are 4-byte ints
add $t0, $s6, $t0 // $t0 = A + (i-j)*4. So $t0 = &A[i-j]
lw $t1, 0($t0) // $t1 = A[i-j]
sw $t1, 32($s7) // B[32/4] = $t1
32($s7) means $s7 + 32. The reason you add 32 because you are accessing the 8th element of an integer array, which is located in the memory address B + 8*sizeof(int) = B + 32
Related
I'm very new to MIPs and trying to create a for loop for an assignment.
for (int i=1; i < 16; i+=2)
{
A[i] = A[i] + B[3*i]
}
With the current code I have when I try to load the value of A[i] it says fetch address not aligned on word boundary.
Here is my code:
main:
li $t0, 1 # Starting index of t0=i
lw $s7, aSize # Loop bound
la $s0, A # &A
la $s6, endA # &endA
la $s1, B # &B
loop:
#TODO: Write the loop code
addi $t3, $zero, 3 # $t3 = 3
mul $t4, $t0,$t3 # $t4 = i * 3
sll $t4, $t4, 2 # $t4 into a byte offset
add $s1, $s1, $t4 # $s1 = &B[i*3]
add $s0, $s0, $t0 # $s0 = &A[i]
lw $t1, 0($s0) # value of A[i]
lw $t2, 0($s1) # value of B[i * 3]
add $t2, $t1, $t2 # A[i] + B[i]
sw $t2, 0($s0) # A[i] = A[i] + B[i]
addi $s0, $s0, 2
addi $s1, $s1, 2
addi $t0, $t0, 1 #i++
bne $t0, $s7, loop
I'm very new to MIPs so not sure whats going on or where to even look. I appreciate any help.
When you do:
mul $t4, $t0,$t3 # $t4 = i * 3
You are calculating the array index [as you would in c].
But, before you can add that to the base address of the array, you need to convert this index into a byte offset. That is, you have to multiply it by 4. This can be done [as in c] with a shift left of 2.
So, after the mul, do:
sll $t4,$t4,2
You have to do this multiply/shift for all index values before adding them in.
UPDATE:
Okay that makes sense. I added that in but I'm still getting that word boundary error on the line "lw $t1, 0($s0)"
You're not showing the definition of A or B, so there could be an alignment issue.
When you do:
add $s1, $s1, $t4 # $s1 = &B[i*3]
You are modifying the original/base value of &B[0]. That's not what you want. Use a different register for the final address value (i.e. leave $s1 unchanged throughout the loop)
Do something like:
add $s3, $s1, $t4 # $s3 = &B[i*3]
lw $t2, 0($s3) # value of B[i * 3]
Adjust other similar register usage in a similar manner (i.e. you have a similar problem with the A array)
I've coded up a cleaned up version. I've not assembled nor tested it, but I think it will get you closer. This may have an off-by-one error [it's hard to tell without the entire program] as I'm not sure what aSize is.
main:
li $t0,1 # Starting index of t0=i
lw $s7,aSize # Loop bound
la $s0,A # &A
la $s6,endA # &endA
la $s1,B # &B
addi $t3,$zero,3 # $t3 = 3
loop:
# TODO: Write the loop code
mul $t4,$t0,$t3 # $t4 = i * 3
sll $t4,$t4,2 # $t4 into a byte offset
add $s3,$s1,$t4 # $s3 = &B[i*3]
sll $t4,$t0,2 # $t4 into a byte offset
add $s2,$s0,$t4 # $s2 = &A[i]
lw $t1,0($s2) # value of A[i]
lw $t2,0($s3) # value of B[i * 3]
add $t2,$t1,$t2 # A[i] + B[i]
sw $t2,0($s2) # A[i] = A[i] + B[i]
addi $t0,$t0,2 # i += 2
bne $t0,$s7,loop
so my professor put this problem in his slides and this was his answer, not understanding how he converted it into MIPS so if anyone could help explain this that would be great.
Variable i is in $s3, k is in $s5, and the base address of save[] is in $s6
He gave us this C code:
while( save[i] == k ) {
i += 1;
}
And gave us this MIPS code in response:
Loop: sll $t1, $s3, 2
add $t1, $t1, $s6
lw $t0, 0($t1)
bne $t0, $s5, Exit
addi $s3, $s3, 1
j Loop
Exit:
Loop: sll $t1, $s3, 2 # $t1 = 4*i (this is the offset to get to the ith element in your array)
add $t1, $t1, $s6 # $t1 = 4*i + base addr of save (getting the address of save[i])
lw $t0, 0($t1) # $t0 = save[i] (actually loading 4B from address of save[i], so getting the actual number here)
bne $t0, $s5, Exit # branch to Exit if save[i] != k
addi $s3, $s3, 1 # i++
j Loop
Exit:
Things to note here:
save is an int array, so each element is 4B. That's why the offset is 4*i.
int MyArray[30];
int n = 2;
MyArray[0] = 1;
MyArray[1] = 1;
do{
MyArray[n] = MyArray[n-1] + MyArray[n-2];
n++;
}
while(n < 30);
While I was doing this I got stuck on how i can recursively call the function without the use of return address $ra or $sp since the code doesn't actually return anything.
This is my work so far :
#s1= Myarray[0]
addi $s0, $0, 2 #$s0=n=2
addi $t0, $s1,0
addi $t1,$0,1
sw $t1, 0 ($t0) #Myarray[0]=1
addi $t0,$t0,4
sw $t1, 0 ($t0) #Myarray[1]=1
add $t0,$s0,$s1 #MyArray[n]= Myarray[0] +n
Loop:
addi $t2,$t0,-4
addi $t3,$t0,-8
lw $t4,0 ($t2)
lw $t5,0 ($t3)
add $t5,$t4,$t5
sw $t5, 0 ($t0)
addi $t0, $t0 ,4
addi $s0,s0,4
slti $s6,$s0,30
beq #s6,$0,Exit
j loop
Exit
This code
sw $t1, 0 ($t0) #Myarray[0]=1
addi $t0,$t0,4
sw $t1, 0 ($t0) #Myarray[1]=1
add $t0,$s0,$s1 #MyArray[n]= Myarray[0] +n
should be
sw $t1, 0 ($t0) #Myarray[0]=1
addi $t0,$t0,4 #update 't0' to point to Myarray[1]
sw $t1, 0 ($t0) #Myarray[1]=1
addi $t0,$t0,4 #update 't0' to point to Myarray[2]
The error is in the last line. Note that $s1 points to the array, and $s0 has the value 2, so t0=s1+s0 points t0 to the wrong address. You really want t0=s1+(s0*4) since each int is four bytes.
However, since you've already updated t0 to point to Myarray[1] (in the second line), you can just update it again (in the fourth line).
I was trying to convert C code to MIPS assembly. There are these two following C code snippets. The problem is that my solution differs from the standard solution. Also, I don't understand the standard solution. I hoped, someone could explain me the two following mips assembly code snippets.
First of all some additional information for the task. Only the following MIPS instructions are allowed: lw, add, beq, bne and j.
The register:
$s3 contains i
$s4 contains j
$s5 contains k
A is an array of 32-Bit-Integer and the initial address of A is in $s6
$t0 and $t1 can be used for storing temporary variables
The first one is a simple do-while loop:
do {
i = i + j;
} while(A[i] == k);
MIPS Assembly
loop: add $s3, $s3, $s4 // this is i = i+j
add $t1, $s3, $s3 // from now on
add $t1, $t1, $t1 // I cant follow anymore
add $t1, $t1, $s6 // What happens in these three lines?
lw $t0, 0($t1) // 0($t1) is new for me. What does this zero do?
beq $t0, $s5, loop
Now the second C code:
if ( i == j )
i = i + A[k];
else if( i == k )
i = i + A[j];
else
i = i + k;
Here is the MIPS assembly code:
bne $s3, $s4, Else1 // this line is if(i==j)
add $t1, $s5, $s5 // from here on
add $t1, $t1, $t1 // till
add $t1, $t1, $s6 //
lw $t0, 0($t1) //
add $s3, $s3, $t0 // here I don't understand
j done
ELSE1: bne $s3, $s5, Else2 // this line is if(i==k)
add $t1, $s4, $s4 // The same game as above
add $t1, $t1, $t1
add $t1, $t1, $s6
lw $t0, 0($t1)
add $s3, $s3, $t0 // till here
j done
ELSE2: add $s3, $s4, $s5
Could anyone explain me what really goes on? That would be very helpful
O.k. the most interesting and not-understandable piece of code is the following:add $t1,
add $t1, $s5, $s5
add $t1, $t1, $t1
add $t1, $t1, $s6
this code multiplies $s5 by four, and stores it in $t1, then adds to $t1 $s6. That is equivalent to:
$t1 = A[k]
after you understand this, the code looks much clearer.
about the lw $t0, 0($t1):
you can use an offset point in the address. Here the offset is 0.
lw is load. The mode here is indirect addressing, the most common is:
lw $t2, ($t0)
But you can also include a byte offset,
lw $t2, 4($t0) # load word at RAM address ($t0 + 4) into register $t2
The compiler is just putting the 0 placeholder in the non-offset version.
So, to load A[i] you need to do two things. Take the base address of A[] and then add i times the sizeof(A[0]). I am guessing that the values in A are 32 bit.
add $t1, $s3, $s3
$t1 = j + j or 2 * j
add $t1, $t1, $t1
$t1 = $t1 + $t1 or j +j +j +j or 4 * j
So why did it do it this way? Well, doing a straight multiply is slow in terms of clock cycles. The next choice would be a shift operation, but in this case, the compiler designers decided that two adds beat a shift.
add $t1, $t1, $s6
I would guess that $s6 is the base address of A[]. So ultimately '$t1 = A[] + 4 * j`
I have a answer.The loop, a is array of elements have basic address :0x0FE3B128.
Thanks all so much..
and this is my homework, I don't sure that it is correct.
for(i=1; i!=20;i+=3){
a[i]= a[5]+1;
}
lui $s0, 0x0FE3
ori $s0, $0, B128
lw $t1, 20($s0)
addi $s1, $0, 1
addi $s2, $0, 20
LOOP beq $s1, $s2, DONE
add $t1, $t1, $s1
sll $t1, $t1, 2
sw $t2, 0($t1)
addi $s1, $0, 3
j LOOP
DONE
I need to translate some MIPS assembly instructions to C code. I think I got it, but it seems counter-intuitive. Any help? We have variables f, g, h, i, j stored in registers $s0, $s1, $s2, $s3 and $s4 respectively. The base of arrays A and B are stored in $s6 and $s7 respectively. 4 byte words. Comments in the code are my own.
addi $t0, $s6, 4 # $t0 = A[1]
add $t1, $s6, $0 # $t1 = A[0]
sw $t1, 0($t0) # $t0 = A[0]
lw $t0, 0($t0) # $t0 = A[0]
add $s0, $t1, $t0 # f = A[0] + A[0]
I just feel like I'm wrong. Why make $t0 A[1] first if we never use it?
I think you have got in completely wrong.
addi $t0, $s6, 4 # $t0 = A[1]
After the addi, register $t0 became the memory address of A[1], which would be &A[1], not A[1]. To get value of A[1], you need to use lw after you done the addi
lw $t0, 0($t0) # $t0 =A[1]
sw $t1, 0($t0) # $t0 = A[0]
You've got this back-to-front. It is a store, so it is used:
sw $t1, 0($t0) # A[1] = $t1
Just a little addition to the previous answers:
The store word means that you cannot access $t1 anymore because it is copied to memory. At least you should not use the $t1 from the store word instruction. You should use the one before (add $t1, $s6, $0). This means that the answer is f ( which is in $s0) = &A[0] (base address in register $t1) + A[1] (value of the array with word index 1, which is in register $t0)
Mnush's answer is incorrect.
The last line is adding $t1 and $t0.
$t1 = A[0] and
$t0 = A[1].
With proper comments:
addi $t0, $s6, 4 # $t0 = &A[1]
add $t1, $s6, $0 # $t1 = &A[0]
sw $t1, 0($t0) # A[0] = A[1]
lw $t0, 0($t0) # $t0 = A[0]
add $s0, $t1, $t0 # f = A[0] + A[1]
The C Code:
A[1] = A[0];
f = A[0] + A[1];
Actually you are using A[1] twice as shown:
Register $t0 carries the address of the array from the first instruction
sw $t1, 0($t0) # A[1] = $t1 => A[1] = &A[0]
Load the value of the address ($t0 + 0) into register $t0
lw $t0, 0($t0) # $t0 = A[1]
Essentialy =>
$t0 = &A[0]
addi $t0, $s6, 4 # $t0 = &A[1]
add $t1, $s6, $0 # $t1 = &A[0]
sw $t1, 0($t0) # A[1] = &A[0]
lw $t0, 0($t0) # $t0 = A[1]
add $s0, $t1, $t0 # f = &A[0] + A[1]
C code:
f = &A[0] + A[1]
Guess this is correct.
A[1] = A[0]
f= A[1] + A[1]