What is the correct syntax of MIPS instruction sll? - mips

Should the shift amount be an immediate value, or a value stored in a register? Does both work?
I've had different websites tell me different things and am confused.
Based on my research the sll (shift left logical) instruction should be used like this:
sll $d, $t, h
Which makes $d = $t shifted left h times.
I've been told that h should be a immediate value, but I was wondering if a register could be used as the third argument, and the value inside that register used as the shift amount. Would that also work?

You are correct.
sll is specific in that it is a R-format instruction where only two registers are used, rd and rs (destination and source), and the shamt field is a immediate value (a constant).
There is another instruction sllv which uses a third register where you specify shift by variable (the register).

Let me clear the point Shift left logical in MIPS 32 bit has following syntax:
SLL destination, Target, Shift amount(Should be immediate value)
Where as in 8086 if we want shift amount more than 1 we have to use a register to store the value of shift amount!

Related

array address addition in MIPS and translating to C

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.

what happens if the destination address j jumps to is an immediate value?

3. Mr.Noob is pondering about this strange line of MIPS instruction in his program:
beq $t3, $t9, 0 #0 is the immediate value
Which of the following statements is TRUE?
A. That instruction is an “infinite loop”.
B. That instruction can be removed from the program with NO impact on execution
result.
C. That instruction is equivalent to a branch‐lesser‐or‐equal (ble).
D. That instruction jumps to the instruction at instruction address 0.
E. None of the above.
Can I ask why is the answer B? Thank you.
The beq instruction is an I-Type, which means that part of the instruction encodes a 16-bit signed immediate.  The instruction is a conditional branch.  The immediate for this instruction is used as the taken branch target.  If the condition is:
false, then pc := pc + 4 is the operation it performs (fall through to next instruction).  Since the branch is not taken, this advances the pc in sequential manner just like any other instruction, such as add.
true, then branch is taken and the operation is that pc := pc + 4 + sxt32(imm16)*4, which transfers control to the target, usually a label in assembly language.  However, since the immediate is zero, this equation evaluates to pc := pc + 4 + sxt32(0)*4, which is pc := pc + 4 + 0 -or- pc := pc + 4.
Thus, whether condition is true or false, whether the branch is taken or not taken, it has the same effect of merely advancing the pc by 1 instruction.
Using labels instead of an immediate:
beq $t3, $t9, next
next:
...
This will also produce an immediate value of 0 in the machine code for the beq.
If the immediate for a taken beq is -1, then it branches to itself, which will cause an infinite loop.  If the immediate is -2, then it branches backwards by 1 instruction; if the immediate is 0, it simply goes on to the next instruction; if the immediate is 1, the branch skips one instruction.
Removing the instruction will reduce code size and could improve performance but will not otherwise affect the logic of the program — assuming the program does not somehow depend on code size or position.
Let's note that code using branches with immediates tends to be dependent upon position and if you remove an instruction, you may have to fix up these branches — that's why we use labels instead, to get the assembler to compute the proper immediate (so we're free to add and remove instructions, just reassemble).

Extending MIPS datapath to implement SLL and SRL

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.

Implementing SLR and SLL instructions into MIPS Processor

Given the MIPS Processor design as seen
I was thinking of adding the sll and srl functions to the processor. I can't seem to have any intuition on how I can retrieve the amounts of zeros to append (shift dynamically from the given shamt from [10:6] of the instruction).
Can anyone give me one headstart on this? Thanks!
The answer is a delayed but I hope that someone in the future will find it helpful.
As you mention the bits in the shamt (shift amount) field are 5 (10 -> 6). So, 2**5=32 which corresponds to the number of bits that can be shifted right/left.
Example:
Assuming that we execute a srl (shift right logical) operation and the value in the shamt field is 00010 (2 in
decimal) and the value in the register we want to shift is
00000000000000000000000000010100
The value becomes shifted by 2 00000000000000000000000000000101
Another example:
Instruction = srl (Shift Right Logical)
Shamt field = 11110 (30 in decimal) Register Value = 11110000000000000000000000000000 Result = 00000000000000000000000000000001
The value in the register gets shifted to the right by 30 bits
indicated by the shamt field and becomes 1.
Depending on the value in the shamt field you shift by N bits the register that needs shifting to the right or to the left; logical or arithmetic.

What can a negative offset means in "load word" instruction in MIPS decompiled code

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.