diff options
author | Nathan Froyd <froydnj@codesourcery.com> | 2010-06-08 13:29:59 -0700 |
---|---|---|
committer | Aurelien Jarno <aurelien@aurel32.net> | 2010-06-09 16:10:50 +0200 |
commit | 3c824109da076d2a1df4b798f9df81b385131f92 (patch) | |
tree | 504d7c603ec17658f473702dd2034e0b8bba0e49 /target-mips/op_helper.c | |
parent | 620e48f66350991918dd78e9a686a9b159fec111 (diff) |
target-mips: microMIPS ASE support
Add instruction decoding for the microMIPS ASE. All we do is decode and
then forward to the existing gen_* routines.
Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Diffstat (limited to 'target-mips/op_helper.c')
-rw-r--r-- | target-mips/op_helper.c | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 2bfdd5002f..d09d6ed546 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -565,6 +565,142 @@ void helper_sdr(target_ulong arg1, target_ulong arg2, int mem_idx) } #endif /* TARGET_MIPS64 */ +static const int multiple_regs[] = { 16, 17, 18, 19, 20, 21, 22, 23, 30 }; + +void helper_lwm (target_ulong addr, target_ulong reglist, uint32_t mem_idx) +{ + target_ulong base_reglist = reglist & 0xf; + target_ulong do_r31 = reglist & 0x10; +#ifdef CONFIG_USER_ONLY +#undef ldfun +#define ldfun ldl_raw +#else + uint32_t (*ldfun)(target_ulong); + + switch (mem_idx) + { + case 0: ldfun = ldl_kernel; break; + case 1: ldfun = ldl_super; break; + default: + case 2: ldfun = ldl_user; break; + } +#endif + + if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) { + target_ulong i; + + for (i = 0; i < base_reglist; i++) { + env->active_tc.gpr[multiple_regs[i]] = (target_long) ldfun(addr); + addr += 4; + } + } + + if (do_r31) { + env->active_tc.gpr[31] = (target_long) ldfun(addr); + } +} + +void helper_swm (target_ulong addr, target_ulong reglist, uint32_t mem_idx) +{ + target_ulong base_reglist = reglist & 0xf; + target_ulong do_r31 = reglist & 0x10; +#ifdef CONFIG_USER_ONLY +#undef stfun +#define stfun stl_raw +#else + void (*stfun)(target_ulong, uint32_t); + + switch (mem_idx) + { + case 0: stfun = stl_kernel; break; + case 1: stfun = stl_super; break; + default: + case 2: stfun = stl_user; break; + } +#endif + + if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) { + target_ulong i; + + for (i = 0; i < base_reglist; i++) { + stfun(addr, env->active_tc.gpr[multiple_regs[i]]); + addr += 4; + } + } + + if (do_r31) { + stfun(addr, env->active_tc.gpr[31]); + } +} + +#if defined(TARGET_MIPS64) +void helper_ldm (target_ulong addr, target_ulong reglist, uint32_t mem_idx) +{ + target_ulong base_reglist = reglist & 0xf; + target_ulong do_r31 = reglist & 0x10; +#ifdef CONFIG_USER_ONLY +#undef ldfun +#define ldfun ldq_raw +#else + uint64_t (*ldfun)(target_ulong); + + switch (mem_idx) + { + case 0: ldfun = ldq_kernel; break; + case 1: ldfun = ldq_super; break; + default: + case 2: ldfun = ldq_user; break; + } +#endif + + if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) { + target_ulong i; + + for (i = 0; i < base_reglist; i++) { + env->active_tc.gpr[multiple_regs[i]] = ldfun(addr); + addr += 8; + } + } + + if (do_r31) { + env->active_tc.gpr[31] = ldfun(addr); + } +} + +void helper_sdm (target_ulong addr, target_ulong reglist, uint32_t mem_idx) +{ + target_ulong base_reglist = reglist & 0xf; + target_ulong do_r31 = reglist & 0x10; +#ifdef CONFIG_USER_ONLY +#undef stfun +#define stfun stq_raw +#else + void (*stfun)(target_ulong, uint64_t); + + switch (mem_idx) + { + case 0: stfun = stq_kernel; break; + case 1: stfun = stq_super; break; + default: + case 2: stfun = stq_user; break; + } +#endif + + if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) { + target_ulong i; + + for (i = 0; i < base_reglist; i++) { + stfun(addr, env->active_tc.gpr[multiple_regs[i]]); + addr += 8; + } + } + + if (do_r31) { + stfun(addr, env->active_tc.gpr[31]); + } +} +#endif + #ifndef CONFIG_USER_ONLY /* CP0 helpers */ target_ulong helper_mfc0_mvpcontrol (void) |