What happens in the receiving register if I do the following operation
sw $t3,0(t2) ? where t3 and t2 are two already known registers.
Does the value of t2 register get evoked during the operation or does the compiler just uses the default answer to any multiplication by zero which is (0)?
Thanks!
You are missing the '$' before 't2'. For sw and other similar instructions, the number outside of the parenthesis is the offset. For example if the base address of an array is stored in $t2, the value in $t3 will be stored at the 0 offset of that address (the 0 index of the array). Since MIPS is based off of 32-bits, each index in the array that you want to access can be multiplied by 4 to get the correct offset.
Related
I just started learning MIPS and don't have much idea what's going on. The following problem asks to translate the last add instruction to C code :
.data
A: .word 0:16 # in C: int A[16];
.text
la $s6, A # in C: int* s6 = A;
li $t0, 3 # in C: int t0 = 3; // integer array index
sll $t0, $t0, 2 # (In MIPS: $t0 = $t0 << 2) ($t0*4 is the byte offset used in MIPS.)
add $s0, $s6, $t0 # <--- What is the equivalent C code
What I understood was this : the address of array A is stored in register $s6, then the constant 3 denoting an array index is stored in $t0, the sll instruction stores 3*2^2 = 12 into register $t0. Then, the add instruction adds the contents of $s6 and $t0 and stores the sum into $s0.
$s6 + $t0 = address of A + 12 ?? I am not able to make sense of this, please help me? Does it mean it adds 12 to the address of A and stores that into $s0?
In C, we do array indexing as follows:
a[i]
which by definition of the operators in C is equivalent to
*(a+i)
This construct represents pointer arithmetic (pointer addition, with binary + operator), followed by dereference (the unary * operator, applied after the addition).
What you're showing is just the pointer arithmetic without the dereference, so basically:
a+i
C knows which one is the pointer and which one is the index, so even i+a would be the same in C (we can also do *(i+a) and i[a] in C, believe it or not, and these are both equivalent to a[i] and *(a+i), indexing into the array to access an element.)
The fundamental difference here between C and assembly (beyond syntax) is that C knows the data type of the pointer, and so automatically scales the index by the element size and you never see that explicitly done in C — whereas in assembly it must be done explicitly, which is sll (shift of two) being used to multiply the index by 4.
So the addition of the array base pointer and index in C is more or less formally called pointer arithmetic and is equivalent to the shift and add in assembly. Since C hides the scaling, though, there's no direct equivalent to just the add alone.
In C, pointer arithmetic also includes subtraction of pointer and index, with the same scaling automatically applied to the index.
In C, pointer arithmetic also include subtraction of two pointers, so a-b if they are both pointers to the same type and same array or memory block, will compute the index that represents the difference between two pointers. In C, this is also inversely scaled to obtain a regular index. In assembly we can do the same with subtraction followed by shifting in the opposite direction, namely right.
Of course there is no addition of pointer to pointer (it doesn't make sense).
Most hardware these days is byte addressable, so we need to use byte addressing both in C and in assembly. (In languages like Java that don't have pointers we don't see the byte addressing that the language does for you, much like C hides index scaling.)
Any pointer is, in some sense, a pointer to a single byte. Data items that occupy more than one byte are referred to by their first byte, and this includes arrays, structs, etc..
To do array indexing (into an integer array) we convert the index (0,1,2,3) into a byte offset (0,4,8,12) by scaling (multiplying the index by the pointer's element size). Then add the byte address (base of the array) to that byte offset, yielding another byte address, but this one refers to the element at the index.
Here's the datapath:
So this seems like a pretty common question but I can't seem to find any answers on how to extend the datapath to implement SLL and SRL.
This is how I would think to do it but I'm not entirely sure:
It would need another mux right next to Read data 1 next to the register file. This mux would take Read data 1 (rs) and Read data 2 (rt) as inputs. It would select Read data 1 if we're not doing a shift operation, and it would select rt if we ARE doing a shift operation (since sll and srl use rt, not rs). This would then be fed into the ALU.
Next, we would need to branch Instruction[10:6] (the shift amount) off of Instruction[15:0], and Instruction[10:6] would then be fed into the other port of the ALU. Is this correct thinking?
This is sll on single cycle datapath, but i am not sure if the ALU now gets 5 instead of 4 bits control input.
If u make sll then the first ALU input would be shamt and the second is the register to be shifted, ALU know if it must make shift because of instruction field, because it is a R-Type instruction. Then the shifted data will be saved in rd register.
SLL SC datapath
You need to modify the datapath for the SLL instruction, adding a input line to the ALU with the "shamt" field in order to determine de shift amount. The ALU will identify the SLL operation by the ALUop field.
Modiffied datapath
You are going in the correct direction. As stated in one of the answers, there can be one additional port added to the ALU which will consider the shamt amount (bits [10:6]). There can be some internal hardware such as a MUX in the ALU which takes care of selecting either the shamt field or Read Data 2 from the output of register file.
I am reverse engineering a C MIPS application, in some places I can see negative offsets in lw opcode, like:
80032910 lw $v0, -4($s4)
Positive offsets usually indicate some kind of structure, where one of the members is being accessed, but what code can lead to a negative offset?
For example, it can be generated if you read the previous value of a pointer, e.g. traversing an array from the end to the beginning
int *myDataEnd;
... code ...
while(*myDataEnd > *(myDataEnd-1))
myDataEnd--;
Referencing the integer pointed by myDataEnd-1 may generate that instruction.
Position independent code uses $gp as a pointer into the middle of a 64K region of global data, so you will often see lw $t0, -nnn($gp) in code. If the depth of a stack frame is unpredictable at compile-time, a frame pointer may be used to mark the start of the stack frame, causing there to be memory references with negative offsets to the frame pointer.
Hand optimized code can also use negative offsets to save reloading an address into a register.
Im reviewing a problem where given a MIPS instruction, I have to write down the decimal value of the 4 fields corresponding to the opcode, rs, rt, and the function. I understand that the decimal value for rs and rt are just the decimal representations of the registers (i.e, $s0 is 16) but how could i figure out the 16 bit function code?
You can not determine that value.You need to be given that values.Each function code does different things,there are many instruction that has the same format.
Every instruction has its own opcode & function code. You can find the opcodes here, for example:
https://www.student.cs.uwaterloo.ca/~isg/res/mips/opcodes
For example, addi is 001000 in binary for the first 6 bytes (the opcode), followed by 2x5 bytes for the registers, followed by 16 bytes for the immediate value
add is 000000 (opcode), followed by 3x5 bytes for the registers, 00000 for shift amount (not used for this instruction), followed by 100000 for the function code.
So Im having trouble with a problem. Im givin that a is an array of words and the base address of a is saved in $a0. So for int a[10] find the sum of this array using mips. I really don't know where to start can someone help me start and I think I should be able to finish it. Thanks a bunch!
Since you are given the address of the start of the array, you know that is also your first element. Since this is an array of int, I will assume it means it will use a storage space the size of a word on mips32 which is 4 bytes. Therefore a[1] is located at the address of a[0]+4bytes. A[2] is located at the address of a[0]+8bytes or a[1]+4bytes etc...
From that it follows that all you have to do is just loop 10 times, loading a word each time and adding the value.
The basic flow is:
Let count = 0, sum = 0 (sum is your return value, so $v0)
Load a word value from $a0 into a register
Set $a0 = $a0 + 4 (move from a[count] to a[count+1], integer is 4 bytes on mips32)
Set sum = sum + the register you loaded the word value into
count = count + 1
if count < 10? (set less than, branch) go to #2
jump and link (assuming our sum is already in $v0)
Note: The base address you are given MUST be word-aligned.
Optimization note: You can optimize the number of instructions executed by setting some register to $a0 + 40 before step 1. This means you can get rid of step 5 and step 6 will be a check if $a0 is less than that register you set before step 1. (The last optimization is moving step 4 to step 6's delay slot. If you are using a simulator, this might not be supported though)