From patchwork Wed Sep 12 02:01:52 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jia Liu X-Patchwork-Id: 183244 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 109D82C0086 for ; Wed, 12 Sep 2012 12:50:48 +1000 (EST) Received: from localhost ([::1]:55365 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TBcKC-0002cT-Sx for incoming@patchwork.ozlabs.org; Tue, 11 Sep 2012 22:05:08 -0400 Received: from eggs.gnu.org ([208.118.235.92]:58092) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TBcJz-0002NG-NV for qemu-devel@nongnu.org; Tue, 11 Sep 2012 22:04:59 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1TBcJv-0007t9-QW for qemu-devel@nongnu.org; Tue, 11 Sep 2012 22:04:55 -0400 Received: from mail-pz0-f45.google.com ([209.85.210.45]:56677) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TBcJv-0007t2-9b for qemu-devel@nongnu.org; Tue, 11 Sep 2012 22:04:51 -0400 Received: by dadn15 with SMTP id n15so711115dad.4 for ; Tue, 11 Sep 2012 19:04:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references :content-type; bh=JQ/JmFDug1aLAtNNiikOOifc28JIF6sRrUJnrQi02xE=; b=HahHzqV+n++xG7a5Jh5NhptQ54sURoQlMgyfB4K2HSeQxZWp+hwyWokf1CVBsTm3bJ MutENlwWfBw/sIVO1RU4V3HYl1zxy6rFjOQOg6ilCanr+zI+DAV/stiJkw/TFjvRw6bD EMN3ixhI3tngXDwmkvvykdNtPuDRJRKGKQbg1wKmcjfmlbNz85ROwgzMLfsL8dSYlg9y 8A18owt8La48f14zqEh0EYAAlG5kA5/3jDhJaf3RXyrHsbxpCog7Kfd97XoBfxdQoGNO 7RIJ0EDntx+Gs6UFqWgqxkIdkJblYnfOldLIrX61QhOuMtRH1I/ql3VTz4BEH/NgC9Nv uWoA== Received: by 10.66.72.197 with SMTP id f5mr29538876pav.20.1347415490663; Tue, 11 Sep 2012 19:04:50 -0700 (PDT) Received: from localhost ([1.202.183.51]) by mx.google.com with ESMTPS id pj10sm10666395pbb.46.2012.09.11.19.04.43 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 11 Sep 2012 19:04:49 -0700 (PDT) From: Jia Liu To: qemu-devel@nongnu.org Date: Wed, 12 Sep 2012 10:01:52 +0800 Message-Id: <1347415315-2180-12-git-send-email-proljc@gmail.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1347415315-2180-1-git-send-email-proljc@gmail.com> References: <1347415315-2180-1-git-send-email-proljc@gmail.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 209.85.210.45 Cc: aurelien@aurel32.net Subject: [Qemu-devel] [PATCH v8 11/14] target-mips-ase-dsp: Add DSP accumulator instructions X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Add MIPS ASE DSP Accumulator and DSPControl Access instructions. Signed-off-by: Jia Liu --- target-mips/dsp_helper.c | 1009 ++++++++++++++++++++++++++++++++++++++++++++++ target-mips/helper.h | 52 +++ target-mips/translate.c | 425 +++++++++++++++++++ 3 files changed, 1486 insertions(+) diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c index 2ba16d8..b2c22ce 100644 --- a/target-mips/dsp_helper.c +++ b/target-mips/dsp_helper.c @@ -6397,6 +6397,1015 @@ target_ulong helper_packrl_pw(target_ulong rs, target_ulong rt) } #endif +/** DSP Accumulator and DSPControl Access Sub-class insns **/ +target_ulong helper_extr_w(CPUMIPSState *env, uint32_t ac, uint32_t shift) +{ + int32_t tempI; + int64_t tempDL[2]; + + mipsdsp_rndrashift_short_acc(env, tempDL, ac, shift); + if ((tempDL[1] != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) && + (tempDL[1] != 1 || (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) { + set_DSPControl_overflow_flag(env, 1, 23); + } + + tempI = (tempDL[0] >> 1) & MIPSDSP_LLO; + + tempDL[0] += 1; + if (tempDL[0] == 0) { + tempDL[1] += 1; + } + + if ((!(tempDL[1] == 0 && (tempDL[0] & MIPSDSP_LHI) == 0x00)) && + (!(tempDL[1] == 1 && (tempDL[0] & MIPSDSP_LHI) == MIPSDSP_LHI))) { + set_DSPControl_overflow_flag(env, 1, 23); + } + + return (target_long)tempI; +} + +target_ulong helper_extr_r_w(CPUMIPSState *env, uint32_t ac, uint32_t shift) +{ + int64_t tempDL[2]; + + mipsdsp_rndrashift_short_acc(env, tempDL, ac, shift); + if ((tempDL[1] != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) && + (tempDL[1] != 1 || (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) { + set_DSPControl_overflow_flag(env, 1, 23); + } + + tempDL[0] += 1; + if (tempDL[0] == 0) { + tempDL[1] += 1; + } + + if ((tempDL[1] != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) && + (tempDL[1] != 1 && (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) { + set_DSPControl_overflow_flag(env, 1, 23); + } + + return (target_long)(int32_t)(tempDL[0] >> 1); +} + +target_ulong helper_extr_rs_w(CPUMIPSState *env, uint32_t ac, uint32_t shift) +{ + int32_t tempI, temp64; + int64_t tempDL[2]; + + mipsdsp_rndrashift_short_acc(env, tempDL, ac, shift); + if ((tempDL[1] != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) && + (tempDL[1] != 1 || (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) { + set_DSPControl_overflow_flag(env, 1, 23); + } + tempDL[0] += 1; + if (tempDL[0] == 0) { + tempDL[1] += 1; + } + tempI = tempDL[0] >> 1; + + if ((tempDL[1] != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) && + (tempDL[1] != 1 || (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) { + temp64 = tempDL[1]; + if (temp64 == 0) { + tempI = 0x7FFFFFFF; + } else { + tempI = 0x80000000; + } + set_DSPControl_overflow_flag(env, 1, 23); + } + + return (target_long)tempI; +} + +#if defined(TARGET_MIPS64) +target_ulong helper_dextr_w(CPUMIPSState *env, uint32_t ac, uint32_t shift) +{ + uint64_t temp[3]; + + mipsdsp_rndrashift_acc(env, temp, ac, shift); + + return (int64_t)(int32_t)(temp[0] >> 1); +} + +target_ulong helper_dextr_r_w(CPUMIPSState *env, uint32_t ac, uint32_t shift) +{ + uint64_t temp[3]; + uint32_t temp128; + + mipsdsp_rndrashift_acc(env, temp, ac, shift); + + temp[0] += 1; + if (temp[0] == 0) { + temp[1] += 1; + if (temp[1] == 0) { + temp[2] += 1; + } + } + + temp128 = temp[2] & 0x01; + + if ((temp128 != 0 || temp[1] != 0) && + (temp128 != 1 || temp[1] != ~0ull)) { + set_DSPControl_overflow_flag(env, 1, 23); + } + + return (int64_t)(int32_t)(temp[0] >> 1); +} + +target_ulong helper_dextr_rs_w(CPUMIPSState *env, uint32_t ac, uint32_t shift) +{ + uint64_t temp[3]; + uint32_t temp128; + + mipsdsp_rndrashift_acc(env, temp, ac, shift); + + temp[0] += 1; + if (temp[0] == 0) { + temp[1] += 1; + if (temp[1] == 0) { + temp[2] += 1; + } + } + + temp128 = temp[2] & 0x01; + + if ((temp128 != 0 || temp[1] != 0) && + (temp128 != 1 || temp[1] != ~0ull)) { + if (temp128 == 0) { + temp[0] = 0x0FFFFFFFF; + } else { + temp[0] = 0x0100000000; + } + set_DSPControl_overflow_flag(env, 1, 23); + } + + return (int64_t)(int32_t)(temp[0] >> 1); +} + +target_ulong helper_dextr_l(CPUMIPSState *env, uint32_t ac, uint32_t shift) +{ + uint64_t temp[3]; + target_ulong result; + + mipsdsp_rndrashift_acc(env, temp, ac, shift); + result = (temp[1] << 63) | (temp[0] >> 1); + + return result; +} + +target_ulong helper_dextr_r_l(CPUMIPSState *env, uint32_t ac, uint32_t shift) +{ + uint64_t temp[3]; + uint32_t temp128; + target_ulong result; + + mipsdsp_rndrashift_acc(env, temp, ac, shift); + + temp[0] += 1; + if (temp[0] == 0) { + temp[1] += 1; + if (temp[1] == 0) { + temp[2] += 1; + } + } + + temp128 = temp[2] & 0x01; + + if ((temp128 != 0 || temp[1] != 0) && + (temp128 != 1 || temp[1] != ~0ull)) { + set_DSPControl_overflow_flag(env, 1, 23); + } + + result = (temp[1] << 63) | (temp[0] >> 1); + + return result; +} + +target_ulong helper_dextr_rs_l(CPUMIPSState *env, uint32_t ac, uint32_t shift) +{ + uint64_t temp[3]; + uint32_t temp128; + target_ulong result; + + mipsdsp_rndrashift_acc(env, temp, ac, shift); + + temp[0] += 1; + if (temp[0] == 0) { + temp[1] += 1; + if (temp[1] == 0) { + temp[2] += 1; + } + } + + temp128 = temp[2] & 0x01; + + if ((temp128 != 0 || temp[1] != 0) && + (temp128 != 1 || temp[1] != ~0ull)) { + if (temp128 == 0) { + temp[1] &= 0xFFFFFFFFFFFFFFFEull; + temp[0] |= 0xFFFFFFFFFFFFFFFEull; + } else { + temp[1] |= 0x01; + temp[0] &= 0x01; + } + set_DSPControl_overflow_flag(env, 1, 23); + } + result = (temp[1] << 63) | (temp[0] >> 1); + + return result; +} +#endif + +target_ulong helper_extr_s_h(CPUMIPSState *env, uint32_t ac, uint32_t shift) +{ + int64_t temp; + + temp = mipsdsp_rashift_short_acc(env, ac, shift); + if (temp > 0x0000000000007FFFull) { + temp = 0x00007FFF; + set_DSPControl_overflow_flag(env, 1, 23); + } else if (temp < 0xFFFFFFFFFFFF8000ull) { + temp = 0xFFFF8000; + set_DSPControl_overflow_flag(env, 1, 23); + } + + return (target_long)(int32_t)(temp & 0xFFFFFFFF); +} + +target_ulong helper_extrv_s_h(CPUMIPSState *env, uint32_t ac, target_ulong rs) +{ + int32_t shift, tempI; + int64_t tempL; + + shift = rs & 0x0F; + tempL = mipsdsp_rashift_short_acc(env, ac, shift); + if (tempL > 0x000000000007FFFull) { + tempI = 0x00007FFF; + set_DSPControl_overflow_flag(env, 1, 23); + } else if (tempL < 0xFFFFFFFFFFF8000ull) { + tempI = 0xFFFF8000; + set_DSPControl_overflow_flag(env, 1, 23); + } + + return (target_long)(int32_t)tempI; +} + +#if defined(TARGET_MIPS64) +target_ulong helper_dextr_s_h(CPUMIPSState *env, uint32_t ac, uint32_t shift) +{ + int64_t temp[2]; + uint32_t temp127; + + mipsdsp_rashift_acc(env, (uint64_t *)temp, ac, shift); + + temp127 = (temp[1] >> 63) & 0x01; + + if ((temp127 == 0) && (temp[1] > 0 || temp[0] > 32767)) { + temp[0] &= 0xFFFF0000; + temp[0] |= 0x00007FFF; + set_DSPControl_overflow_flag(env, 1, 23); + } else if ((temp127 == 1) && + (temp[1] < 0xFFFFFFFFFFFFFFFFll + || temp[0] < 0xFFFFFFFFFFFF1000ll)) { + temp[0] &= 0xFFFF0000; + temp[0] |= 0x00008000; + set_DSPControl_overflow_flag(env, 1, 23); + } + + return (int64_t)(int16_t)(temp[0] & MIPSDSP_LO); +} + +target_ulong helper_dextrv_s_h(CPUMIPSState *env, + uint32_t ac, target_ulong shift) +{ + int64_t temp[2]; + uint32_t temp127; + + shift = shift & 0x1F; + mipsdsp_rashift_acc(env, (uint64_t *)temp, ac, shift); + + temp127 = (temp[1] >> 63) & 0x01; + + if ((temp127 == 0) && (temp[1] > 0 || temp[0] > 32767)) { + temp[0] &= 0xFFFF0000; + temp[0] |= 0x00007FFF; + set_DSPControl_overflow_flag(env, 1, 23); + } else if ((temp127 == 1) && + (temp[1] < ~0ull || temp[0] < 0xFFFFFFFFFFFF1000ull)) { + temp[0] &= 0xFFFF0000; + temp[0] |= 0x00008000; + set_DSPControl_overflow_flag(env, 1, 23); + } + + return (int64_t)(int16_t)(temp[0] & MIPSDSP_LO); +} +#endif + +target_ulong helper_extrv_w(CPUMIPSState *env, uint32_t ac, target_ulong rs) +{ + int32_t shift, tempI; + int64_t tempDL[2]; + + shift = rs & 0x0F; + mipsdsp_rndrashift_short_acc(env, tempDL, ac, shift); + if ((tempDL[1] != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) && + (tempDL[1] != 1 || (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) { + set_DSPControl_overflow_flag(env, 1, 23); + } + + tempI = tempDL[0] >> 1; + + tempDL[0] += 1; + if (tempDL[0] == 0) { + tempDL[1] += 1; + } + if ((tempDL[1] != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) && + (tempDL[1] != 1 || (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) { + set_DSPControl_overflow_flag(env, 1, 23); + } + + return (target_long)tempI; +} + +target_ulong helper_extrv_r_w(CPUMIPSState *env, uint32_t ac, target_ulong rs) +{ + int32_t shift; + int64_t tempDL[2]; + + shift = rs & 0x0F; + mipsdsp_rndrashift_short_acc(env, tempDL, ac, shift); + if ((tempDL[1] != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) && + (tempDL[1] != 1 || (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) { + set_DSPControl_overflow_flag(env, 1, 23); + } + + tempDL[0] += 1; + if (tempDL[0] == 0) { + tempDL[1] += 1; + } + + if ((tempDL[1] != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) && + (tempDL[1] != 1 || (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) { + set_DSPControl_overflow_flag(env, 1, 23); + } + + return (target_long)(int32_t)(tempDL[0] >> 1); +} + +target_ulong helper_extrv_rs_w(CPUMIPSState *env, uint32_t ac, target_ulong rs) +{ + int32_t shift, tempI; + int64_t tempDL[2]; + + shift = rs & 0x0F; + mipsdsp_rndrashift_short_acc(env, tempDL, ac, shift); + if ((tempDL[1] != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) && + (tempDL[1] != 1 || (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) { + set_DSPControl_overflow_flag(env, 1, 23); + } + + tempDL[0] += 1; + if (tempDL[0] == 0) { + tempDL[1] += 1; + } + tempI = tempDL[0] >> 1; + + if ((tempDL[1] != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) && + (tempDL[1] != 1 || (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) { + if (tempDL[1] == 0) { + tempI = 0x7FFFFFFF; + } else { + tempI = 0x80000000; + } + set_DSPControl_overflow_flag(env, 1, 23); + } + + return (target_long)tempI; +} + +#if defined(TARGET_MIPS64) +target_ulong helper_dextrv_w(CPUMIPSState *env, uint32_t ac, target_ulong shift) +{ + uint64_t temp[3]; + + shift = shift & 0x1F; + + mipsdsp_rndrashift_acc(env, temp, ac, shift); + + return (int64_t)(int32_t)(temp[0] >> 1); +} + +target_ulong helper_dextrv_r_w(CPUMIPSState *env, + uint32_t ac, target_ulong shift) +{ + uint64_t temp[3]; + uint32_t temp128; + + shift = shift & 0x1F; + + mipsdsp_rndrashift_acc(env, temp, ac, shift); + + temp[0] += 1; + if (temp[0] == 0) { + temp[1] += 1; + if (temp[1] == 0) { + temp[2] += 1; + } + } + + temp128 = temp[2] & 0x01; + + if ((temp128 != 0 || temp[1] != 0) && + (temp128 != 1 || temp[1] != ~0ull)) { + set_DSPControl_overflow_flag(env, 1, 23); + } + + return (int64_t)(int32_t)(temp[0] >> 1); +} + +target_ulong helper_dextrv_rs_w(CPUMIPSState *env, + uint32_t ac, target_ulong shift) +{ + uint64_t temp[3]; + uint32_t temp128; + + shift = shift & 0x1F; + + mipsdsp_rndrashift_acc(env, temp, ac, shift); + + temp[0] += 1; + if (temp[0] == 0) { + temp[1] += 1; + if (temp[1] == 0) { + temp[2] += 1; + } + } + + temp128 = temp[2] & 0x01; + + if ((temp128 != 0 || temp[1] != 0) && + (temp128 != 1 || temp[1] != ~0ull)) { + if (temp128 == 0) { + temp[0] |= 0x0FFFFFFFF; + } else { + temp[0] = 0x0100000000; + } + set_DSPControl_overflow_flag(env, 1, 23); + } + + return (int64_t)(int32_t)(temp[0] >> 1); +} + +target_ulong helper_dextrv_l(CPUMIPSState *env, uint32_t ac, target_ulong shift) +{ + uint64_t temp[3]; + target_ulong result; + + shift = shift & 0x1F; + + mipsdsp_rndrashift_acc(env, temp, ac, shift); + + result = (temp[1] << 63) | (temp[0] >> 1); + + return result; +} + +target_ulong helper_dextrv_r_l(CPUMIPSState *env, + uint32_t ac, target_ulong shift) +{ + uint64_t temp[3]; + uint32_t temp128; + target_ulong result; + + shift = shift & 0x1F; + + mipsdsp_rndrashift_acc(env, temp, ac, shift); + + temp[0] += 1; + if (temp[0] == 0) { + temp[1] += 1; + if (temp[1] == 0) { + temp[2] += 1; + } + } + + temp128 = temp[2] & 0x01; + + if ((temp128 != 0 || temp[1] != 0) && + (temp128 != 1 || temp[1] != ~0ull)) { + set_DSPControl_overflow_flag(env, 1, 23); + } + result = (temp[1] << 63) | (temp[0] >> 1); + + return result; +} + +target_ulong helper_dextrv_rs_l(CPUMIPSState *env, + uint32_t ac, target_ulong shift) +{ + uint64_t temp[3]; + uint32_t temp128; + target_ulong result; + + shift = shift & 0x1F; + + mipsdsp_rndrashift_acc(env, temp, ac, shift); + + temp[0] += 1; + if (temp[0] == 0) { + temp[1] += 1; + if (temp[1] == 0) { + temp[2] += 1; + } + } + + temp128 = temp[2] & 0x01; + + if ((temp128 != 0 || temp[1] != 0) && + (temp128 != 1 || temp[1] != ~0ull)) { + if (temp128 == 0) { + temp[1] &= 0xFFFFFFFFFFFFFFFEull; + temp[0] |= 0xFFFFFFFFFFFFFFFEull; + } else { + temp[1] |= 0x01; + temp[0] &= 0x01; + } + set_DSPControl_overflow_flag(env, 1, 23); + } + + result = (temp[1] << 63) | (temp[0] >> 1); + + return result; +} +#endif + +target_ulong helper_extp(CPUMIPSState *env, uint32_t ac, uint32_t size) +{ + int32_t start_pos; + int sub; + uint32_t temp; + uint64_t acc; + + temp = 0; + start_pos = get_DSPControl_pos(env); + sub = start_pos - (size + 1); + if (sub >= -1) { + acc = ((uint64_t)env->active_tc.HI[ac] << 32) | + ((uint64_t)env->active_tc.LO[ac] & MIPSDSP_LLO); + temp = (acc >> (start_pos - size)) & + (((uint32_t)0x01 << (size + 1)) - 1); + set_DSPControl_efi(env, 0); + } else { + set_DSPControl_efi(env, 1); + } + + return (target_ulong)temp; +} + +target_ulong helper_extpv(CPUMIPSState *env, uint32_t ac, target_ulong rs) +{ + int32_t start_pos, size; + uint32_t temp; + uint64_t acc; + + temp = 0; + start_pos = get_DSPControl_pos(env); + size = rs & 0x1F; + + if (start_pos - (size + 1) >= -1) { + acc = ((uint64_t)env->active_tc.HI[ac] << 32) | + ((uint64_t)env->active_tc.LO[ac] & MIPSDSP_LLO); + temp = (acc >> (start_pos - size)) & + (((uint32_t)0x01 << (size + 1)) - 1); + set_DSPControl_efi(env, 0); + } else { + set_DSPControl_efi(env, 1); + } + + return (target_ulong)temp; +} + +target_ulong helper_extpdp(CPUMIPSState *env, uint32_t ac, uint32_t size) +{ + int32_t start_pos; + int sub; + uint32_t temp; + uint64_t acc; + + temp = 0; + start_pos = get_DSPControl_pos(env); + sub = start_pos - (size + 1); + if (sub >= -1) { + acc = ((uint64_t)env->active_tc.HI[ac] << 32) | + ((uint64_t)env->active_tc.LO[ac] & MIPSDSP_LLO); + temp = (acc >> (start_pos - size)) & + (((uint32_t)0x01 << (size + 1)) - 1); + + set_DSPControl_pos(env, start_pos - (size + 1)); + set_DSPControl_efi(env, 0); + } else { + set_DSPControl_efi(env, 1); + } + + return (target_ulong)temp; +} + +target_ulong helper_extpdpv(CPUMIPSState *env, uint32_t ac, target_ulong rs) +{ + int32_t start_pos, size; + uint32_t temp; + uint64_t acc; + + temp = 0; + start_pos = get_DSPControl_pos(env); + size = rs & 0x1F; + + if (start_pos - (size + 1) >= -1) { + acc = ((uint64_t)env->active_tc.HI[ac] << 32) | + ((uint64_t)env->active_tc.LO[ac] & MIPSDSP_LLO); + temp = (acc >> (start_pos - size)) & (((int)0x01 << (size + 1)) - 1); + set_DSPControl_pos(env, start_pos - (size + 1)); + set_DSPControl_efi(env, 0); + } else { + set_DSPControl_efi(env, 1); + } + + return (target_ulong)temp; +} + +#if defined(TARGET_MIPS64) +target_ulong helper_dextp(CPUMIPSState *env, uint32_t ac, uint32_t size) +{ + int start_pos; + int len; + int sub; + uint64_t tempB, tempA; + uint64_t temp; + + temp = 0; + + size = size & 0x3F; + start_pos = get_DSPControl_pos(env); + len = start_pos - size; + tempB = env->active_tc.HI[ac]; + tempA = env->active_tc.LO[ac]; + + sub = start_pos - (size + 1); + + if (sub >= -1) { + temp = (tempB << (64 - len)) | (tempA >> len); + temp = temp & ((0x01 << (size + 1)) - 1); + set_DSPControl_efi(env, 0); + } else { + set_DSPControl_efi(env, 1); + } + + return temp; +} + +target_ulong helper_dextpv(CPUMIPSState *env, uint32_t ac, target_ulong size) +{ + uint8_t start_pos; + uint8_t len; + int sub; + uint64_t tempB, tempA; + uint64_t temp; + + temp = 0; + + size = size & 0x3F; + start_pos = get_DSPControl_pos(env); + len = start_pos - size; + tempB = env->active_tc.HI[ac]; + tempA = env->active_tc.LO[ac]; + + sub = start_pos - (size + 1); + + if (sub >= -1) { + temp = (tempB << (64 - len)) | (tempA >> len); + temp = temp & ((0x01 << (size + 1)) - 1); + set_DSPControl_efi(env, 0); + } else { + set_DSPControl_efi(env, 1); + } + + return temp; +} + +target_ulong helper_dextpdp(CPUMIPSState *env, uint32_t ac, uint32_t size) +{ + int start_pos; + int len; + int sub; + uint64_t tempB, tempA; + uint64_t temp; + + temp = 0; + start_pos = get_DSPControl_pos(env); + len = start_pos - size; + tempB = env->active_tc.HI[ac]; + tempA = env->active_tc.LO[ac]; + + sub = start_pos - (size + 1); + + if (sub >= -1) { + temp = (tempB << (64 - len)) | (tempA >> len); + temp = temp & ((0x01 << (size + 1)) - 1); + set_DSPControl_pos(env, sub); + set_DSPControl_efi(env, 0); + } else { + set_DSPControl_efi(env, 1); + } + + return temp; +} + +target_ulong helper_dextpdpv(CPUMIPSState *env, uint32_t ac, target_ulong size) +{ + int start_pos; + int len; + int sub; + uint64_t tempB, tempA; + uint64_t temp; + + temp = 0; + start_pos = get_DSPControl_pos(env); + size = size & 0x3F; + len = start_pos - size; + tempB = env->active_tc.HI[ac]; + tempA = env->active_tc.LO[ac]; + + sub = start_pos - (size + 1); + + if (sub >= -1) { + temp = (tempB << (64 - len)) | (tempA >> len); + temp = temp & ((0x01 << (size + 1)) - 1); + set_DSPControl_pos(env, sub); + set_DSPControl_efi(env, 0); + } else { + set_DSPControl_efi(env, 1); + } + + return temp; +} +#endif + +void helper_shilo(CPUMIPSState *env, uint32_t ac, uint32_t shift) +{ + uint8_t sign; + uint64_t temp, acc; + + shift = (int32_t)((int32_t)shift << 26) >> 26; + sign = (shift >> 5) & 0x01; + shift = (sign == 0) ? shift : -shift; + acc = (((uint64_t)env->active_tc.HI[ac] << 32) & MIPSDSP_LHI) | + ((uint64_t)env->active_tc.LO[ac] & MIPSDSP_LLO); + + if (shift == 0) { + temp = acc; + } else { + if (sign == 0) { + temp = acc >> shift; + } else { + temp = acc << shift; + } + } + + env->active_tc.HI[ac] = (target_long)(int32_t)((temp & MIPSDSP_LHI) >> 32); + env->active_tc.LO[ac] = (target_long)(int32_t)(temp & MIPSDSP_LLO); +} + +void helper_shilov(CPUMIPSState *env, uint32_t ac, target_ulong rs) +{ + uint8_t sign; + int8_t rs5_0; + uint64_t temp, acc; + + rs5_0 = rs & 0x3F; + rs = (int8_t)(rs5_0 << 2) >> 2; + sign = (rs5_0 >> 5) & 0x01; + rs5_0 = (sign == 0) ? rs : -rs; + acc = (((uint64_t)env->active_tc.HI[ac] << 32) & MIPSDSP_LHI) | + ((uint64_t)env->active_tc.LO[ac] & MIPSDSP_LLO); + if (rs5_0 == 0) { + temp = acc; + } else { + if (sign == 0) { + temp = acc >> rs5_0; + } else { + temp = acc << rs5_0; + } + } + + env->active_tc.HI[ac] = (target_ulong)(int32_t)((temp & MIPSDSP_LHI) >> 32); + env->active_tc.LO[ac] = (target_ulong)(int32_t)(temp & MIPSDSP_LLO); +} + +#if defined(TARGET_MIPS64) +void helper_dshilo(CPUMIPSState *env, uint32_t shift, uint32_t ac) +{ + uint8_t shift6; + int8_t shift_t; + uint64_t tempB, tempA; + + shift6 = (shift >> 6) & 0x01; + shift_t = (shift6 << 7) | (uint8_t)shift; + shift_t = shift6 == 0 ? shift_t : -shift_t; + + tempB = env->active_tc.HI[ac]; + tempA = env->active_tc.LO[ac]; + + if (shift_t != 0) { + if (shift6 == 0) { + tempA = (tempB << (64 - shift)) | (tempA >> shift); + tempB = tempB >> shift; + } else { + tempB = (tempB << shift) | (tempA >> (64 - shift)); + tempA = tempA << shift; + } + } + + env->active_tc.HI[ac] = tempB; + env->active_tc.LO[ac] = tempA; +} + +void helper_dshilov(CPUMIPSState *env, target_ulong shift, uint32_t ac) +{ + uint8_t shift6; + int8_t shift_t; + uint64_t tempB, tempA; + + shift6 = (shift >> 6) & 0x01; + shift_t = (shift6 << 7) | ((uint8_t)shift & 0x7F); + shift_t = shift6 == 0 ? shift_t : -shift_t; + + tempB = env->active_tc.HI[ac]; + tempA = env->active_tc.LO[ac]; + + if (shift_t != 0) { + if (shift6 == 0) { + tempA = (tempB << (64 - shift)) | (tempA >> shift); + tempB = tempB >> shift; + } else { + tempB = (tempB << shift) | (tempA >> (64 - shift)); + tempA = tempA << shift; + } + } + + env->active_tc.HI[ac] = tempB; + env->active_tc.LO[ac] = tempA; +} +#endif +void helper_mthlip(CPUMIPSState *env, uint32_t ac, target_ulong rs) +{ + int32_t tempA, tempB, pos; + + tempA = rs; + tempB = env->active_tc.LO[ac]; + env->active_tc.HI[ac] = (target_long)tempB; + env->active_tc.LO[ac] = (target_long)tempA; + pos = get_DSPControl_pos(env); + + if (pos > 32) { + return; + } else { + set_DSPControl_pos(env, pos + 32); + } +} + +#if defined(TARGET_MIPS64) +void helper_dmthlip(CPUMIPSState *env, target_ulong rs, uint32_t ac) +{ + uint8_t ac_t; + uint8_t pos; + uint64_t tempB, tempA; + + ac_t = ac & 0x3; + + tempA = rs; + tempB = env->active_tc.LO[ac_t]; + + env->active_tc.HI[ac_t] = tempB; + env->active_tc.LO[ac_t] = tempA; + + pos = get_DSPControl_pos(env); + + if (pos <= 64) { + pos = pos + 64; + set_DSPControl_pos(env, pos); + } +} +#endif + +void helper_wrdsp(CPUMIPSState *env, target_ulong rs, uint32_t mask_num) +{ + uint8_t mask[6]; + uint8_t i; + uint32_t newbits, overwrite; + target_ulong dsp; + + newbits = 0x00; + overwrite = 0xFFFFFFFF; + dsp = env->active_tc.DSPControl; + + for (i = 0; i < 6; i++) { + mask[i] = (mask_num >> i) & 0x01; + } + + if (mask[0] == 1) { +#if defined(TARGET_MIPS64) + overwrite &= 0xFFFFFF80; + newbits &= 0xFFFFFF80; + newbits |= 0x0000007F & rs; +#else + overwrite &= 0xFFFFFFC0; + newbits &= 0xFFFFFFC0; + newbits |= 0x0000003F & rs; +#endif + } + + if (mask[1] == 1) { + overwrite &= 0xFFFFE07F; + newbits &= 0xFFFFE07F; + newbits |= 0x00001F80 & rs; + } + + if (mask[2] == 1) { + overwrite &= 0xFFFFDFFF; + newbits &= 0xFFFFDFFF; + newbits |= 0x00002000 & rs; + } + + if (mask[3] == 1) { + overwrite &= 0xFF00FFFF; + newbits &= 0xFF00FFFF; + newbits |= 0x00FF0000 & rs; + } + + if (mask[4] == 1) { + overwrite &= 0x00FFFFFF; + newbits &= 0x00FFFFFF; + newbits |= 0xFF000000 & rs; + } + + if (mask[5] == 1) { + overwrite &= 0xFFFFBFFF; + newbits &= 0xFFFFBFFF; + newbits |= 0x00004000 & rs; + } + + dsp = dsp & overwrite; + dsp = dsp | newbits; + env->active_tc.DSPControl = dsp; +} + +target_ulong helper_rddsp(CPUMIPSState *env, uint32_t masknum) +{ + uint8_t mask[6]; + uint32_t ruler, i; + target_ulong temp; + target_ulong dsp; + + ruler = 0x01; + for (i = 0; i < 6; i++) { + mask[i] = (masknum & ruler) >> i ; + ruler = ruler << 1; + } + + temp = 0x00; + dsp = env->active_tc.DSPControl; + + if (mask[0] == 1) { +#if defined(TARGET_MIPS64) + temp |= dsp & 0x7F; +#else + temp |= dsp & 0x3F; +#endif + } + + if (mask[1] == 1) { + temp |= dsp & 0x1F80; + } + + if (mask[2] == 1) { + temp |= dsp & 0x2000; + } + + if (mask[3] == 1) { + temp |= dsp & 0x00FF0000; + } + + if (mask[4] == 1) { + temp |= dsp & 0xFF000000; + } + + if (mask[5] == 1) { + temp |= dsp & 0x4000; + } + + return temp; +} + #undef MIPSDSP_LHI #undef MIPSDSP_LLO #undef MIPSDSP_HI diff --git a/target-mips/helper.h b/target-mips/helper.h index daacb60..aa3b76e 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -635,4 +635,56 @@ DEF_HELPER_FLAGS_2(packrl_ph, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl) DEF_HELPER_FLAGS_2(packrl_pw, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl) #endif +/* DSP Accumulator and DSPControl Access Sub-class insns */ +DEF_HELPER_FLAGS_3(extr_w, 0, tl, env, i32, i32) +DEF_HELPER_FLAGS_3(extr_r_w, 0, tl, env, i32, i32) +DEF_HELPER_FLAGS_3(extr_rs_w, 0, tl, env, i32, i32) +#if defined(TARGET_MIPS64) +DEF_HELPER_FLAGS_3(dextr_w, 0, tl, env, i32, i32) +DEF_HELPER_FLAGS_3(dextr_r_w, 0, tl, env, i32, i32) +DEF_HELPER_FLAGS_3(dextr_rs_w, 0, tl, env, i32, i32) +DEF_HELPER_FLAGS_3(dextr_l, 0, tl, env, i32, i32) +DEF_HELPER_FLAGS_3(dextr_r_l, 0, tl, env, i32, i32) +DEF_HELPER_FLAGS_3(dextr_rs_l, 0, tl, env, i32, i32) +#endif +DEF_HELPER_FLAGS_3(extr_s_h, 0, tl, env, i32, i32) +DEF_HELPER_FLAGS_3(extrv_s_h, 0, tl, env, i32, tl) +#if defined(TARGET_MIPS64) +DEF_HELPER_FLAGS_3(dextr_s_h, 0, tl, env, i32, i32) +DEF_HELPER_FLAGS_3(dextrv_s_h, 0, tl, env, i32, tl) +#endif +DEF_HELPER_FLAGS_3(extrv_w, 0, tl, env, i32, tl) +DEF_HELPER_FLAGS_3(extrv_r_w, 0, tl, env, i32, tl) +DEF_HELPER_FLAGS_3(extrv_rs_w, 0, tl, env, i32, tl) +#if defined(TARGET_MIPS64) +DEF_HELPER_FLAGS_3(dextrv_w, 0, tl, env, i32, tl) +DEF_HELPER_FLAGS_3(dextrv_r_w, 0, tl, env, i32, tl) +DEF_HELPER_FLAGS_3(dextrv_rs_w, 0, tl, env, i32, tl) +DEF_HELPER_FLAGS_3(dextrv_l, 0, tl, env, i32, tl) +DEF_HELPER_FLAGS_3(dextrv_r_l, 0, tl, env, i32, tl) +DEF_HELPER_FLAGS_3(dextrv_rs_l, 0, tl, env, i32, tl) +#endif +DEF_HELPER_FLAGS_3(extp, 0, tl, env, i32, i32) +DEF_HELPER_FLAGS_3(extpv, 0, tl, env, i32, tl) +DEF_HELPER_FLAGS_3(extpdp, 0, tl, env, i32, i32) +DEF_HELPER_FLAGS_3(extpdpv, 0, tl, env, i32, tl) +#if defined(TARGET_MIPS64) +DEF_HELPER_FLAGS_3(dextp, 0, tl, env, i32, i32) +DEF_HELPER_FLAGS_3(dextpv, 0, tl, env, i32, tl) +DEF_HELPER_FLAGS_3(dextpdp, 0, tl, env, i32, i32) +DEF_HELPER_FLAGS_3(dextpdpv, 0, tl, env, i32, tl) +#endif +DEF_HELPER_FLAGS_3(shilo, 0, void, env, i32, i32) +DEF_HELPER_FLAGS_3(shilov, 0, void, env, i32, tl) +#if defined(TARGET_MIPS64) +DEF_HELPER_FLAGS_3(dshilo, 0, void, env, i32, i32) +DEF_HELPER_FLAGS_3(dshilov, 0, void, env, tl, i32) +#endif +DEF_HELPER_FLAGS_3(mthlip, 0, void, env, i32, tl) +#if defined(TARGET_MIPS64) +DEF_HELPER_FLAGS_3(dmthlip, 0, void, env, tl, i32) +#endif +DEF_HELPER_FLAGS_3(wrdsp, 0, void, env, tl, i32) +DEF_HELPER_FLAGS_2(rddsp, 0, tl, env, i32) + #include "def-helper.h" diff --git a/target-mips/translate.c b/target-mips/translate.c index 9e18c46..9ad54f1 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -353,6 +353,11 @@ enum { #if defined(TARGET_MIPS64) OPC_DAPPEND_DSP = 0x35 | OPC_SPECIAL3, #endif + /* MIPS DSP Accumulator and DSPControl Access Sub-class */ + OPC_EXTR_W_DSP = 0x38 | OPC_SPECIAL3, +#if defined(TARGET_MIPS64) + OPC_DEXTR_W_DSP = 0x3C | OPC_SPECIAL3, +#endif }; /* BSHFL opcodes */ @@ -564,6 +569,28 @@ enum { OPC_BALIGN = (0x10 << 6) | OPC_APPEND_DSP, }; +#define MASK_EXTR_W(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6))) +enum { + /* MIPS DSP Accumulator and DSPControl Access Sub-class */ + OPC_EXTR_W = (0x00 << 6) | OPC_EXTR_W_DSP, + OPC_EXTR_R_W = (0x04 << 6) | OPC_EXTR_W_DSP, + OPC_EXTR_RS_W = (0x06 << 6) | OPC_EXTR_W_DSP, + OPC_EXTR_S_H = (0x0E << 6) | OPC_EXTR_W_DSP, + OPC_EXTRV_S_H = (0x0F << 6) | OPC_EXTR_W_DSP, + OPC_EXTRV_W = (0x01 << 6) | OPC_EXTR_W_DSP, + OPC_EXTRV_R_W = (0x05 << 6) | OPC_EXTR_W_DSP, + OPC_EXTRV_RS_W = (0x07 << 6) | OPC_EXTR_W_DSP, + OPC_EXTP = (0x02 << 6) | OPC_EXTR_W_DSP, + OPC_EXTPV = (0x03 << 6) | OPC_EXTR_W_DSP, + OPC_EXTPDP = (0x0A << 6) | OPC_EXTR_W_DSP, + OPC_EXTPDPV = (0x0B << 6) | OPC_EXTR_W_DSP, + OPC_SHILO = (0x1A << 6) | OPC_EXTR_W_DSP, + OPC_SHILOV = (0x1B << 6) | OPC_EXTR_W_DSP, + OPC_MTHLIP = (0x1F << 6) | OPC_EXTR_W_DSP, + OPC_WRDSP = (0x13 << 6) | OPC_EXTR_W_DSP, + OPC_RDDSP = (0x12 << 6) | OPC_EXTR_W_DSP, +}; + #if defined(TARGET_MIPS64) #define MASK_ABSQ_S_QH(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6))) enum { @@ -676,6 +703,34 @@ enum { #endif #if defined(TARGET_MIPS64) +#define MASK_DEXTR_W(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6))) +enum { + /* MIPS DSP Accumulator and DSPControl Access Sub-class */ + OPC_DMTHLIP = (0x1F << 6) | OPC_DEXTR_W_DSP, + OPC_DSHILO = (0x1A << 6) | OPC_DEXTR_W_DSP, + OPC_DEXTP = (0x02 << 6) | OPC_DEXTR_W_DSP, + OPC_DEXTPDP = (0x0A << 6) | OPC_DEXTR_W_DSP, + OPC_DEXTPDPV = (0x0B << 6) | OPC_DEXTR_W_DSP, + OPC_DEXTPV = (0x03 << 6) | OPC_DEXTR_W_DSP, + OPC_DEXTR_L = (0x10 << 6) | OPC_DEXTR_W_DSP, + OPC_DEXTR_R_L = (0x14 << 6) | OPC_DEXTR_W_DSP, + OPC_DEXTR_RS_L = (0x16 << 6) | OPC_DEXTR_W_DSP, + OPC_DEXTR_W = (0x00 << 6) | OPC_DEXTR_W_DSP, + OPC_DEXTR_R_W = (0x04 << 6) | OPC_DEXTR_W_DSP, + OPC_DEXTR_RS_W = (0x06 << 6) | OPC_DEXTR_W_DSP, + OPC_DEXTR_S_H = (0x0E << 6) | OPC_DEXTR_W_DSP, + OPC_DEXTRV_L = (0x11 << 6) | OPC_DEXTR_W_DSP, + OPC_DEXTRV_R_L = (0x15 << 6) | OPC_DEXTR_W_DSP, + OPC_DEXTRV_RS_L = (0x17 << 6) | OPC_DEXTR_W_DSP, + OPC_DEXTRV_S_H = (0x0F << 6) | OPC_DEXTR_W_DSP, + OPC_DEXTRV_W = (0x01 << 6) | OPC_DEXTR_W_DSP, + OPC_DEXTRV_R_W = (0x05 << 6) | OPC_DEXTR_W_DSP, + OPC_DEXTRV_RS_W = (0x07 << 6) | OPC_DEXTR_W_DSP, + OPC_DSHILOV = (0x1B << 6) | OPC_DEXTR_W_DSP, +}; +#endif + +#if defined(TARGET_MIPS64) #define MASK_DINSV(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6))) enum { /* DSP Bit/Manipulation Sub-class */ @@ -13485,6 +13540,162 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) break; } break; + case OPC_EXTR_W_DSP: + check_dsp(ctx); + op2 = MASK_EXTR_W(ctx->opcode); + switch (op2) { + case OPC_EXTR_W: + { + TCGv_i32 temp_rd = tcg_const_i32(rd); + TCGv_i32 temp_rs = tcg_const_i32(rs); + gen_helper_extr_w(cpu_gpr[rt], cpu_env, temp_rd, temp_rs); + tcg_temp_free_i32(temp_rd); + tcg_temp_free_i32(temp_rs); + break; + } + case OPC_EXTR_R_W: + { + TCGv_i32 temp_rd = tcg_const_i32(rd); + TCGv_i32 temp_rs = tcg_const_i32(rs); + gen_helper_extr_r_w(cpu_gpr[rt], cpu_env, temp_rd, temp_rs); + tcg_temp_free_i32(temp_rd); + tcg_temp_free_i32(temp_rs); + break; + } + case OPC_EXTR_RS_W: + { + TCGv_i32 temp_rd = tcg_const_i32(rd); + TCGv_i32 temp_rs = tcg_const_i32(rs); + gen_helper_extr_rs_w(cpu_gpr[rt], cpu_env, + temp_rd, temp_rs); + tcg_temp_free_i32(temp_rd); + tcg_temp_free_i32(temp_rs); + break; + } + case OPC_EXTR_S_H: + { + TCGv_i32 temp_rd = tcg_const_i32(rd); + TCGv_i32 temp_rs = tcg_const_i32(rs); + gen_helper_extr_s_h(cpu_gpr[rt], cpu_env, temp_rd, temp_rs); + tcg_temp_free_i32(temp_rd); + tcg_temp_free_i32(temp_rs); + break; + } + case OPC_EXTRV_S_H: + { + TCGv_i32 temp_rd = tcg_const_i32(rd); + gen_helper_extrv_s_h(cpu_gpr[rt], cpu_env, + temp_rd, cpu_gpr[rs]); + tcg_temp_free_i32(temp_rd); + break; + } + case OPC_EXTRV_W: + { + TCGv_i32 temp_rd = tcg_const_i32(rd); + gen_helper_extrv_w(cpu_gpr[rt], cpu_env, + temp_rd, cpu_gpr[rs]); + tcg_temp_free_i32(temp_rd); + break; + } + case OPC_EXTRV_R_W: + { + TCGv_i32 temp_rd = tcg_const_i32(rd); + gen_helper_extrv_r_w(cpu_gpr[rt], cpu_env, + temp_rd, cpu_gpr[rs]); + tcg_temp_free_i32(temp_rd); + break; + } + case OPC_EXTRV_RS_W: + { + TCGv_i32 temp_rd = tcg_const_i32(rd); + gen_helper_extrv_rs_w(cpu_gpr[rt], cpu_env, + temp_rd, cpu_gpr[rs]); + tcg_temp_free_i32(temp_rd); + break; + } + case OPC_EXTP: + { + TCGv_i32 temp_rd = tcg_const_i32(rd); + TCGv_i32 temp_rs = tcg_const_i32(rs); + gen_helper_extp(cpu_gpr[rt], cpu_env, temp_rd, temp_rs); + tcg_temp_free_i32(temp_rd); + tcg_temp_free_i32(temp_rs); + break; + } + case OPC_EXTPV: + { + TCGv_i32 temp_rd = tcg_const_i32(rd); + gen_helper_extpv(cpu_gpr[rt], cpu_env, + temp_rd, cpu_gpr[rs]); + tcg_temp_free_i32(temp_rd); + break; + } + case OPC_EXTPDP: + { + TCGv_i32 temp_rd = tcg_const_i32(rd); + TCGv_i32 temp_rs = tcg_const_i32(rs); + gen_helper_extpdp(cpu_gpr[rt], cpu_env, temp_rd, temp_rs); + tcg_temp_free_i32(temp_rd); + tcg_temp_free_i32(temp_rs); + break; + } + case OPC_EXTPDPV: + { + TCGv_i32 temp_rd = tcg_const_i32(rd); + gen_helper_extpdpv(cpu_gpr[rt], cpu_env, + temp_rd, cpu_gpr[rs]); + tcg_temp_free_i32(temp_rd); + break; + } + case OPC_SHILO: + { + TCGv_i32 temp_imm; + TCGv_i32 temp_rd = tcg_const_i32(rd); + imm = (ctx->opcode >> 20) & 0x3F; + temp_imm = tcg_const_i32(imm); + gen_helper_shilo(cpu_env, temp_rd, temp_imm); + tcg_temp_free_i32(temp_imm); + tcg_temp_free_i32(temp_rd); + break; + } + case OPC_SHILOV: + { + TCGv_i32 temp_rd = tcg_const_i32(rd); + gen_helper_shilov(cpu_env, temp_rd, cpu_gpr[rs]); + tcg_temp_free_i32(temp_rd); + break; + } + case OPC_MTHLIP: + { + TCGv_i32 temp_rd = tcg_const_i32(rd); + gen_helper_mthlip(cpu_env, temp_rd, cpu_gpr[rs]); + tcg_temp_free_i32(temp_rd); + break; + } + case OPC_WRDSP: + { + TCGv_i32 temp_imm; + imm = (ctx->opcode >> 11) & 0x3FF; + temp_imm = tcg_const_i32(imm); + gen_helper_wrdsp(cpu_env, cpu_gpr[rs], temp_imm); + tcg_temp_free_i32(temp_imm); + break; + } + case OPC_RDDSP: + { + TCGv_i32 temp_imm; + imm = (ctx->opcode >> 16) & 0x03FF; + temp_imm = tcg_const_i32(imm); + gen_helper_rddsp(cpu_gpr[rd], cpu_env, temp_imm); + tcg_temp_free_i32(temp_imm); + break; + } + default: /* Invalid */ + MIPS_INVAL("MASK EXTR.W"); + generate_exception(ctx, EXCP_RI); + break; + } + break; #if defined(TARGET_MIPS64) case OPC_DEXTM ... OPC_DEXT: case OPC_DINSM ... OPC_DINS: @@ -14004,6 +14215,220 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) break; #endif #if defined(TARGET_MIPS64) + case OPC_DEXTR_W_DSP: + check_dsp(ctx); + op2 = MASK_DEXTR_W(ctx->opcode); + switch (op2) { + case OPC_DMTHLIP: + { + TCGv_i32 ac_v = tcg_const_i32(rd); + gen_helper_dmthlip(cpu_env, cpu_gpr[rs], ac_v); + tcg_temp_free_i32(ac_v); + break; + } + case OPC_DSHILO: + { + int shift = (ctx->opcode >> 19) & 0x7F; + int ac = (ctx->opcode >> 11) & 0x03; + TCGv_i32 shift_v = tcg_const_i32(shift); + TCGv_i32 ac_v = tcg_const_i32(ac); + + gen_helper_dshilo(cpu_env, shift_v, ac_v); + + tcg_temp_free_i32(shift_v); + tcg_temp_free_i32(ac_v); + break; + } + case OPC_DSHILOV: + { + int ac = (ctx->opcode >> 11) & 0x03; + TCGv_i32 ac_v = tcg_const_i32(ac); + gen_helper_dshilov(cpu_env, cpu_gpr[rs], ac_v); + tcg_temp_free_i32(ac_v); + break; + } + case OPC_DEXTP: + { + int ac = (ctx->opcode >> 11) & 0x03; + TCGv_i32 ac_v = tcg_const_i32(ac); + TCGv_i32 size_v = tcg_const_i32(rs); + gen_helper_dextp(cpu_gpr[rt], cpu_env, ac_v, size_v); + tcg_temp_free_i32(ac_v); + tcg_temp_free_i32(size_v); + break; + } + case OPC_DEXTPV: + { + int ac = (ctx->opcode >> 11) & 0x03; + TCGv_i32 ac_v = tcg_const_i32(ac); + gen_helper_dextpv(cpu_gpr[rt], cpu_env, + ac_v, cpu_gpr[rs]); + tcg_temp_free_i32(ac_v); + break; + } + case OPC_DEXTPDP: + { + int ac = (ctx->opcode >> 11) & 0x03; + TCGv_i32 ac_v = tcg_const_i32(ac); + TCGv_i32 size_v = tcg_const_i32(rs); + gen_helper_dextpdp(cpu_gpr[rt], cpu_env, ac_v, size_v); + tcg_temp_free_i32(ac_v); + tcg_temp_free_i32(size_v); + break; + } + case OPC_DEXTPDPV: + { + int ac = (ctx->opcode >> 11) & 0x03; + TCGv_i32 ac_v = tcg_const_i32(ac); + gen_helper_dextpdpv(cpu_gpr[rt], cpu_env, + ac_v, cpu_gpr[rs]); + tcg_temp_free_i32(ac_v); + break; + } + case OPC_DEXTR_L: + { + int ac = (ctx->opcode >> 11) & 0x03; + TCGv_i32 ac_v = tcg_const_i32(ac); + TCGv_i32 shift_v = tcg_const_i32(rs); + gen_helper_dextr_l(cpu_gpr[rt], cpu_env, ac_v, shift_v); + tcg_temp_free_i32(ac_v); + tcg_temp_free_i32(shift_v); + break; + } + case OPC_DEXTR_R_L: + { + int ac = (ctx->opcode >> 11) & 0x03; + TCGv_i32 ac_v = tcg_const_i32(ac); + TCGv_i32 shift_v = tcg_const_i32(rs); + gen_helper_dextr_r_l(cpu_gpr[rt], cpu_env, ac_v, shift_v); + tcg_temp_free_i32(ac_v); + tcg_temp_free_i32(shift_v); + break; + } + case OPC_DEXTR_RS_L: + { + int ac = (ctx->opcode >> 11) & 0x03; + TCGv_i32 ac_v = tcg_const_i32(ac); + TCGv_i32 shift_v = tcg_const_i32(rs); + gen_helper_dextr_rs_l(cpu_gpr[rt], cpu_env, + ac_v, shift_v); + tcg_temp_free_i32(ac_v); + tcg_temp_free_i32(shift_v); + break; + } + case OPC_DEXTR_W: + { + int ac = (ctx->opcode >> 11) & 0x03; + TCGv_i32 ac_v = tcg_const_i32(ac); + TCGv_i32 shift_v = tcg_const_i32(rs); + gen_helper_dextr_w(cpu_gpr[rt], cpu_env, ac_v, shift_v); + tcg_temp_free_i32(ac_v); + tcg_temp_free_i32(shift_v); + break; + } + case OPC_DEXTR_R_W: + { + int ac = (ctx->opcode >> 11) & 0x03; + TCGv_i32 ac_v = tcg_const_i32(ac); + TCGv_i32 shift_v = tcg_const_i32(rs); + gen_helper_dextr_r_w(cpu_gpr[rt], cpu_env, ac_v, shift_v); + tcg_temp_free_i32(ac_v); + tcg_temp_free_i32(shift_v); + break; + } + case OPC_DEXTR_RS_W: + { + int ac = (ctx->opcode >> 11) & 0x03; + TCGv_i32 ac_v = tcg_const_i32(ac); + TCGv_i32 shift_v = tcg_const_i32(rs); + gen_helper_dextr_rs_w(cpu_gpr[rt], cpu_env, ac_v, shift_v); + tcg_temp_free_i32(ac_v); + tcg_temp_free_i32(shift_v); + break; + } + case OPC_DEXTR_S_H: + { + int ac = (ctx->opcode >> 11) & 0x03; + TCGv_i32 ac_v = tcg_const_i32(ac); + TCGv_i32 shift_v = tcg_const_i32(rs); + gen_helper_dextr_s_h(cpu_gpr[rt], cpu_env, ac_v, shift_v); + tcg_temp_free_i32(ac_v); + tcg_temp_free_i32(shift_v); + break; + } + case OPC_DEXTRV_S_H: + { + int ac = (ctx->opcode >> 11) & 0x03; + TCGv_i32 ac_v = tcg_const_i32(ac); + TCGv_i32 shift_v = tcg_const_i32(rs); + gen_helper_dextrv_s_h(cpu_gpr[rt], cpu_env, + ac_v, cpu_gpr[rs]); + tcg_temp_free_i32(ac_v); + tcg_temp_free_i32(shift_v); + break; + } + case OPC_DEXTRV_L: + { + int ac = (ctx->opcode >> 11) & 0x03; + TCGv_i32 ac_v = tcg_const_i32(ac); + gen_helper_dextrv_l(cpu_gpr[rt], cpu_env, + ac_v, cpu_gpr[rs]); + tcg_temp_free_i32(ac_v); + break; + } + case OPC_DEXTRV_R_L: + { + int ac = (ctx->opcode >> 11) & 0x03; + TCGv_i32 ac_v = tcg_const_i32(ac); + gen_helper_dextrv_r_l(cpu_gpr[rt], cpu_env, + ac_v, cpu_gpr[rs]); + tcg_temp_free_i32(ac_v); + break; + } + case OPC_DEXTRV_RS_L: + { + int ac = (ctx->opcode >> 11) & 0x03; + TCGv_i32 ac_v = tcg_const_i32(ac); + gen_helper_dextrv_rs_l(cpu_gpr[rt], cpu_env, + ac_v, cpu_gpr[rs]); + tcg_temp_free_i32(ac_v); + break; + } + case OPC_DEXTRV_W: + { + int ac = (ctx->opcode >> 11) & 0x03; + TCGv_i32 ac_v = tcg_const_i32(ac); + gen_helper_dextrv_w(cpu_gpr[rt], cpu_env, + ac_v, cpu_gpr[rs]); + tcg_temp_free_i32(ac_v); + break; + } + case OPC_DEXTRV_R_W: + { + int ac = (ctx->opcode >> 11) & 0x03; + TCGv_i32 ac_v = tcg_const_i32(ac); + gen_helper_dextrv_r_w(cpu_gpr[rt], cpu_env, + ac_v, cpu_gpr[rs]); + tcg_temp_free_i32(ac_v); + break; + } + case OPC_DEXTRV_RS_W: + { + int ac = (ctx->opcode >> 11) & 0x03; + TCGv_i32 ac_v = tcg_const_i32(ac); + gen_helper_dextrv_rs_w(cpu_gpr[rt], cpu_env, + ac_v, cpu_gpr[rs]); + tcg_temp_free_i32(ac_v); + break; + } + default: /* Invalid */ + MIPS_INVAL("MASK EXTR.W"); + generate_exception(ctx, EXCP_RI); + break; + } + break; +#endif +#if defined(TARGET_MIPS64) case OPC_DPAQ_W_QH_DSP: { int ac = rd & 0x03;