Understanding MIPS Assembly Code Segment - c

Just started learning assembly for one of my classes and I am a bit confused over this code segment. This is from a textbook question which asks you to translate from MIPS instructions to C. The rest of the question is in the attached image.
For the MIPS assembly instructions above, what is the corresponding
C statement? Assume that the variables f, g, h, i, and j are assigned to registers $s0, $s1, $s2, $s3, and $s4, respectively. Assume that the base address of the arrays A and B are in registers $s6 and $s7, respectively.
sll $t0, $s0, 2 # $t0 = f * 4
add $t0, $s6, $t0 # $t0 = &A[f]
sll $t1, $s1, 2 # $t1 = g * 4
add $t0, $s6, $t0 # $t1 = &B[g]
lw $s0, 0($t0) # f = A[f]
addi $t2, $t0, 4
lw $t0, 0($t2)
add $t0, $t0, $s0
sw $t0, 0($t1)
I have a basic understanding of some MIPS instructions but frankly, the stuff with arrays confuses me a bit. Could anyone here point me in the right direction? Thanks!

It's been a while since I last wrote MIPS assembly. However, from what I can understand from the first few instructions:
sll $t0, $s0, 2 # t0 = 4 * f
add $t0, $s6, $t0 # t0 = &A[f]
s0 holds the index f at which you want to access array A. Since you multiply f by 4, A is an array of some datatype with 4 bytes length (probably an int). s6 is holding the array address, because to access the address of A[f] you would essentially do (in pseudocode)
address_of_A[f] = base_address_of(A) + offset_of_type_int(f)
The same stuff in principle happens in the next 2 instructions, but this time for array B. After that:
lw $s0, 0($t0) # f = A[f]
addi $t2, $t0, 4 # t2 = t0 + 4
The first load is obvious, s0 gets the value at address t0, which is of course A[f]. The second increments t0 by 4 and stores it to t2, which means that t2 now contains the address &A[f+1], since we know that array A contains 4-byte data.
The last lw command:
lw $t0, 0($t2)
stores the value at address $t2 on $t0, so $t0 is now A[f+1].

Related

Index MIPS array with an integer loop counter [duplicate]

What is the following C code in MIPS?
f = A[B[i]]
I'm told it can be done in 6 lines but can't quite figure out how.
f is in $t0, i is in $t3, A[] is in $s0, and B[] is in $s1. All types are integer.
The best I am able to think of is
lw $t5, $t3($s0); # Doesn't work because lw syntax doesn't accept a register as an offset
lw $t6, $t5($s1);
sadd $t0, $t6, $zero
Obviously this is wrong. How would i go about getting the correct offset for each line?
Thanks.
There might be more efficient ways, but here's one way in 6 lines:
sll $t2,$t3,2 # t2 = i * sizeof(int)
addu $t2,$t2,$s1 # t2 = &B[i]
lw $t0,0($t2) # t0 = B[i]
sll $t0,$t0,2 # t0 *= sizeof(int)
addu $s0,$s0,$t0 # s0 = &A[B[i]]
lw $t0,0($s0) # t0 = A[B[i]]
Read a MIPS instruction set reference to get more information about what individual instructions do.

Simple MIPS for loop not running

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

C to MIPS Assembly [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I was trying to solve this and convert it to MIPS assembly code
but the answer in the book confused me.so, can anyone explain how this code get this result in c ?
B[g] = A[f] + A[f+1];
I have inserted comments for what I think that's right please correct me if I was wrong.
Assume we have variables f, g, h, i, j stored in $s0, $s1, $s2, $s3 and $s4, respectively. Assume the base addresses of arrays A and B are at $s6 and $s7.
The code:
add $t0, $s6, $s0 #This will add f bytes to the base address and it's not equal to A[f].
add $t1, $s7, $s1 #This will add g bytes to the base address and it's not equal to B[g]
lw $s0, 0($t0) #This will point to the value in (f +base address of A +0) bytes
lw $t0, 4($t0) #This will point to the value in (f +base address of A +4) bytes
add $t0, $t0, $s0
sw $t0, 0($t1)
Your compiled fragment annotated by me:
add $t0, $s6, $s0
add and store in register t0 whatever is in register s6 and s0. Since you have pointed out that f is stored in s0 and the base address of A is stored in s6, this adds the addresses in preparation for a register indirect load later on. More simply A[f] == *(A + f) in C, and this is preparing for the (A + f) de-reference later on.
add $t1, $s7, $s1
The same thing happening for B and g. Add their contents and store them in an intermediate register, to be later used as address based de-reference targets.
lw $s0, 0($t0)
This is loading to the s0 register, using what's known as the register-indirect addressing mode of the cpu, whatever is at the address pointed to by t0 plus 0 bytes. In c this is equal to s0 = *(A + f).
lw $t0, 4($t0)
The same thing as above, only that this time it loads to register t0 whatever is pointed at t0 plus 4 bytes. Equal to C t0 = *(A + f + 1).
add $t0, $t0, $s0
This is the point where it performs the addition in your code. It's equal to the C code fragment of A[f] + A[f + 1].
sw $t0, 0($t1)
This is storing the result of the previous addition to the address pointed to by t1.
~~~~~~~~~~~
If you are looking for some references for the code you have, I found both this MIPS instruction set reference useful and, of course, Matt Godbolt's interactive compiler.
If you want to see what code does what using the interactive compiler, just wrap your code in a void function, select as the compiler x86 clang and at the compiler options --target=mips. Then from the filter apply colourise, and you will be able to see what C code generates what assembly code, to get something like the image below
add $t0, $s6, $s0 # t0 = A + f
add $t1, $s7, $s1 # t1 = B + g
lw $s0, 0($t0) # s0 = *(t0 + 0) = *(A + f) = A[f]
lw $t0, 4($t0) # t0 = *(t0 + 4) = *(A + f + 1) = A[f+1]
add $t0, $t0, $s0 # t0 = t0 + s0 = A[f] + A[f+1]
sw $t0, 0($t1) # *(t1 + 0) = *(B + g) = B[g] = t0
Remember that C pointer arithmetic scales by item size, but assembly uses bytes. Hence, advancing 4 bytes is advancing 1 item in C.
On second thought, this in fact means f and g should also be scaled by 4, which they don't seem to be.
sll $t0, $s0, 2 # $t0 = f * 4
add $t0, $s6, $t0
sll $t1, $s1, 2 # $t1 = g * 4
add $t1, $s7, $t1
lw $s0, 0($t0)
lw $t0, 4($t0)
add $t0, $t0, $s0
sw $t0, 0($t1)
Yes, the code is missing these two lines, you just need to scale both f and g by 4.

converting C code to MIPS Assembly Language with arrays

Ok, so I have to convert the following C code segment to MIPS Assembly.
f = k + A[5]
The question tells me that f is stored in register $s3, k is in $s2 and the base address of array A is $s4. This is what I put as my answer:
add $s3, $s2, $s4
Is this correct? Do I have to do anything special with the 5 in the array? I'm very new to MIPS, so any and all help if VERY much appreciated.
Are you working on this for homework? If so, are you actually writing out an executable program or just responding to a list of questions?
Either way yes, you do need to account for the 5 in the array. The question is telling you that $s4 points to the base address of the array, not the 5th index.
hint: A[0] would be at the same address as the base of the array.
Try this out. (Off the top of my head). Remember each index is * 4.
li $t2, 6 # init 6 to $t2
addi $t2, $t2, $t2 # $t2 * 2
addi $t2, $t2, $t2 # $t2 * 2
addi $t1, $t2, $s4 # A[6 * 4]
lw $t4, 0($t1) # load A[6] int $t4
addi $s3, $s2, $t4 # obtain f

Copying elements from one array to another in MIPS assembly

I'm new at MIPS and have been trying to copy elements from one array to another. I'm unsure about how to go about this. It doesn't really matter what size the array is but lets just say for the sake of doing it that its size 10. I am little weak with MIPS loops and am kind of confused on how to proceed.
add $s0, $zero, $zero
add $t0, $zero, $zero
lui $s0, 0x1001
ori $s0,$s0,0
lui $t0, 0x1001
ori $t0, $t0, 0x0040
There my initialization with $s0 being the address first element in the first array and $t0 being the address of the first element in the 2nd one.
I do not believe the code you have provided is correct, but assuming it is, you would do something like this:
xor $t1, $t1, $t1 ; Zero out $t1
lw $t2, array_length ; Load the length of the array in $t2
loop_start:
lb $t3, $s0 ; Load the next byte from $s0 into $t3
sb $t3, $t0 ; Store the by in $t3 into $t0
addi $s0, $s0, 1 ; Move to the next byte in the source
addi $t0, $t0, 1 ; Move to the next byte in the destination
addi $t1, $t1, 1 ; increment the counter
blt $t1, $t2, loop_start ; Jump to the start of the loop of there are more bytes
Disclaimer: I have not programmed in MIPS since college so this code may not be 100% accurate, but I believe it will give you a place to start.

Resources