mirror of https://gitee.com/openkylin/qemu.git
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
This commit is contained in:
parent
3b63c04e1b
commit
22e0e17337
|
@ -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"
|
||||
|
|
112
target-ppc/op.c
112
target-ppc/op.c
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue