From patchwork Fri Dec 12 17:31:41 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bastian Koppelmann X-Patchwork-Id: 420554 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 2F3D214003E for ; Sat, 13 Dec 2014 03:34:52 +1100 (AEDT) Received: from localhost ([::1]:58192 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XzTB4-0003tW-BQ for incoming@patchwork.ozlabs.org; Fri, 12 Dec 2014 11:34:50 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38987) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XzT8A-0006zM-90 for qemu-devel@nongnu.org; Fri, 12 Dec 2014 11:31:55 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1XzT7z-0005nZ-7P for qemu-devel@nongnu.org; Fri, 12 Dec 2014 11:31:50 -0500 Received: from mail.uni-paderborn.de ([131.234.142.9]:47346) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XzT7y-0005n1-RC for qemu-devel@nongnu.org; Fri, 12 Dec 2014 11:31:39 -0500 From: Bastian Koppelmann To: qemu-devel@nongnu.org Date: Fri, 12 Dec 2014 17:31:41 +0000 Message-Id: <1418405504-11175-6-git-send-email-kbastian@mail.uni-paderborn.de> X-Mailer: git-send-email 2.1.3 In-Reply-To: <1418405504-11175-1-git-send-email-kbastian@mail.uni-paderborn.de> References: <1418405504-11175-1-git-send-email-kbastian@mail.uni-paderborn.de> X-IMT-Spam-Score: 0.0 () X-PMX-Version: 6.2.0.2453472, Antispam-Engine: 2.7.2.2107409, Antispam-Data: 2014.12.12.162119 X-IMT-Authenticated-Sender: uid=kbastian,ou=People,o=upb,c=de X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 131.234.142.9 Cc: rth@twiddle.net Subject: [Qemu-devel] [PATCH 5/8] target-tricore: Add instructions of RR opcode format, that have 0x4b as the first opcode 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 instructions of RR opcode format, that have 0x4b as the first opcode. Add helper functions: * parity: Calculates the parity bits for every byte of a 32 int. * bmerge/bsplit: Merges two regs into one bitwise/Splits one reg into two bitwise. * unpack: unpack a IEEE 754 single precision floating point number as exponent and mantissa. * dvinit_b_13/131: (ISA v1.3/v1.31)Prepare operands for a divide operation, where the quotient result is guaranteed to fit into 8 bit. * dvinit_h_13/131: (ISA v1.3/v1.31)Prepare operands for a divide operation, where the quotient result is guaranteed to fit into 16 bit. OPCM_32_RR_FLOAT -> OPCM_32_RR_DIVIDE. Signed-off-by: Bastian Koppelmann Reviewed-by: Richard Henderson --- target-tricore/helper.h | 11 +++ target-tricore/op_helper.c | 195 +++++++++++++++++++++++++++++++++++++++ target-tricore/translate.c | 186 +++++++++++++++++++++++++++++++++++++ target-tricore/tricore-opcodes.h | 2 +- 4 files changed, 393 insertions(+), 1 deletion(-) diff --git a/target-tricore/helper.h b/target-tricore/helper.h index 8e57e77..8d7958d 100644 --- a/target-tricore/helper.h +++ b/target-tricore/helper.h @@ -76,6 +76,17 @@ DEF_HELPER_2(sh, i32, i32, i32) DEF_HELPER_2(sh_h, i32, i32, i32) DEF_HELPER_3(sha, i32, env, i32, i32) DEF_HELPER_2(sha_h, i32, i32, i32) +/* merge/split/parity */ +DEF_HELPER_2(bmerge, i32, i32, i32) +DEF_HELPER_1(bsplit, i64, i32) +DEF_HELPER_1(parity, i32, i32) +/* float */ +DEF_HELPER_1(unpack, i64, i32) +/* dvinit */ +DEF_HELPER_3(dvinit_b_13, i64, env, i32, i32) +DEF_HELPER_3(dvinit_b_131, i64, env, i32, i32) +DEF_HELPER_3(dvinit_h_13, i64, env, i32, i32) +DEF_HELPER_3(dvinit_h_131, i64, env, i32, i32) /* CSA */ DEF_HELPER_2(call, void, env, i32) DEF_HELPER_1(ret, void, env) diff --git a/target-tricore/op_helper.c b/target-tricore/op_helper.c index 914d051..0fd38b5 100644 --- a/target-tricore/op_helper.c +++ b/target-tricore/op_helper.c @@ -1059,6 +1059,201 @@ uint32_t helper_sha_h(target_ulong r1, target_ulong r2) } } +uint32_t helper_bmerge(target_ulong r1, target_ulong r2) +{ + uint32_t i, ret; + + ret = 0; + for (i = 0; i < 16; i++) { + ret |= (r1 & 1) << (2 * i + 1); + ret |= (r2 & 1) << (2 * i); + r1 = r1 >> 1; + r2 = r2 >> 1; + } + return ret; +} + +uint64_t helper_bsplit(uint32_t r1) +{ + int32_t i; + uint64_t ret; + + ret = 0; + for (i = 0; i < 32; i = i + 2) { + /* even */ + ret |= (r1 & 1) << (i/2); + r1 = r1 >> 1; + /* odd */ + ret |= (uint64_t)(r1 & 1) << (i/2 + 32); + r1 = r1 >> 1; + } + return ret; +} + +uint32_t helper_parity(target_ulong r1) +{ + uint32_t ret; + uint32_t nOnes, i; + + ret = 0; + nOnes = 0; + for (i = 0; i < 8; i++) { + ret ^= (r1 & 1); + r1 = r1 >> 1; + } + /* second byte */ + nOnes = 0; + for (i = 0; i < 8; i++) { + nOnes ^= (r1 & 1); + r1 = r1 >> 1; + } + ret |= nOnes << 8; + /* third byte */ + nOnes = 0; + for (i = 0; i < 8; i++) { + nOnes ^= (r1 & 1); + r1 = r1 >> 1; + } + ret |= nOnes << 16; + /* fourth byte */ + nOnes = 0; + for (i = 0; i < 8; i++) { + nOnes ^= (r1 & 1); + r1 = r1 >> 1; + } + ret |= nOnes << 24; + + return ret; +} + +uint64_t helper_unpack(target_ulong arg1) +{ + int32_t fp_exp = extract32(arg1, 23, 8); + int32_t fp_frac = extract32(arg1, 0, 23); + uint64_t ret; + int32_t int_exp, int_mant; + + if (fp_exp == 255) { + int_exp = 255; + int_mant = (fp_frac << 7); + } else if ((fp_exp == 0) && (fp_frac == 0)) { + int_exp = -127; + int_mant = 0; + } else if ((fp_exp == 0) && (fp_frac != 0)) { + int_exp = -126; + int_mant = (fp_frac << 7); + } else { + int_exp = fp_exp - 127; + int_mant = (fp_frac << 7); + int_mant |= (1 << 30); + } + ret = int_exp; + ret = ret << 32; + ret |= int_mant; + + return ret; +} + +uint64_t helper_dvinit_b_13(CPUTriCoreState *env, uint32_t r1, uint32_t r2) +{ + uint64_t ret; + int32_t abs_sig_dividend, abs_base_dividend, abs_divisor; + int32_t quotient_sign; + + ret = sextract32(r1, 0, 32); + ret = ret << 24; + quotient_sign = 0; + if (!((r1 & 0x80000000) == (r2 & 0x80000000))) { + ret |= 0xffffff; + quotient_sign = 1; + } + + abs_sig_dividend = abs(r1) >> 7; + abs_base_dividend = abs(r1) & 0x7f; + abs_divisor = abs(r1); + /* calc overflow */ + env->PSW_USB_V = 0; + if ((quotient_sign) && (abs_divisor)) { + env->PSW_USB_V = (((abs_sig_dividend == abs_divisor) && + (abs_base_dividend >= abs_divisor)) || + (abs_sig_dividend > abs_divisor)); + } else { + env->PSW_USB_V = (abs_sig_dividend >= abs_divisor); + } + env->PSW_USB_V = env->PSW_USB_V << 31; + env->PSW_USB_SV |= env->PSW_USB_V; + env->PSW_USB_AV = 0; + + return ret; +} + +uint64_t helper_dvinit_b_131(CPUTriCoreState *env, uint32_t r1, uint32_t r2) +{ + uint64_t ret = sextract32(r1, 0, 32); + + ret = ret << 24; + if (!((r1 & 0x80000000) == (r2 & 0x80000000))) { + ret |= 0xffffff; + } + /* calc overflow */ + env->PSW_USB_V = ((r2 == 0) || ((r2 == 0xffffffff) && (r1 == 0xffffff80))); + env->PSW_USB_V = env->PSW_USB_V << 31; + env->PSW_USB_SV |= env->PSW_USB_V; + env->PSW_USB_AV = 0; + + return ret; +} + +uint64_t helper_dvinit_h_13(CPUTriCoreState *env, uint32_t r1, uint32_t r2) +{ + uint64_t ret; + int32_t abs_sig_dividend, abs_base_dividend, abs_divisor; + int32_t quotient_sign; + + ret = sextract32(r1, 0, 32); + ret = ret << 16; + quotient_sign = 0; + if (!((r1 & 0x80000000) == (r2 & 0x80000000))) { + ret |= 0xffff; + quotient_sign = 1; + } + + abs_sig_dividend = abs(r1) >> 7; + abs_base_dividend = abs(r1) & 0x7f; + abs_divisor = abs(r1); + /* calc overflow */ + env->PSW_USB_V = 0; + if ((quotient_sign) && (abs_divisor)) { + env->PSW_USB_V = (((abs_sig_dividend == abs_divisor) && + (abs_base_dividend >= abs_divisor)) || + (abs_sig_dividend > abs_divisor)); + } else { + env->PSW_USB_V = (abs_sig_dividend >= abs_divisor); + } + env->PSW_USB_V = env->PSW_USB_V << 31; + env->PSW_USB_SV |= env->PSW_USB_V; + env->PSW_USB_AV = 0; + + return ret; +} + +uint64_t helper_dvinit_h_131(CPUTriCoreState *env, uint32_t r1, uint32_t r2) +{ + uint64_t ret = sextract32(r1, 0, 32); + + ret = ret << 16; + if (!((r1 & 0x80000000) == (r2 & 0x80000000))) { + ret |= 0xffff; + } + /* calc overflow */ + env->PSW_USB_V = ((r2 == 0) || ((r2 == 0xffffffff) && (r1 == 0xffff8000))); + env->PSW_USB_V = env->PSW_USB_V << 31; + env->PSW_USB_SV |= env->PSW_USB_V; + env->PSW_USB_AV = 0; + + return ret; +} + /* context save area (CSA) related helpers */ static int cdc_increment(target_ulong *psw) diff --git a/target-tricore/translate.c b/target-tricore/translate.c index 37daad1..87945f4 100644 --- a/target-tricore/translate.c +++ b/target-tricore/translate.c @@ -1352,6 +1352,56 @@ static inline void gen_insert(TCGv ret, TCGv r1, TCGv r2, TCGv width, TCGv pos) tcg_temp_free(temp2); } +static inline void gen_bsplit(TCGv rl, TCGv rh, TCGv r1) +{ + TCGv_i64 temp = tcg_temp_new_i64(); + + gen_helper_bsplit(temp, r1); + tcg_gen_extr_i64_i32(rl, rh, temp); + + tcg_temp_free_i64(temp); +} + +static inline void gen_unpack(TCGv rl, TCGv rh, TCGv r1) +{ + TCGv_i64 temp = tcg_temp_new_i64(); + + gen_helper_unpack(temp, r1); + tcg_gen_extr_i64_i32(rl, rh, temp); + + tcg_temp_free_i64(temp); +} + +static inline void +gen_dvinit_b(CPUTriCoreState *env, TCGv rl, TCGv rh, TCGv r1, TCGv r2) +{ + TCGv_i64 ret = tcg_temp_new_i64(); + + if (!tricore_feature(env, TRICORE_FEATURE_131)) { + gen_helper_dvinit_b_13(ret, cpu_env, r1, r2); + } else { + gen_helper_dvinit_b_131(ret, cpu_env, r1, r2); + } + tcg_gen_extr_i64_i32(rl, rh, ret); + + tcg_temp_free_i64(ret); +} + +static inline void +gen_dvinit_h(CPUTriCoreState *env, TCGv rl, TCGv rh, TCGv r1, TCGv r2) +{ + TCGv_i64 ret = tcg_temp_new_i64(); + + if (!tricore_feature(env, TRICORE_FEATURE_131)) { + gen_helper_dvinit_h_13(ret, cpu_env, r1, r2); + } else { + gen_helper_dvinit_h_131(ret, cpu_env, r1, r2); + } + tcg_gen_extr_i64_i32(rl, rh, ret); + + tcg_temp_free_i64(ret); +} + /* helpers for generating program flow micro-ops */ static inline void gen_save_pc(target_ulong pc) @@ -4347,6 +4397,139 @@ static void decode_rr_idirect(CPUTriCoreState *env, DisasContext *ctx) ctx->bstate = BS_BRANCH; } +static void decode_rr_divide(CPUTriCoreState *env, DisasContext *ctx) +{ + uint32_t op2; + int r1, r2, r3; + + TCGv temp, temp2; + + op2 = MASK_OP_RR_OP2(ctx->opcode); + r3 = MASK_OP_RR_D(ctx->opcode); + r2 = MASK_OP_RR_S2(ctx->opcode); + r1 = MASK_OP_RR_S1(ctx->opcode); + + temp = tcg_temp_new(); + temp2 = tcg_temp_new(); + + switch (op2) { + case OPC2_32_RR_BMERGE: + gen_helper_bmerge(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]); + break; + case OPC2_32_RR_BSPLIT: + gen_bsplit(cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1]); + break; + case OPC2_32_RR_DVINIT_B: + gen_dvinit_b(env, cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1], + cpu_gpr_d[r2]); + break; + case OPC2_32_RR_DVINIT_BU: + temp = tcg_temp_new(); + temp2 = tcg_temp_new(); + /* reset av */ + tcg_gen_movi_tl(cpu_PSW_AV, 0); + if (!tricore_feature(env, TRICORE_FEATURE_131)) { + /* overflow = (abs(D[r3+1]) >= abs(D[r2])) */ + tcg_gen_neg_tl(temp, cpu_gpr_d[r3+1]); + /* use cpu_PSW_AV to compare against 0 */ + tcg_gen_movcond_tl(TCG_COND_LT, temp, cpu_gpr_d[r3+1], cpu_PSW_AV, + temp, cpu_gpr_d[r3+1]); + tcg_gen_neg_tl(temp2, cpu_gpr_d[r2]); + tcg_gen_movcond_tl(TCG_COND_LT, temp2, cpu_gpr_d[r2], cpu_PSW_AV, + temp2, cpu_gpr_d[r2]); + tcg_gen_setcond_tl(TCG_COND_GE, cpu_PSW_V, temp, temp2); + } else { + /* overflow = (D[b] == 0) */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_PSW_V, cpu_gpr_d[r2], 0); + } + tcg_gen_shli_tl(cpu_PSW_V, cpu_PSW_V, 31); + /* sv */ + tcg_gen_or_tl(cpu_PSW_SV, cpu_PSW_SV, cpu_PSW_V); + /* write result */ + tcg_gen_shri_tl(temp, cpu_gpr_d[r1], 8); + tcg_gen_shli_tl(cpu_gpr_d[r3], cpu_gpr_d[r1], 24); + tcg_gen_mov_tl(cpu_gpr_d[r3+1], temp); + + tcg_temp_free(temp); + tcg_temp_free(temp2); + break; + case OPC2_32_RR_DVINIT_H: + gen_dvinit_h(env, cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1], + cpu_gpr_d[r2]); + break; + case OPC2_32_RR_DVINIT_HU: + temp = tcg_temp_new(); + temp2 = tcg_temp_new(); + /* reset av */ + tcg_gen_movi_tl(cpu_PSW_AV, 0); + if (!tricore_feature(env, TRICORE_FEATURE_131)) { + /* overflow = (abs(D[r3+1]) >= abs(D[r2])) */ + tcg_gen_neg_tl(temp, cpu_gpr_d[r3+1]); + /* use cpu_PSW_AV to compare against 0 */ + tcg_gen_movcond_tl(TCG_COND_LT, temp, cpu_gpr_d[r3+1], cpu_PSW_AV, + temp, cpu_gpr_d[r3+1]); + tcg_gen_neg_tl(temp2, cpu_gpr_d[r2]); + tcg_gen_movcond_tl(TCG_COND_LT, temp2, cpu_gpr_d[r2], cpu_PSW_AV, + temp2, cpu_gpr_d[r2]); + tcg_gen_setcond_tl(TCG_COND_GE, cpu_PSW_V, temp, temp2); + } else { + /* overflow = (D[b] == 0) */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_PSW_V, cpu_gpr_d[r2], 0); + } + tcg_gen_shli_tl(cpu_PSW_V, cpu_PSW_V, 31); + /* sv */ + tcg_gen_or_tl(cpu_PSW_SV, cpu_PSW_SV, cpu_PSW_V); + /* write result */ + tcg_gen_mov_tl(temp, cpu_gpr_d[r1]); + tcg_gen_shri_tl(cpu_gpr_d[r3+1], temp, 16); + tcg_gen_shli_tl(cpu_gpr_d[r3], temp, 16); + tcg_temp_free(temp); + tcg_temp_free(temp2); + break; + case OPC2_32_RR_DVINIT: + temp = tcg_temp_new(); + temp2 = tcg_temp_new(); + /* overflow = ((D[b] == 0) || + ((D[b] == 0xFFFFFFFF) && (D[a] == 0x80000000))) */ + tcg_gen_setcondi_tl(TCG_COND_EQ, temp, cpu_gpr_d[r2], 0xffffffff); + tcg_gen_setcondi_tl(TCG_COND_EQ, temp2, cpu_gpr_d[r1], 0x80000000); + tcg_gen_and_tl(temp, temp, temp2); + tcg_gen_setcondi_tl(TCG_COND_EQ, temp2, cpu_gpr_d[r2], 0); + tcg_gen_or_tl(cpu_PSW_V, temp, temp2); + tcg_gen_shli_tl(cpu_PSW_V, cpu_PSW_V, 31); + /* sv */ + tcg_gen_or_tl(cpu_PSW_SV, cpu_PSW_SV, cpu_PSW_V); + /* reset av */ + tcg_gen_movi_tl(cpu_PSW_AV, 0); + /* write result */ + tcg_gen_mov_tl(cpu_gpr_d[r3], cpu_gpr_d[r1]); + /* sign extend to high reg */ + tcg_gen_sari_tl(cpu_gpr_d[r3+1], cpu_gpr_d[r1], 31); + tcg_temp_free(temp); + tcg_temp_free(temp2); + break; + case OPC2_32_RR_DVINIT_U: + /* overflow = (D[b] == 0) */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_PSW_V, cpu_gpr_d[r2], 0); + tcg_gen_shli_tl(cpu_PSW_V, cpu_PSW_V, 31); + /* sv */ + tcg_gen_or_tl(cpu_PSW_SV, cpu_PSW_SV, cpu_PSW_V); + /* reset av */ + tcg_gen_movi_tl(cpu_PSW_AV, 0); + /* write result */ + tcg_gen_mov_tl(cpu_gpr_d[r3], cpu_gpr_d[r1]); + /* zero extend to high reg*/ + tcg_gen_movi_tl(cpu_gpr_d[r3+1], 0); + break; + case OPC2_32_RR_PARITY: + gen_helper_parity(cpu_gpr_d[r3], cpu_gpr_d[r1]); + break; + case OPC2_32_RR_UNPACK: + gen_unpack(cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1]); + break; + } +} + static void decode_32Bit_opc(CPUTriCoreState *env, DisasContext *ctx) { int op1; @@ -4590,6 +4773,9 @@ static void decode_32Bit_opc(CPUTriCoreState *env, DisasContext *ctx) case OPCM_32_RR_IDIRECT: decode_rr_idirect(env, ctx); break; + case OPCM_32_RR_DIVIDE: + decode_rr_divide(env, ctx); + break; } } diff --git a/target-tricore/tricore-opcodes.h b/target-tricore/tricore-opcodes.h index 40ca202..0badb28 100644 --- a/target-tricore/tricore-opcodes.h +++ b/target-tricore/tricore-opcodes.h @@ -495,7 +495,7 @@ enum { OPCM_32_RR_LOGICAL_SHIFT = 0x0f, OPCM_32_RR_ACCUMULATOR = 0x0b, OPCM_32_RR_ADRESS = 0x01, - OPCM_32_RR_FLOAT = 0x4b, + OPCM_32_RR_DIVIDE = 0x4b, OPCM_32_RR_IDIRECT = 0x2d, /* RR1 Format */ OPCM_32_RR1_MUL = 0xb3,