Project F

RISC-V Assembler: Logical

Published · Updated

This RISC-V assembler post covers bitwise logical instructions, such as and, not, and xori. Bitwise instructions carry out the specified operator on each bit of the sources in turn. These instructions are included in RV32I, the base integer instruction set. You can also check out my other RISC-V posts.

In the last few years, we’ve seen an explosion of RISC-V CPU designs, especially on FPGA. Thankfully, RISC-V is ideal for assembly programming with its compact, easy-to-learn instruction set. This series will help you learn and understand 32-bit RISC-V instructions and programming.

Share your thoughts with @WillFlux on Mastodon or X. If you like what I do, sponsor me. 🙏

AND

The and and andi instructions perform logical AND on individual bits. The AND instructions are commonly used to mask parts of a register. Immediates are sign extended; see arithmetic sign extension for details.

and  rd, rs1, rs2  # rd = rs1 & rs2
andi rd, rs1, imm  # rd = rs1 & imm

These examples select the 4 least significant bits from the register t0:

li   t0, 42       # t0 = 42 (0...101010)
li   t1, 15       # t1 = 15 (0...001111)

and  t2, t0, t1   # t2 = 42 (0...101010) & 15 (0...001111) = 10 (0...001010)
andi t3, t0, 15   # t3 = 42 (0...101010) & 15 (0...001111) = 10 (0...001010)

Binary values are in brackets with ... indicating many identical bits.

OR

The or and ori instructions perform logical OR on individual bits.

or  rd, rs1, rs2  # rd = rs1 | rs2
ori rd, rs1, imm  # rd = rs1 | imm

Examples:

li   t0, 42      # t0 = 42 (0...101010)
li   t1, 15      # t1 = 15 (0...001111)

or   t2, t0, t1  # t2 = 42 (0...101010) | 15 (0...001111) = 47 (0...101111)
ori  t3, t0, 15  # t3 = 42 (0...101010) | 15 (0...001111) = 47 (0...101111)

XOR

The xor and xori instructions perform logical XOR (exclusive OR) on individual bits.

xor  rd, rs1, rs2  # rd = rs1 ^ rs2
xori rd, rs1, imm  # rd = rs1 ^ imm

Examples:

li   t0, 42      # t0 = 42 (0...101010)
li   t1, 15      # t1 = 15 (0...001111)

xor  t2, t0, t1  # t2 = 42 (0...101010) ^ 15 (0...001111) = 37 (0...100101)
xori t3, t0, 15  # t3 = 42 (0...101010) ^ 15 (0...001111) = 37 (0...100101)

NOT

The not pseudoinstruction inverts the bits in a register (0 → 1 and 1 → 0). The assembler converts not to xori (see example below). Verilog and C use tilde ~ for bitwise NOT, so I have used that notation here.

not  rd, rs1     # rd = ~rs1 (pseudoinstruction)

Example:

li   t0, 42      # t0 = 42 (0...101010)

# these two examples generate the same machine code
not  t2, t0      # t2 = ~(0...101010) = (1...010101)
xori t3, t0, -1  # t3 = (0...101010) ^ (1...111111) = (1...010101)

Notice how -1 is sign extended to 32 bits, so all the bits of the immediate are 1.

What’s Next?

The next post looks at RISC-V Shift Instructions, including fast multiplication and division.

If you enjoyed this post, please sponsor me. Sponsors help me create more FPGA and RISC-V projects for everyone, and they get early access to blog posts and source code. 🙏

Check out the RISC-V Assembler Cheat Sheet and all my FPGA & RISC-V Tutorials.

References