mirror of https://gitee.com/openkylin/qemu.git
correct split between helper.c and op_helper.c - moved some uops to op_helper.c (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1504 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
2157fa0682
commit
fdabc366bd
|
@ -32,6 +32,15 @@
|
|||
|
||||
#define TARGET_HAS_ICE 1
|
||||
|
||||
/* XXX: this should be tunable: PowerPC 601 & 64 bits PowerPC
|
||||
* have different cache line sizes
|
||||
*/
|
||||
#define ICACHE_LINE_SIZE 32
|
||||
#define DCACHE_LINE_SIZE 32
|
||||
|
||||
/* XXX: put this in a common place */
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
|
||||
/*****************************************************************************/
|
||||
/* PVR definitions for most known PowerPC */
|
||||
enum {
|
||||
|
|
|
@ -20,8 +20,12 @@
|
|||
#if !defined (__PPC_H__)
|
||||
#define __PPC_H__
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "dyngen-exec.h"
|
||||
|
||||
#define TARGET_LONG_BITS 32
|
||||
|
||||
register struct CPUPPCState *env asm(AREG0);
|
||||
register uint32_t T0 asm(AREG1);
|
||||
register uint32_t T1 asm(AREG2);
|
||||
|
|
|
@ -17,11 +17,21 @@
|
|||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "exec.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <signal.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
|
||||
//#define DEBUG_MMU
|
||||
//#define DEBUG_BATS
|
||||
//#define DEBUG_EXCEPTIONS
|
||||
//#define FLUSH_ALL_TLBS
|
||||
|
||||
/*****************************************************************************/
|
||||
/* PowerPC MMU emulation */
|
||||
|
@ -394,92 +404,6 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
||||
#define MMUSUFFIX _mmu
|
||||
#define GETPC() (__builtin_return_address(0))
|
||||
|
||||
#define SHIFT 0
|
||||
#include "softmmu_template.h"
|
||||
|
||||
#define SHIFT 1
|
||||
#include "softmmu_template.h"
|
||||
|
||||
#define SHIFT 2
|
||||
#include "softmmu_template.h"
|
||||
|
||||
#define SHIFT 3
|
||||
#include "softmmu_template.h"
|
||||
|
||||
/* try to fill the TLB and return an exception if error. If retaddr is
|
||||
NULL, it means that the function was called in C code (i.e. not
|
||||
from generated code or from helper.c) */
|
||||
/* XXX: fix it to restore all registers */
|
||||
void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr)
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
CPUState *saved_env;
|
||||
unsigned long pc;
|
||||
int ret;
|
||||
|
||||
/* XXX: hack to restore env in all cases, even if not called from
|
||||
generated code */
|
||||
saved_env = env;
|
||||
env = cpu_single_env;
|
||||
#if 0
|
||||
{
|
||||
unsigned long tlb_addrr, tlb_addrw;
|
||||
int index;
|
||||
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
tlb_addrr = env->tlb_read[is_user][index].address;
|
||||
tlb_addrw = env->tlb_write[is_user][index].address;
|
||||
if (loglevel) {
|
||||
fprintf(logfile,
|
||||
"%s 1 %p %p idx=%d addr=0x%08lx tbl_addr=0x%08lx 0x%08lx "
|
||||
"(0x%08lx 0x%08lx)\n", __func__, env,
|
||||
&env->tlb_read[is_user][index], index, addr,
|
||||
tlb_addrr, tlb_addrw, addr & TARGET_PAGE_MASK,
|
||||
tlb_addrr & (TARGET_PAGE_MASK | TLB_INVALID_MASK));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, is_user, 1);
|
||||
if (ret) {
|
||||
if (retaddr) {
|
||||
/* now we have a real cpu fault */
|
||||
pc = (unsigned long)retaddr;
|
||||
tb = tb_find_pc(pc);
|
||||
if (tb) {
|
||||
/* the PC is inside the translated code. It means that we have
|
||||
a virtual CPU fault */
|
||||
cpu_restore_state(tb, env, pc, NULL);
|
||||
}
|
||||
}
|
||||
do_raise_exception_err(env->exception_index, env->error_code);
|
||||
}
|
||||
#if 0
|
||||
{
|
||||
unsigned long tlb_addrr, tlb_addrw;
|
||||
int index;
|
||||
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
tlb_addrr = env->tlb_read[is_user][index].address;
|
||||
tlb_addrw = env->tlb_write[is_user][index].address;
|
||||
printf("%s 2 %p %p idx=%d addr=0x%08lx tbl_addr=0x%08lx 0x%08lx "
|
||||
"(0x%08lx 0x%08lx)\n", __func__, env,
|
||||
&env->tlb_read[is_user][index], index, addr,
|
||||
tlb_addrr, tlb_addrw, addr & TARGET_PAGE_MASK,
|
||||
tlb_addrr & (TARGET_PAGE_MASK | TLB_INVALID_MASK));
|
||||
}
|
||||
#endif
|
||||
env = saved_env;
|
||||
}
|
||||
|
||||
void cpu_ppc_init_mmu(CPUState *env)
|
||||
{
|
||||
/* Nothing to do: all translation are disabled */
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Perform address translation */
|
||||
int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
|
||||
int is_user, int is_softmmu)
|
||||
|
@ -576,13 +500,14 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
|
|||
error_code = EXCP_INVAL | EXCP_INVAL_INVAL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case -5:
|
||||
/* No match in segment table */
|
||||
exception = EXCP_DSEG;
|
||||
error_code = 0;
|
||||
break;
|
||||
}
|
||||
if (rw)
|
||||
if (exception == EXCP_DSI && rw == 1)
|
||||
error_code |= 0x02000000;
|
||||
/* Store fault address */
|
||||
env->spr[SPR_DAR] = address;
|
||||
|
@ -1491,12 +1416,14 @@ void do_interrupt (CPUState *env)
|
|||
/* Jump to handler */
|
||||
env->nip = excp;
|
||||
env->exception_index = EXCP_NONE;
|
||||
#if 0
|
||||
/* ensure that no TB jump will be modified as
|
||||
the program flow was changed */
|
||||
#ifdef __sparc__
|
||||
tmp_T0 = 0;
|
||||
#else
|
||||
T0 = 0;
|
||||
#endif
|
||||
#endif
|
||||
env->interrupt_request |= CPU_INTERRUPT_EXITTB;
|
||||
}
|
||||
|
|
267
target-ppc/op.c
267
target-ppc/op.c
|
@ -548,16 +548,10 @@ PPC_OP(add)
|
|||
RETURN();
|
||||
}
|
||||
|
||||
PPC_OP(addo)
|
||||
void do_addo (void);
|
||||
void op_addo (void)
|
||||
{
|
||||
T2 = T0;
|
||||
T0 += T1;
|
||||
if ((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)) {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
} else {
|
||||
xer_ov = 0;
|
||||
}
|
||||
do_addo();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
|
@ -574,53 +568,24 @@ PPC_OP(addc)
|
|||
RETURN();
|
||||
}
|
||||
|
||||
PPC_OP(addco)
|
||||
void do_addco (void);
|
||||
void op_addco (void)
|
||||
{
|
||||
T2 = T0;
|
||||
T0 += T1;
|
||||
if (T0 < T2) {
|
||||
xer_ca = 1;
|
||||
} else {
|
||||
xer_ca = 0;
|
||||
}
|
||||
if ((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)) {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
} else {
|
||||
xer_ov = 0;
|
||||
}
|
||||
do_addco();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* add extended */
|
||||
/* candidate for helper (too long) */
|
||||
PPC_OP(adde)
|
||||
void do_adde (void);
|
||||
void op_adde (void)
|
||||
{
|
||||
T2 = T0;
|
||||
T0 += T1 + xer_ca;
|
||||
if (T0 < T2 || (xer_ca == 1 && T0 == T2)) {
|
||||
xer_ca = 1;
|
||||
} else {
|
||||
xer_ca = 0;
|
||||
}
|
||||
RETURN();
|
||||
do_adde();
|
||||
}
|
||||
|
||||
void do_addeo (void);
|
||||
PPC_OP(addeo)
|
||||
{
|
||||
T2 = T0;
|
||||
T0 += T1 + xer_ca;
|
||||
if (T0 < T2 || (xer_ca == 1 && T0 == T2)) {
|
||||
xer_ca = 1;
|
||||
} else {
|
||||
xer_ca = 0;
|
||||
}
|
||||
if ((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)) {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
} else {
|
||||
xer_ov = 0;
|
||||
}
|
||||
do_addeo();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
|
@ -654,18 +619,10 @@ PPC_OP(addme)
|
|||
RETURN();
|
||||
}
|
||||
|
||||
PPC_OP(addmeo)
|
||||
void do_addmeo (void);
|
||||
void op_addmeo (void)
|
||||
{
|
||||
T1 = T0;
|
||||
T0 += xer_ca + (-1);
|
||||
if (T1 & (T1 ^ T0) & (1 << 31)) {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
} else {
|
||||
xer_ov = 0;
|
||||
}
|
||||
if (T1 != 0)
|
||||
xer_ca = 1;
|
||||
do_addmeo();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
|
@ -682,26 +639,14 @@ PPC_OP(addze)
|
|||
RETURN();
|
||||
}
|
||||
|
||||
PPC_OP(addzeo)
|
||||
void do_addzeo (void);
|
||||
void op_addzeo (void)
|
||||
{
|
||||
T1 = T0;
|
||||
T0 += xer_ca;
|
||||
if ((T1 ^ (-1)) & (T1 ^ T0) & (1 << 31)) {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
} else {
|
||||
xer_ov = 0;
|
||||
}
|
||||
if (T0 < T1) {
|
||||
xer_ca = 1;
|
||||
} else {
|
||||
xer_ca = 0;
|
||||
}
|
||||
do_addzeo();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* divide word */
|
||||
/* candidate for helper (too long) */
|
||||
PPC_OP(divw)
|
||||
{
|
||||
if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) {
|
||||
|
@ -712,16 +657,10 @@ PPC_OP(divw)
|
|||
RETURN();
|
||||
}
|
||||
|
||||
PPC_OP(divwo)
|
||||
void do_divwo (void);
|
||||
void op_divwo (void)
|
||||
{
|
||||
if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
T0 = (-1) * (T0 >> 31);
|
||||
} else {
|
||||
xer_ov = 0;
|
||||
T0 = (Ts0 / Ts1);
|
||||
}
|
||||
do_divwo();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
|
@ -736,16 +675,10 @@ PPC_OP(divwu)
|
|||
RETURN();
|
||||
}
|
||||
|
||||
PPC_OP(divwuo)
|
||||
void do_divwuo (void);
|
||||
void op_divwuo (void)
|
||||
{
|
||||
if (T1 == 0) {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
T0 = 0;
|
||||
} else {
|
||||
xer_ov = 0;
|
||||
T0 /= T1;
|
||||
}
|
||||
do_divwuo();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
|
@ -777,17 +710,10 @@ PPC_OP(mullw)
|
|||
RETURN();
|
||||
}
|
||||
|
||||
PPC_OP(mullwo)
|
||||
void do_mullwo (void);
|
||||
void op_mullwo (void)
|
||||
{
|
||||
int64_t res = (int64_t)Ts0 * (int64_t)Ts1;
|
||||
|
||||
if ((int32_t)res != res) {
|
||||
xer_ov = 1;
|
||||
xer_so = 1;
|
||||
} else {
|
||||
xer_ov = 0;
|
||||
}
|
||||
T0 = (int32_t)res;
|
||||
do_mullwo();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
|
@ -800,15 +726,10 @@ PPC_OP(neg)
|
|||
RETURN();
|
||||
}
|
||||
|
||||
PPC_OP(nego)
|
||||
void do_nego (void);
|
||||
void op_nego (void)
|
||||
{
|
||||
if (T0 == 0x80000000) {
|
||||
xer_ov = 1;
|
||||
xer_so = 1;
|
||||
} else {
|
||||
xer_ov = 0;
|
||||
T0 = -Ts0;
|
||||
}
|
||||
do_nego();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
|
@ -819,16 +740,10 @@ PPC_OP(subf)
|
|||
RETURN();
|
||||
}
|
||||
|
||||
PPC_OP(subfo)
|
||||
void do_subfo (void);
|
||||
void op_subfo (void)
|
||||
{
|
||||
T2 = T0;
|
||||
T0 = T1 - T0;
|
||||
if (((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)) {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
} else {
|
||||
xer_ov = 0;
|
||||
}
|
||||
do_subfo();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
|
@ -844,52 +759,25 @@ PPC_OP(subfc)
|
|||
RETURN();
|
||||
}
|
||||
|
||||
PPC_OP(subfco)
|
||||
void do_subfco (void);
|
||||
void op_subfco (void)
|
||||
{
|
||||
T2 = T0;
|
||||
T0 = T1 - T0;
|
||||
if (T0 <= T1) {
|
||||
xer_ca = 1;
|
||||
} else {
|
||||
xer_ca = 0;
|
||||
}
|
||||
if (((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)) {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
} else {
|
||||
xer_ov = 0;
|
||||
}
|
||||
do_subfco();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* substract from extended */
|
||||
/* candidate for helper (too long) */
|
||||
PPC_OP(subfe)
|
||||
void do_subfe (void);
|
||||
void op_subfe (void)
|
||||
{
|
||||
T0 = T1 + ~T0 + xer_ca;
|
||||
if (T0 < T1 || (xer_ca == 1 && T0 == T1)) {
|
||||
xer_ca = 1;
|
||||
} else {
|
||||
xer_ca = 0;
|
||||
}
|
||||
do_subfe();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void do_subfeo (void);
|
||||
PPC_OP(subfeo)
|
||||
{
|
||||
T2 = T0;
|
||||
T0 = T1 + ~T0 + xer_ca;
|
||||
if ((~T2 ^ T1 ^ (-1)) & (~T2 ^ T0) & (1 << 31)) {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
} else {
|
||||
xer_ov = 0;
|
||||
}
|
||||
if (T0 < T1 || (xer_ca == 1 && T0 == T1)) {
|
||||
xer_ca = 1;
|
||||
} else {
|
||||
xer_ca = 0;
|
||||
}
|
||||
do_subfeo();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
|
@ -915,18 +803,10 @@ PPC_OP(subfme)
|
|||
RETURN();
|
||||
}
|
||||
|
||||
PPC_OP(subfmeo)
|
||||
void do_subfmeo (void);
|
||||
void op_subfmeo (void)
|
||||
{
|
||||
T1 = T0;
|
||||
T0 = ~T0 + xer_ca - 1;
|
||||
if (~T1 & (~T1 ^ T0) & (1 << 31)) {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
} else {
|
||||
xer_ov = 0;
|
||||
}
|
||||
if (T1 != -1)
|
||||
xer_ca = 1;
|
||||
do_subfmeo();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
|
@ -943,21 +823,10 @@ PPC_OP(subfze)
|
|||
RETURN();
|
||||
}
|
||||
|
||||
PPC_OP(subfzeo)
|
||||
void do_subfzeo (void);
|
||||
void op_subfzeo (void)
|
||||
{
|
||||
T1 = T0;
|
||||
T0 = ~T0 + xer_ca;
|
||||
if ((~T1 ^ (-1)) & ((~T1) ^ T0) & (1 << 31)) {
|
||||
xer_ov = 1;
|
||||
xer_so = 1;
|
||||
} else {
|
||||
xer_ov = 0;
|
||||
}
|
||||
if (T0 < ~T1) {
|
||||
xer_ca = 1;
|
||||
} else {
|
||||
xer_ca = 0;
|
||||
}
|
||||
do_subfzeo();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
|
@ -1174,7 +1043,7 @@ PPC_OP(slw)
|
|||
}
|
||||
|
||||
/* shift right algebraic word */
|
||||
PPC_OP(sraw)
|
||||
void op_sraw (void)
|
||||
{
|
||||
do_sraw();
|
||||
RETURN();
|
||||
|
@ -1227,10 +1096,9 @@ PPC_OP(fmul)
|
|||
}
|
||||
|
||||
/* fdiv - fdiv. */
|
||||
void do_fdiv (void);
|
||||
PPC_OP(fdiv)
|
||||
{
|
||||
do_fdiv();
|
||||
FT0 = float64_div(FT0, FT1, &env->fp_status);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
|
@ -1331,25 +1199,24 @@ PPC_OP(fcmpo)
|
|||
|
||||
/*** Floating-point move ***/
|
||||
/* fabs */
|
||||
void do_fabs (void);
|
||||
PPC_OP(fabs)
|
||||
{
|
||||
do_fabs();
|
||||
FT0 = float64_abs(FT0);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* fnabs */
|
||||
void do_fnabs (void);
|
||||
PPC_OP(fnabs)
|
||||
{
|
||||
do_fnabs();
|
||||
FT0 = float64_abs(FT0);
|
||||
FT0 = float64_chs(FT0);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* fneg */
|
||||
PPC_OP(fneg)
|
||||
{
|
||||
FT0 = -FT0;
|
||||
FT0 = float64_chs(FT0);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
|
@ -1367,40 +1234,30 @@ PPC_OP(fneg)
|
|||
/* Special op to check and maybe clear reservation */
|
||||
PPC_OP(check_reservation)
|
||||
{
|
||||
do_check_reservation();
|
||||
if ((uint32_t)env->reserve == (uint32_t)(T0 & ~0x00000003))
|
||||
env->reserve = -1;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* Return from interrupt */
|
||||
PPC_OP(rfi)
|
||||
void do_rfi (void);
|
||||
void op_rfi (void)
|
||||
{
|
||||
env->nip = env->spr[SPR_SRR0] & ~0x00000003;
|
||||
T0 = env->spr[SPR_SRR1] & ~0xFFFF0000UL;
|
||||
do_store_msr(env, T0);
|
||||
env->interrupt_request |= CPU_INTERRUPT_EXITTB;
|
||||
do_rfi();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* Trap word */
|
||||
PPC_OP(tw)
|
||||
void do_tw (uint32_t cmp, int flags);
|
||||
void op_tw (void)
|
||||
{
|
||||
if ((Ts0 < Ts1 && (PARAM(1) & 0x10)) ||
|
||||
(Ts0 > Ts1 && (PARAM(1) & 0x08)) ||
|
||||
(Ts0 == Ts1 && (PARAM(1) & 0x04)) ||
|
||||
(T0 < T1 && (PARAM(1) & 0x02)) ||
|
||||
(T0 > T1 && (PARAM(1) & 0x01)))
|
||||
do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP);
|
||||
do_tw(T1, PARAM(1));
|
||||
RETURN();
|
||||
}
|
||||
|
||||
PPC_OP(twi)
|
||||
void op_twi (void)
|
||||
{
|
||||
if ((Ts0 < SPARAM(1) && (PARAM(2) & 0x10)) ||
|
||||
(Ts0 > SPARAM(1) && (PARAM(2) & 0x08)) ||
|
||||
(Ts0 == SPARAM(1) && (PARAM(2) & 0x04)) ||
|
||||
(T0 < (uint32_t)SPARAM(1) && (PARAM(2) & 0x02)) ||
|
||||
(T0 > (uint32_t)SPARAM(1) && (PARAM(2) & 0x01)))
|
||||
do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP);
|
||||
do_tw(PARAM(1), PARAM(2));
|
||||
RETURN();
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,14 @@
|
|||
#include "op_helper_mem.h"
|
||||
#endif
|
||||
|
||||
//#define DEBUG_OP
|
||||
//#define DEBUG_EXCEPTIONS
|
||||
//#define FLUSH_ALL_TLBS
|
||||
|
||||
#define Ts0 (long)((target_long)T0)
|
||||
#define Ts1 (long)((target_long)T1)
|
||||
#define Ts2 (long)((target_long)T2)
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Exceptions processing helpers */
|
||||
void cpu_loop_exit(void)
|
||||
|
@ -60,29 +68,260 @@ void do_raise_exception (uint32_t exception)
|
|||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Helpers for "fat" micro operations */
|
||||
/* Fixed point operations helpers */
|
||||
void do_addo (void)
|
||||
{
|
||||
T2 = T0;
|
||||
T0 += T1;
|
||||
if (likely(!((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)))) {
|
||||
xer_ov = 0;
|
||||
} else {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void do_addco (void)
|
||||
{
|
||||
T2 = T0;
|
||||
T0 += T1;
|
||||
if (likely(T0 >= T2)) {
|
||||
xer_ca = 0;
|
||||
} else {
|
||||
xer_ca = 1;
|
||||
}
|
||||
if (likely(!((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)))) {
|
||||
xer_ov = 0;
|
||||
} else {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void do_adde (void)
|
||||
{
|
||||
T2 = T0;
|
||||
T0 += T1 + xer_ca;
|
||||
if (likely(!(T0 < T2 || (xer_ca == 1 && T0 == T2)))) {
|
||||
xer_ca = 0;
|
||||
} else {
|
||||
xer_ca = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void do_addeo (void)
|
||||
{
|
||||
T2 = T0;
|
||||
T0 += T1 + xer_ca;
|
||||
if (likely(!(T0 < T2 || (xer_ca == 1 && T0 == T2)))) {
|
||||
xer_ca = 0;
|
||||
} else {
|
||||
xer_ca = 1;
|
||||
}
|
||||
if (likely(!((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)))) {
|
||||
xer_ov = 0;
|
||||
} else {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void do_addmeo (void)
|
||||
{
|
||||
T1 = T0;
|
||||
T0 += xer_ca + (-1);
|
||||
if (likely(!(T1 & (T1 ^ T0) & (1 << 31)))) {
|
||||
xer_ov = 0;
|
||||
} else {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
}
|
||||
if (likely(T1 != 0))
|
||||
xer_ca = 1;
|
||||
}
|
||||
|
||||
void do_addzeo (void)
|
||||
{
|
||||
T1 = T0;
|
||||
T0 += xer_ca;
|
||||
if (likely(!((T1 ^ (-1)) & (T1 ^ T0) & (1 << 31)))) {
|
||||
xer_ov = 0;
|
||||
} else {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
}
|
||||
if (likely(T0 >= T1)) {
|
||||
xer_ca = 0;
|
||||
} else {
|
||||
xer_ca = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void do_divwo (void)
|
||||
{
|
||||
if (likely(!((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0))) {
|
||||
xer_ov = 0;
|
||||
T0 = (Ts0 / Ts1);
|
||||
} else {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
T0 = (-1) * ((uint32_t)T0 >> 31);
|
||||
}
|
||||
}
|
||||
|
||||
void do_divwuo (void)
|
||||
{
|
||||
if (likely((uint32_t)T1 != 0)) {
|
||||
xer_ov = 0;
|
||||
T0 = (uint32_t)T0 / (uint32_t)T1;
|
||||
} else {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
T0 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void do_mullwo (void)
|
||||
{
|
||||
int64_t res = (int64_t)Ts0 * (int64_t)Ts1;
|
||||
|
||||
if (likely((int32_t)res == res)) {
|
||||
xer_ov = 0;
|
||||
} else {
|
||||
xer_ov = 1;
|
||||
xer_so = 1;
|
||||
}
|
||||
T0 = (int32_t)res;
|
||||
}
|
||||
|
||||
void do_nego (void)
|
||||
{
|
||||
if (likely(T0 != INT32_MIN)) {
|
||||
xer_ov = 0;
|
||||
T0 = -Ts0;
|
||||
} else {
|
||||
xer_ov = 1;
|
||||
xer_so = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void do_subfo (void)
|
||||
{
|
||||
T2 = T0;
|
||||
T0 = T1 - T0;
|
||||
if (likely(!(((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)))) {
|
||||
xer_ov = 0;
|
||||
} else {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
}
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void do_subfco (void)
|
||||
{
|
||||
T2 = T0;
|
||||
T0 = T1 - T0;
|
||||
if (likely(T0 > T1)) {
|
||||
xer_ca = 0;
|
||||
} else {
|
||||
xer_ca = 1;
|
||||
}
|
||||
if (likely(!(((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)))) {
|
||||
xer_ov = 0;
|
||||
} else {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void do_subfe (void)
|
||||
{
|
||||
T0 = T1 + ~T0 + xer_ca;
|
||||
if (likely(T0 >= T1 && (xer_ca == 0 || T0 != T1))) {
|
||||
xer_ca = 0;
|
||||
} else {
|
||||
xer_ca = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void do_subfeo (void)
|
||||
{
|
||||
T2 = T0;
|
||||
T0 = T1 + ~T0 + xer_ca;
|
||||
if (likely(!((~T2 ^ T1 ^ (-1)) & (~T2 ^ T0) & (1 << 31)))) {
|
||||
xer_ov = 0;
|
||||
} else {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
}
|
||||
if (likely(T0 >= T1 && (xer_ca == 0 || T0 != T1))) {
|
||||
xer_ca = 0;
|
||||
} else {
|
||||
xer_ca = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void do_subfmeo (void)
|
||||
{
|
||||
T1 = T0;
|
||||
T0 = ~T0 + xer_ca - 1;
|
||||
if (likely(!(~T1 & (~T1 ^ T0) & (1 << 31)))) {
|
||||
xer_ov = 0;
|
||||
} else {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
}
|
||||
if (likely(T1 != -1))
|
||||
xer_ca = 1;
|
||||
}
|
||||
|
||||
void do_subfzeo (void)
|
||||
{
|
||||
T1 = T0;
|
||||
T0 = ~T0 + xer_ca;
|
||||
if (likely(!((~T1 ^ (-1)) & ((~T1) ^ T0) & (1 << 31)))) {
|
||||
xer_ov = 0;
|
||||
} else {
|
||||
xer_ov = 1;
|
||||
xer_so = 1;
|
||||
}
|
||||
if (likely(T0 >= ~T1)) {
|
||||
xer_ca = 0;
|
||||
} else {
|
||||
xer_ca = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* shift right arithmetic helper */
|
||||
void do_sraw (void)
|
||||
{
|
||||
int32_t ret;
|
||||
|
||||
if (likely(!(T1 & 0x20UL))) {
|
||||
if (likely(T1 != 0)) {
|
||||
ret = (int32_t)T0 >> (T1 & 0x1fUL);
|
||||
if (likely(ret >= 0 || ((int32_t)T0 & ((1 << T1) - 1)) == 0)) {
|
||||
xer_ca = 0;
|
||||
if (T1 & 0x20) {
|
||||
ret = (-1) * (T0 >> 31);
|
||||
if (ret < 0 && (T0 & ~0x80000000) != 0)
|
||||
} else {
|
||||
xer_ca = 1;
|
||||
#if 1 // TRY
|
||||
} else if (T1 == 0) {
|
||||
}
|
||||
} else {
|
||||
ret = T0;
|
||||
#endif
|
||||
xer_ca = 0;
|
||||
}
|
||||
} else {
|
||||
ret = (-1) * ((uint32_t)T0 >> 31);
|
||||
if (likely(ret >= 0 || ((uint32_t)T0 & ~0x80000000UL) == 0)) {
|
||||
xer_ca = 0;
|
||||
} else {
|
||||
ret = (int32_t)T0 >> (T1 & 0x1f);
|
||||
if (ret < 0 && ((int32_t)T0 & ((1 << T1) - 1)) != 0)
|
||||
xer_ca = 1;
|
||||
}
|
||||
}
|
||||
T0 = ret;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Floating point operations helpers */
|
||||
void do_fctiw (void)
|
||||
{
|
||||
|
@ -116,29 +355,23 @@ void do_fctiwz (void)
|
|||
|
||||
void do_fnmadd (void)
|
||||
{
|
||||
FT0 = (FT0 * FT1) + FT2;
|
||||
if (!isnan(FT0))
|
||||
FT0 = -FT0;
|
||||
FT0 = float64_mul(FT0, FT1, &env->fp_status);
|
||||
FT0 = float64_add(FT0, FT2, &env->fp_status);
|
||||
if (likely(!isnan(FT0)))
|
||||
FT0 = float64_chs(FT0);
|
||||
}
|
||||
|
||||
void do_fnmsub (void)
|
||||
{
|
||||
FT0 = (FT0 * FT1) - FT2;
|
||||
if (!isnan(FT0))
|
||||
FT0 = -FT0;
|
||||
}
|
||||
|
||||
void do_fdiv (void)
|
||||
{
|
||||
if (FT0 == -0.0 && FT1 == -0.0)
|
||||
FT0 = 0.0 / 0.0;
|
||||
else
|
||||
FT0 /= FT1;
|
||||
FT0 = float64_mul(FT0, FT1, &env->fp_status);
|
||||
FT0 = float64_sub(FT0, FT2, &env->fp_status);
|
||||
if (likely(!isnan(FT0)))
|
||||
FT0 = float64_chs(FT0);
|
||||
}
|
||||
|
||||
void do_fsqrt (void)
|
||||
{
|
||||
FT0 = sqrt(FT0);
|
||||
FT0 = float64_sqrt(FT0, &env->fp_status);
|
||||
}
|
||||
|
||||
void do_fres (void)
|
||||
|
@ -148,7 +381,7 @@ void do_fres (void)
|
|||
uint64_t i;
|
||||
} p;
|
||||
|
||||
if (isnormal(FT0)) {
|
||||
if (likely(isnormal(FT0))) {
|
||||
FT0 = (float)(1.0 / FT0);
|
||||
} else {
|
||||
p.d = FT0;
|
||||
|
@ -174,8 +407,9 @@ void do_frsqrte (void)
|
|||
uint64_t i;
|
||||
} p;
|
||||
|
||||
if (isnormal(FT0) && FT0 > 0.0) {
|
||||
FT0 = (float)(1.0 / sqrt(FT0));
|
||||
if (likely(isnormal(FT0) && FT0 > 0.0)) {
|
||||
FT0 = float64_sqrt(FT0, &env->fp_status);
|
||||
FT0 = float32_div(1.0, FT0, &env->fp_status);
|
||||
} else {
|
||||
p.d = FT0;
|
||||
if (p.i == 0x8000000000000000ULL) {
|
||||
|
@ -204,16 +438,18 @@ void do_fsel (void)
|
|||
|
||||
void do_fcmpu (void)
|
||||
{
|
||||
if (isnan(FT0) || isnan(FT1)) {
|
||||
T0 = 0x01;
|
||||
if (likely(!isnan(FT0) && !isnan(FT1))) {
|
||||
if (float64_lt(FT0, FT1, &env->fp_status)) {
|
||||
T0 = 0x08UL;
|
||||
} else if (!float64_le(FT0, FT1, &env->fp_status)) {
|
||||
T0 = 0x04UL;
|
||||
} else {
|
||||
T0 = 0x02UL;
|
||||
}
|
||||
} else {
|
||||
T0 = 0x01UL;
|
||||
env->fpscr[4] |= 0x1;
|
||||
env->fpscr[6] |= 0x1;
|
||||
} else if (FT0 < FT1) {
|
||||
T0 = 0x08;
|
||||
} else if (FT0 > FT1) {
|
||||
T0 = 0x04;
|
||||
} else {
|
||||
T0 = 0x02;
|
||||
}
|
||||
env->fpscr[3] = T0;
|
||||
}
|
||||
|
@ -221,8 +457,16 @@ void do_fcmpu (void)
|
|||
void do_fcmpo (void)
|
||||
{
|
||||
env->fpscr[4] &= ~0x1;
|
||||
if (isnan(FT0) || isnan(FT1)) {
|
||||
T0 = 0x01;
|
||||
if (likely(!isnan(FT0) && !isnan(FT1))) {
|
||||
if (float64_lt(FT0, FT1, &env->fp_status)) {
|
||||
T0 = 0x08UL;
|
||||
} else if (!float64_le(FT0, FT1, &env->fp_status)) {
|
||||
T0 = 0x04UL;
|
||||
} else {
|
||||
T0 = 0x02UL;
|
||||
}
|
||||
} else {
|
||||
T0 = 0x01UL;
|
||||
env->fpscr[4] |= 0x1;
|
||||
/* I don't know how to test "quiet" nan... */
|
||||
if (0 /* || ! quiet_nan(...) */) {
|
||||
|
@ -232,56 +476,51 @@ void do_fcmpo (void)
|
|||
} else {
|
||||
env->fpscr[4] |= 0x8;
|
||||
}
|
||||
} else if (FT0 < FT1) {
|
||||
T0 = 0x08;
|
||||
} else if (FT0 > FT1) {
|
||||
T0 = 0x04;
|
||||
} else {
|
||||
T0 = 0x02;
|
||||
}
|
||||
env->fpscr[3] = T0;
|
||||
}
|
||||
|
||||
void do_fabs (void)
|
||||
void do_rfi (void)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint64_t i;
|
||||
} p;
|
||||
|
||||
p.d = FT0;
|
||||
p.i &= ~0x8000000000000000ULL;
|
||||
FT0 = p.d;
|
||||
env->nip = env->spr[SPR_SRR0] & ~0x00000003;
|
||||
T0 = env->spr[SPR_SRR1] & ~0xFFFF0000UL;
|
||||
do_store_msr(env, T0);
|
||||
#if defined (DEBUG_OP)
|
||||
dump_rfi();
|
||||
#endif
|
||||
env->interrupt_request |= CPU_INTERRUPT_EXITTB;
|
||||
}
|
||||
|
||||
void do_fnabs (void)
|
||||
void do_tw (uint32_t cmp, int flags)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint64_t i;
|
||||
} p;
|
||||
|
||||
p.d = FT0;
|
||||
p.i |= 0x8000000000000000ULL;
|
||||
FT0 = p.d;
|
||||
if (!likely(!((Ts0 < (int32_t)cmp && (flags & 0x10)) ||
|
||||
(Ts0 > (int32_t)cmp && (flags & 0x08)) ||
|
||||
(Ts0 == (int32_t)cmp && (flags & 0x04)) ||
|
||||
(T0 < cmp && (flags & 0x02)) ||
|
||||
(T0 > cmp && (flags & 0x01)))))
|
||||
do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP);
|
||||
}
|
||||
|
||||
/* Instruction cache invalidation helper */
|
||||
#define ICACHE_LINE_SIZE 32
|
||||
|
||||
void do_check_reservation (void)
|
||||
{
|
||||
if ((env->reserve & ~0x03) == T0)
|
||||
env->reserve = -1;
|
||||
}
|
||||
|
||||
void do_icbi (void)
|
||||
{
|
||||
/* Invalidate one cache line */
|
||||
uint32_t tmp;
|
||||
/* Invalidate one cache line :
|
||||
* PowerPC specification says this is to be treated like a load
|
||||
* (not a fetch) by the MMU. To be sure it will be so,
|
||||
* do the load "by hand".
|
||||
*/
|
||||
#if defined(TARGET_PPC64)
|
||||
if (!msr_sf)
|
||||
T0 &= 0xFFFFFFFFULL;
|
||||
#endif
|
||||
tmp = ldl_kernel(T0);
|
||||
T0 &= ~(ICACHE_LINE_SIZE - 1);
|
||||
tb_invalidate_page_range(T0, T0 + ICACHE_LINE_SIZE);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* MMU related helpers */
|
||||
/* TLB invalidation helpers */
|
||||
void do_tlbia (void)
|
||||
{
|
||||
|
@ -290,6 +529,62 @@ void do_tlbia (void)
|
|||
|
||||
void do_tlbie (void)
|
||||
{
|
||||
#if !defined(FLUSH_ALL_TLBS)
|
||||
tlb_flush_page(env, T0);
|
||||
#else
|
||||
do_tlbia();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Softmmu support */
|
||||
#if !defined (CONFIG_USER_ONLY)
|
||||
|
||||
#define MMUSUFFIX _mmu
|
||||
#define GETPC() (__builtin_return_address(0))
|
||||
|
||||
#define SHIFT 0
|
||||
#include "softmmu_template.h"
|
||||
|
||||
#define SHIFT 1
|
||||
#include "softmmu_template.h"
|
||||
|
||||
#define SHIFT 2
|
||||
#include "softmmu_template.h"
|
||||
|
||||
#define SHIFT 3
|
||||
#include "softmmu_template.h"
|
||||
|
||||
/* try to fill the TLB and return an exception if error. If retaddr is
|
||||
NULL, it means that the function was called in C code (i.e. not
|
||||
from generated code or from helper.c) */
|
||||
/* XXX: fix it to restore all registers */
|
||||
void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr)
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
CPUState *saved_env;
|
||||
target_phys_addr_t pc;
|
||||
int ret;
|
||||
|
||||
/* XXX: hack to restore env in all cases, even if not called from
|
||||
generated code */
|
||||
saved_env = env;
|
||||
env = cpu_single_env;
|
||||
ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, is_user, 1);
|
||||
if (!likely(ret == 0)) {
|
||||
if (likely(retaddr)) {
|
||||
/* now we have a real cpu fault */
|
||||
pc = (target_phys_addr_t)retaddr;
|
||||
tb = tb_find_pc(pc);
|
||||
if (likely(tb)) {
|
||||
/* the PC is inside the translated code. It means that we have
|
||||
a virtual CPU fault */
|
||||
cpu_restore_state(tb, env, pc, NULL);
|
||||
}
|
||||
}
|
||||
do_raise_exception_err(env->exception_index, env->error_code);
|
||||
}
|
||||
env = saved_env;
|
||||
}
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
||||
|
|
Loading…
Reference in New Issue