For Loop With Array in C to MIPS With Offset - c

So I have an assignment problem which asks for a for loop in C to be converted into MIPS. My professor moves extremely fast so I couldn't catch half of what he said. Here is the code:
for (i=0; i<10; i++){
a[i] = b[i] + c[i];
}
This fragment is stored in memory starting from location 00000100 Hex.
Convert this code to MIPS and provide numeric offsets for each branch or jump instruction used.
I don't quite understand the use of offsets. From the lecture slides given to us, it seems load word and store word commands are used for the offsets, which are also used for the arrays but I'm not sure how to go about it. Below is something I put together based on other solutions I saw, but am of course open to changes. I'm hoping it's at least going in the right direction. Any help would be appreciated.
#t0 = i
#s0 = a
#s1 = b
#s2 = c
#t3, t4, t5, t6, t7 = free
loop:
bgt $t0,9,exit #exit before i reaches 10
addi $t3,$s1,$t0 #temp reg $t3 = address of b[i]
addi $t4,$s2,$t0 #temp reg $t4 = address of c[i]
lw $t5,0($t3) #temp reg $t5 = c[i]
lw $t6,0($t4) #temp reg $t6 = a[i]
add $t3,$t5,$t6 #temp reg $t10 = b[i] + c[i]
addi $t7,$s0,$t0 #temp reg $t7 = address of a[i]
sw $t3,0($t7) #store word a[i] = b[i] + c[i]
addi $t0,$t0,1 #increment i by 1
j loop #jump to start of loop
exit:

From what I can see, you are storing it in the same index each time. In MIPS, every 4 bytes is a word, so you must store it in 0, 4, 8, etc. Also, you need to allocate memory for your array before you start using one. Here's an example.
li $v0, 9 # create an array, start address in $v0
li $a0, 80 # allocate 80 bytes, or 20 words
syscall
move $t0, $v0 # move from $v0 (temp) to $t0
Check out this tutorial and see if it helps at all.

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.

Mips 2d array function

I am attempting to create an algorithm that finds the trace of an n-by-n square matrix A.the trace of an n-by-n square matrix A is defined to be the sum of the elements on the main diagonal (the diagonal from the upper left to the lower right) of A.The main idea involved is that at this level multi-dimensional arrays are stored as one-dimensional arrays, and the multi-dimensional indexing (for a matrix with m rows and n columns) is converted to one-dimensional indexing.As I'am unfamiliar with mips attempts to integrate it into code are unsuccessful my latest attempt below.
I have set the registers to the following:
$a0 = base address of array (matrix), a
$a1 = n, number of rows and columns
$v0 = trace
$t0 = i
trace: move $v0, $zero
move $t0, $zero
bne $t0,$a1,end
sll $t1,$a0,4
add $t1,$t1,$t0
sll $t1,$t1,2
add $t2,$t1,$a0
lw $t0,0($t1)
addi $sp, $sp, 8
sw $t1,0($t0)
j trace
end: jr $ra
but to no avail the answer does not come out as desired the format of the algorithm should be as follows;
trace = 0
for i = 0 to n-1
trace = trace + a[i,i]
end for
I have added some comments indicating suspicious behaviour
trace: move $v0, $zero
move $t0, $zero
loop: bne $t0,$a1,end
sll $t1,$a0,4 ; t1 = a0 * 16, a0 is the base address, should probably be $t0
add $t1,$t1,$t0
sll $t1,$t1,2
add $t2,$t1,$a0
lw $t0,0($t1)
addi $sp, $sp, 8 ; What are you doing with $sp? perhaps this should be add $v0,$v0,$t0
sw $t1,0($t0) ; What are you storing here?
j trace ; This should probably jump to loop, or the code will never end
end: jr $ra
Also note that the sll assumes that the size of your matrix is 16.

Swapping two elements in an array in MIPS assembly

I'm trying to learns the MIPS ISA. If I want to do this function in MIPS:
A[2*i]=A[2*k+j];
How would I go about this? I would also appreciate any other content that I can read, i.e links where I can read up on how to solve this kind of problem.
We can break this down to 2 parts:
Calculate the addresses of A[2*i] and A[2*k+j]
Assign the value at the second address to memory at the first address
I'm only going to address (ahem) #1.
To calculate the address of an array element, you need to know 3 things:
The address of the start of the array
The index of the element you want
The size of the array elements
I assume you know how to compute, or just know, #1 & #3. That leaves #2, which involves simple arithmetic. (Since you haven't indicated how i, j & k are represented, I can't help too much there).
The final step, then, is to multiply the index by the size of an array element; this gives you the offset of your desired element from the start of the array. Add that to the address of the start of the array, and you have your element's address.
P.S. The code you're translating doesn't swap two elements; it copies one over the other.
It's been a while, but this could be close. You'll never learn assembly language without trying youself. Make more examples and code them. More study material here .
# int calc(int *A, int i, int j, int k)
# {
# return A[2 * i] = A[2 * k + j];
# }
# Args: a0=A, a1=i, a1=j, a3=k Rtn: v0
.text
.set nomacro
.set noreorder
.global calc
.ent calc
calc:
sll $t0, $a1, 3 ; t0 = i * 8
sll $t1, $a3, 1 ; t1 = k * 2
add $t1, $t1, $a1 ; t1 += j
sll $t1, $t1, 2 ; t1 *= 4
add $t0, $t0, $a0 ; t0 += A
add $t1, $t1, $a0 ; t1 += A
lw $v0, 0($t1) ; r = A[4 * (2 * k + j)]
sw $v0, 0($t0) ; A[4 * (2 * i)] = r
.end calc

Converting C code to MIPS (arrays)

for (i = 0; i < 64; i++) {
A[i] = B[i] + C[i];
}
The MIPS instructions for the above C code is:
add $t4, $zero, $zero # I1 i is initialized to 0, $t4 = 0
Loop:
add $t5, $t4, $t1 # I2 temp reg $t5 = address of b[i]
lw $t6, 0($t5) # I3 temp reg $t6 = b[i]
add $t5, $t4, $t2 # I4 temp reg $t5 = address of c[i]
lw $t7, 0($t5) # I5 temp reg $t7 = c[i]
add $t6, $t6, $t7 # I6 temp reg $t6 = b[i] + c[i]
add $t5, $t4, $t0 # I7 temp reg $t5 = address of a[i]
sw $t6, 0($t5) # I8 a[i] = b[i] + c[i]
addi $t4, $t4, 4 # I9 i = i + 1
slti $t5, $t4, 256 # I10 $t5 = 1 if $t4 < 256, i.e. i < 64
bne $t5, $zero, Loop # I11 go to Loop if $t4 < 256
For I8, could the sw instruction not be replaced with an addi instruction? i.e addi $t5, $t6, 0
Wouldn't it achieve the same task of copying the address of $t6 into $t5? I would like to know the difference and when to use either of them. Same could be said about the lw instruction.
Also, maybe a related question, how does MIPS handle pointers?
edit: changed addi $t6, $t5, 0.
The sw instruction in MIPS stores the first argument (value in $t6) to the address in the second argument (value in $t5) offset by the constant value (0).
You're not actually trying to store the $t5 address into a register, but rather storing the value in $t6 into the memory location represented by the value of $t5.
If you like, you could consider the value in $t5 to be analogous to a C pointer. In other words, MIPS does not handle pointers vs values differently-- all that matters is where you use the values. If you use a register's value as the second argument to lw or sw, then you are effectively using that register as a pointer. If you use a register's value as the first argument to lw or sw, or in most other places, you are operating directly on the value. (Of course, just like in C pointer arithmetic, you might manipulate an address so you can store a piece of data somewhere else in memory.)
For I8, could the sw instruction not be replaced with an addi instruction? i.e addi $t6, $t5, 0
No. The sw instruction stores the result to memory. The add just manipulates registers. And lw gets a word from memory. It's the only MIPS instruction that does so. (Other processors might and do have versions of add that access memory, but not MIPS.)
It's necessary to adjust your thinking when working in assembly language. Registers and memory are separate. In higher level languages, registers are (nearly) completely hidden. In assembly, registers are a separate resource that the programmer must manage. And they're a scarce resource. A HLL compiler would do this for you, but by programming in assembly, you have taken the job for yourself.
how does MIPS handle pointers?
In MIPS, pointers are just integers (in registers or memory) that happen to be memory addresses. The only way they're distinguished from data values is by your brain. The "pointer" is something invented by higher level language designers to relieve you the programmer of this burden. If you look closely, you'll see that $t5 actually holds a pointer. It's a memory address used by lw and sw as the address to load from or store to.
For I8, could the sw instruction not be replaced with an add instruction? Wouldn't it achieve the same task of copying the address of $t5 into $t0? I would like to know the difference and when to use either of them.
I think you are confused with what a store word actually does. In I8, the value of the register in $t6 is being stored into $t5 at position zero. An add will overwrite whatever data is stored in the destination register with the sum of the two other registers' values.
Also, maybe a related question, how does MIPS handle pointers?
The "pointers" are just addresses in memory stored in the registers (as opposed to values).
lw and sw read/write to memory. addi and other arithmetic operations operate on registers.
Registers are like little buckets the CPU uses to store data. They can be addressed in 5 bits or so if I remember my MIPS architecture correctly.
Memory is like a vast ocean of data that requires well over 16 bits to address. So you actually have to store the address in a register.
Pointers are simply memory addresses (32 bit on a 32 bit architecture).

Resources