C to MIPS Assembly [closed] - c

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.

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.

How do I find out why a "address out of range in MIPS", although temporary variables are declared

I am doing a homework problem for the computer design and architecture class where we are required to implement a simple for loop in C, into MIPS using the MARSim. I implemented the for loop step by step, initialized (if that is the proper term) the variables in memory, yet when I assemble and run it throws this error: question1.asm line 11: Runtime exception at 0x00400008: address out of range 0x00000000
I've looked at line 11 : lw $t1, 0($a1),
and as I understand it, this should work properly. As I understand here we are setting our t1 value to a1 (b[i]).
Here is the C we have to reproduce:
for (i=0; i<=100; i++) { a[i] = b[i] + C ; }
Here is my attempt:
# t0 = i
# t1 = b[i]
# t2 = a[i]
# t3 = 101 (the end value of i)
# s0 = c
# $a0 = a
# $a1 = b
begin:
addi $t3, $zero, 101 #loop terminate value
add $t0, $zero, $zero # set our counter to zero
loop: lw $t1, 0($a1) # set t1 to b[i]
add $t1, $t1, $s0 # B[i] + c
sw $t1, 0($a0) #store $t1 into a[i]
addi $t0, $t0, 1 # loop increment
addi $a0,$a0,4 # increment a0 to point to the next block in the array (4 bits)
addi $a1, $a1, 4 # likewise with b[i]
beq $t0, $s0, finish
finish:
The MIPS code I've written, should mimic the action of the C code w/o error. However on the first iteration of the loop it states it is accessing an out of range address 0x00000000. Could someone shine some light on what I am doing wrong? I would really appreciate a thorough explanation so I can understand this better for my class. Thanks for your assistance and much love.
Cheers.

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

Understanding MIPS Assembly Code Segment

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].

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

Resources