I'm new to MIPs, and I have some confusion over the solution of this problem. I have attempted reading various sources and non of them really explained how the shifting was obtained or why its needed.
For the following C statement, what is the corresponding MIPS assembly code? Assume that the
variables i, and j are assigned to registers $s3, and $s4, respectively. Assume that the base address of
the arrays A and B are in registers $s6 and $s7, respectively.
Problem is: B[8] = A[i − j];
Solution is:
sub $t0, $s3, $s4
sll $t0, $t0, 2
add $t1, $s6, $t0
lw $t2, 0($t1)
sw $t2, 32($s7)
I don't understand why this left shift is needed after the subtraction of i and j. I understand that it shifts the result of i and j by 4 bits, but why is that needed?
The left shift is needed to compute the offset of the item A[i-j].
Every item of arrays A and B are 32-bit wide (4 bytes). But MIPS has byte addressing so each item of the array requires 4 addresses.
By shifting left 2 bits you are actually multiplying by 4. So (i-j) * 4 is the offset of the i-j'th item of the array.
That is also the reason for last line of your code sw $t2, 32($s7), which stores the result in the 8th item of array, to use 32 as the offset.
Related
f,g,h,i,j == $s0-$s4.
Base address of arrays A and B are $s6 and $s7
sll $t0, $s0, 2
add $t0, $s6, $t0
sll $t1, $s1, 2
add $t1, $s7, $t1
lw $s0, 0($t0)
as far as i understand, the first line takes the value of f*4 and stores it in $t0. ive been told that we have the first line because the array is holding 4-byte values. Please explain the rest. I know the program is accessing the array somewhere but i dont understand the syntax, it just looks like the base case of array A is being added to the f*4. thanks.
sll is shift-left-logical -- so sll $t0, $s0, 2 takes the value in $s0 (f), and shifts it left by 2 bit places, sticking the result is $t0. That's the same as multiplying by 4, but much faster.
add is addition -- so add $t0, $s6, $t0 takes the value in $s6 (the base address of A), and adds the $t0 value just computed above, sticking the result in $t0 (replacing the old value). This gives you the address of A[f]
lw is load word -- so lw $s0, 0($t0) loads the 4-byte value at a 0 byte offset from $t0 and sticks it in $s0. Given the previous two instructions, this is the value of A[f]
The other two instructions are computing the address of B[g] in $t1
Say I have a word array, wa, if I say:
wa: .word 1, 2, 3, 4
la $s0, wa
lw $t0, 8($s0)
does $t0 now contain the third element from right-to-left ot left-to-right (would it be 3 or 2)?
Similarly, if I have a single byte, in s0 and a constant 0 in t3, would saying:
srlv $t0, $s0, $t3
would $t0 contain the 0th bit (rightmost) or seventh bit (leftmost)>
BTW, if you have an idea, I have to do a single read to get an 8-bit value that I can shift, as how I ask above, how should I read this?
Currently, I do read int, but just realized, the shifting will not work because it is a 4 byte value.
Thanks, in advance, if you can answer anyof these questions!
Memory array is word-addressable.Each 32-bit data word has a unique 32-bit address. Both the 32-bit word
address and the 32-bit data value are written in hexadecimal.
For example, data 0xF2F1AC07 is stored at memory address 1. Hexadecimal constants are written with the prefix 0x. By convention, memory is
drawn with low memory addresses toward the bottom and high memory
addresses toward the top.[Petterson & Hennessey].
So in your case lw $t0, 8($s0) take the 3 from memory and place it in register $t0.
I am new to MIPS and do not understand what is going on here:
Suppose word array A stores 0,1,2,3,4,5,6,7,8,9, in this order. Assume the starting address of A is in $s0. After the following instructions, what will be the values this array?
addi $t0, $s0, 32
lw $t1, 0($t0)
sw $t1, 4($t0)
(a) 0,1,2,3,4,5,6,7,8,9
(b) 0,1,2,3,4,5,6,7,9,9
(c) 0,1,2,3,4,5,6,7,8,8
(d) None of the above.
The answer is "c", but I do not understand why. Here is my thought process:
First line of code:
Since this is an integer array, adding 32 to the address $s0 and giving it to $t0 would mean giving the address of A[8] to $t0. A[8] because each integer requires 4 bytes, thus adding 0 to $s0 would result in the address of A[0] and adding 4 to $s0 would result in the address of A[1], and so on...
Second line of code:
0($t0) is referencing the first element in $t0 (which I have no idea what that is) and loading it to the register $t1.
Third line of code:
The address of $t1 is stored in memory to the first element of $t0, which is symbolized by 4($t0).
Again, the above is my thought process, which is most likely wrong
Your thought process is right, and that is the reason why answer c) is the correct one.
The first line, addi $t0, $s0, 32 assigns $t0 = $s0 + 32. As $s0 contains the address of the first element of array A, and knowing that each element of this array occupies 4 bytes, $t0 will now hold the address of the ninth element of the array A, A[8] (indices starting with 0). So *$t0=address_of(A[8])*
So, the second line, lw $t1, 0($t0), will load word stored at address $t0+0, which is A[8], and stores this word in register $t1. Therefore, $t1=8.
The third line, sw $t1, 4($t0), will store the word contained in $t1 at address $t0+4, which is the address_of(A[9]). Therefore, A[9]=8.
I am studying the MIPS assembly language and came across this example in the book and to me it seems incorrect. If it is it wouldn't be the first mistake I found in this book.
The variables f and g are assigned registers $s0 and $s1 respectively, the base addresses for the arrays A and B are $s6 and $s7 respectively.
The c code example is:
f = g - A[B[4]];
And the corresponding MIPS assembly provided is:
lw $t0, 16($s7)
lw $s0, 0($t0)
sub $s0, $s1, $s0
From my understanding the above MIPS code would load some random data from memory at the address provided by $t0 and then subtract it from $s1 and not access the index $t0 of the array denoted in $s6.
The correct MIPS assembly from my understanding would be along the lines of:
lw $t0, 4($s7)
add $t0, $t0, $s6
sll $t0, $t0, 2
lw $s0, 0($t0)
sub $s0, $s1, $s0
I am correct that this is an error in the book or am I misunderstanding something.
Edit: Fixed an error in the corrected mips code as pointed out by Chris Dodd
This is for anyone (possibly CprE 381 students) who may stumble upon this looking for a good example. The OP's edited code is still incorrect. The offset in the first load word function should be 16. It could be 4 if the memory width is 32 bits, but then the shift/multiplication would not be needed. Assuming the memory is 8 bits wide, the add and shift functions need to be switched. In OP's code, it's multiplying the address of A[B[4] / 4] by 4. Shifting/multiplying first will get the correct index. The correct code is:
lw $t0, 16($s7) # gets the value of B[4]
# offset could be 4 depending on memory width
# but then the shift would not be needed
sll $t0, $t0, 2 # this multiplies the index by 4 to get the address offset
add $t0, $t0, $s6 # adds the base address of A and the offset
lw $t0, 0($t0) # loads the value at the address
sub $s0, $s1, $t0 # performs subtraction and stores in f
In case anyone is confused about the whole offset of 16 vs 4 and whether the shift is needed, let me explain. If the memory width is 32 bits then an entire 32-bit integer can be stored in one memory location. If this is the case, then the array index is the same as the address offset. However, if the memory is only 8 bits (1 byte) wide, then a 32-bit integer is stored across 4 memory locations (1 address for each byte). This is why you need to shift the index by 2 (or multiply by 4) to get the correct address offset.
As pointed out my many there was an error in the book. Since discovering this error I found several such errors.
But it could very well be that the author copied the code before link time. This would leave open the possibility that the linker fills in the memory address of A[] in place of the 0 in the statement
lw $s0, 0($t0)
in the final executable. I don't know if MIPS allows offsets of that size (that is, the address range where A[] is being placed finally). This of course is no nice way to explain something in a book, breaking one's own premises silently and generally not knowing what is going on.
I have a homework question and it is troubling me.
It goes like
sll $t0, $s0, 2 // $t0 = $s0 << 2;
add $t1, $t0, $s2 // $t1 = $t + $s2;
lw $s3, $0($t1)
I'm confused about the $0, does it have the same effect as 0?
What value would the result give?
It is a question asking me to translate mips into c, where $s0 is represented as variable name a, $s1 b, $s2 c etc.
The answer for this section is supposed to be d = c[a];,
but i really dont see why.
In MIPS, $0 or $zero is the 0th indexed and first register, and has value 0. See here.
Although that looks like a typo, since lw uses a 16-bit offset, which isn't the value from a register but rather a constant (recall that a register is 32 bits). So it should actually be lw $s3, 0($t1).
The reason the code performs d = c[a] might seem simpler if I translate the MIPS into pseudo C-code:
$t0 = a*4
$t1 = $t0 + c (= c + a*4)
d = *(c + a*4)
So we end up loading into d the value in memory at location c + 4a, which is the base address of the array c, and the index of the element we want, a. We multiply by four because the type of the array is obviously a 4-byte long type, for example a 4-byte integer, so we need to jump 4*a bytes from the beginning of the array to reach the appropriate point in memory.