aboutsummaryrefslogtreecommitdiff
path: root/sim/msp430
diff options
context:
space:
mode:
authorJozef Lawrynowicz <jozef.l@mittosystems.com>2020-07-28 10:36:10 +0100
committerJozef Lawrynowicz <jozef.l@mittosystems.com>2020-08-05 15:02:30 +0100
commite8a387fb5f91cdb9674f19703c0e7bfbaf895a84 (patch)
tree162d6decb4ea00d04438bf2e2ce3620cd8b1b9da /sim/msp430
parent5555c86d3e85e85d76555acdb955aba062beb02f (diff)
downloadbinutils-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')
-rw-r--r--sim/msp430/ChangeLog7
-rw-r--r--sim/msp430/msp430-sim.c28
-rw-r--r--sim/msp430/msp430-sim.h8
3 files changed, 31 insertions, 12 deletions
diff --git a/sim/msp430/ChangeLog b/sim/msp430/ChangeLog
index 0f27982..41da2a7 100644
--- a/sim/msp430/ChangeLog
+++ b/sim/msp430/ChangeLog
@@ -1,3 +1,10 @@
+2020-08-05 Jozef Lawrynowicz <jozef.l@mittosystems.com>
+
+ * 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.
+
2020-01-22 Jozef Lawrynowicz <jozef.l@mittosystems.com>
* msp430-sim.c (msp430_step_once): Ignore the carry flag when executing
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;
}
diff --git a/sim/msp430/msp430-sim.h b/sim/msp430/msp430-sim.h
index ad83e5b..7c486c2 100644
--- a/sim/msp430/msp430-sim.h
+++ b/sim/msp430/msp430-sim.h
@@ -31,16 +31,16 @@ struct msp430_cpu_state
int cio_buffer;
hwmult_type hwmult_type;
- unsigned32 hwmult_op1;
- unsigned32 hwmult_op2;
+ unsigned16 hwmult_op1;
+ unsigned16 hwmult_op2;
unsigned32 hwmult_result;
signed32 hwmult_signed_result;
unsigned32 hwmult_accumulator;
signed32 hwmult_signed_accumulator;
hw32mult_type hw32mult_type;
- unsigned64 hw32mult_op1;
- unsigned64 hw32mult_op2;
+ unsigned32 hw32mult_op1;
+ unsigned32 hw32mult_op2;
unsigned64 hw32mult_result;
};