Skip to content

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 to NOT (a OR b) (i.e., not or is combined into nor).
  • a XOR b is equivalent to a != 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
sll $rd, $rt, shamt
MipC
1
$rd = $rt << shamt;

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
srl $rd, $rt, shamt
MipC
1
$rd = $rt >> shamt;
Move all the bits in a word (i.e. 32-bits) from $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
sll $t2, $s0, 4   # $t2 = $s0 << 4; // in MipC

sll

srl
1
srl $t2, $s0, 4   # $t2 = $s0 >> 4; // in MipC

sll

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
and $rd, $rs, $rt
MipC
1
$rd = $rs & $rt;

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
or $rd, $rs, $rt
MipC
1
$rd = $rs | $rt;

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
xor $rd, $rs, $rt
MipC
1
$rd = $rs ^ $rt;

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
nor $rd, $rs, $rt

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.

Design Principle #1

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
nor $rd, $rs, $zero
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
xor $rd, $rs, $rt
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
ori $t0, $zero, 0xAAAA    # t0 = 0x0000AAAA
sll $t0, $t0  , 16        # t0 = 0xAAAA0000
ori $t0, $t0, 0xF0F0      # t0 = 0xAAAAF0F0

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
lui $t0, 0xAAAA           # t0 = 0xAAAA0000
ori $t0, $t0, 0xF0F0      # t0 = 0xAAAAF0F0

  1. 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. 

  2. 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.