diff options
author | Jozef Lawrynowicz <jozef.l@mittosystems.com> | 2020-07-28 10:36:10 +0100 |
---|---|---|
committer | Jozef Lawrynowicz <jozef.l@mittosystems.com> | 2020-08-05 15:02:30 +0100 |
commit | e8a387fb5f91cdb9674f19703c0e7bfbaf895a84 (patch) | |
tree | 162d6decb4ea00d04438bf2e2ce3620cd8b1b9da /sim/msp430/msp430-sim.c | |
parent | 5555c86d3e85e85d76555acdb955aba062beb02f (diff) | |
download | binutils-e8a387fb5f91cdb9674f19703c0e7bfbaf895a84.zip binutils-e8a387fb5f91cdb9674f19703c0e7bfbaf895a84.tar.gz binutils-e8a387fb5f91cdb9674f19703c0e7bfbaf895a84.tar.bz2 |
MSP430: sim: Fix incorrect simulation of unsigned widening multiply
Operand sizes used for simulation of MSP430 hardware multiply
operations are not aligned with the sizes used on the target, resulting
in the simulator storing signed operands with too much precision.
Additionally, simulation of unsigned multiplication is missing explicit
casts to prevent any implicit sign extension.
gcc.c-torture/execute/pr91450-1.c uses unsigned widening multiplication
of 32-bit operands -4 and 2, to produce a 64-bit result:
0xffff fffc * 0x2 = 0x1 ffff fff8
If -4 is stored in 64-bit precision, then the multiplication is
essentially signed and the result is -8 in 64-bit precision
(0xffff ffff ffff fffc), which is not correct.
sim/msp430/ChangeLog:
* msp430-sim.c (put_op): For unsigned multiplication, explicitly cast
operands to the unsigned type before multiplying.
* msp430-sim.h (struct msp430_cpu_state): Fix types used to store hwmult
operands.
sim/testsuite/sim/msp430/ChangeLog:
* mpyull_hwmult.s: New test.
Diffstat (limited to 'sim/msp430/msp430-sim.c')
-rw-r--r-- | sim/msp430/msp430-sim.c | 28 |
1 files changed, 20 insertions, 8 deletions
diff --git a/sim/msp430/msp430-sim.c b/sim/msp430/msp430-sim.c index e21c8cf..a330c6c 100644 --- a/sim/msp430/msp430-sim.c +++ b/sim/msp430/msp430-sim.c @@ -566,8 +566,13 @@ put_op (SIM_DESC sd, MSP430_Opcode_Decoded *opc, int n, int val) switch (HWMULT (sd, hwmult_type)) { case UNSIGN_32: - HWMULT (sd, hwmult_result) = HWMULT (sd, hwmult_op1) * HWMULT (sd, hwmult_op2); - HWMULT (sd, hwmult_signed_result) = (signed) HWMULT (sd, hwmult_result); + a = HWMULT (sd, hwmult_op1); + b = HWMULT (sd, hwmult_op2); + /* For unsigned 32-bit multiplication of 16-bit operands, an + explicit cast is required to prevent any implicit + sign-extension. */ + HWMULT (sd, hwmult_result) = (unsigned32) a * (unsigned32) b; + HWMULT (sd, hwmult_signed_result) = a * b; HWMULT (sd, hwmult_accumulator) = HWMULT (sd, hwmult_signed_accumulator) = 0; break; @@ -575,13 +580,16 @@ put_op (SIM_DESC sd, MSP430_Opcode_Decoded *opc, int n, int val) a = sign_ext (HWMULT (sd, hwmult_op1), 16); b = sign_ext (HWMULT (sd, hwmult_op2), 16); HWMULT (sd, hwmult_signed_result) = a * b; - HWMULT (sd, hwmult_result) = (unsigned) HWMULT (sd, hwmult_signed_result); + HWMULT (sd, hwmult_result) = (unsigned32) a * (unsigned32) b; HWMULT (sd, hwmult_accumulator) = HWMULT (sd, hwmult_signed_accumulator) = 0; break; case UNSIGN_MAC_32: - HWMULT (sd, hwmult_accumulator) += HWMULT (sd, hwmult_op1) * HWMULT (sd, hwmult_op2); - HWMULT (sd, hwmult_signed_accumulator) += HWMULT (sd, hwmult_op1) * HWMULT (sd, hwmult_op2); + a = HWMULT (sd, hwmult_op1); + b = HWMULT (sd, hwmult_op2); + HWMULT (sd, hwmult_accumulator) + += (unsigned32) a * (unsigned32) b; + HWMULT (sd, hwmult_signed_accumulator) += a * b; HWMULT (sd, hwmult_result) = HWMULT (sd, hwmult_accumulator); HWMULT (sd, hwmult_signed_result) = HWMULT (sd, hwmult_signed_accumulator); break; @@ -589,7 +597,8 @@ put_op (SIM_DESC sd, MSP430_Opcode_Decoded *opc, int n, int val) case SIGN_MAC_32: a = sign_ext (HWMULT (sd, hwmult_op1), 16); b = sign_ext (HWMULT (sd, hwmult_op2), 16); - HWMULT (sd, hwmult_accumulator) += a * b; + HWMULT (sd, hwmult_accumulator) + += (unsigned32) a * (unsigned32) b; HWMULT (sd, hwmult_signed_accumulator) += a * b; HWMULT (sd, hwmult_result) = HWMULT (sd, hwmult_accumulator); HWMULT (sd, hwmult_signed_result) = HWMULT (sd, hwmult_signed_accumulator); @@ -648,10 +657,13 @@ put_op (SIM_DESC sd, MSP430_Opcode_Decoded *opc, int n, int val) switch (HWMULT (sd, hw32mult_type)) { case UNSIGN_64: - HWMULT (sd, hw32mult_result) = HWMULT (sd, hw32mult_op1) * HWMULT (sd, hw32mult_op2); + HWMULT (sd, hw32mult_result) + = (unsigned64) HWMULT (sd, hw32mult_op1) + * (unsigned64) HWMULT (sd, hw32mult_op2); break; case SIGN_64: - HWMULT (sd, hw32mult_result) = sign_ext (HWMULT (sd, hw32mult_op1), 32) + HWMULT (sd, hw32mult_result) + = sign_ext (HWMULT (sd, hw32mult_op1), 32) * sign_ext (HWMULT (sd, hw32mult_op2), 32); break; } |