Menu Close

Instruction Address Alignment and Addition/Subtraction Overflow Handling – RISC-V Instruction Set (7)

Posted in Risc-V

1. RISC-V Instruction Address Alignment

For load/store instructions, the address of the data in memory should be aligned.

  • If accessing 32-bit data, the memory address should be aligned with 32-bit data, which means the lowest two bits of D_PC should be 0 (if the memory stores data in units of 32 bits, indicating that the data is aligned in 4-byte units).
  • If accessing 16-bit data, the memory address should be aligned with 16-bit data, and the lowest bit of D_PC should be 0 (indicating that the data is aligned in 2-byte units).
  • If accessing 8-bit data, no alignment is required because the memory unit is one byte. The specific implementation of address shifting in hardware in CPU design can be found in the RISC-V LSU, SRAM, and GPIO modules (2) and the D_sram module.

Note: RISC-V only supports the little-endian format. The comparison between little-endian format and big-endian format is shown in Figure 1. If the same 32-bit number 0x0A0B0C0D is stored in different byte orders, the situations are shown in the figure below.

  • The highest byte of little-endian is 0x0A, and the lowest byte is 0x0D.
  • The highest byte of big-endian is 0x0D, and the lowest byte is 0x0A.

If data exchange is required between systems with different byte orders, it is necessary to ensure that the transmitted data is in units of 32-bit numbers. If data is exchanged in units of one byte, there may be issues when exchanging data between systems with different byte orders. For example, in the little-endian system, the address (a+3) corresponds to 0x0A, but in a big-endian system, the data stored at that address is 0x0D.

Related:   RISC-V Pseudo-Instruction Lookup Table
Format of Big Endian and Little Endian
Figure 1. Format of Big Endian and Little Endian

RISC-V chose the little-endian format as the byte order because it currently dominates the commercial market. All X86-32 systems, as well as Apple iOS, Google Android operating systems, and Microsoft Windows for ARM, use the little-endian format for address sorting (i.e., the least significant byte comes first).

2. RISC-V Instructions – Addition/Subtraction Overflow Handling

As previously mentioned, instructions such as ADD, ADDI, and SUB may result in overflow during computation. In general, hardware design ignores arithmetic overflow, so RISC-V relies on software checks. The following examples illustrate how addition is handled (subtraction is similar):

  • Unsigned addition overflow (assuming x6 and x7 are unsigned):
    • ADD x5, x6, x7
    • BLTU x5, x6, overflow (jump to the branch for handling incorrect results)
    • Explanation: x5 is the sum of x6 and x7. If the sum is less than either of the addends, it indicates overflow, and the code jumps to the overflow branch.
  • Signed addition with a positive imm:
    • ADDI x5, x6, +imm (positive)
    • BLT x5, x6, overflow (jump to the branch for handling incorrect results)
    • Explanation: whether x6 is positive or negative, adding a positive number to it should result in a larger value. If x5 is less than x6 in a signed comparison, it indicates overflow, and the code jumps to the overflow branch.

Excluding the two special cases mentioned above, for the general case of addition, the handling is as follows:

(x7 < 0)  &&  (x6 + x7 >= x6)  ||  (x7 >= 0)  &&  (x6 + x7 < x6)
ADD x5,x6,x7
SLTI x28,x7,0
SLT x29,x5,x6
BNE x28,x29,overflow (jump to the branch for incorrect results)

Explanation:

Related:   U-Type Integer Register-Immediate Instructions - RISC-V Instruction Set Explanation (3)

If x7 is less than zero, x28 will be set to 1, and the sum of x6 and x7 should be less than x6. x5 and x6 are then compared, and if x5 is less than x6, x29 is set to 1. If x5 is not less than x6, which means there is an overflow, x29 is set to 0. If x28 is not equal to x29, the execution will jump to the incorrect handling branch.

If x7 is greater than or equal to zero, x28 will be set to 0, and the sum of x6 and x7 should be greater than or equal to x6. x5 and x6 are then compared, and if x5 is less than x6, x29 is set to 1, which indicates an overflow. If x28 is not equal to x29, the execution will jump to the incorrect handling branch.

Alternatively, it can be understood that if (x7 < 0) && (x6 + x7 >= x6) || (x7 >= 0) && (x6 + x7 < x6), it is considered an incorrect handling branch.

 

Leave a Reply