X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=target-ppc%2Ftranslate.c;h=e09e9a7fd1bee7d3b04553f2f339be0b4fdc6509;hb=6d463de2b3e261e95f224767605eef02acbd2701;hp=e410cb2d1f9bd3846914ef357d61e797dc191425;hpb=e63c59cb34fdad20f70c83dd4bfe938fb37433ab;p=qemu diff --git a/target-ppc/translate.c b/target-ppc/translate.c index e410cb2..e09e9a7 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -17,14 +17,18 @@ * 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 +#include +#include +#include +#include + #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 enum { #define DEF(s, n, copy_size) INDEX_op_ ## s, @@ -130,10 +134,6 @@ typedef struct DisasContext { uint32_t nip; uint32_t opcode; uint32_t exception; - /* Time base offset */ - uint32_t tb_offset; - /* Decrementer offset */ - uint32_t decr_offset; /* Execution mode */ #if !defined(CONFIG_USER_ONLY) int supervisor; @@ -151,21 +151,26 @@ typedef struct opc_handler_t { 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(ctx) \ +RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_OPC) -#define RET_PRIVOPC() \ -RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_OPC) +#define RET_PRIVREG(ctx) \ +RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG) -#define RET_PRIVREG() \ -RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG) +#define RET_MTMSR(ctx) \ +RET_EXCP((ctx), EXCP_MTMSR, 0) #define GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \ static void gen_##name (DisasContext *ctx); \ @@ -177,10 +182,6 @@ typedef struct opcode_t { opc_handler_t handler; } 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) \ @@ -307,29 +308,26 @@ GEN_OPCODE_MARK(start); /* Invalid instruction */ GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE) { - RET_INVAL(); + RET_INVAL(ctx); } /* Special opcode to stop emulation */ GEN_HANDLER(stop, 0x06, 0x00, 0xFF, 0x03FFFFC1, PPC_COMMON) { - gen_op_queue_exception(EXCP_HLT); - ctx->exception = EXCP_HLT; + RET_EXCP(ctx, EXCP_HLT, 0); } /* 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; + RET_EXCP(ctx, EXCP_OFCALL, 0); } /* 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_EXCP(ctx, EXCP_RTASCALL, 0); } static opc_handler_t invalid_handler = { @@ -639,7 +637,7 @@ GEN_HANDLER(xori, 0x1A, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) } 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)); } @@ -654,7 +652,7 @@ GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) } 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)); } @@ -682,25 +680,29 @@ GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) 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: @@ -1005,7 +1007,8 @@ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ 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) \ @@ -1020,7 +1023,8 @@ GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ { \ 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)); \ @@ -1081,7 +1085,8 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ { \ 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) \ @@ -1095,7 +1100,8 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ 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)); \ @@ -1231,7 +1237,8 @@ GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_INTEGER) 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); @@ -1263,12 +1270,16 @@ GEN_HANDLER(lswx, 0x1F, 0x15, 0x10, 0x00000001, PPC_INTEGER) /* 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); op_ldsts(stsw, rS(ctx->opcode)); } @@ -1371,7 +1382,8 @@ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ 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) \ @@ -1386,7 +1398,8 @@ GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ { \ 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)); \ @@ -1443,7 +1456,8 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ { \ 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) \ @@ -1457,7 +1471,8 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ 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)); \ @@ -1497,7 +1512,7 @@ GEN_STFS(fs, 0x14); /* stfiwx */ GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT) { - RET_INVAL(); + RET_INVAL(ctx); } /*** Branch ***/ @@ -1505,11 +1520,11 @@ GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT) /* 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(ctx->nip - 4); if (AA(ctx->opcode) == 0) target = ctx->nip + li - 4; else @@ -1533,10 +1548,6 @@ static inline void gen_bcond(DisasContext *ctx, int type) uint32_t mask; uint32_t li; - gen_op_update_tb(ctx->tb_offset); - gen_op_update_decr(ctx->decr_offset); - gen_op_process_exceptions(ctx->nip - 4); - if ((bo & 0x4) == 0) gen_op_dec_ctr(); switch(type) { @@ -1678,14 +1689,15 @@ GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER) 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_EXCP(ctx, EXCP_RFI, 0); #endif } @@ -1693,11 +1705,10 @@ GEN_HANDLER(rfi, 0x13, 0x12, 0xFF, 0x03FF8001, PPC_FLOW) 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 ***/ @@ -1765,10 +1776,11 @@ GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x001FF801, PPC_MISC) 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)); @@ -1787,11 +1799,11 @@ GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC) #endif { case -1: - RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR); - break; + RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR); + return; case 0: - RET_PRIVREG(); - break; + RET_PRIVREG(ctx); + return; default: break; } @@ -1905,19 +1917,13 @@ GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC) gen_op_load_sdr1(); break; case V_TBL: - gen_op_update_tb(ctx->tb_offset); - ctx->tb_offset = 0; - /* TBL is still in T0 */ + gen_op_load_tbl(); break; case V_TBU: - gen_op_update_tb(ctx->tb_offset); - ctx->tb_offset = 0; - gen_op_load_tb(1); + gen_op_load_tbu(); break; case DECR: - gen_op_update_decr(ctx->decr_offset); - ctx->decr_offset = 0; - /* decr is still in T0 */ + gen_op_load_decr(); break; default: gen_op_load_spr(sprn); @@ -1934,18 +1940,15 @@ GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_MISC) /* 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 */ + gen_op_load_tbl(); break; case V_TBU: - gen_op_update_tb(ctx->tb_offset); - gen_op_load_tb(1); + gen_op_load_tbu(); break; default: - RET_INVAL(); - break; + RET_INVAL(ctx); + return; } - ctx->tb_offset = 0; gen_op_store_T0_gpr(rD(ctx->opcode)); } @@ -1960,15 +1963,16 @@ GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00100801, PPC_MISC) 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_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_MTMSR(ctx); #endif } @@ -1990,10 +1994,10 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) #endif { case -1: - RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR); + RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR); break; case 0: - RET_PRIVREG(); + RET_PRIVREG(ctx); break; default: break; @@ -2011,148 +2015,150 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) break; case IBAT0U: gen_op_store_ibat(0, 0); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case IBAT1U: gen_op_store_ibat(0, 1); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case IBAT2U: gen_op_store_ibat(0, 2); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case IBAT3U: gen_op_store_ibat(0, 3); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case IBAT4U: gen_op_store_ibat(0, 4); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case IBAT5U: gen_op_store_ibat(0, 5); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case IBAT6U: gen_op_store_ibat(0, 6); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case IBAT7U: gen_op_store_ibat(0, 7); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case IBAT0L: gen_op_store_ibat(1, 0); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case IBAT1L: gen_op_store_ibat(1, 1); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case IBAT2L: gen_op_store_ibat(1, 2); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case IBAT3L: gen_op_store_ibat(1, 3); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case IBAT4L: gen_op_store_ibat(1, 4); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case IBAT5L: gen_op_store_ibat(1, 5); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case IBAT6L: gen_op_store_ibat(1, 6); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case IBAT7L: gen_op_store_ibat(1, 7); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case DBAT0U: gen_op_store_dbat(0, 0); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case DBAT1U: gen_op_store_dbat(0, 1); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case DBAT2U: gen_op_store_dbat(0, 2); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case DBAT3U: gen_op_store_dbat(0, 3); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case DBAT4U: gen_op_store_dbat(0, 4); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case DBAT5U: gen_op_store_dbat(0, 5); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case DBAT6U: gen_op_store_dbat(0, 6); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case DBAT7U: gen_op_store_dbat(0, 7); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case DBAT0L: gen_op_store_dbat(1, 0); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case DBAT1L: gen_op_store_dbat(1, 1); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case DBAT2L: gen_op_store_dbat(1, 2); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case DBAT3L: gen_op_store_dbat(1, 3); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case DBAT4L: gen_op_store_dbat(1, 4); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case DBAT5L: gen_op_store_dbat(1, 5); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case DBAT6L: gen_op_store_dbat(1, 6); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case DBAT7L: gen_op_store_dbat(1, 7); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case SDR1: gen_op_store_sdr1(); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case O_TBL: - gen_op_store_tb(0); - ctx->tb_offset = 0; + gen_op_store_tbl(); break; case O_TBU: - gen_op_store_tb(1); - ctx->tb_offset = 0; + gen_op_store_tbu(); break; case DECR: gen_op_store_decr(); - ctx->decr_offset = 0; break; +#if 0 + case HID0: + gen_op_store_hid0(); + break; +#endif default: gen_op_store_spr(sprn); break; @@ -2181,10 +2187,11 @@ GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03E00001, PPC_CACHE) 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)); @@ -2242,6 +2249,7 @@ GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_CACHE) gen_op_add(); } op_dcbz(); + gen_op_check_reservation(); } /* icbi */ @@ -2269,10 +2277,11 @@ GEN_HANDLER(dcba, 0x1F, 0x16, 0x07, 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)); @@ -2283,10 +2292,11 @@ GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT) 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(); @@ -2298,14 +2308,14 @@ GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, 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(); #endif } @@ -2313,15 +2323,15 @@ GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT) 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(); #endif } @@ -2331,12 +2341,16 @@ GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT) GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_OPT) { #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_MTMSR(ctx); #endif } @@ -2344,13 +2358,15 @@ GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_OPT) 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_MTMSR(ctx); #endif } @@ -2358,14 +2374,16 @@ GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, 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_MTMSR(ctx); #endif } @@ -2686,59 +2704,78 @@ static void init_spr_rights (uint32_t pvr) 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) */ + /* Special registers for PPC 604 */ + if ((pvr & 0xFFFF0000) == 0x00040000) { + /* IABR */ + spr_set_rights(IABR , SPR_SR | SPR_SW); + /* DABR (SPR 1013) */ + spr_set_rights(DABR, SPR_SR | SPR_SW); + /* HID0 */ + spr_set_rights(HID0, SPR_SR | SPR_SW); + /* PIR */ spr_set_rights(PIR, SPR_SR | SPR_SW); + /* PMC1 */ + spr_set_rights(PMC1, SPR_SR | SPR_SW); + /* PMC2 */ + spr_set_rights(PMC2, SPR_SR | SPR_SW); + /* MMCR0 */ + spr_set_rights(MMCR0, SPR_SR | SPR_SW); + /* SIA */ + spr_set_rights(SIA, SPR_SR | SPR_SW); + /* SDA */ + spr_set_rights(SDA, 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); + spr_set_rights(HID0, SPR_SR | SPR_SW); /* HID1 */ - spr_set_rights(SPR_ENCODE(1009), SPR_SR | SPR_SW); + spr_set_rights(HID1, SPR_SR | SPR_SW); /* IABR */ - spr_set_rights(SPR_ENCODE(1010), SPR_SR | SPR_SW); + spr_set_rights(IABR, SPR_SR | SPR_SW); /* ICTC */ - spr_set_rights(SPR_ENCODE(1019), SPR_SR | SPR_SW); + spr_set_rights(ICTC, SPR_SR | SPR_SW); /* L2CR */ - spr_set_rights(SPR_ENCODE(1017), SPR_SR | SPR_SW); + spr_set_rights(L2CR, SPR_SR | SPR_SW); /* MMCR0 */ - spr_set_rights(SPR_ENCODE(952), SPR_SR | SPR_SW); + spr_set_rights(MMCR0, SPR_SR | SPR_SW); /* MMCR1 */ - spr_set_rights(SPR_ENCODE(956), SPR_SR | SPR_SW); + spr_set_rights(MMCR1, SPR_SR | SPR_SW); /* PMC1 */ - spr_set_rights(SPR_ENCODE(953), SPR_SR | SPR_SW); + spr_set_rights(PMC1, SPR_SR | SPR_SW); /* PMC2 */ - spr_set_rights(SPR_ENCODE(954), SPR_SR | SPR_SW); + spr_set_rights(PMC2, SPR_SR | SPR_SW); /* PMC3 */ - spr_set_rights(SPR_ENCODE(957), SPR_SR | SPR_SW); + spr_set_rights(PMC3, SPR_SR | SPR_SW); /* PMC4 */ - spr_set_rights(SPR_ENCODE(958), SPR_SR | SPR_SW); + spr_set_rights(PMC4, SPR_SR | SPR_SW); /* SIA */ - spr_set_rights(SPR_ENCODE(955), SPR_SR | SPR_SW); + spr_set_rights(SIA, SPR_SR | SPR_SW); + /* SDA */ + spr_set_rights(SDA, SPR_SR | SPR_SW); /* THRM1 */ - spr_set_rights(SPR_ENCODE(1020), SPR_SR | SPR_SW); + spr_set_rights(THRM1, SPR_SR | SPR_SW); /* THRM2 */ - spr_set_rights(SPR_ENCODE(1021), SPR_SR | SPR_SW); + spr_set_rights(THRM2, SPR_SR | SPR_SW); /* THRM3 */ - spr_set_rights(SPR_ENCODE(1022), SPR_SR | SPR_SW); + spr_set_rights(THRM3, SPR_SR | SPR_SW); /* UMMCR0 */ - spr_set_rights(SPR_ENCODE(936), SPR_UR | SPR_UW); + spr_set_rights(UMMCR0, SPR_UR | SPR_UW); /* UMMCR1 */ - spr_set_rights(SPR_ENCODE(940), SPR_UR | SPR_UW); + spr_set_rights(UMMCR1, SPR_UR | SPR_UW); /* UPMC1 */ - spr_set_rights(SPR_ENCODE(937), SPR_UR | SPR_UW); + spr_set_rights(UPMC1, SPR_UR | SPR_UW); /* UPMC2 */ - spr_set_rights(SPR_ENCODE(938), SPR_UR | SPR_UW); + spr_set_rights(UPMC2, SPR_UR | SPR_UW); /* UPMC3 */ - spr_set_rights(SPR_ENCODE(941), SPR_UR | SPR_UW); + spr_set_rights(UPMC3, SPR_UR | SPR_UW); /* UPMC4 */ - spr_set_rights(SPR_ENCODE(942), SPR_UR | SPR_UW); + spr_set_rights(UPMC4, SPR_UR | SPR_UW); /* USIA */ - spr_set_rights(SPR_ENCODE(939), SPR_UR | SPR_UW); + spr_set_rights(USIA, SPR_UR | SPR_UW); } /* MPC755 has special registers */ if (pvr == 0x00083100) { @@ -2783,23 +2820,23 @@ static void init_spr_rights (uint32_t pvr) /* DBAT7L */ spr_set_rights(DBAT7L, SPR_SR | SPR_SW); /* DMISS */ - spr_set_rights(SPR_ENCODE(976), SPR_SR | SPR_SW); + spr_set_rights(DMISS, SPR_SR | SPR_SW); /* DCMP */ - spr_set_rights(SPR_ENCODE(977), SPR_SR | SPR_SW); + spr_set_rights(DCMP, SPR_SR | SPR_SW); /* DHASH1 */ - spr_set_rights(SPR_ENCODE(978), SPR_SR | SPR_SW); + spr_set_rights(DHASH1, SPR_SR | SPR_SW); /* DHASH2 */ - spr_set_rights(SPR_ENCODE(979), SPR_SR | SPR_SW); + spr_set_rights(DHASH2, SPR_SR | SPR_SW); /* IMISS */ - spr_set_rights(SPR_ENCODE(980), SPR_SR | SPR_SW); + spr_set_rights(IMISS, SPR_SR | SPR_SW); /* ICMP */ - spr_set_rights(SPR_ENCODE(981), SPR_SR | SPR_SW); + spr_set_rights(ICMP, SPR_SR | SPR_SW); /* RPA */ - spr_set_rights(SPR_ENCODE(982), SPR_SR | SPR_SW); + spr_set_rights(RPA, SPR_SR | SPR_SW); /* HID2 */ - spr_set_rights(SPR_ENCODE(1011), SPR_SR | SPR_SW); + spr_set_rights(HID2, SPR_SR | SPR_SW); /* L2PM */ - spr_set_rights(SPR_ENCODE(1016), SPR_SR | SPR_SW); + spr_set_rights(L2PM, SPR_SR | SPR_SW); } } @@ -2880,7 +2917,6 @@ static int create_ppc_proc (opc_handler_t **ppc_opcodes, unsigned long pvr) /*****************************************************************************/ /* Misc PPC helpers */ -FILE *stdout; void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags) { @@ -2911,7 +2947,8 @@ void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags) 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]); + fprintf(f, "TB: 0x%08x %08x\n", cpu_ppc_load_tbu(env), + cpu_ppc_load_tbl(env)); for (i = 0; i < 16; i++) { if ((i & 3) == 0) fprintf(f, "FPR%02d:", i); @@ -2919,8 +2956,8 @@ void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags) 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, "SRR0 0x%08x SRR1 0x%08x DECR=0x%08x\n", + env->spr[SRR0], env->spr[SRR1], cpu_ppc_load_decr(env)); fprintf(f, "reservation 0x%08x\n", env->reserve); fflush(f); } @@ -2935,10 +2972,9 @@ CPUPPCState *cpu_ppc_init(void) cpu_exec_init(); - env = malloc(sizeof(CPUPPCState)); + env = qemu_mallocz(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 @@ -2947,23 +2983,34 @@ CPUPPCState *cpu_ppc_init(void) // 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 + msr_fp = 1; /* Allow floating point exceptions */ + msr_me = 1; /* Allow machine check exceptions */ #if defined(CONFIG_USER_ONLY) msr_pr = 1; + cpu_ppc_register(env, 0x00080000); +#else + env->nip = 0xFFFFFFFC; #endif env->access_type = ACCESS_INT; - + cpu_single_env = env; return env; } +int cpu_ppc_register (CPUPPCState *env, uint32_t pvr) +{ + env->spr[PVR] = pvr; + if (create_ppc_proc(ppc_opcodes, env->spr[PVR]) < 0) + return -1; + init_spr_rights(env->spr[PVR]); + + return 0; +} + void cpu_ppc_close(CPUPPCState *env) { /* Should also remove all opcode tables... */ @@ -2971,14 +3018,13 @@ void cpu_ppc_close(CPUPPCState *env) } /*****************************************************************************/ -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; uint16_t *gen_opc_end; @@ -2989,8 +3035,6 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; gen_opparam_ptr = gen_opparam_buf; ctx.nip = pc_start; - ctx.tb_offset = 0; - ctx.decr_offset = 0; ctx.tb = tb; ctx.exception = EXCP_NONE; #if defined(CONFIG_USER_ONLY) @@ -3018,26 +3062,22 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, 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=%08x super=%d ir=%d\n", ctx.nip, 1 - msr_pr, msr_ir); } #endif ctx.opcode = ldl_code((void *)ctx.nip); -#if defined DEBUG_DISAS - if (loglevel > 0) { +#if defined PPC_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "translate opcode %08x (%02x %02x %02x)\n", ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode)); } #endif ctx.nip += 4; - ctx.tb_offset++; - /* Check decrementer exception */ - if (++ctx.decr_offset == env->decr + 1) - ctx.exception = EXCP_DECR; table = ppc_opcodes; handler = table[opc1(ctx.opcode)]; if (is_indirect_opcode(handler)) { @@ -3049,26 +3089,26 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, } } /* 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) 0x%08x\n", + "%02x - %02x - %02x (%08x) 0x%08x %d\n", opc1(ctx.opcode), opc2(ctx.opcode), - opc3(ctx.opcode), ctx.opcode, ctx.nip - 4); + 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) (0x%08x)\n", ctx.opcode & handler->inval, opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode), ctx.opcode, ctx.nip - 4); - } - } else { - if (handler->handler == &gen_invalid) { - printf("invalid/unsupported opcode: " - "%02x -%02x - %02x (%08x) 0x%08x\n", - opc1(ctx.opcode), opc2(ctx.opcode), - opc3(ctx.opcode), ctx.opcode, ctx.nip - 4); } else { printf("invalid bits: %08x for opcode: " "%02x -%02x - %02x (0x%08x) (0x%08x)\n", @@ -3076,11 +3116,11 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, opc2(ctx.opcode), opc3(ctx.opcode), 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 @@ -3093,26 +3133,17 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, (ctx.nip & 0xFC) != 0x04) && ctx.exception != EXCP_SYSCALL && ctx.exception != EXCP_RFI && 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 ((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) { - if (ctx.exception == EXCP_NONE) { - gen_op_b((long)ctx.tb, ctx.nip); - ctx.exception = EXCP_BRANCH; + RET_EXCP(ctxp, EXCP_BRANCH, 0); } } - } - /* 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(ctx.nip); + if (ctx.exception == EXCP_NONE) { + gen_op_b((unsigned long)ctx.tb, 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 @@ -3137,22 +3168,23 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, } else { 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); + } + if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "IN: %s\n", lookup_symbol((void *)pc_start)); -#if defined(CONFIG_USER_ONLY) disas(logfile, (void *)pc_start, ctx.nip - pc_start, 0, 0); -#endif 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 + env->access_type = ACCESS_INT; return 0; }