]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[riscv] Simplify TCP/IP checksum calculation
authorMichael Brown <mcb30@ipxe.org>
Sun, 24 May 2026 23:05:04 +0000 (00:05 +0100)
committerMichael Brown <mcb30@ipxe.org>
Tue, 26 May 2026 09:52:11 +0000 (10:52 +0100)
Use the tighter provable constraint

  carry.2^n + x <= (2^n - 1) + (2^n - 1)
                <= 2^n + (2^n - 2)

and so

  x + carry <= (2^n - 2) + 1
            <= (2^n - 1)

to eliminate some unnecessary folding steps, and hold the folded value
in the most significant bits of the register rather than the least
significant bits so that the final one's complement negation can be
accomplished naturally without requiring an explicit 0xffff constant.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/arch/riscv/core/riscv_tcpip.S

index f7d8e6a9ddd12f85b841765ce60ce0a440ebd1b8..3b772c1a6884c80eedaae7cc17227d30ab95a1ad 100644 (file)
@@ -56,7 +56,7 @@ tcpip_continue_chksum:
         * a1: data pointer
         * a2: end of data pointer
         * a3: end of data pointer minus a constant offset of interest
-        * a4: checksum high bits (guaranteed to never carry) / constant 0xffff
+        * a4: checksum high bits (guaranteed to never carry)
         * a5: temporary register
         */
        not     a0, a0
@@ -100,40 +100,30 @@ post_aligned:
        lbu     a5, (a1)
        add     a4, a4, a5
 1:
-       /* Fold down to xlen+1 bits */
+       /* Fold down to xlen bits */
        add     a0, a0, a4
        sltu    a4, a0, a4
-
-       /* Fold down to (xlen/2)+2 bits */
-       slli    a5, a0, ( __riscv_xlen / 2 )
-       srli    a0, a0, ( __riscv_xlen / 2 )
-       srli    a5, a5, ( __riscv_xlen / 2 )
        add     a0, a0, a4
-       add     a0, a0, a5
 
-       /* Load constant 0xffff for use in subsequent folding */
-       li      a4, 0xffff
+       /* Fold down to (high) xlen/2 bits */
+       slli    a4, a0, ( __riscv_xlen / 2 )
+       add     a0, a0, a4
+       sltu    a4, a0, a4
+       slli    a4, a4, ( __riscv_xlen / 2 )
+       add     a0, a0, a4
 
 #if __riscv_xlen >= 64
-       /* Fold down to (xlen/4)+3 bits (if xlen >= 64) */
-       and     a5, a0, a4
-       srli    a0, a0, ( __riscv_xlen / 4 )
-       add     a0, a0, a5
+       /* Fold down to (high) xlen/4 bits (if xlen >= 64) */
+       srli    a4, a0, ( __riscv_xlen / 2 )
+       slli    a4, a4, ( __riscv_xlen * 3 / 4 )
+       add     a0, a0, a4
+       sltu    a4, a0, a4
+       slli    a4, a4, ( __riscv_xlen * 3 / 4 )
+       add     a0, a0, a4
 #endif
 
-       /* Fold down to 16+1 bits */
-       and     a5, a0, a4
-       srli    a0, a0, 16
-       add     a0, a0, a5
-
-       /* Fold down to 16 bits */
-       srli    a5, a0, 16
-       add     a0, a0, a5
-       srli    a5, a0, 17
-       add     a0, a0, a5
-       and     a0, a0, a4
-
-       /* Negate and return */
-       xor     a0, a0, a4
+       /* Negate, move to low bits, and return */
+       not     a0, a0
+       srli    a0, a0, ( __riscv_xlen - 16 )
        ret
        .size   tcpip_continue_chksum, . - tcpip_continue_chksum