Concatenating integer values in MIPS - concatenation

I need to code, in MIPS assembly, something that will take the values of 32-bit integers out of a given array, concatenate them instead of adding them, and then store to a variable x.
For example, if Data[1] contained 6, Data[2] contained 9 and Data[3] contained 3, I would need to form the integer 693 and then save it to variable x.
The Java equivalent would be:
x = Data[1] + “” + Data[2] + “” + Data[3];
And here's what I've got for the assembly code so far:
# load root addresses of variable and array
la $s0, x # load address of variable x into register $s0
la $s1, Data # load address of ‘Data’ array into $s1
# load contents of array into registers
lw $t0, 4($s1) # load contents of Data[1] into register $t0
lw $t1, 4($s1) # load contents of Data[2] into register $t1
lw $t2, 4($s1) # load contents of Data[3] into register $t2
# concatenate strings by treating numbers as logic
ori $t3, $zero, $t0 # (I know this is wrong)
???
# store concatenated value into variable
sw $s0, 0($__) # store value of $__ into register of x
How would I go about doing this? I'm extremely puzzled because there does not seem to be a way to concatenate integer values. Am I missing something with how ori is used?
Thanks in advance!

Your Java code concatenates strings. If you want to convert decimal 6, 9 and 3 to decimal 693, try this Java:
int[] data = new int[]{6, 9, 3};
int result = data[0] * 100 + data[1] * 10 + data[2] * 1; // result = 693
That should be easy to translate into assembler.

Related

Not understanding the purpose of the left shift in this problem

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.

How can I store an int array into a local variable in MIPS?

In MIPS, if I have an array newInt (4,5,6), how can I store that as an integer 456 into a register (like $s0)?
If I try doing la $s0,newInt it simply prints out the address but I want $s0 to literally contain all the numbers found in newInt as 1 single number.
Assuming all the items in the array have single digits, you have to:
Initialize $s0 with 0, and some other register e.g. $s1 with 0
repeat until all the array has been read:
$s0 = $s0 * 10 + newInt[$s1]
$s1 = $s1 + 1 (actually it if its an array of ints it would be +4)

Adding integer value to an array?

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.

Convert C to MIPS - Nested Arrays

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.

lw in MIPS (also a bit C)

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.

Resources