Logical
In arithmetic instructions, we view the content of a register as a single number, either signed or unsigned integer. In logical instructions, we have to have a new perspective. We will view the register as a raw 32-bits binary rather than a single 32-bit numbers. In particular, we want to be able to operate on individual bits or bytes within the register.
Operations
Logical Operation | C Operator | MIPS | Immediate |
---|---|---|---|
Shift Left Logical | << |
sll |
|
Shift Right Logical | >> |
srl |
|
Bitwise AND | & |
and |
andi |
Bitwise OR | | |
or |
ori |
Bitwise XOR | ^ |
xor |
xori |
Bitwise NOT1 | ~ |
nor |
Truth Tables
In these truth tables, we use 0 to represent false and 1 to represent true.
a |
b |
a AND b |
a OR b |
a XOR b |
a NOR b |
---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 1 |
0 | 1 | 0 | 1 | 1 | 0 |
1 | 0 | 0 | 1 | 1 | 0 |
1 | 1 | 1 | 1 | 0 | 0 |
From the truth table, we can also see that:
a NOR b
is equivalent toNOT (a OR b)
(i.e., not or is combined into nor).a XOR b
is equivalent toa != b
(i.e., exclusive or).
Logical Operations
Shifting
The truth tables are only applicable for the bitwise operations. For shifting, we will have to describe the operation another way.
Shifting
MIPS | |
---|---|
1 |
|
MipC | |
---|---|
1 |
|
Move all the bits in a word (i.e. 32-bits) from $rt
to the left by a number of positions given in shamt
.
We then fill the emptied positions with zeroes and store the result in $rd
.
MIPS | |
---|---|
1 |
|
MipC | |
---|---|
1 |
|
$rt
to the right by a number of positions given in shamt
.
We then fill the emptied positions with zeroes and store the result in $rd
.
Shift
sll | |
---|---|
1 |
|
srl | |
---|---|
1 |
|
There is a nice property of shifting that has the decimal counterpart. Consider shifting a number to the left and filling the emptied position with zeroes. Assuming that we have enough digits, if we start with a number 123, we will get 1230. That is simply multiplication by 10. Similarly, for binary, shifting to the left is multiplication by 2 since we are looking at base 2.
Right shift is harder. If we start with 1230, then to get 123, we simply divide by 10. But this only works if the last digit is 0. In C, this is basically integer division.
Shift | Math |
---|---|
Shift left by n bits | Multiply by 2n |
Shift right by n bits | Integer division by 2n |
Bitwise
Bitwise
MIPS | |
---|---|
1 |
|
MipC | |
---|---|
1 |
|
Bitwise operation that leaves a 1 only if both the bits of the operands are 1. Bitwise AND operation can be used for masking operation (i.e., bitmask)2.
MIPS | |
---|---|
1 |
|
MipC | |
---|---|
1 |
|
Bitwise operation that places a 1 in the result if either bit of the operands is 1. Bitwise OR operation can be used for setting operation (i.e., bitset)2.
MIPS | |
---|---|
1 |
|
MipC | |
---|---|
1 |
|
Bitwise operation that places a 1 in the result if the bits from the operands are different. Alternatively, it behaves similar to bitwise OR except when both operands are 1. This is the reason why it is called exclusive OR (as opposed to inclusive OR or simply bitwise OR).
MIPS | |
---|---|
1 |
|
Bitwise operation that leaves a 1 only if both the bits of the operands are 0. Alternatively, it behaves like a negation of bitwise OR. In other words, if bitwise OR produces 1 then NOR produces 0 and if bitwise OR produces 0 then NOR produces 1.
Bitwise AND, OR and XOR have the immediate variants: andi
, ori
and xori
.
Strangely, there is no immediate variant for NOR.
In other words, there is no nori
.
Here, the same design principle as before is applicable.
Keep the instruction set small
In particular, we can use other instructions to implement the same functionality as a hypothetical nori
.
Another strange fact is that there is no bitwise NOT operation.
To be more precise, there is no operation that accepts one operand similar to the hypothetical not $rd, $rs
.
However, this can be done using bitwise NOR.
Bitwise NOT | |
---|---|
1 |
|
Bitwise NOT
To deduce that we bitwise NOT is indeed bitwise NOR with 0, we can simply look at the truth table.
Here, reproduced below, we highlight the important part where b
is 0 and ignoring the part where b
is 1.
a |
b |
a NOR b |
---|---|---|
1 | 0 | 0 (¬a ) |
0 | 1 | 0 |
0 | 0 | 1 (¬b ) |
1 | 1 | 0 |
Bitwise NOT from Bitwise XOR
Can we also get bitwise NOT operation from bitwise XOR?
Yes, but it is harder.
Here, we need to let $rt
to contain all 1s.
Then, the simple use of xor
below will be equivalent to bitwise NOT.
Bitwise NOT | |
---|---|
1 |
|
Proof
Again, we deduce this using the truth table.
However, we now focus to the part where b
is 1.
a |
b |
a XOR b |
---|---|---|
1 | 0 | 0 |
0 | 1 | 1 (¬a ) |
0 | 0 | 1 |
1 | 1 | 0 (¬b ) |
Large Constant
Let us take a look at the problem of large constant again now that we know about logical operations.
Naive Implementation
A naive implementation will will be to simply perform the following three operations: ori
, sll
and ori
.
The first ori
is to put the upper half of the large constant into the lower half of the register.
We then use the shift left logical operation to move this to the upper half.
Once we have done that, the lower half will be all 0s.
This 0s can be set into the lower half of the large constant using another ori
.
0xAAAAF0F0
Large Constant V1 | |
---|---|
1 2 3 |
|
Special Instruction
Load Upper Immediate (lui
)
Set the upper 16-bits of the register to the given constant. Additionally, set the lower 16-bits of the register to all 0s.
Since a large constant may be needed a lot, MIPS provide a way to combine the first two operations.
Note that due to the way the instruction is assembled, we cannot combine the three instructions.
This special instruction is a real instruction called load upper immediate (lui
) and not a pseudo-instruction.
0xAAAAF0F0
Large Constant V2 | |
---|---|
1 2 |
|
-
There is no NOT operation that accepts only a single operand here. Instead, we have a NOR operation that accepts two operands. We can simulate the NOT using either NOR or XOR but it is simpler using NOR. Hence why we have NOR. ↩
-
Bitmask and bitset operations are often used in Computer Networking (CS2105). In particular, IP addresses are designed in such a way that to know where to pass a packet, we can simply use bitmask and/or bitset. In the olden days of C, bitmask and bitset are often used to set and check certain settings. This is done by passing multiple setting values as a single integer. If the bit at a certain place is 1, then we set this setting to ON, otherwise we set it to OFF. ↩↩