and
and
rd, rs1, rs2
rd = rs1 & rs2
R
31–25funct7
24–20rs2
19–15rs1
14–12funct3
11–7rd
6–0opcode
I
31–20imm[11:0]
19–15rs1
14–12funct3
11–7rd
6–0opcode
S
31–25imm[11:5]
24–20rs2
19–15rs1
14–12funct3
11–7imm[4:0]
6–0opcode
B
31–25imm[12,10:5]
24–20rs2
19–15rs1
14–12funct3
11–7imm[4:1,11]
6–0opcode
U
31–12imm[31:12]
11–7rd
6–0opcode
J
31–12imm[20,10:1,11,19:12]
11–7rd
6–0opcode

and is the first of the bitwise instructions, so first a word about bits. Every number in a register is really 32 bits — 32 individual 0s and 1s in a row. We usually think of the number as a whole, but instructions like and reach in and work on each of those 32 positions separately. That is what bitwise means: the operation is applied to each bit on its own, with no carrying between positions.

The AND operation, at a single bit, follows one rule: the result is 1 only if *both* input bits are 1; otherwise it is 0. and rd, rs1, rs2 applies that rule across all 32 positions at once, comparing rs1 and rs2 bit by bit and writing the result to rd.

The everyday use of AND is called masking — keeping some bits and clearing others. Wherever the mask has a 1, the original bit survives; wherever the mask has a 0, the result is forced to 0. So ANDing a value against a mask of 00001111 keeps the low four bits and zeroes the rest. This is how you pull one packed field out of a value that has several crammed into it.

In the example, 0b1100 (the 0b prefix just means the digits are binary) is ANDed with 0b1010. Only the leftmost position has a 1 in both, so the result is 0b1000, which lands in t2.

li t0, 0b1100
li t1, 0b1010
and t2, t0, t1   # t2 = 0b1000