/*
- * PPC emulation for qemu: main translation routines.
+ * PowerPC emulation for qemu: main translation routines.
*
- * Copyright (c) 2003 Jocelyn Mayer
+ * Copyright (c) 2003-2005 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* 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 "dyngen-exec.h"
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
#include "cpu.h"
-#include "exec.h"
+#include "exec-all.h"
#include "disas.h"
//#define DO_SINGLE_STEP
-//#define DO_STEP_FLUSH
-//#define DEBUG_DISAS
+//#define PPC_DEBUG_DISAS
+
+#ifdef USE_DIRECT_JUMP
+#define TBPARAM(x)
+#else
+#define TBPARAM(x) (long)(x)
+#endif
enum {
#define DEF(s, n, copy_size) INDEX_op_ ## s,
/* internal defines */
typedef struct DisasContext {
struct TranslationBlock *tb;
- uint32_t *nip;
+ target_ulong nip;
uint32_t opcode;
uint32_t exception;
- /* Time base offset */
- uint32_t tb_offset;
- /* Decrementer offset */
- uint32_t decr_offset;
- /* Execution mode */
+ /* Routine used to access memory */
+ int mem_idx;
+ /* Translation flags */
#if !defined(CONFIG_USER_ONLY)
int supervisor;
#endif
- /* Routine used to access memory */
- int mem_idx;
+ int fpu_enabled;
+ ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */
} DisasContext;
-typedef struct opc_handler_t {
+struct opc_handler_t {
/* invalid bits */
uint32_t inval;
/* instruction type */
uint32_t type;
/* handler */
void (*handler)(DisasContext *ctx);
-} opc_handler_t;
+};
-#define RET_EXCP(excp, error) \
+#define RET_EXCP(ctx, excp, error) \
do { \
- gen_op_queue_exception_err(excp, error); \
- ctx->exception = excp; \
- return; \
+ if ((ctx)->exception == EXCP_NONE) { \
+ gen_op_update_nip((ctx)->nip); \
+ } \
+ gen_op_raise_exception_err((excp), (error)); \
+ ctx->exception = (excp); \
} while (0)
-#define RET_INVAL() \
-RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL)
+#define RET_INVAL(ctx) \
+RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL)
-#define RET_PRIVOPC() \
-RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_OPC)
+#define RET_PRIVOPC(ctx) \
+RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_OPC)
-#define RET_PRIVREG() \
-RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG)
+#define RET_PRIVREG(ctx) \
+RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG)
+
+/* Stop translation */
+static inline void RET_STOP (DisasContext *ctx)
+{
+ gen_op_update_nip((ctx)->nip);
+ ctx->exception = EXCP_MTMSR;
+}
+
+/* No need to update nip here, as execution flow will change */
+static inline void RET_CHG_FLOW (DisasContext *ctx)
+{
+ ctx->exception = EXCP_MTMSR;
+}
#define GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \
static void gen_##name (DisasContext *ctx); \
typedef struct opcode_t {
unsigned char opc1, opc2, opc3;
+#if HOST_LONG_BITS == 64 /* Explicitely align to 64 bits */
+ unsigned char pad[5];
+#else
+ unsigned char pad[1];
+#endif
opc_handler_t handler;
+ const unsigned char *oname;
} opcode_t;
-/* XXX: move that elsewhere */
-extern FILE *logfile;
-extern int loglevel;
-
/*** Instruction decoding ***/
#define EXTRACT_HELPER(name, shift, nb) \
static inline uint32_t name (uint32_t opcode) \
#define EXTRACT_SHELPER(name, shift, nb) \
static inline int32_t name (uint32_t opcode) \
{ \
- return s_ext16((opcode >> (shift)) & ((1 << (nb)) - 1)); \
+ return (int16_t)((opcode >> (shift)) & ((1 << (nb)) - 1)); \
}
/* Opcode part 1 */
EXTRACT_HELPER(crbA, 16, 5);
EXTRACT_HELPER(crbB, 11, 5);
/* SPR / TBL */
-EXTRACT_HELPER(SPR, 11, 10);
+EXTRACT_HELPER(_SPR, 11, 10);
+static inline uint32_t SPR (uint32_t opcode)
+{
+ uint32_t sprn = _SPR(opcode);
+
+ return ((sprn >> 5) & 0x1F) | ((sprn & 0x1F) << 5);
+}
/*** Get constants ***/
EXTRACT_HELPER(IMM, 12, 8);
/* 16 bits signed immediate value */
return ret;
}
+#if HOST_LONG_BITS == 64
+#define OPC_ALIGN 8
+#else
+#define OPC_ALIGN 4
+#endif
+#if defined(__APPLE__)
+#define OPCODES_SECTION \
+ __attribute__ ((section("__TEXT,__opcodes"), unused, aligned (OPC_ALIGN) ))
+#else
+#define OPCODES_SECTION \
+ __attribute__ ((section(".opcodes"), unused, aligned (OPC_ALIGN) ))
+#endif
+
#define GEN_OPCODE(name, op1, op2, op3, invl, _typ) \
-__attribute__ ((section(".opcodes"), unused)) \
-static opcode_t opc_##name = { \
+OPCODES_SECTION opcode_t opc_##name = { \
.opc1 = op1, \
.opc2 = op2, \
.opc3 = op3, \
+ .pad = { 0, }, \
.handler = { \
.inval = invl, \
.type = _typ, \
.handler = &gen_##name, \
}, \
+ .oname = stringify(name), \
}
#define GEN_OPCODE_MARK(name) \
-__attribute__ ((section(".opcodes"), unused)) \
-static opcode_t opc_##name = { \
+OPCODES_SECTION opcode_t opc_##name = { \
.opc1 = 0xFF, \
.opc2 = 0xFF, \
.opc3 = 0xFF, \
+ .pad = { 0, }, \
.handler = { \
.inval = 0x00000000, \
.type = 0x00, \
.handler = NULL, \
}, \
+ .oname = stringify(name), \
}
/* Start opcode list */
/* Invalid instruction */
GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE)
{
- RET_INVAL();
-}
-
-/* Special opcode to stop emulation */
-GEN_HANDLER(stop, 0x06, 0x00, 0xFF, 0x03FFFFC1, PPC_COMMON)
-{
- gen_op_queue_exception(EXCP_HLT);
- ctx->exception = EXCP_HLT;
-}
-
-/* Special opcode to call open-firmware */
-GEN_HANDLER(of_enter, 0x06, 0x01, 0xFF, 0x03FFFFC1, PPC_COMMON)
-{
- gen_op_queue_exception(EXCP_OFCALL);
- ctx->exception = EXCP_OFCALL;
-}
-
-/* Special opcode to call RTAS */
-GEN_HANDLER(rtas_enter, 0x06, 0x02, 0xFF, 0x03FFFFC1, PPC_COMMON)
-{
- printf("RTAS entry point !\n");
- gen_op_queue_exception(EXCP_RTASCALL);
- ctx->exception = EXCP_RTASCALL;
+ RET_INVAL(ctx);
}
static opc_handler_t invalid_handler = {
gen_op_load_gpr_T1(rB(ctx->opcode)); \
gen_op_##name(); \
if (Rc(ctx->opcode) != 0) \
- gen_op_set_Rc0_ov(); \
+ gen_op_set_Rc0(); \
gen_op_store_T0_gpr(rD(ctx->opcode)); \
}
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_##name(); \
if (Rc(ctx->opcode) != 0) \
- gen_op_set_Rc0_ov(); \
+ gen_op_set_Rc0(); \
gen_op_store_T0_gpr(rD(ctx->opcode)); \
}
}
gen_op_load_gpr_T0(rS(ctx->opcode));
if (uimm != 0)
- gen_op_xori(UIMM(ctx->opcode));
+ gen_op_xori(uimm);
gen_op_store_T0_gpr(rA(ctx->opcode));
}
}
gen_op_load_gpr_T0(rS(ctx->opcode));
if (uimm != 0)
- gen_op_xori(UIMM(ctx->opcode) << 16);
+ gen_op_xori(uimm << 16);
gen_op_store_T0_gpr(rA(ctx->opcode));
}
mb = MB(ctx->opcode);
me = ME(ctx->opcode);
gen_op_load_gpr_T0(rS(ctx->opcode));
+#if 1 // TRY
+ if (sh == 0) {
+ gen_op_andi_(MASK(mb, me));
+ goto store;
+ }
+#endif
if (mb == 0) {
if (me == 31) {
gen_op_rotlwi(sh);
goto store;
+#if 0
} else if (me == (31 - sh)) {
gen_op_slwi(sh);
goto store;
- } else if (sh == 0) {
- gen_op_andi_(MASK(0, me));
- goto store;
+#endif
}
} else if (me == 31) {
+#if 0
if (sh == (32 - mb)) {
gen_op_srwi(mb);
goto store;
- } else if (sh == 0) {
- gen_op_andi_(MASK(mb, 31));
- goto store;
}
+#endif
}
gen_op_rlwinm(sh, MASK(mb, me));
store:
GEN_HANDLER(srawi, 0x1F, 0x18, 0x19, 0x00000000, PPC_INTEGER)
{
gen_op_load_gpr_T0(rS(ctx->opcode));
+ if (SH(ctx->opcode) != 0)
gen_op_srawi(SH(ctx->opcode), MASK(32 - SH(ctx->opcode), 31));
if (Rc(ctx->opcode) != 0)
gen_op_set_Rc0();
__GEN_LOGICAL2(srw, 0x18, 0x10);
/*** Floating-Point arithmetic ***/
-#define _GEN_FLOAT_ACB(name, op1, op2) \
+#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat) \
GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, PPC_FLOAT) \
{ \
+ if (!ctx->fpu_enabled) { \
+ RET_EXCP(ctx, EXCP_NO_FP, 0); \
+ return; \
+ } \
gen_op_reset_scrfx(); \
gen_op_load_fpr_FT0(rA(ctx->opcode)); \
gen_op_load_fpr_FT1(rC(ctx->opcode)); \
gen_op_load_fpr_FT2(rB(ctx->opcode)); \
- gen_op_f##name(); \
+ gen_op_f##op(); \
+ if (isfloat) { \
+ gen_op_frsp(); \
+ } \
gen_op_store_FT0_fpr(rD(ctx->opcode)); \
if (Rc(ctx->opcode)) \
gen_op_set_Rc1(); \
}
#define GEN_FLOAT_ACB(name, op2) \
-_GEN_FLOAT_ACB(name, 0x3F, op2); \
-_GEN_FLOAT_ACB(name##s, 0x3B, op2);
+_GEN_FLOAT_ACB(name, name, 0x3F, op2, 0); \
+_GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1);
-#define _GEN_FLOAT_AB(name, op1, op2, inval) \
+#define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat) \
GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \
{ \
+ if (!ctx->fpu_enabled) { \
+ RET_EXCP(ctx, EXCP_NO_FP, 0); \
+ return; \
+ } \
gen_op_reset_scrfx(); \
gen_op_load_fpr_FT0(rA(ctx->opcode)); \
gen_op_load_fpr_FT1(rB(ctx->opcode)); \
- gen_op_f##name(); \
+ gen_op_f##op(); \
+ if (isfloat) { \
+ gen_op_frsp(); \
+ } \
gen_op_store_FT0_fpr(rD(ctx->opcode)); \
if (Rc(ctx->opcode)) \
gen_op_set_Rc1(); \
}
#define GEN_FLOAT_AB(name, op2, inval) \
-_GEN_FLOAT_AB(name, 0x3F, op2, inval); \
-_GEN_FLOAT_AB(name##s, 0x3B, op2, inval);
+_GEN_FLOAT_AB(name, name, 0x3F, op2, inval, 0); \
+_GEN_FLOAT_AB(name##s, name, 0x3B, op2, inval, 1);
-#define _GEN_FLOAT_AC(name, op1, op2, inval) \
+#define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat) \
GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \
{ \
+ if (!ctx->fpu_enabled) { \
+ RET_EXCP(ctx, EXCP_NO_FP, 0); \
+ return; \
+ } \
gen_op_reset_scrfx(); \
gen_op_load_fpr_FT0(rA(ctx->opcode)); \
gen_op_load_fpr_FT1(rC(ctx->opcode)); \
- gen_op_f##name(); \
+ gen_op_f##op(); \
+ if (isfloat) { \
+ gen_op_frsp(); \
+ } \
gen_op_store_FT0_fpr(rD(ctx->opcode)); \
if (Rc(ctx->opcode)) \
gen_op_set_Rc1(); \
}
#define GEN_FLOAT_AC(name, op2, inval) \
-_GEN_FLOAT_AC(name, 0x3F, op2, inval); \
-_GEN_FLOAT_AC(name##s, 0x3B, op2, inval);
+_GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0); \
+_GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1);
#define GEN_FLOAT_B(name, op2, op3) \
GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, PPC_FLOAT) \
{ \
+ if (!ctx->fpu_enabled) { \
+ RET_EXCP(ctx, EXCP_NO_FP, 0); \
+ return; \
+ } \
gen_op_reset_scrfx(); \
gen_op_load_fpr_FT0(rB(ctx->opcode)); \
gen_op_f##name(); \
gen_op_set_Rc1(); \
}
-#define GEN_FLOAT_BS(name, op2) \
-GEN_HANDLER(f##name, 0x3F, op2, 0xFF, 0x001F07C0, PPC_FLOAT) \
+#define GEN_FLOAT_BS(name, op1, op2) \
+GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, PPC_FLOAT) \
{ \
+ if (!ctx->fpu_enabled) { \
+ RET_EXCP(ctx, EXCP_NO_FP, 0); \
+ return; \
+ } \
gen_op_reset_scrfx(); \
gen_op_load_fpr_FT0(rB(ctx->opcode)); \
gen_op_f##name(); \
/* fadd - fadds */
GEN_FLOAT_AB(add, 0x15, 0x000007C0);
-/* fdiv */
+/* fdiv - fdivs */
GEN_FLOAT_AB(div, 0x12, 0x000007C0);
-/* fmul */
+/* fmul - fmuls */
GEN_FLOAT_AC(mul, 0x19, 0x0000F800);
/* fres */
-GEN_FLOAT_BS(res, 0x18);
+GEN_FLOAT_BS(res, 0x3B, 0x18);
/* frsqrte */
-GEN_FLOAT_BS(rsqrte, 0x1A);
+GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A);
/* fsel */
-_GEN_FLOAT_ACB(sel, 0x3F, 0x17);
-/* fsub */
+_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0);
+/* fsub - fsubs */
GEN_FLOAT_AB(sub, 0x14, 0x000007C0);
/* Optional: */
/* fsqrt */
-GEN_FLOAT_BS(sqrt, 0x16);
+GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT)
+{
+ if (!ctx->fpu_enabled) {
+ RET_EXCP(ctx, EXCP_NO_FP, 0);
+ return;
+ }
+ gen_op_reset_scrfx();
+ gen_op_load_fpr_FT0(rB(ctx->opcode));
+ gen_op_fsqrt();
+ gen_op_store_FT0_fpr(rD(ctx->opcode));
+ if (Rc(ctx->opcode))
+ gen_op_set_Rc1();
+}
GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT)
{
+ if (!ctx->fpu_enabled) {
+ RET_EXCP(ctx, EXCP_NO_FP, 0);
+ return;
+ }
gen_op_reset_scrfx();
gen_op_load_fpr_FT0(rB(ctx->opcode));
- gen_op_fsqrts();
+ gen_op_fsqrt();
+ gen_op_frsp();
gen_op_store_FT0_fpr(rD(ctx->opcode));
if (Rc(ctx->opcode))
gen_op_set_Rc1();
}
/*** Floating-Point multiply-and-add ***/
-/* fmadd */
+/* fmadd - fmadds */
GEN_FLOAT_ACB(madd, 0x1D);
-/* fmsub */
+/* fmsub - fmsubs */
GEN_FLOAT_ACB(msub, 0x1C);
-/* fnmadd */
+/* fnmadd - fnmadds */
GEN_FLOAT_ACB(nmadd, 0x1F);
-/* fnmsub */
+/* fnmsub - fnmsubs */
GEN_FLOAT_ACB(nmsub, 0x1E);
/*** Floating-Point round & convert ***/
/* fcmpo */
GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT)
{
+ if (!ctx->fpu_enabled) {
+ RET_EXCP(ctx, EXCP_NO_FP, 0);
+ return;
+ }
gen_op_reset_scrfx();
gen_op_load_fpr_FT0(rA(ctx->opcode));
gen_op_load_fpr_FT1(rB(ctx->opcode));
/* fcmpu */
GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT)
{
+ if (!ctx->fpu_enabled) {
+ RET_EXCP(ctx, EXCP_NO_FP, 0);
+ return;
+ }
gen_op_reset_scrfx();
gen_op_load_fpr_FT0(rA(ctx->opcode));
gen_op_load_fpr_FT1(rB(ctx->opcode));
/* fmr - fmr. */
GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT)
{
+ if (!ctx->fpu_enabled) {
+ RET_EXCP(ctx, EXCP_NO_FP, 0);
+ return;
+ }
gen_op_reset_scrfx();
gen_op_load_fpr_FT0(rB(ctx->opcode));
gen_op_store_FT0_fpr(rD(ctx->opcode));
/* mcrfs */
GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT)
{
+ if (!ctx->fpu_enabled) {
+ RET_EXCP(ctx, EXCP_NO_FP, 0);
+ return;
+ }
gen_op_load_fpscr_T0(crfS(ctx->opcode));
gen_op_store_T0_crf(crfD(ctx->opcode));
gen_op_clear_fpscr(crfS(ctx->opcode));
/* mffs */
GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT)
{
+ if (!ctx->fpu_enabled) {
+ RET_EXCP(ctx, EXCP_NO_FP, 0);
+ return;
+ }
gen_op_load_fpscr();
gen_op_store_FT0_fpr(rD(ctx->opcode));
if (Rc(ctx->opcode))
{
uint8_t crb;
+ if (!ctx->fpu_enabled) {
+ RET_EXCP(ctx, EXCP_NO_FP, 0);
+ return;
+ }
crb = crbD(ctx->opcode) >> 2;
gen_op_load_fpscr_T0(crb);
gen_op_andi_(~(1 << (crbD(ctx->opcode) & 0x03)));
{
uint8_t crb;
+ if (!ctx->fpu_enabled) {
+ RET_EXCP(ctx, EXCP_NO_FP, 0);
+ return;
+ }
crb = crbD(ctx->opcode) >> 2;
gen_op_load_fpscr_T0(crb);
gen_op_ori(1 << (crbD(ctx->opcode) & 0x03));
/* mtfsf */
GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x02010000, PPC_FLOAT)
{
+ if (!ctx->fpu_enabled) {
+ RET_EXCP(ctx, EXCP_NO_FP, 0);
+ return;
+ }
gen_op_load_fpr_FT0(rB(ctx->opcode));
gen_op_store_fpscr(FM(ctx->opcode));
if (Rc(ctx->opcode))
/* mtfsfi */
GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT)
{
+ if (!ctx->fpu_enabled) {
+ RET_EXCP(ctx, EXCP_NO_FP, 0);
+ return;
+ }
gen_op_store_T0_fpscri(crbD(ctx->opcode) >> 2, FPIMM(ctx->opcode));
if (Rc(ctx->opcode))
gen_op_set_Rc1();
}
/*** Integer load ***/
+#define op_ldst(name) (*gen_op_##name[ctx->mem_idx])()
#if defined(CONFIG_USER_ONLY)
-#define op_ldst(name) gen_op_##name##_raw()
-#define OP_LD_TABLE(width)
-#define OP_ST_TABLE(width)
+#define OP_LD_TABLE(width) \
+static GenOpFunc *gen_op_l##width[] = { \
+ &gen_op_l##width##_raw, \
+ &gen_op_l##width##_le_raw, \
+};
+#define OP_ST_TABLE(width) \
+static GenOpFunc *gen_op_st##width[] = { \
+ &gen_op_st##width##_raw, \
+ &gen_op_st##width##_le_raw, \
+};
+/* Byte access routine are endian safe */
+#define gen_op_stb_le_raw gen_op_stb_raw
+#define gen_op_lbz_le_raw gen_op_lbz_raw
#else
-#define op_ldst(name) (*gen_op_##name[ctx->mem_idx])()
#define OP_LD_TABLE(width) \
static GenOpFunc *gen_op_l##width[] = { \
&gen_op_l##width##_user, \
+ &gen_op_l##width##_le_user, \
&gen_op_l##width##_kernel, \
-}
+ &gen_op_l##width##_le_kernel, \
+};
#define OP_ST_TABLE(width) \
static GenOpFunc *gen_op_st##width[] = { \
&gen_op_st##width##_user, \
+ &gen_op_st##width##_le_user, \
&gen_op_st##width##_kernel, \
-}
+ &gen_op_st##width##_le_kernel, \
+};
+/* Byte access routine are endian safe */
+#define gen_op_stb_le_user gen_op_stb_user
+#define gen_op_lbz_le_user gen_op_lbz_user
+#define gen_op_stb_le_kernel gen_op_stb_kernel
+#define gen_op_lbz_le_kernel gen_op_lbz_kernel
#endif
#define GEN_LD(width, opc) \
uint32_t simm = SIMM(ctx->opcode); \
if (rA(ctx->opcode) == 0 || \
rA(ctx->opcode) == rD(ctx->opcode)) { \
- RET_INVAL(); \
+ RET_INVAL(ctx); \
+ return; \
} \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
if (simm != 0) \
{ \
if (rA(ctx->opcode) == 0 || \
rA(ctx->opcode) == rD(ctx->opcode)) { \
- RET_INVAL(); \
+ RET_INVAL(ctx); \
+ return; \
} \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_load_gpr_T1(rB(ctx->opcode)); \
{ \
uint32_t simm = SIMM(ctx->opcode); \
if (rA(ctx->opcode) == 0) { \
- RET_INVAL(); \
+ RET_INVAL(ctx); \
+ return; \
} \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
if (simm != 0) \
GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \
{ \
if (rA(ctx->opcode) == 0) { \
- RET_INVAL(); \
+ RET_INVAL(ctx); \
+ return; \
} \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_load_gpr_T1(rB(ctx->opcode)); \
GEN_STX(wbr, 0x16, 0x14);
/*** Integer load and store multiple ***/
+#define op_ldstm(name, reg) (*gen_op_##name[ctx->mem_idx])(reg)
#if defined(CONFIG_USER_ONLY)
-#define op_ldstm(name, reg) gen_op_##name##_raw(reg)
+static GenOpFunc1 *gen_op_lmw[] = {
+ &gen_op_lmw_raw,
+ &gen_op_lmw_le_raw,
+};
+static GenOpFunc1 *gen_op_stmw[] = {
+ &gen_op_stmw_raw,
+ &gen_op_stmw_le_raw,
+};
#else
-#define op_ldstm(name, reg) (*gen_op_##name[ctx->mem_idx])(reg)
static GenOpFunc1 *gen_op_lmw[] = {
&gen_op_lmw_user,
+ &gen_op_lmw_le_user,
&gen_op_lmw_kernel,
+ &gen_op_lmw_le_kernel,
};
static GenOpFunc1 *gen_op_stmw[] = {
&gen_op_stmw_user,
+ &gen_op_stmw_le_user,
&gen_op_stmw_kernel,
+ &gen_op_stmw_le_kernel,
};
#endif
}
/*** Integer load and store strings ***/
-#if defined(CONFIG_USER_ONLY)
-#define op_ldsts(name, start) gen_op_##name##_raw(start)
-#define op_ldstsx(name, rd, ra, rb) gen_op_##name##_raw(rd, ra, rb)
-#else
#define op_ldsts(name, start) (*gen_op_##name[ctx->mem_idx])(start)
#define op_ldstsx(name, rd, ra, rb) (*gen_op_##name[ctx->mem_idx])(rd, ra, rb)
+#if defined(CONFIG_USER_ONLY)
+static GenOpFunc1 *gen_op_lswi[] = {
+ &gen_op_lswi_raw,
+ &gen_op_lswi_le_raw,
+};
+static GenOpFunc3 *gen_op_lswx[] = {
+ &gen_op_lswx_raw,
+ &gen_op_lswx_le_raw,
+};
+static GenOpFunc1 *gen_op_stsw[] = {
+ &gen_op_stsw_raw,
+ &gen_op_stsw_le_raw,
+};
+#else
static GenOpFunc1 *gen_op_lswi[] = {
&gen_op_lswi_user,
+ &gen_op_lswi_le_user,
&gen_op_lswi_kernel,
+ &gen_op_lswi_le_kernel,
};
static GenOpFunc3 *gen_op_lswx[] = {
&gen_op_lswx_user,
+ &gen_op_lswx_le_user,
&gen_op_lswx_kernel,
+ &gen_op_lswx_le_kernel,
};
static GenOpFunc1 *gen_op_stsw[] = {
&gen_op_stsw_user,
+ &gen_op_stsw_le_user,
&gen_op_stsw_kernel,
+ &gen_op_stsw_le_kernel,
};
#endif
/* lswi */
-/* PPC32 specification says we must generate an exception if
+/* PowerPC32 specification says we must generate an exception if
* rA is in the range of registers to be loaded.
* In an other hand, IBM says this is valid, but rA won't be loaded.
* For now, I'll follow the spec...
nr = nb / 4;
if (((start + nr) > 32 && start <= ra && (start + nr - 32) > ra) ||
((start + nr) <= 32 && start <= ra && (start + nr) > ra)) {
- RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX);
+ RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX);
+ return;
}
if (ra == 0) {
gen_op_set_T0(0);
gen_op_load_gpr_T0(ra);
}
gen_op_set_T1(nb);
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_op_update_nip((ctx)->nip - 4);
op_ldsts(lswi, start);
}
gen_op_add();
}
gen_op_load_xer_bc();
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_op_update_nip((ctx)->nip - 4);
op_ldstsx(lswx, rD(ctx->opcode), ra, rb);
}
/* stswi */
GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_INTEGER)
{
+ int nb = NB(ctx->opcode);
+
if (rA(ctx->opcode) == 0) {
gen_op_set_T0(0);
} else {
gen_op_load_gpr_T0(rA(ctx->opcode));
}
- gen_op_set_T1(NB(ctx->opcode));
+ if (nb == 0)
+ nb = 32;
+ gen_op_set_T1(nb);
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_op_update_nip((ctx)->nip - 4);
op_ldsts(stsw, rS(ctx->opcode));
}
gen_op_add();
}
gen_op_load_xer_bc();
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_op_update_nip((ctx)->nip - 4);
op_ldsts(stsw, rS(ctx->opcode));
}
{
}
-/* lwarx */
+#define op_lwarx() (*gen_op_lwarx[ctx->mem_idx])()
+#define op_stwcx() (*gen_op_stwcx[ctx->mem_idx])()
#if defined(CONFIG_USER_ONLY)
-#define op_lwarx() gen_op_lwarx_raw()
-#define op_stwcx() gen_op_stwcx_raw()
+static GenOpFunc *gen_op_lwarx[] = {
+ &gen_op_lwarx_raw,
+ &gen_op_lwarx_le_raw,
+};
+static GenOpFunc *gen_op_stwcx[] = {
+ &gen_op_stwcx_raw,
+ &gen_op_stwcx_le_raw,
+};
#else
-#define op_lwarx() (*gen_op_lwarx[ctx->mem_idx])()
static GenOpFunc *gen_op_lwarx[] = {
&gen_op_lwarx_user,
+ &gen_op_lwarx_le_user,
&gen_op_lwarx_kernel,
+ &gen_op_lwarx_le_kernel,
};
-#define op_stwcx() (*gen_op_stwcx[ctx->mem_idx])()
static GenOpFunc *gen_op_stwcx[] = {
&gen_op_stwcx_user,
+ &gen_op_stwcx_le_user,
&gen_op_stwcx_kernel,
+ &gen_op_stwcx_le_kernel,
};
#endif
+/* lwarx */
GEN_HANDLER(lwarx, 0x1F, 0x14, 0xFF, 0x00000001, PPC_RES)
{
if (rA(ctx->opcode) == 0) {
/*** Floating-point load ***/
#define GEN_LDF(width, opc) \
-GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
+GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
{ \
uint32_t simm = SIMM(ctx->opcode); \
+ if (!ctx->fpu_enabled) { \
+ RET_EXCP(ctx, EXCP_NO_FP, 0); \
+ return; \
+ } \
if (rA(ctx->opcode) == 0) { \
gen_op_set_T0(simm); \
} else { \
}
#define GEN_LDUF(width, opc) \
-GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
+GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
{ \
uint32_t simm = SIMM(ctx->opcode); \
+ if (!ctx->fpu_enabled) { \
+ RET_EXCP(ctx, EXCP_NO_FP, 0); \
+ return; \
+ } \
if (rA(ctx->opcode) == 0 || \
rA(ctx->opcode) == rD(ctx->opcode)) { \
- RET_INVAL(); \
+ RET_INVAL(ctx); \
+ return; \
} \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
if (simm != 0) \
}
#define GEN_LDUXF(width, opc) \
-GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \
+GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \
{ \
+ if (!ctx->fpu_enabled) { \
+ RET_EXCP(ctx, EXCP_NO_FP, 0); \
+ return; \
+ } \
if (rA(ctx->opcode) == 0 || \
rA(ctx->opcode) == rD(ctx->opcode)) { \
- RET_INVAL(); \
+ RET_INVAL(ctx); \
+ return; \
} \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_load_gpr_T1(rB(ctx->opcode)); \
}
#define GEN_LDXF(width, opc2, opc3) \
-GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \
+GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_FLOAT) \
{ \
+ if (!ctx->fpu_enabled) { \
+ RET_EXCP(ctx, EXCP_NO_FP, 0); \
+ return; \
+ } \
if (rA(ctx->opcode) == 0) { \
gen_op_load_gpr_T0(rB(ctx->opcode)); \
} else { \
/*** Floating-point store ***/
#define GEN_STF(width, opc) \
-GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
+GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
{ \
uint32_t simm = SIMM(ctx->opcode); \
+ if (!ctx->fpu_enabled) { \
+ RET_EXCP(ctx, EXCP_NO_FP, 0); \
+ return; \
+ } \
if (rA(ctx->opcode) == 0) { \
gen_op_set_T0(simm); \
} else { \
}
#define GEN_STUF(width, opc) \
-GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
+GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
{ \
uint32_t simm = SIMM(ctx->opcode); \
+ if (!ctx->fpu_enabled) { \
+ RET_EXCP(ctx, EXCP_NO_FP, 0); \
+ return; \
+ } \
if (rA(ctx->opcode) == 0) { \
- RET_INVAL(); \
+ RET_INVAL(ctx); \
+ return; \
} \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
if (simm != 0) \
}
#define GEN_STUXF(width, opc) \
-GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \
+GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \
{ \
+ if (!ctx->fpu_enabled) { \
+ RET_EXCP(ctx, EXCP_NO_FP, 0); \
+ return; \
+ } \
if (rA(ctx->opcode) == 0) { \
- RET_INVAL(); \
+ RET_INVAL(ctx); \
+ return; \
} \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_load_gpr_T1(rB(ctx->opcode)); \
}
#define GEN_STXF(width, opc2, opc3) \
-GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \
+GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_FLOAT) \
{ \
+ if (!ctx->fpu_enabled) { \
+ RET_EXCP(ctx, EXCP_NO_FP, 0); \
+ return; \
+ } \
if (rA(ctx->opcode) == 0) { \
gen_op_load_gpr_T0(rB(ctx->opcode)); \
} else { \
/* stfiwx */
GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT)
{
- RET_INVAL();
+ if (!ctx->fpu_enabled) {
+ RET_EXCP(ctx, EXCP_NO_FP, 0);
+ return;
+ }
+ RET_INVAL(ctx);
}
/*** Branch ***/
+static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
+{
+ TranslationBlock *tb;
+ tb = ctx->tb;
+ if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
+ if (n == 0)
+ gen_op_goto_tb0(TBPARAM(tb));
+ else
+ gen_op_goto_tb1(TBPARAM(tb));
+ gen_op_set_T1(dest);
+ gen_op_b_T1();
+ gen_op_set_T0((long)tb + n);
+ gen_op_exit_tb();
+ } else {
+ gen_op_set_T1(dest);
+ gen_op_b_T1();
+ gen_op_set_T0(0);
+ gen_op_exit_tb();
+ }
+}
+
/* b ba bl bla */
GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
{
- uint32_t li = s_ext24(LI(ctx->opcode)), target;
+ uint32_t li, target;
+
+ /* sign extend LI */
+ li = ((int32_t)LI(ctx->opcode) << 6) >> 6;
- gen_op_update_tb(ctx->tb_offset);
- gen_op_update_decr(ctx->decr_offset);
- gen_op_process_exceptions((uint32_t)ctx->nip - 4);
if (AA(ctx->opcode) == 0)
- target = (uint32_t)ctx->nip + li - 4;
+ target = ctx->nip + li - 4;
else
target = li;
if (LK(ctx->opcode)) {
- gen_op_setlr((uint32_t)ctx->nip);
+ gen_op_setlr(ctx->nip);
}
- gen_op_b((long)ctx->tb, target);
+ gen_goto_tb(ctx, 0, target);
ctx->exception = EXCP_BRANCH;
}
uint32_t mask;
uint32_t li;
- gen_op_update_tb(ctx->tb_offset);
- gen_op_update_decr(ctx->decr_offset);
- gen_op_process_exceptions((uint32_t)ctx->nip - 4);
-
if ((bo & 0x4) == 0)
gen_op_dec_ctr();
switch(type) {
case BCOND_IM:
- li = s_ext16(BD(ctx->opcode));
+ li = (int32_t)((int16_t)(BD(ctx->opcode)));
if (AA(ctx->opcode) == 0) {
- target = (uint32_t)ctx->nip + li - 4;
+ target = ctx->nip + li - 4;
} else {
target = li;
}
break;
}
if (LK(ctx->opcode)) {
- gen_op_setlr((uint32_t)ctx->nip);
+ gen_op_setlr(ctx->nip);
}
if (bo & 0x10) {
/* No CR condition */
case 4:
case 6:
if (type == BCOND_IM) {
- gen_op_b((long)ctx->tb, target);
+ gen_goto_tb(ctx, 0, target);
} else {
gen_op_b_T1();
}
}
}
if (type == BCOND_IM) {
- gen_op_btest((long)ctx->tb, target, (uint32_t)ctx->nip);
+ int l1 = gen_new_label();
+ gen_op_jz_T0(l1);
+ gen_goto_tb(ctx, 0, target);
+ gen_set_label(l1);
+ gen_goto_tb(ctx, 1, ctx->nip);
} else {
- gen_op_btest_T1((uint32_t)ctx->nip);
+ gen_op_btest_T1(ctx->nip);
}
no_test:
ctx->exception = EXCP_BRANCH;
GEN_HANDLER(rfi, 0x13, 0x12, 0xFF, 0x03FF8001, PPC_FLOW)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC();
+ RET_PRIVOPC(ctx);
#else
/* Restore CPU state */
if (!ctx->supervisor) {
- RET_PRIVOPC();
+ RET_PRIVOPC(ctx);
+ return;
}
gen_op_rfi();
- ctx->exception = EXCP_RFI;
+ RET_CHG_FLOW(ctx);
#endif
}
GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFFFFD, PPC_FLOW)
{
#if defined(CONFIG_USER_ONLY)
- gen_op_queue_exception(EXCP_SYSCALL_USER);
+ RET_EXCP(ctx, EXCP_SYSCALL_USER, 0);
#else
- gen_op_queue_exception(EXCP_SYSCALL);
+ RET_EXCP(ctx, EXCP_SYSCALL, 0);
#endif
- ctx->exception = EXCP_SYSCALL;
}
/*** Trap ***/
GEN_HANDLER(mfmsr, 0x1F, 0x13, 0x02, 0x001FF801, PPC_MISC)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVREG();
+ RET_PRIVREG(ctx);
#else
if (!ctx->supervisor) {
- RET_PRIVREG();
+ RET_PRIVREG(ctx);
+ return;
}
gen_op_load_msr();
gen_op_store_T0_gpr(rD(ctx->opcode));
#endif
}
+#if 0
+#define SPR_NOACCESS ((void *)(-1))
+#else
+static void spr_noaccess (void *opaque, int sprn)
+{
+ sprn = ((sprn >> 5) & 0x1F) | ((sprn & 0x1F) << 5);
+ printf("ERROR: try to access SPR %d !\n", sprn);
+}
+#define SPR_NOACCESS (&spr_noaccess)
+#endif
+
/* mfspr */
-GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC)
+static inline void gen_op_mfspr (DisasContext *ctx)
{
+ void (*read_cb)(void *opaque, int sprn);
uint32_t sprn = SPR(ctx->opcode);
-#if defined(CONFIG_USER_ONLY)
- switch (check_spr_access(sprn, 0, 0))
-#else
- switch (check_spr_access(sprn, 0, ctx->supervisor))
+#if !defined(CONFIG_USER_ONLY)
+ if (ctx->supervisor)
+ read_cb = ctx->spr_cb[sprn].oea_read;
+ else
#endif
- {
- case -1:
- RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR);
- break;
- case 0:
- RET_PRIVREG();
- break;
- default:
- break;
+ read_cb = ctx->spr_cb[sprn].uea_read;
+ if (read_cb != NULL) {
+ if (read_cb != SPR_NOACCESS) {
+ (*read_cb)(ctx, sprn);
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+ } else {
+ /* Privilege exception */
+ if (loglevel) {
+ fprintf(logfile, "Trying to read priviledged spr %d %03x\n",
+ sprn, sprn);
+ }
+ printf("Trying to read priviledged spr %d %03x\n", sprn, sprn);
+ RET_PRIVREG(ctx);
}
- switch (sprn) {
- case XER:
- gen_op_load_xer();
- break;
- case LR:
- gen_op_load_lr();
- break;
- case CTR:
- gen_op_load_ctr();
- break;
- case IBAT0U:
- gen_op_load_ibat(0, 0);
- break;
- case IBAT1U:
- gen_op_load_ibat(0, 1);
- break;
- case IBAT2U:
- gen_op_load_ibat(0, 2);
- break;
- case IBAT3U:
- gen_op_load_ibat(0, 3);
- break;
- case IBAT4U:
- gen_op_load_ibat(0, 4);
- break;
- case IBAT5U:
- gen_op_load_ibat(0, 5);
- break;
- case IBAT6U:
- gen_op_load_ibat(0, 6);
- break;
- case IBAT7U:
- gen_op_load_ibat(0, 7);
- break;
- case IBAT0L:
- gen_op_load_ibat(1, 0);
- break;
- case IBAT1L:
- gen_op_load_ibat(1, 1);
- break;
- case IBAT2L:
- gen_op_load_ibat(1, 2);
- break;
- case IBAT3L:
- gen_op_load_ibat(1, 3);
- break;
- case IBAT4L:
- gen_op_load_ibat(1, 4);
- break;
- case IBAT5L:
- gen_op_load_ibat(1, 5);
- break;
- case IBAT6L:
- gen_op_load_ibat(1, 6);
- break;
- case IBAT7L:
- gen_op_load_ibat(1, 7);
- break;
- case DBAT0U:
- gen_op_load_dbat(0, 0);
- break;
- case DBAT1U:
- gen_op_load_dbat(0, 1);
- break;
- case DBAT2U:
- gen_op_load_dbat(0, 2);
- break;
- case DBAT3U:
- gen_op_load_dbat(0, 3);
- break;
- case DBAT4U:
- gen_op_load_dbat(0, 4);
- break;
- case DBAT5U:
- gen_op_load_dbat(0, 5);
- break;
- case DBAT6U:
- gen_op_load_dbat(0, 6);
- break;
- case DBAT7U:
- gen_op_load_dbat(0, 7);
- break;
- case DBAT0L:
- gen_op_load_dbat(1, 0);
- break;
- case DBAT1L:
- gen_op_load_dbat(1, 1);
- break;
- case DBAT2L:
- gen_op_load_dbat(1, 2);
- break;
- case DBAT3L:
- gen_op_load_dbat(1, 3);
- break;
- case DBAT4L:
- gen_op_load_dbat(1, 4);
- break;
- case DBAT5L:
- gen_op_load_dbat(1, 5);
- break;
- case DBAT6L:
- gen_op_load_dbat(1, 6);
- break;
- case DBAT7L:
- gen_op_load_dbat(1, 7);
- break;
- case SDR1:
- gen_op_load_sdr1();
- break;
- case V_TBL:
- gen_op_update_tb(ctx->tb_offset);
- ctx->tb_offset = 0;
- /* TBL is still in T0 */
- break;
- case V_TBU:
- gen_op_update_tb(ctx->tb_offset);
- ctx->tb_offset = 0;
- gen_op_load_tb(1);
- break;
- case DECR:
- gen_op_update_decr(ctx->decr_offset);
- ctx->decr_offset = 0;
- /* decr is still in T0 */
- break;
- default:
- gen_op_load_spr(sprn);
- break;
+ } else {
+ /* Not defined */
+ if (loglevel) {
+ fprintf(logfile, "Trying to read invalid spr %d %03x\n",
+ sprn, sprn);
+ }
+ printf("Trying to read invalid spr %d %03x\n", sprn, sprn);
+ RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR);
}
- gen_op_store_T0_gpr(rD(ctx->opcode));
}
-/* mftb */
-GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_MISC)
+GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC)
{
- uint32_t sprn = SPR(ctx->opcode);
-
- /* We need to update the time base before reading it */
- switch (sprn) {
- case V_TBL:
- gen_op_update_tb(ctx->tb_offset);
- /* TBL is still in T0 */
- break;
- case V_TBU:
- gen_op_update_tb(ctx->tb_offset);
- gen_op_load_tb(1);
- break;
- default:
- RET_INVAL();
- break;
+ gen_op_mfspr(ctx);
}
- ctx->tb_offset = 0;
- gen_op_store_T0_gpr(rD(ctx->opcode));
+
+/* mftb */
+GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_TB)
+{
+ gen_op_mfspr(ctx);
}
/* mtcrf */
-GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00100801, PPC_MISC)
+/* The mask should be 0x00100801, but Mac OS X 10.4 use an alternate form */
+GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00000801, PPC_MISC)
{
gen_op_load_gpr_T0(rS(ctx->opcode));
gen_op_store_cr(CRM(ctx->opcode));
GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVREG();
+ RET_PRIVREG(ctx);
#else
if (!ctx->supervisor) {
- RET_PRIVREG();
+ RET_PRIVREG(ctx);
+ return;
}
+ gen_op_update_nip((ctx)->nip);
gen_op_load_gpr_T0(rS(ctx->opcode));
gen_op_store_msr();
/* Must stop the translation as machine state (may have) changed */
- ctx->exception = EXCP_MTMSR;
+ RET_CHG_FLOW(ctx);
#endif
}
/* mtspr */
GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC)
{
+ void (*write_cb)(void *opaque, int sprn);
uint32_t sprn = SPR(ctx->opcode);
-#if 0
- if (loglevel > 0) {
- fprintf(logfile, "MTSPR %d src=%d (%d)\n", SPR_ENCODE(sprn),
- rS(ctx->opcode), sprn);
- }
-#endif
-#if defined(CONFIG_USER_ONLY)
- switch (check_spr_access(sprn, 1, 0))
-#else
- switch (check_spr_access(sprn, 1, ctx->supervisor))
+#if !defined(CONFIG_USER_ONLY)
+ if (ctx->supervisor)
+ write_cb = ctx->spr_cb[sprn].oea_write;
+ else
#endif
- {
- case -1:
- RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR);
- break;
- case 0:
- RET_PRIVREG();
- break;
- default:
- break;
+ write_cb = ctx->spr_cb[sprn].uea_write;
+ if (write_cb != NULL) {
+ if (write_cb != SPR_NOACCESS) {
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ (*write_cb)(ctx, sprn);
+ } else {
+ /* Privilege exception */
+ if (loglevel) {
+ fprintf(logfile, "Trying to write priviledged spr %d %03x\n",
+ sprn, sprn);
+ }
+ printf("Trying to write priviledged spr %d %03x\n", sprn, sprn);
+ RET_PRIVREG(ctx);
}
- gen_op_load_gpr_T0(rS(ctx->opcode));
- switch (sprn) {
- case XER:
- gen_op_store_xer();
- break;
- case LR:
- gen_op_andi_(~0x03);
- gen_op_store_lr();
- break;
- case CTR:
- gen_op_store_ctr();
- break;
- case IBAT0U:
- gen_op_store_ibat(0, 0);
- gen_op_tlbia();
- break;
- case IBAT1U:
- gen_op_store_ibat(0, 1);
- gen_op_tlbia();
- break;
- case IBAT2U:
- gen_op_store_ibat(0, 2);
- gen_op_tlbia();
- break;
- case IBAT3U:
- gen_op_store_ibat(0, 3);
- gen_op_tlbia();
- break;
- case IBAT4U:
- gen_op_store_ibat(0, 4);
- gen_op_tlbia();
- break;
- case IBAT5U:
- gen_op_store_ibat(0, 5);
- gen_op_tlbia();
- break;
- case IBAT6U:
- gen_op_store_ibat(0, 6);
- gen_op_tlbia();
- break;
- case IBAT7U:
- gen_op_store_ibat(0, 7);
- gen_op_tlbia();
- break;
- case IBAT0L:
- gen_op_store_ibat(1, 0);
- gen_op_tlbia();
- break;
- case IBAT1L:
- gen_op_store_ibat(1, 1);
- gen_op_tlbia();
- break;
- case IBAT2L:
- gen_op_store_ibat(1, 2);
- gen_op_tlbia();
- break;
- case IBAT3L:
- gen_op_store_ibat(1, 3);
- gen_op_tlbia();
- break;
- case IBAT4L:
- gen_op_store_ibat(1, 4);
- gen_op_tlbia();
- break;
- case IBAT5L:
- gen_op_store_ibat(1, 5);
- gen_op_tlbia();
- break;
- case IBAT6L:
- gen_op_store_ibat(1, 6);
- gen_op_tlbia();
- break;
- case IBAT7L:
- gen_op_store_ibat(1, 7);
- gen_op_tlbia();
- break;
- case DBAT0U:
- gen_op_store_dbat(0, 0);
- gen_op_tlbia();
- break;
- case DBAT1U:
- gen_op_store_dbat(0, 1);
- gen_op_tlbia();
- break;
- case DBAT2U:
- gen_op_store_dbat(0, 2);
- gen_op_tlbia();
- break;
- case DBAT3U:
- gen_op_store_dbat(0, 3);
- gen_op_tlbia();
- break;
- case DBAT4U:
- gen_op_store_dbat(0, 4);
- gen_op_tlbia();
- break;
- case DBAT5U:
- gen_op_store_dbat(0, 5);
- gen_op_tlbia();
- break;
- case DBAT6U:
- gen_op_store_dbat(0, 6);
- gen_op_tlbia();
- break;
- case DBAT7U:
- gen_op_store_dbat(0, 7);
- gen_op_tlbia();
- break;
- case DBAT0L:
- gen_op_store_dbat(1, 0);
- gen_op_tlbia();
- break;
- case DBAT1L:
- gen_op_store_dbat(1, 1);
- gen_op_tlbia();
- break;
- case DBAT2L:
- gen_op_store_dbat(1, 2);
- gen_op_tlbia();
- break;
- case DBAT3L:
- gen_op_store_dbat(1, 3);
- gen_op_tlbia();
- break;
- case DBAT4L:
- gen_op_store_dbat(1, 4);
- gen_op_tlbia();
- break;
- case DBAT5L:
- gen_op_store_dbat(1, 5);
- gen_op_tlbia();
- break;
- case DBAT6L:
- gen_op_store_dbat(1, 6);
- gen_op_tlbia();
- break;
- case DBAT7L:
- gen_op_store_dbat(1, 7);
- gen_op_tlbia();
- break;
- case SDR1:
- gen_op_store_sdr1();
- gen_op_tlbia();
- break;
- case O_TBL:
- gen_op_store_tb(0);
- ctx->tb_offset = 0;
- break;
- case O_TBU:
- gen_op_store_tb(1);
- ctx->tb_offset = 0;
- break;
- case DECR:
- gen_op_store_decr();
- ctx->decr_offset = 0;
- break;
- default:
- gen_op_store_spr(sprn);
- break;
+ } else {
+ /* Not defined */
+ if (loglevel) {
+ fprintf(logfile, "Trying to write invalid spr %d %03x\n",
+ sprn, sprn);
+ }
+ printf("Trying to write invalid spr %d %03x\n", sprn, sprn);
+ RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR);
}
}
GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC();
+ RET_PRIVOPC(ctx);
#else
if (!ctx->supervisor) {
- RET_PRIVOPC();
+ RET_PRIVOPC(ctx);
+ return;
}
if (rA(ctx->opcode) == 0) {
gen_op_load_gpr_T0(rB(ctx->opcode));
#define op_dcbz() (*gen_op_dcbz[ctx->mem_idx])()
static GenOpFunc *gen_op_dcbz[] = {
&gen_op_dcbz_user,
+ &gen_op_dcbz_user,
+ &gen_op_dcbz_kernel,
&gen_op_dcbz_kernel,
};
#endif
gen_op_add();
}
op_dcbz();
+ gen_op_check_reservation();
}
/* icbi */
/* Optional: */
/* dcba */
-GEN_HANDLER(dcba, 0x1F, 0x16, 0x07, 0x03E00001, PPC_CACHE_OPT)
+GEN_HANDLER(dcba, 0x1F, 0x16, 0x17, 0x03E00001, PPC_CACHE_OPT)
{
}
GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVREG();
+ RET_PRIVREG(ctx);
#else
if (!ctx->supervisor) {
- RET_PRIVREG();
+ RET_PRIVREG(ctx);
+ return;
}
gen_op_load_sr(SR(ctx->opcode));
gen_op_store_T0_gpr(rD(ctx->opcode));
GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVREG();
+ RET_PRIVREG(ctx);
#else
if (!ctx->supervisor) {
- RET_PRIVREG();
+ RET_PRIVREG(ctx);
+ return;
}
gen_op_load_gpr_T1(rB(ctx->opcode));
gen_op_load_srin();
}
/* mtsr */
-GEN_HANDLER(mtsr, 0x1F, 0x12, 0x02, 0x0010F801, PPC_SEGMENT)
+GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVREG();
+ RET_PRIVREG(ctx);
#else
if (!ctx->supervisor) {
- RET_PRIVREG();
+ RET_PRIVREG(ctx);
+ return;
}
gen_op_load_gpr_T0(rS(ctx->opcode));
gen_op_store_sr(SR(ctx->opcode));
- gen_op_tlbia();
+ RET_STOP(ctx);
#endif
}
GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVREG();
+ RET_PRIVREG(ctx);
#else
if (!ctx->supervisor) {
- RET_PRIVREG();
+ RET_PRIVREG(ctx);
+ return;
}
gen_op_load_gpr_T0(rS(ctx->opcode));
gen_op_load_gpr_T1(rB(ctx->opcode));
gen_op_store_srin();
- gen_op_tlbia();
+ RET_STOP(ctx);
#endif
}
/*** Lookaside buffer management ***/
/* Optional & supervisor only: */
/* tlbia */
-GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_OPT)
+GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC();
+ RET_PRIVOPC(ctx);
#else
if (!ctx->supervisor) {
- RET_PRIVOPC();
+ if (loglevel)
+ fprintf(logfile, "%s: ! supervisor\n", __func__);
+ RET_PRIVOPC(ctx);
+ return;
}
gen_op_tlbia();
+ RET_STOP(ctx);
#endif
}
GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC();
+ RET_PRIVOPC(ctx);
#else
if (!ctx->supervisor) {
- RET_PRIVOPC();
+ RET_PRIVOPC(ctx);
+ return;
}
gen_op_load_gpr_T0(rB(ctx->opcode));
gen_op_tlbie();
+ RET_STOP(ctx);
#endif
}
/* tlbsync */
-GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFFC01, PPC_MEM)
+GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC();
+ RET_PRIVOPC(ctx);
#else
if (!ctx->supervisor) {
- RET_PRIVOPC();
+ RET_PRIVOPC(ctx);
+ return;
}
/* This has no effect: it should ensure that all previous
* tlbie have completed
*/
+ RET_STOP(ctx);
#endif
}
/*** External control ***/
/* Optional: */
-/* eciwx */
-#if defined(CONFIG_USER_ONLY)
-#define op_eciwx() gen_op_eciwx_raw()
-#define op_ecowx() gen_op_ecowx_raw()
-#else
#define op_eciwx() (*gen_op_eciwx[ctx->mem_idx])()
#define op_ecowx() (*gen_op_ecowx[ctx->mem_idx])()
+#if defined(CONFIG_USER_ONLY)
+static GenOpFunc *gen_op_eciwx[] = {
+ &gen_op_eciwx_raw,
+ &gen_op_eciwx_le_raw,
+};
+static GenOpFunc *gen_op_ecowx[] = {
+ &gen_op_ecowx_raw,
+ &gen_op_ecowx_le_raw,
+};
+#else
static GenOpFunc *gen_op_eciwx[] = {
&gen_op_eciwx_user,
+ &gen_op_eciwx_le_user,
&gen_op_eciwx_kernel,
+ &gen_op_eciwx_le_kernel,
};
static GenOpFunc *gen_op_ecowx[] = {
&gen_op_ecowx_user,
+ &gen_op_ecowx_le_user,
&gen_op_ecowx_kernel,
+ &gen_op_ecowx_le_kernel,
};
#endif
+/* eciwx */
GEN_HANDLER(eciwx, 0x1F, 0x16, 0x0D, 0x00000001, PPC_EXTERN)
{
/* Should check EAR[E] & alignment ! */
/* End opcode list */
GEN_OPCODE_MARK(end);
-/*****************************************************************************/
-#include <stdlib.h>
-#include <string.h>
-
-int fflush (FILE *stream);
-
-/* Main ppc opcodes table:
- * at init, all opcodes are invalids
- */
-static opc_handler_t *ppc_opcodes[0x40];
-
-/* Opcode types */
-enum {
- PPC_DIRECT = 0, /* Opcode routine */
- PPC_INDIRECT = 1, /* Indirect opcode table */
-};
-
-static inline int is_indirect_opcode (void *handler)
-{
- return ((unsigned long)handler & 0x03) == PPC_INDIRECT;
-}
-
-static inline opc_handler_t **ind_table(void *handler)
-{
- return (opc_handler_t **)((unsigned long)handler & ~3);
-}
-
-/* Instruction table creation */
-/* Opcodes tables creation */
-static void fill_new_table (opc_handler_t **table, int len)
-{
- int i;
-
- for (i = 0; i < len; i++)
- table[i] = &invalid_handler;
-}
-
-static int create_new_table (opc_handler_t **table, unsigned char idx)
-{
- opc_handler_t **tmp;
-
- tmp = malloc(0x20 * sizeof(opc_handler_t));
- if (tmp == NULL)
- return -1;
- fill_new_table(tmp, 0x20);
- table[idx] = (opc_handler_t *)((unsigned long)tmp | PPC_INDIRECT);
-
- return 0;
-}
-
-static int insert_in_table (opc_handler_t **table, unsigned char idx,
- opc_handler_t *handler)
-{
- if (table[idx] != &invalid_handler)
- return -1;
- table[idx] = handler;
-
- return 0;
-}
-
-static int register_direct_insn (opc_handler_t **ppc_opcodes,
- unsigned char idx, opc_handler_t *handler)
-{
- if (insert_in_table(ppc_opcodes, idx, handler) < 0) {
- printf("*** ERROR: opcode %02x already assigned in main "
- "opcode table\n", idx);
- return -1;
- }
-
- return 0;
-}
-
-static int register_ind_in_table (opc_handler_t **table,
- unsigned char idx1, unsigned char idx2,
- opc_handler_t *handler)
-{
- if (table[idx1] == &invalid_handler) {
- if (create_new_table(table, idx1) < 0) {
- printf("*** ERROR: unable to create indirect table "
- "idx=%02x\n", idx1);
- return -1;
- }
- } else {
- if (!is_indirect_opcode(table[idx1])) {
- printf("*** ERROR: idx %02x already assigned to a direct "
- "opcode\n", idx1);
- return -1;
- }
- }
- if (handler != NULL &&
- insert_in_table(ind_table(table[idx1]), idx2, handler) < 0) {
- printf("*** ERROR: opcode %02x already assigned in "
- "opcode table %02x\n", idx2, idx1);
- return -1;
- }
-
- return 0;
-}
-
-static int register_ind_insn (opc_handler_t **ppc_opcodes,
- unsigned char idx1, unsigned char idx2,
- opc_handler_t *handler)
-{
- int ret;
-
- ret = register_ind_in_table(ppc_opcodes, idx1, idx2, handler);
-
- return ret;
-}
-
-static int register_dblind_insn (opc_handler_t **ppc_opcodes,
- unsigned char idx1, unsigned char idx2,
- unsigned char idx3, opc_handler_t *handler)
-{
- if (register_ind_in_table(ppc_opcodes, idx1, idx2, NULL) < 0) {
- printf("*** ERROR: unable to join indirect table idx "
- "[%02x-%02x]\n", idx1, idx2);
- return -1;
- }
- if (register_ind_in_table(ind_table(ppc_opcodes[idx1]), idx2, idx3,
- handler) < 0) {
- printf("*** ERROR: unable to insert opcode "
- "[%02x-%02x-%02x]\n", idx1, idx2, idx3);
- return -1;
- }
-
- return 0;
-}
-
-static int register_insn (opc_handler_t **ppc_opcodes, opcode_t *insn)
-{
- if (insn->opc2 != 0xFF) {
- if (insn->opc3 != 0xFF) {
- if (register_dblind_insn(ppc_opcodes, insn->opc1, insn->opc2,
- insn->opc3, &insn->handler) < 0)
- return -1;
- } else {
- if (register_ind_insn(ppc_opcodes, insn->opc1,
- insn->opc2, &insn->handler) < 0)
- return -1;
- }
- } else {
- if (register_direct_insn(ppc_opcodes, insn->opc1, &insn->handler) < 0)
- return -1;
- }
-
- return 0;
-}
-
-static int test_opcode_table (opc_handler_t **table, int len)
-{
- int i, count, tmp;
-
- for (i = 0, count = 0; i < len; i++) {
- /* Consistency fixup */
- if (table[i] == NULL)
- table[i] = &invalid_handler;
- if (table[i] != &invalid_handler) {
- if (is_indirect_opcode(table[i])) {
- tmp = test_opcode_table(ind_table(table[i]), 0x20);
- if (tmp == 0) {
- free(table[i]);
- table[i] = &invalid_handler;
- } else {
- count++;
- }
- } else {
- count++;
- }
- }
- }
-
- return count;
-}
-
-static void fix_opcode_tables (opc_handler_t **ppc_opcodes)
-{
- if (test_opcode_table(ppc_opcodes, 0x40) == 0)
- printf("*** WARNING: no opcode defined !\n");
-}
-
-#define SPR_RIGHTS(rw, priv) (1 << ((2 * (priv)) + (rw)))
-#define SPR_UR SPR_RIGHTS(0, 0)
-#define SPR_UW SPR_RIGHTS(1, 0)
-#define SPR_SR SPR_RIGHTS(0, 1)
-#define SPR_SW SPR_RIGHTS(1, 1)
-
-#define spr_set_rights(spr, rights) \
-do { \
- spr_access[(spr) >> 1] |= ((rights) << (4 * ((spr) & 1))); \
-} while (0)
-
-static void init_spr_rights (uint32_t pvr)
-{
- /* XER (SPR 1) */
- spr_set_rights(XER, SPR_UR | SPR_UW | SPR_SR | SPR_SW);
- /* LR (SPR 8) */
- spr_set_rights(LR, SPR_UR | SPR_UW | SPR_SR | SPR_SW);
- /* CTR (SPR 9) */
- spr_set_rights(CTR, SPR_UR | SPR_UW | SPR_SR | SPR_SW);
- /* TBL (SPR 268) */
- spr_set_rights(V_TBL, SPR_UR | SPR_SR);
- /* TBU (SPR 269) */
- spr_set_rights(V_TBU, SPR_UR | SPR_SR);
- /* DSISR (SPR 18) */
- spr_set_rights(DSISR, SPR_SR | SPR_SW);
- /* DAR (SPR 19) */
- spr_set_rights(DAR, SPR_SR | SPR_SW);
- /* DEC (SPR 22) */
- spr_set_rights(DECR, SPR_SR | SPR_SW);
- /* SDR1 (SPR 25) */
- spr_set_rights(SDR1, SPR_SR | SPR_SW);
- /* SRR0 (SPR 26) */
- spr_set_rights(SRR0, SPR_SR | SPR_SW);
- /* SRR1 (SPR 27) */
- spr_set_rights(SRR1, SPR_SR | SPR_SW);
- /* SPRG0 (SPR 272) */
- spr_set_rights(SPRG0, SPR_SR | SPR_SW);
- /* SPRG1 (SPR 273) */
- spr_set_rights(SPRG1, SPR_SR | SPR_SW);
- /* SPRG2 (SPR 274) */
- spr_set_rights(SPRG2, SPR_SR | SPR_SW);
- /* SPRG3 (SPR 275) */
- spr_set_rights(SPRG3, SPR_SR | SPR_SW);
- /* ASR (SPR 280) */
- spr_set_rights(ASR, SPR_SR | SPR_SW);
- /* EAR (SPR 282) */
- spr_set_rights(EAR, SPR_SR | SPR_SW);
- /* TBL (SPR 284) */
- spr_set_rights(O_TBL, SPR_SW);
- /* TBU (SPR 285) */
- spr_set_rights(O_TBU, SPR_SW);
- /* PVR (SPR 287) */
- spr_set_rights(PVR, SPR_SR);
- /* IBAT0U (SPR 528) */
- spr_set_rights(IBAT0U, SPR_SR | SPR_SW);
- /* IBAT0L (SPR 529) */
- spr_set_rights(IBAT0L, SPR_SR | SPR_SW);
- /* IBAT1U (SPR 530) */
- spr_set_rights(IBAT1U, SPR_SR | SPR_SW);
- /* IBAT1L (SPR 531) */
- spr_set_rights(IBAT1L, SPR_SR | SPR_SW);
- /* IBAT2U (SPR 532) */
- spr_set_rights(IBAT2U, SPR_SR | SPR_SW);
- /* IBAT2L (SPR 533) */
- spr_set_rights(IBAT2L, SPR_SR | SPR_SW);
- /* IBAT3U (SPR 534) */
- spr_set_rights(IBAT3U, SPR_SR | SPR_SW);
- /* IBAT3L (SPR 535) */
- spr_set_rights(IBAT3L, SPR_SR | SPR_SW);
- /* DBAT0U (SPR 536) */
- spr_set_rights(DBAT0U, SPR_SR | SPR_SW);
- /* DBAT0L (SPR 537) */
- spr_set_rights(DBAT0L, SPR_SR | SPR_SW);
- /* DBAT1U (SPR 538) */
- spr_set_rights(DBAT1U, SPR_SR | SPR_SW);
- /* DBAT1L (SPR 539) */
- spr_set_rights(DBAT1L, SPR_SR | SPR_SW);
- /* DBAT2U (SPR 540) */
- spr_set_rights(DBAT2U, SPR_SR | SPR_SW);
- /* DBAT2L (SPR 541) */
- spr_set_rights(DBAT2L, SPR_SR | SPR_SW);
- /* DBAT3U (SPR 542) */
- spr_set_rights(DBAT3U, SPR_SR | SPR_SW);
- /* DBAT3L (SPR 543) */
- spr_set_rights(DBAT3L, SPR_SR | SPR_SW);
- /* DABR (SPR 1013) */
- spr_set_rights(DABR, SPR_SR | SPR_SW);
- /* FPECR (SPR 1022) */
- spr_set_rights(FPECR, SPR_SR | SPR_SW);
- /* PIR (SPR 1023) */
- spr_set_rights(PIR, SPR_SR | SPR_SW);
- /* Special registers for MPC740/745/750/755 (aka G3) & IBM 750 */
- if ((pvr & 0xFFFF0000) == 0x00080000 ||
- (pvr & 0xFFFF0000) == 0x70000000) {
- /* HID0 */
- spr_set_rights(SPR_ENCODE(1008), SPR_SR | SPR_SW);
- /* HID1 */
- spr_set_rights(SPR_ENCODE(1009), SPR_SR | SPR_SW);
- /* IABR */
- spr_set_rights(SPR_ENCODE(1010), SPR_SR | SPR_SW);
- /* ICTC */
- spr_set_rights(SPR_ENCODE(1019), SPR_SR | SPR_SW);
- /* L2CR */
- spr_set_rights(SPR_ENCODE(1017), SPR_SR | SPR_SW);
- /* MMCR0 */
- spr_set_rights(SPR_ENCODE(952), SPR_SR | SPR_SW);
- /* MMCR1 */
- spr_set_rights(SPR_ENCODE(956), SPR_SR | SPR_SW);
- /* PMC1 */
- spr_set_rights(SPR_ENCODE(953), SPR_SR | SPR_SW);
- /* PMC2 */
- spr_set_rights(SPR_ENCODE(954), SPR_SR | SPR_SW);
- /* PMC3 */
- spr_set_rights(SPR_ENCODE(957), SPR_SR | SPR_SW);
- /* PMC4 */
- spr_set_rights(SPR_ENCODE(958), SPR_SR | SPR_SW);
- /* SIA */
- spr_set_rights(SPR_ENCODE(955), SPR_SR | SPR_SW);
- /* THRM1 */
- spr_set_rights(SPR_ENCODE(1020), SPR_SR | SPR_SW);
- /* THRM2 */
- spr_set_rights(SPR_ENCODE(1021), SPR_SR | SPR_SW);
- /* THRM3 */
- spr_set_rights(SPR_ENCODE(1022), SPR_SR | SPR_SW);
- /* UMMCR0 */
- spr_set_rights(SPR_ENCODE(936), SPR_UR | SPR_UW);
- /* UMMCR1 */
- spr_set_rights(SPR_ENCODE(940), SPR_UR | SPR_UW);
- /* UPMC1 */
- spr_set_rights(SPR_ENCODE(937), SPR_UR | SPR_UW);
- /* UPMC2 */
- spr_set_rights(SPR_ENCODE(938), SPR_UR | SPR_UW);
- /* UPMC3 */
- spr_set_rights(SPR_ENCODE(941), SPR_UR | SPR_UW);
- /* UPMC4 */
- spr_set_rights(SPR_ENCODE(942), SPR_UR | SPR_UW);
- /* USIA */
- spr_set_rights(SPR_ENCODE(939), SPR_UR | SPR_UW);
- }
- /* MPC755 has special registers */
- if (pvr == 0x00083100) {
- /* SPRG4 */
- spr_set_rights(SPRG4, SPR_SR | SPR_SW);
- /* SPRG5 */
- spr_set_rights(SPRG5, SPR_SR | SPR_SW);
- /* SPRG6 */
- spr_set_rights(SPRG6, SPR_SR | SPR_SW);
- /* SPRG7 */
- spr_set_rights(SPRG7, SPR_SR | SPR_SW);
- /* IBAT4U */
- spr_set_rights(IBAT4U, SPR_SR | SPR_SW);
- /* IBAT4L */
- spr_set_rights(IBAT4L, SPR_SR | SPR_SW);
- /* IBAT5U */
- spr_set_rights(IBAT5U, SPR_SR | SPR_SW);
- /* IBAT5L */
- spr_set_rights(IBAT5L, SPR_SR | SPR_SW);
- /* IBAT6U */
- spr_set_rights(IBAT6U, SPR_SR | SPR_SW);
- /* IBAT6L */
- spr_set_rights(IBAT6L, SPR_SR | SPR_SW);
- /* IBAT7U */
- spr_set_rights(IBAT7U, SPR_SR | SPR_SW);
- /* IBAT7L */
- spr_set_rights(IBAT7L, SPR_SR | SPR_SW);
- /* DBAT4U */
- spr_set_rights(DBAT4U, SPR_SR | SPR_SW);
- /* DBAT4L */
- spr_set_rights(DBAT4L, SPR_SR | SPR_SW);
- /* DBAT5U */
- spr_set_rights(DBAT5U, SPR_SR | SPR_SW);
- /* DBAT5L */
- spr_set_rights(DBAT5L, SPR_SR | SPR_SW);
- /* DBAT6U */
- spr_set_rights(DBAT6U, SPR_SR | SPR_SW);
- /* DBAT6L */
- spr_set_rights(DBAT6L, SPR_SR | SPR_SW);
- /* DBAT7U */
- spr_set_rights(DBAT7U, SPR_SR | SPR_SW);
- /* DBAT7L */
- spr_set_rights(DBAT7L, SPR_SR | SPR_SW);
- /* DMISS */
- spr_set_rights(SPR_ENCODE(976), SPR_SR | SPR_SW);
- /* DCMP */
- spr_set_rights(SPR_ENCODE(977), SPR_SR | SPR_SW);
- /* DHASH1 */
- spr_set_rights(SPR_ENCODE(978), SPR_SR | SPR_SW);
- /* DHASH2 */
- spr_set_rights(SPR_ENCODE(979), SPR_SR | SPR_SW);
- /* IMISS */
- spr_set_rights(SPR_ENCODE(980), SPR_SR | SPR_SW);
- /* ICMP */
- spr_set_rights(SPR_ENCODE(981), SPR_SR | SPR_SW);
- /* RPA */
- spr_set_rights(SPR_ENCODE(982), SPR_SR | SPR_SW);
- /* HID2 */
- spr_set_rights(SPR_ENCODE(1011), SPR_SR | SPR_SW);
- /* L2PM */
- spr_set_rights(SPR_ENCODE(1016), SPR_SR | SPR_SW);
- }
-}
-
-/*****************************************************************************/
-/* PPC "main stream" common instructions (no optional ones) */
-
-typedef struct ppc_proc_t {
- int flags;
- void *specific;
-} ppc_proc_t;
-
-typedef struct ppc_def_t {
- unsigned long pvr;
- unsigned long pvr_mask;
- ppc_proc_t *proc;
-} ppc_def_t;
-
-static ppc_proc_t ppc_proc_common = {
- .flags = PPC_COMMON,
- .specific = NULL,
-};
-
-static ppc_proc_t ppc_proc_G3 = {
- .flags = PPC_750,
- .specific = NULL,
-};
-
-static ppc_def_t ppc_defs[] =
-{
- /* MPC740/745/750/755 (G3) */
- {
- .pvr = 0x00080000,
- .pvr_mask = 0xFFFF0000,
- .proc = &ppc_proc_G3,
- },
- /* IBM 750FX (G3 embedded) */
- {
- .pvr = 0x70000000,
- .pvr_mask = 0xFFFF0000,
- .proc = &ppc_proc_G3,
- },
- /* Fallback (generic PPC) */
- {
- .pvr = 0x00000000,
- .pvr_mask = 0x00000000,
- .proc = &ppc_proc_common,
- },
-};
-
-static int create_ppc_proc (opc_handler_t **ppc_opcodes, unsigned long pvr)
-{
- opcode_t *opc;
- int i, flags;
-
- fill_new_table(ppc_opcodes, 0x40);
- for (i = 0; ; i++) {
- if ((ppc_defs[i].pvr & ppc_defs[i].pvr_mask) ==
- (pvr & ppc_defs[i].pvr_mask)) {
- flags = ppc_defs[i].proc->flags;
- break;
- }
- }
-
- for (opc = &opc_start + 1; opc != &opc_end; opc++) {
- if ((opc->handler.type & flags) != 0)
- if (register_insn(ppc_opcodes, opc) < 0) {
- printf("*** ERROR initializing PPC instruction "
- "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2,
- opc->opc3);
- return -1;
- }
- }
- fix_opcode_tables(ppc_opcodes);
-
- return 0;
-}
-
+#include "translate_init.c"
/*****************************************************************************/
-/* Misc PPC helpers */
-FILE *stdout;
+/* Misc PowerPC helpers */
+void cpu_dump_state(CPUState *env, FILE *f,
+ int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+ int flags)
+{
+#if defined(TARGET_PPC64) || 1
+#define FILL ""
+#define REGX "%016llx"
+#define RGPL 4
+#define RFPL 4
+#else
+#define FILL " "
+#define REGX "%08llx"
+#define RGPL 8
+#define RFPL 4
+#endif
-void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags)
-{
int i;
- fprintf(f, "nip=0x%08x LR=0x%08x CTR=0x%08x XER=0x%08x "
- "MSR=0x%08x\n", env->nip, env->lr, env->ctr,
- _load_xer(env), _load_msr(env));
+ cpu_fprintf(f, "NIP " REGX " LR " REGX " CTR " REGX "\n",
+ env->nip, env->lr, env->ctr);
+ cpu_fprintf(f, "MSR " REGX FILL " XER %08x TB %08x %08x DECR %08x\n",
+ do_load_msr(env), do_load_xer(env), cpu_ppc_load_tbu(env),
+ cpu_ppc_load_tbl(env), cpu_ppc_load_decr(env));
for (i = 0; i < 32; i++) {
- if ((i & 7) == 0)
- fprintf(f, "GPR%02d:", i);
- fprintf(f, " %08x", env->gpr[i]);
- if ((i & 7) == 7)
- fprintf(f, "\n");
+ if ((i & (RGPL - 1)) == 0)
+ cpu_fprintf(f, "GPR%02d", i);
+ cpu_fprintf(f, " " REGX, env->gpr[i]);
+ if ((i & (RGPL - 1)) == (RGPL - 1))
+ cpu_fprintf(f, "\n");
}
- fprintf(f, "CR: 0x");
+ cpu_fprintf(f, "CR ");
for (i = 0; i < 8; i++)
- fprintf(f, "%01x", env->crf[i]);
- fprintf(f, " [");
+ cpu_fprintf(f, "%01x", env->crf[i]);
+ cpu_fprintf(f, " [");
for (i = 0; i < 8; i++) {
char a = '-';
if (env->crf[i] & 0x08)
a = 'G';
else if (env->crf[i] & 0x02)
a = 'E';
- fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' ');
+ cpu_fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' ');
}
- fprintf(f, " ] ");
- fprintf(f, "TB: 0x%08x %08x\n", env->tb[1], env->tb[0]);
- for (i = 0; i < 16; i++) {
- if ((i & 3) == 0)
- fprintf(f, "FPR%02d:", i);
- fprintf(f, " %016llx", *((uint64_t *)&env->fpr[i]));
- if ((i & 3) == 3)
- fprintf(f, "\n");
- }
- fprintf(f, "SRR0 0x%08x SRR1 0x%08x DECR=0x%08x excp:0x%08x\n",
- env->spr[SRR0], env->spr[SRR1], env->decr, env->exceptions);
- fprintf(f, "reservation 0x%08x\n", env->reserve);
- fflush(f);
-}
-
-#if !defined(CONFIG_USER_ONLY) && defined (USE_OPENFIRMWARE)
-int setup_machine (CPUPPCState *env, uint32_t mid);
-#endif
-
-CPUPPCState *cpu_ppc_init(void)
-{
- CPUPPCState *env;
-
- cpu_exec_init();
-
- env = malloc(sizeof(CPUPPCState));
- if (!env)
- return NULL;
- memset(env, 0, sizeof(CPUPPCState));
-#if !defined(CONFIG_USER_ONLY) && defined (USE_OPEN_FIRMWARE)
- setup_machine(env, 0);
-#else
-// env->spr[PVR] = 0; /* Basic PPC */
- env->spr[PVR] = 0x00080100; /* G3 CPU */
-// env->spr[PVR] = 0x00083100; /* MPC755 (G3 embedded) */
-// env->spr[PVR] = 0x00070100; /* IBM 750FX */
-#endif
- env->decr = 0xFFFFFFFF;
- if (create_ppc_proc(ppc_opcodes, env->spr[PVR]) < 0)
- return NULL;
- init_spr_rights(env->spr[PVR]);
- tlb_flush(env, 1);
-#if defined (DO_SINGLE_STEP)
- /* Single step trace mode */
- msr_se = 1;
-#endif
-#if defined(CONFIG_USER_ONLY)
- msr_pr = 1;
-#endif
- env->access_type = ACCESS_INT;
-
- return env;
-}
+ cpu_fprintf(f, " ] " FILL "RES " REGX "\n", env->reserve);
+ for (i = 0; i < 32; i++) {
+ if ((i & (RFPL - 1)) == 0)
+ cpu_fprintf(f, "FPR%02d", i);
+ cpu_fprintf(f, " %016llx", *((uint64_t *)&env->fpr[i]));
+ if ((i & (RFPL - 1)) == (RFPL - 1))
+ cpu_fprintf(f, "\n");
+ }
+ cpu_fprintf(f, "SRR0 " REGX " SRR1 " REGX " " FILL FILL FILL
+ "SDR1 " REGX "\n",
+ env->spr[SPR_SRR0], env->spr[SPR_SRR1], env->sdr1);
-void cpu_ppc_close(CPUPPCState *env)
-{
- /* Should also remove all opcode tables... */
- free(env);
+#undef REGX
+#undef RGPL
+#undef RFPL
+#undef FILL
}
/*****************************************************************************/
-void raise_exception_err (int exception_index, int error_code);
-int print_insn_powerpc (FILE *out, unsigned long insn, unsigned memaddr,
- int dialect);
-
int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
int search_pc)
{
- DisasContext ctx;
+ DisasContext ctx, *ctxp = &ctx;
opc_handler_t **table, *handler;
- uint32_t pc_start;
+ target_ulong pc_start;
uint16_t *gen_opc_end;
int j, lj = -1;
gen_opc_ptr = gen_opc_buf;
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
gen_opparam_ptr = gen_opparam_buf;
- ctx.nip = (uint32_t *)pc_start;
- ctx.tb_offset = 0;
- ctx.decr_offset = 0;
+ nb_gen_labels = 0;
+ ctx.nip = pc_start;
ctx.tb = tb;
ctx.exception = EXCP_NONE;
+ ctx.spr_cb = env->spr_cb;
#if defined(CONFIG_USER_ONLY)
- ctx.mem_idx = 0;
+ ctx.mem_idx = msr_le;
#else
ctx.supervisor = 1 - msr_pr;
- ctx.mem_idx = (1 - msr_pr);
+ ctx.mem_idx = ((1 - msr_pr) << 1) | msr_le;
#endif
-#if defined (DO_SINGLE_STEP)
+ ctx.fpu_enabled = msr_fp;
+#if defined (DO_SINGLE_STEP) && 0
/* Single step trace mode */
msr_se = 1;
#endif
- env->access_type = ACCESS_CODE;
/* Set env in case of segfault during code fetch */
while (ctx.exception == EXCP_NONE && gen_opc_ptr < gen_opc_end) {
if (search_pc) {
- if (loglevel > 0)
- fprintf(logfile, "Search PC...\n");
j = gen_opc_ptr - gen_opc_buf;
if (lj < j) {
lj++;
while (lj < j)
gen_opc_instr_start[lj++] = 0;
- gen_opc_pc[lj] = (uint32_t)ctx.nip;
+ gen_opc_pc[lj] = ctx.nip;
gen_opc_instr_start[lj] = 1;
}
}
-#if defined DEBUG_DISAS
- if (loglevel > 0) {
+#if defined PPC_DEBUG_DISAS
+ if (loglevel & CPU_LOG_TB_IN_ASM) {
fprintf(logfile, "----------------\n");
- fprintf(logfile, "nip=%p super=%d ir=%d\n",
+ fprintf(logfile, "nip=%08x super=%d ir=%d\n",
ctx.nip, 1 - msr_pr, msr_ir);
}
#endif
ctx.opcode = ldl_code(ctx.nip);
-#if defined DEBUG_DISAS
- if (loglevel > 0) {
- fprintf(logfile, "translate opcode %08x (%02x %02x %02x)\n",
+ if (msr_le) {
+ ctx.opcode = ((ctx.opcode & 0xFF000000) >> 24) |
+ ((ctx.opcode & 0x00FF0000) >> 8) |
+ ((ctx.opcode & 0x0000FF00) << 8) |
+ ((ctx.opcode & 0x000000FF) << 24);
+ }
+#if defined PPC_DEBUG_DISAS
+ if (loglevel & CPU_LOG_TB_IN_ASM) {
+ fprintf(logfile, "translate opcode %08x (%02x %02x %02x) (%s)\n",
ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode),
- opc3(ctx.opcode));
+ opc3(ctx.opcode), msr_le ? "little" : "big");
}
#endif
- ctx.nip++;
- ctx.tb_offset++;
- /* Check decrementer exception */
- if (++ctx.decr_offset == env->decr + 1)
- ctx.exception = EXCP_DECR;
- table = ppc_opcodes;
+ ctx.nip += 4;
+ table = env->opcodes;
handler = table[opc1(ctx.opcode)];
if (is_indirect_opcode(handler)) {
table = ind_table(handler);
}
}
/* Is opcode *REALLY* valid ? */
- if ((ctx.opcode & handler->inval) != 0) {
- if (loglevel > 0) {
if (handler->handler == &gen_invalid) {
+ if (loglevel > 0) {
fprintf(logfile, "invalid/unsupported opcode: "
- "%02x -%02x - %02x (%08x) %p\n",
+ "%02x - %02x - %02x (%08x) 0x%08x %d\n",
opc1(ctx.opcode), opc2(ctx.opcode),
- opc3(ctx.opcode), ctx.opcode, ctx.nip - 1);
+ opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir);
+ } else {
+ printf("invalid/unsupported opcode: "
+ "%02x - %02x - %02x (%08x) 0x%08x %d\n",
+ opc1(ctx.opcode), opc2(ctx.opcode),
+ opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir);
+ }
} else {
+ if ((ctx.opcode & handler->inval) != 0) {
+ if (loglevel > 0) {
fprintf(logfile, "invalid bits: %08x for opcode: "
- "%02x -%02x - %02x (0x%08x) (%p)\n",
+ "%02x -%02x - %02x (0x%08x) (0x%08x)\n",
ctx.opcode & handler->inval, opc1(ctx.opcode),
opc2(ctx.opcode), opc3(ctx.opcode),
- ctx.opcode, ctx.nip - 1);
- }
- } else {
- if (handler->handler == &gen_invalid) {
- printf("invalid/unsupported opcode: "
- "%02x -%02x - %02x (%08x) %p\n",
- opc1(ctx.opcode), opc2(ctx.opcode),
- opc3(ctx.opcode), ctx.opcode, ctx.nip - 1);
+ ctx.opcode, ctx.nip - 4);
} else {
printf("invalid bits: %08x for opcode: "
- "%02x -%02x - %02x (0x%08x) (%p)\n",
+ "%02x -%02x - %02x (0x%08x) (0x%08x)\n",
ctx.opcode & handler->inval, opc1(ctx.opcode),
opc2(ctx.opcode), opc3(ctx.opcode),
- ctx.opcode, ctx.nip - 1);
+ ctx.opcode, ctx.nip - 4);
}
+ RET_INVAL(ctxp);
+ break;
}
- (*gen_invalid)(&ctx);
- } else {
- (*(handler->handler))(&ctx);
}
+ (*(handler->handler))(&ctx);
/* Check trace mode exceptions */
if ((msr_be && ctx.exception == EXCP_BRANCH) ||
/* Check in single step trace mode
* - rfi, trap or syscall
* - first instruction of an exception handler
*/
- (msr_se && ((uint32_t)ctx.nip < 0x100 ||
- (uint32_t)ctx.nip > 0xF00 ||
- ((uint32_t)ctx.nip & 0xFC) != 0x04) &&
- ctx.exception != EXCP_SYSCALL && ctx.exception != EXCP_RFI &&
+ (msr_se && (ctx.nip < 0x100 ||
+ ctx.nip > 0xF00 ||
+ (ctx.nip & 0xFC) != 0x04) &&
+ ctx.exception != EXCP_SYSCALL &&
+ ctx.exception != EXCP_SYSCALL_USER &&
ctx.exception != EXCP_TRAP)) {
-#if !defined(CONFIG_USER_ONLY)
- gen_op_queue_exception(EXCP_TRACE);
-#endif
- if (ctx.exception == EXCP_NONE) {
- ctx.exception = EXCP_TRACE;
- }
+ RET_EXCP(ctxp, EXCP_TRACE, 0);
}
/* if we reach a page boundary, stop generation */
- if (((uint32_t)ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) {
- if (ctx.exception == EXCP_NONE) {
- gen_op_b((long)ctx.tb, (uint32_t)ctx.nip);
- ctx.exception = EXCP_BRANCH;
- }
+ if ((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) {
+ break;
}
+#if defined (DO_SINGLE_STEP)
+ break;
+#endif
}
- /* In case of branch, this has already been done *BEFORE* the branch */
- if (ctx.exception != EXCP_BRANCH && ctx.exception != EXCP_RFI) {
- gen_op_update_tb(ctx.tb_offset);
- gen_op_update_decr(ctx.decr_offset);
- gen_op_process_exceptions((uint32_t)ctx.nip);
+ if (ctx.exception == EXCP_NONE) {
+ gen_goto_tb(&ctx, 0, ctx.nip);
+ } else if (ctx.exception != EXCP_BRANCH) {
+ gen_op_set_T0(0);
}
#if 1
/* TO BE FIXED: T0 hasn't got a proper value, which makes tb_add_jump
}
#endif
} else {
- tb->size = (uint32_t)ctx.nip - pc_start;
+ tb->size = ctx.nip - pc_start;
}
- env->access_type = ACCESS_INT;
#ifdef DEBUG_DISAS
- if (loglevel > 0) {
+ if (loglevel & CPU_LOG_TB_CPU) {
fprintf(logfile, "---------------- excp: %04x\n", ctx.exception);
- cpu_ppc_dump_state(env, logfile, 0);
- fprintf(logfile, "IN: %s\n", lookup_symbol((void *)pc_start));
- disas(logfile, (void *)pc_start, (uint32_t)ctx.nip - pc_start, 0, 0);
+ cpu_dump_state(env, logfile, fprintf, 0);
+ }
+ if (loglevel & CPU_LOG_TB_IN_ASM) {
+ fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
+ target_disas(logfile, pc_start, ctx.nip - pc_start, msr_le);
fprintf(logfile, "\n");
-
+ }
+ if (loglevel & CPU_LOG_TB_OP) {
fprintf(logfile, "OP:\n");
dump_ops(gen_opc_buf, gen_opparam_buf);
fprintf(logfile, "\n");
}
#endif
-
return 0;
}