Skip to content

Fix incorrect MULH/MULHU/MULHSU calculation logic in 64-bit ALU#434

Merged
mortbopet merged 3 commits intomortbopet:masterfrom
brian049:fix/rv64-mulh-implementation
Feb 18, 2026
Merged

Fix incorrect MULH/MULHU/MULHSU calculation logic in 64-bit ALU#434
mortbopet merged 3 commits intomortbopet:masterfrom
brian049:fix/rv64-mulh-implementation

Conversation

@brian049
Copy link
Contributor

This PR fixes a bug in the ALU implementation where mulh, mulhu, and mulhsu instructions were calculating incorrect results when running on a 64-bit processor model.

The original implementation shared the same logic for both 32-bit and 64-bit architectures (take mulh for example):

    const auto result = static_cast<int64_t>(op1.sValue()) *
                        static_cast<int64_t>(op2.sValue());
    return VT_U(result >> 32);

For RV64, this logic is flawed because it truncates the 128-bit product (64-bit * 64-bit) into a 64-bit container and it shift by only 32 bits, which means returning bits [63:32] of the result instead of [127:64].

The commit updated rv_alu.h to check for XLEN. If XLEN=64, the ALU now uses __int128_t for calculation and shifts the result by 64 bits to correctly retrieve the high part of the product.

Verification

I verified the fix using a custom assembly program provided in issue#344, which performs multiplication that exceeds 64 bits.

Assembly Codes for Testing (from Issue #344)
li x8, 11
slli x8, x8, 35
ori x8, x8, 254

li x9, 23
slli x9, x9, 35
ori x8, x8, 424

mul x10, x8, x9
mulh x11, x8, x9
mulhu x12, x8, x9
mulhsu x13, x8, x9

Operand 1 (x8): 0x00000058000001fe
Operand 2 (x9): 0x000000b800000000
Expected High Part (x11): 0x0000000000003f40

Before Fix:
Result in x11: 0x0000000000016E90 (Matches bits [63:32] of the product)

before

After Fix:
Result in x11: 0x0000000000003F40 (Matches the expected 128-bit high part)

after

@mortbopet
Copy link
Owner

Great! Mind adding (rewriting) the program that you've used to test into the 64-bit test suite?

The ALU implementation for MULH, MULHU, and MULHSU used a fixed
32-bit shift logic (>> 32) and casted operands to 64-bit integers.
This logic is incorrect for RV64.

In 64-bit mode, multiplying two 64-bit intergers produces a
128-bit result. The original codes would return the upper half of
the lower 64-bits (bits 32-63) instead of the actual high 64-bits
(bits 64-127), which is incorrect.

This commit fixes the issue by using `__int128_t` and
`unsigned __int128` for intermediate calculation when XLEN is 64,
and also shifting the result by 64 bits to correctly retrieve the
high part of the product.

Signed-off-by: brian049 <brianshih1203@gmail.com>
Signed-off-by: brian049 <brianshih1203@gmail.com>
@brian049 brian049 force-pushed the fix/rv64-mulh-implementation branch from c2490db to 4c4ffec Compare February 17, 2026 13:42
@brian049
Copy link
Contributor Author

Hello @mortbopet , I've added the test to the 64-bit test suite as requested.

Additionally, I noticed the CI failed on the Windows build (due to MSVC not supporting __int128) and flagged some clang-format errors. I went ahead and included fixes for those issues as well to ensure all checks pass.

@mortbopet mortbopet merged commit 4981e31 into mortbopet:master Feb 18, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants