Watch out for the sign bit
==========================
[Written 2019-10-12]
In RISC-V, immediate values are usually sign-extended before they are
stored in registers or used for some computation. Sign extension
means that the highest significant bit in the specified number is
repeated to the higher bit positions so that the two's complement
value stays the same. Example of two 8-bit values that are
sign-extended to 16 bits:
00011001 -> 00000000_00011001
10010111 -> 11111111_10010111
The RISC-V instruction addi is an example that does sign-extension on
the 12-bit value imm:
addi rd, rs1, imm
That makes it possible to add two numbers even if they have a
different number of bits (register rs1 is 32 bits on 32-bit RISC-V and
imm is 12 bits). The value of imm is sign-extended to 32 bits so it
can be added to rs1 and the sum is written to register rd.
Something less expected is that sign-extension is used for logic
instruction like `andi` and `ori` too.
andi rd, rs1, imm
ori rd, rs1, imm
In both of these instructions imm is 12 bits. Let's look at what
happens when imm gets big. Assume rs1 = -1 (32 ones in binary).
andi rd, rs1, 0b10_00000000 -> rd = 2^9
andi rd, rs1, 0b100_00000000 -> rd = 2^10
andi rd, rs1, 0b1000_00000000 -> rd = (2^32-1) - (2^11-1)
On the last line we do not get 2^11. This happens because in the last
line, imm has the most significant of its 12 bits set and that bit is
repeated before used with rs1. In other words, the value that is used
is in binary 21 ones followed by 11 zeros.
This means that if you want to extract one bit from a number and that
bit is 2^11, you cannot use addi even if it takes a 12-bit immediate
value. You can only use it to extract up to bit 2^10.
Assemblers should check this and never accept values larger than
2^11-1 for 12-bit immediates. To use the most significant bit of the
12 bits you should specify a negative value to make it clear that you
know what is happening and that it will be sign-extended.