-
Notifications
You must be signed in to change notification settings - Fork 0
RISC V Addressing
While it simplifies hardware to have all RISC-V instructions be 32 bits long, there are situations in which 32-bit or bigger constants or locations might be useful. The generic solution for big constants is presented in this section first, followed by the optimisations for instruction addresses utilised in branches.
Constants might be larger or shorter, although they are usually small and fit within the 12-bit fields. Among the instructions in the RISC-V instruction set are To load a 20-bit constant into bits 12 through 31 of a register, use the load upper immediate (lui) function. Bit 31 copies occupy the leftmost 32 bits, whereas zeros occupy the rightmost 12 bits. For instance, this instruction makes it possible to generate a 32-bit constant using just two instructions. Lui employs the U-type instruction format since the other forms are unable to hold such a big constant.

The constant's bit 11 in the preceding example was 0. A further issue would have arisen if bit 11 had been set: the addend would have been negative since the 12-bit immediate is sign-extended. This indicates that we would have deducted 212 in addition to adding the constant's final 11 bits. Since the lui constant is scaled by 212, all that is needed to correct for this issue is to add 1 to the constant loaded using lui.

The SB-type RISC-V instruction format is used by the RISC-V branch instructions. Branch addresses in multiples of two from 4096 to 4094 can be represented using this format. For reasons that will become clear soon, you can only branch to even addresses. A 7-bit opcode, a 3-bit function code, two 5-bit register operands (rs1 and rs2), and a 12-bit address immediate make up the SB-type format. The address utilises a unique encoding that makes assembly more difficult but simplifies datapath construction.
The instruction bne x10, x11, 2000 // if x10 != x11, go to location 2000ten = 0111 1101 0000 could be assembled into this format
where the opcode for conditional branches is 1100111two and bne’s funct3 code is 001two.
The sole instruction that employs the UJ-type format is the unconditional jump-and-link instruction (jal). This instruction is made up of a 20-bit address immediate, a 5-bit destination register operand (rd), and a 7-bit opcode. The command that comes after the jal is written to rd., and that is the link address.
The address operand of the UJ-type format employs an uncommon immediate encoding, just like the SB-type format, and it is unable to encode odd addresses. Thus, jal x0, 2000 // go to 2000ten = 0111 1101 0000 is put together in the following format:
Programme addresses would not be able to exceed 220 if they had to fit in this 20-bit field, which is far too little to be a practical option in the modern world. A register that would always be added to the branch offset would be specified as an alternative, allowing a branch instruction to compute the following:
This sum resolves the branch address size issue by enabling the programme to have a maximum size of 264 and yet support conditional branches, But which register, then, is the question?

Observing the application of conditional branches yields the solution. Conditional branches typically branch to a neighbouring instruction because they are found in if statements and loops. For instance, in the SPEC benchmarks, over half of all conditional branches point to places that are fewer than 16 instructions away.
Given that the address of the current instruction is contained in programme counter (PC) 241, we can branch within ±210 words of the instruction or jump within ±218 words of the instruction if we utilise the PC as the register to be added to the address.
The PC is the best option in almost all loops and if statements are less than 210 words. **PC-relative addressing** is the term for this type of branch addressing.