diff options
author | Petar Jovanovic <petar.jovanovic@imgtec.com> | 2013-05-08 13:17:40 +0200 |
---|---|---|
committer | Aurelien Jarno <aurelien@aurel32.net> | 2013-05-08 18:46:38 +0200 |
commit | c0f5f9ce86ddca0a7d7ca60012059a5a18aa9c07 (patch) | |
tree | cef6856b1ab0a712df749604b1a1dc862564f549 | |
parent | 639eadb9a32775e1c70bbf37d347972ca41128d1 (diff) |
target-mips: fix incorrect behaviour for INSV
Corner case for INSV instruction when size=32 has not been correctly
implemented. The mask for size should be one bit wider, and preparing the
filter variable should be aware of this case too.
The test for INSV has been extended to include the case that triggers the
bug.
Signed-off-by: Petar Jovanovic <petar.jovanovic@imgtec.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
-rw-r--r-- | target-mips/dsp_helper.c | 4 | ||||
-rw-r--r-- | tests/tcg/mips/mips32-dsp/insv.c | 13 |
2 files changed, 15 insertions, 2 deletions
diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c index 805247d252..9212789b4e 100644 --- a/target-mips/dsp_helper.c +++ b/target-mips/dsp_helper.c @@ -2921,7 +2921,7 @@ target_ulong helper_##name(CPUMIPSState *env, target_ulong rs, \ return rt; \ } \ \ - filter = ((int32_t)0x01 << size) - 1; \ + filter = ((int64_t)0x01 << size) - 1; \ filter = filter << pos; \ temprs = (rs << pos) & filter; \ temprt = rt & ~filter; \ @@ -2930,7 +2930,7 @@ target_ulong helper_##name(CPUMIPSState *env, target_ulong rs, \ return (target_long)(ret_type)temp; \ } -BIT_INSV(insv, 0x1F, 0x1F, int32_t); +BIT_INSV(insv, 0x1F, 0x3F, int32_t); #ifdef TARGET_MIPS64 BIT_INSV(dinsv, 0x7F, 0x3F, target_long); #endif diff --git a/tests/tcg/mips/mips32-dsp/insv.c b/tests/tcg/mips/mips32-dsp/insv.c index 243b00733d..9d674697cc 100644 --- a/tests/tcg/mips/mips32-dsp/insv.c +++ b/tests/tcg/mips/mips32-dsp/insv.c @@ -19,5 +19,18 @@ int main() ); assert(rt == result); + dsp = 0x1000; + rt = 0xF0F0F0F0; + rs = 0xA5A5A5A5; + result = 0xA5A5A5A5; + + __asm + ("wrdsp %2\n\t" + "insv %0, %1\n\t" + : "+r"(rt) + : "r"(rs), "r"(dsp) + ); + assert(rt == result); + return 0; } |