target-ppc: convert POWER bridge instructions to TCG

Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5891 c046a42c-6fe2-441c-8c8c-71466251a162
master
aurel32 2008-12-06 12:19:14 +00:00
parent 3b63c04e1b
commit 22e0e17337
5 changed files with 219 additions and 287 deletions

View File

@ -171,5 +171,13 @@ DEF_HELPER_1(602_mfrom, tl, tl)
#endif
DEF_HELPER_3(dlmzb, tl, tl, tl, i32)
DEF_HELPER_1(clcs, tl, i32)
#if !defined(CONFIG_USER_ONLY)
DEF_HELPER_1(rac, tl, tl)
#endif
DEF_HELPER_2(div, tl, tl, tl)
DEF_HELPER_2(divo, tl, tl, tl)
DEF_HELPER_2(divs, tl, tl, tl)
DEF_HELPER_2(divso, tl, tl, tl)
#include "def-helper.h"

View File

@ -370,112 +370,6 @@ void OPPROTO op_store_601_batu (void)
}
#endif /* !defined(CONFIG_USER_ONLY) */
/* PowerPC 601 specific instructions (POWER bridge) */
/* XXX: those micro-ops need tests ! */
void OPPROTO op_POWER_abs (void)
{
if ((int32_t)T0 == INT32_MIN)
T0 = INT32_MAX;
else if ((int32_t)T0 < 0)
T0 = -T0;
RETURN();
}
void OPPROTO op_POWER_abso (void)
{
do_POWER_abso();
RETURN();
}
void OPPROTO op_POWER_clcs (void)
{
do_POWER_clcs();
RETURN();
}
void OPPROTO op_POWER_div (void)
{
do_POWER_div();
RETURN();
}
void OPPROTO op_POWER_divo (void)
{
do_POWER_divo();
RETURN();
}
void OPPROTO op_POWER_divs (void)
{
do_POWER_divs();
RETURN();
}
void OPPROTO op_POWER_divso (void)
{
do_POWER_divso();
RETURN();
}
void OPPROTO op_POWER_doz (void)
{
if ((int32_t)T1 > (int32_t)T0)
T0 = T1 - T0;
else
T0 = 0;
RETURN();
}
void OPPROTO op_POWER_dozo (void)
{
do_POWER_dozo();
RETURN();
}
void OPPROTO op_POWER_maskg (void)
{
do_POWER_maskg();
RETURN();
}
void OPPROTO op_POWER_maskir (void)
{
T0 = (T0 & ~T2) | (T1 & T2);
RETURN();
}
void OPPROTO op_POWER_mul (void)
{
uint64_t tmp;
tmp = (uint64_t)T0 * (uint64_t)T1;
env->spr[SPR_MQ] = tmp >> 32;
T0 = tmp;
RETURN();
}
void OPPROTO op_POWER_mulo (void)
{
do_POWER_mulo();
RETURN();
}
void OPPROTO op_POWER_nabs (void)
{
if (T0 > 0)
T0 = -T0;
RETURN();
}
void OPPROTO op_POWER_nabso (void)
{
/* nabs never overflows */
if (T0 > 0)
T0 = -T0;
env->xer &= ~(1 << XER_OV);
RETURN();
}
/* POWER instructions not implemented in PowerPC 601 */
#if !defined(CONFIG_USER_ONLY)
void OPPROTO op_POWER_mfsri (void)
@ -484,12 +378,6 @@ void OPPROTO op_POWER_mfsri (void)
T0 = env->sr[T1];
RETURN();
}
void OPPROTO op_POWER_rac (void)
{
do_POWER_rac();
RETURN();
}
#endif
/* PowerPC 4xx specific micro-ops */

View File

@ -1587,147 +1587,101 @@ void do_POWER_abso (void)
}
}
void do_POWER_clcs (void)
target_ulong helper_clcs (uint32_t arg)
{
switch (T0) {
switch (arg) {
case 0x0CUL:
/* Instruction cache line size */
T0 = env->icache_line_size;
return env->icache_line_size;
break;
case 0x0DUL:
/* Data cache line size */
T0 = env->dcache_line_size;
return env->dcache_line_size;
break;
case 0x0EUL:
/* Minimum cache line size */
T0 = env->icache_line_size < env->dcache_line_size ?
env->icache_line_size : env->dcache_line_size;
return (env->icache_line_size < env->dcache_line_size) ?
env->icache_line_size : env->dcache_line_size;
break;
case 0x0FUL:
/* Maximum cache line size */
T0 = env->icache_line_size > env->dcache_line_size ?
env->icache_line_size : env->dcache_line_size;
return (env->icache_line_size > env->dcache_line_size) ?
env->icache_line_size : env->dcache_line_size;
break;
default:
/* Undefined */
return 0;
break;
}
}
void do_POWER_div (void)
target_ulong helper_div (target_ulong arg1, target_ulong arg2)
{
uint64_t tmp;
uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) ||
(int32_t)T1 == 0) {
T0 = UINT32_MAX * ((uint32_t)T0 >> 31);
if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
(int32_t)arg2 == 0) {
env->spr[SPR_MQ] = 0;
return INT32_MIN;
} else {
tmp = ((uint64_t)T0 << 32) | env->spr[SPR_MQ];
env->spr[SPR_MQ] = tmp % T1;
T0 = tmp / (int32_t)T1;
env->spr[SPR_MQ] = tmp % arg2;
return tmp / (int32_t)arg2;
}
}
void do_POWER_divo (void)
target_ulong helper_divo (target_ulong arg1, target_ulong arg2)
{
int64_t tmp;
uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) ||
(int32_t)T1 == 0) {
T0 = UINT32_MAX * ((uint32_t)T0 >> 31);
env->spr[SPR_MQ] = 0;
if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
(int32_t)arg2 == 0) {
env->xer |= (1 << XER_OV) | (1 << XER_SO);
env->spr[SPR_MQ] = 0;
return INT32_MIN;
} else {
tmp = ((uint64_t)T0 << 32) | env->spr[SPR_MQ];
env->spr[SPR_MQ] = tmp % T1;
tmp /= (int32_t)T1;
if (tmp > (int64_t)INT32_MAX || tmp < (int64_t)INT32_MIN) {
env->spr[SPR_MQ] = tmp % arg2;
tmp /= (int32_t)arg2;
if ((int32_t)tmp != tmp) {
env->xer |= (1 << XER_OV) | (1 << XER_SO);
} else {
env->xer &= ~(1 << XER_OV);
}
T0 = tmp;
return tmp;
}
}
void do_POWER_divs (void)
target_ulong helper_divs (target_ulong arg1, target_ulong arg2)
{
if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) ||
(int32_t)T1 == 0) {
T0 = UINT32_MAX * ((uint32_t)T0 >> 31);
if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
(int32_t)arg2 == 0) {
env->spr[SPR_MQ] = 0;
return INT32_MIN;
} else {
env->spr[SPR_MQ] = T0 % T1;
T0 = (int32_t)T0 / (int32_t)T1;
env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
return (int32_t)arg1 / (int32_t)arg2;
}
}
void do_POWER_divso (void)
target_ulong helper_divso (target_ulong arg1, target_ulong arg2)
{
if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) ||
(int32_t)T1 == 0) {
T0 = UINT32_MAX * ((uint32_t)T0 >> 31);
if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
(int32_t)arg2 == 0) {
env->xer |= (1 << XER_OV) | (1 << XER_SO);
env->spr[SPR_MQ] = 0;
env->xer |= (1 << XER_OV) | (1 << XER_SO);
} else {
T0 = (int32_t)T0 / (int32_t)T1;
env->spr[SPR_MQ] = (int32_t)T0 % (int32_t)T1;
env->xer &= ~(1 << XER_OV);
}
}
void do_POWER_dozo (void)
{
if ((int32_t)T1 > (int32_t)T0) {
T2 = T0;
T0 = T1 - T0;
if (((uint32_t)(~T2) ^ (uint32_t)T1 ^ UINT32_MAX) &
((uint32_t)(~T2) ^ (uint32_t)T0) & (1UL << 31)) {
env->xer |= (1 << XER_OV) | (1 << XER_SO);
} else {
env->xer &= ~(1 << XER_OV);
}
} else {
T0 = 0;
env->xer &= ~(1 << XER_OV);
}
}
void do_POWER_maskg (void)
{
uint32_t ret;
if ((uint32_t)T0 == (uint32_t)(T1 + 1)) {
ret = UINT32_MAX;
} else {
ret = (UINT32_MAX >> ((uint32_t)T0)) ^
((UINT32_MAX >> ((uint32_t)T1)) >> 1);
if ((uint32_t)T0 > (uint32_t)T1)
ret = ~ret;
}
T0 = ret;
}
void do_POWER_mulo (void)
{
uint64_t tmp;
tmp = (uint64_t)T0 * (uint64_t)T1;
env->spr[SPR_MQ] = tmp >> 32;
T0 = tmp;
if (tmp >> 32 != ((uint64_t)T0 >> 16) * ((uint64_t)T1 >> 16)) {
env->xer |= (1 << XER_OV) | (1 << XER_SO);
return INT32_MIN;
} else {
env->xer &= ~(1 << XER_OV);
env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
return (int32_t)arg1 / (int32_t)arg2;
}
}
#if !defined (CONFIG_USER_ONLY)
void do_POWER_rac (void)
target_ulong helper_rac (target_ulong addr)
{
mmu_ctx_t ctx;
int nb_BATs;
target_ulong ret = 0;
/* We don't have to generate many instances of this instruction,
* as rac is supervisor only.
@ -1735,9 +1689,10 @@ void do_POWER_rac (void)
/* XXX: FIX THIS: Pretend we have no BAT */
nb_BATs = env->nb_BATs;
env->nb_BATs = 0;
if (get_physical_address(env, &ctx, T0, 0, ACCESS_INT) == 0)
T0 = ctx.raddr;
if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0)
ret = ctx.raddr;
env->nb_BATs = nb_BATs;
return ret;
}
void helper_rfsvc (void)

View File

@ -33,15 +33,6 @@ void do_store_msr (void);
#endif
/* POWER / PowerPC 601 specific helpers */
void do_POWER_abso (void);
void do_POWER_clcs (void);
void do_POWER_div (void);
void do_POWER_divo (void);
void do_POWER_divs (void);
void do_POWER_divso (void);
void do_POWER_dozo (void);
void do_POWER_maskg (void);
void do_POWER_mulo (void);
#if !defined(CONFIG_USER_ONLY)
void do_POWER_rac (void);
void do_store_hid0_601 (void);

View File

@ -4435,105 +4435,139 @@ GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 0x00000001, PPC_EXTERN)
/* abs - abs. */
GEN_HANDLER(abs, 0x1F, 0x08, 0x0B, 0x0000F800, PPC_POWER_BR)
{
tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
gen_op_POWER_abs();
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
int l1 = gen_new_label();
int l2 = gen_new_label();
tcg_gen_brcondi_tl(TCG_COND_GE, cpu_gpr[rA(ctx->opcode)], 0, l1);
tcg_gen_neg_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
tcg_gen_br(l2);
gen_set_label(l1);
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
gen_set_label(l2);
if (unlikely(Rc(ctx->opcode) != 0))
gen_set_Rc0(ctx, cpu_T[0]);
gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
}
/* abso - abso. */
GEN_HANDLER(abso, 0x1F, 0x08, 0x1B, 0x0000F800, PPC_POWER_BR)
{
tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
gen_op_POWER_abso();
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
int l1 = gen_new_label();
int l2 = gen_new_label();
int l3 = gen_new_label();
/* Start with XER OV disabled, the most likely case */
tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
tcg_gen_brcondi_tl(TCG_COND_GE, cpu_gpr[rA(ctx->opcode)], 0, l2);
tcg_gen_brcondi_tl(TCG_COND_NE, cpu_gpr[rA(ctx->opcode)], 0x80000000, l1);
tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO));
tcg_gen_br(l2);
gen_set_label(l1);
tcg_gen_neg_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
tcg_gen_br(l3);
gen_set_label(l2);
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
gen_set_label(l3);
if (unlikely(Rc(ctx->opcode) != 0))
gen_set_Rc0(ctx, cpu_T[0]);
gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
}
/* clcs */
GEN_HANDLER(clcs, 0x1F, 0x10, 0x13, 0x0000F800, PPC_POWER_BR)
{
tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
gen_op_POWER_clcs();
TCGv_i32 t0 = tcg_const_i32(rA(ctx->opcode));
gen_helper_clcs(cpu_gpr[rD(ctx->opcode)], t0);
tcg_temp_free_i32(t0);
/* Rc=1 sets CR0 to an undefined state */
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
}
/* div - div. */
GEN_HANDLER(div, 0x1F, 0x0B, 0x0A, 0x00000000, PPC_POWER_BR)
{
tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
gen_op_POWER_div();
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
gen_helper_div(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
if (unlikely(Rc(ctx->opcode) != 0))
gen_set_Rc0(ctx, cpu_T[0]);
gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
}
/* divo - divo. */
GEN_HANDLER(divo, 0x1F, 0x0B, 0x1A, 0x00000000, PPC_POWER_BR)
{
tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
gen_op_POWER_divo();
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
gen_helper_divo(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
if (unlikely(Rc(ctx->opcode) != 0))
gen_set_Rc0(ctx, cpu_T[0]);
gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
}
/* divs - divs. */
GEN_HANDLER(divs, 0x1F, 0x0B, 0x0B, 0x00000000, PPC_POWER_BR)
{
tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
gen_op_POWER_divs();
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
gen_helper_divs(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
if (unlikely(Rc(ctx->opcode) != 0))
gen_set_Rc0(ctx, cpu_T[0]);
gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
}
/* divso - divso. */
GEN_HANDLER(divso, 0x1F, 0x0B, 0x1B, 0x00000000, PPC_POWER_BR)
{
tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
gen_op_POWER_divso();
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
gen_helper_divso(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
if (unlikely(Rc(ctx->opcode) != 0))
gen_set_Rc0(ctx, cpu_T[0]);
gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
}
/* doz - doz. */
GEN_HANDLER(doz, 0x1F, 0x08, 0x08, 0x00000000, PPC_POWER_BR)
{
tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
gen_op_POWER_doz();
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
int l1 = gen_new_label();
int l2 = gen_new_label();
tcg_gen_brcond_tl(TCG_COND_GE, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], l1);
tcg_gen_sub_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
tcg_gen_br(l2);
gen_set_label(l1);
tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], 0);
gen_set_label(l2);
if (unlikely(Rc(ctx->opcode) != 0))
gen_set_Rc0(ctx, cpu_T[0]);
gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
}
/* dozo - dozo. */
GEN_HANDLER(dozo, 0x1F, 0x08, 0x18, 0x00000000, PPC_POWER_BR)
{
tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
gen_op_POWER_dozo();
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
int l1 = gen_new_label();
int l2 = gen_new_label();
TCGv t0 = tcg_temp_new();
TCGv t1 = tcg_temp_new();
TCGv t2 = tcg_temp_new();
/* Start with XER OV disabled, the most likely case */
tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
tcg_gen_brcond_tl(TCG_COND_GE, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], l1);
tcg_gen_sub_tl(t0, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
tcg_gen_xor_tl(t1, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
tcg_gen_xor_tl(t2, cpu_gpr[rA(ctx->opcode)], t0);
tcg_gen_andc_tl(t1, t1, t2);
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0);
tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l2);
tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO));
tcg_gen_br(l2);
gen_set_label(l1);
tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], 0);
gen_set_label(l2);
tcg_temp_free(t0);
tcg_temp_free(t1);
tcg_temp_free(t2);
if (unlikely(Rc(ctx->opcode) != 0))
gen_set_Rc0(ctx, cpu_T[0]);
gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
}
/* dozi */
GEN_HANDLER(dozi, 0x09, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR)
{
tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
tcg_gen_movi_tl(cpu_T[1], SIMM(ctx->opcode));
gen_op_POWER_doz();
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
target_long simm = SIMM(ctx->opcode);
int l1 = gen_new_label();
int l2 = gen_new_label();
tcg_gen_brcondi_tl(TCG_COND_LT, cpu_gpr[rA(ctx->opcode)], simm, l1);
tcg_gen_subfi_tl(cpu_gpr[rD(ctx->opcode)], simm, cpu_gpr[rA(ctx->opcode)]);
tcg_gen_br(l2);
gen_set_label(l1);
tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], 0);
gen_set_label(l2);
if (unlikely(Rc(ctx->opcode) != 0))
gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
}
/* lscbx - lscbx. */
@ -4561,66 +4595,120 @@ GEN_HANDLER(lscbx, 0x1F, 0x15, 0x08, 0x00000000, PPC_POWER_BR)
/* maskg - maskg. */
GEN_HANDLER(maskg, 0x1F, 0x1D, 0x00, 0x00000000, PPC_POWER_BR)
{
tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
gen_op_POWER_maskg();
tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
int l1 = gen_new_label();
TCGv t0 = tcg_temp_new();
TCGv t1 = tcg_temp_new();
TCGv t2 = tcg_temp_new();
TCGv t3 = tcg_temp_new();
tcg_gen_movi_tl(t3, 0xFFFFFFFF);
tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1F);
tcg_gen_andi_tl(t1, cpu_gpr[rS(ctx->opcode)], 0x1F);
tcg_gen_addi_tl(t2, t0, 1);
tcg_gen_shr_tl(t2, t3, t2);
tcg_gen_shr_tl(t3, t3, t1);
tcg_gen_xor_tl(cpu_gpr[rA(ctx->opcode)], t2, t3);
tcg_gen_brcond_tl(TCG_COND_GE, t0, t1, l1);
tcg_gen_neg_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
gen_set_label(l1);
tcg_temp_free(t0);
tcg_temp_free(t1);
tcg_temp_free(t2);
tcg_temp_free(t3);
if (unlikely(Rc(ctx->opcode) != 0))
gen_set_Rc0(ctx, cpu_T[0]);
gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
}
/* maskir - maskir. */
GEN_HANDLER(maskir, 0x1F, 0x1D, 0x10, 0x00000000, PPC_POWER_BR)
{
tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]);
tcg_gen_mov_tl(cpu_T[2], cpu_gpr[rB(ctx->opcode)]);
gen_op_POWER_maskir();
tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
TCGv t0 = tcg_temp_new();
TCGv t1 = tcg_temp_new();
tcg_gen_and_tl(t0, cpu_gpr[rS(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
tcg_gen_andc_tl(t1, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
tcg_temp_free(t0);
tcg_temp_free(t1);
if (unlikely(Rc(ctx->opcode) != 0))
gen_set_Rc0(ctx, cpu_T[0]);
gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
}
/* mul - mul. */
GEN_HANDLER(mul, 0x1F, 0x0B, 0x03, 0x00000000, PPC_POWER_BR)
{
tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
gen_op_POWER_mul();
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_temp_new_i64();
TCGv t2 = tcg_temp_new();
tcg_gen_extu_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]);
tcg_gen_extu_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]);
tcg_gen_mul_i64(t0, t0, t1);
tcg_gen_trunc_i64_tl(t2, t0);
gen_store_spr(SPR_MQ, t2);
tcg_gen_shri_i64(t1, t0, 32);
tcg_gen_trunc_i64_tl(cpu_gpr[rD(ctx->opcode)], t1);
tcg_temp_free_i64(t0);
tcg_temp_free_i64(t1);
tcg_temp_free(t2);
if (unlikely(Rc(ctx->opcode) != 0))
gen_set_Rc0(ctx, cpu_T[0]);
gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
}
/* mulo - mulo. */
GEN_HANDLER(mulo, 0x1F, 0x0B, 0x13, 0x00000000, PPC_POWER_BR)
{
tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
gen_op_POWER_mulo();
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
int l1 = gen_new_label();
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_temp_new_i64();
TCGv t2 = tcg_temp_new();
/* Start with XER OV disabled, the most likely case */
tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
tcg_gen_extu_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]);
tcg_gen_extu_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]);
tcg_gen_mul_i64(t0, t0, t1);
tcg_gen_trunc_i64_tl(t2, t0);
gen_store_spr(SPR_MQ, t2);
tcg_gen_shri_i64(t1, t0, 32);
tcg_gen_trunc_i64_tl(cpu_gpr[rD(ctx->opcode)], t1);
tcg_gen_ext32s_i64(t1, t0);
tcg_gen_brcond_i64(TCG_COND_EQ, t0, t1, l1);
tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO));
gen_set_label(l1);
tcg_temp_free_i64(t0);
tcg_temp_free_i64(t1);
tcg_temp_free(t2);
if (unlikely(Rc(ctx->opcode) != 0))
gen_set_Rc0(ctx, cpu_T[0]);
gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
}
/* nabs - nabs. */
GEN_HANDLER(nabs, 0x1F, 0x08, 0x0F, 0x00000000, PPC_POWER_BR)
{
tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
gen_op_POWER_nabs();
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
int l1 = gen_new_label();
int l2 = gen_new_label();
tcg_gen_brcondi_tl(TCG_COND_GT, cpu_gpr[rA(ctx->opcode)], 0, l1);
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
tcg_gen_br(l2);
gen_set_label(l1);
tcg_gen_neg_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
gen_set_label(l2);
if (unlikely(Rc(ctx->opcode) != 0))
gen_set_Rc0(ctx, cpu_T[0]);
gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
}
/* nabso - nabso. */
GEN_HANDLER(nabso, 0x1F, 0x08, 0x1F, 0x00000000, PPC_POWER_BR)
{
tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
gen_op_POWER_nabso();
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
int l1 = gen_new_label();
int l2 = gen_new_label();
tcg_gen_brcondi_tl(TCG_COND_GT, cpu_gpr[rA(ctx->opcode)], 0, l1);
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
tcg_gen_br(l2);
gen_set_label(l1);
tcg_gen_neg_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
gen_set_label(l2);
/* nabs never overflows */
tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
if (unlikely(Rc(ctx->opcode) != 0))
gen_set_Rc0(ctx, cpu_T[0]);
gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
}
/* rlmi - rlmi. */
@ -5122,13 +5210,15 @@ GEN_HANDLER(rac, 0x1F, 0x12, 0x19, 0x00000001, PPC_POWER)
#if defined(CONFIG_USER_ONLY)
GEN_EXCP_PRIVOPC(ctx);
#else
TCGv t0;
if (unlikely(!ctx->supervisor)) {
GEN_EXCP_PRIVOPC(ctx);
return;
}
gen_addr_reg_index(cpu_T[0], ctx);
gen_op_POWER_rac();
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
t0 = tcg_temp_new();
gen_addr_reg_index(t0, ctx);
gen_helper_rac(cpu_gpr[rD(ctx->opcode)], t0);
tcg_temp_free(t0);
#endif
}