/** ** Supermodel ** A Sega Model 3 Arcade Emulator. ** Copyright 2011 Bart Trzynadlowski, Nik Henson ** ** This file is part of Supermodel. ** ** Supermodel is free software: you can redistribute it and/or modify it under ** the terms of the GNU General Public License as published by the Free ** Software Foundation, either version 3 of the License, or (at your option) ** any later version. ** ** Supermodel is distributed in the hope that it will be useful, but WITHOUT ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ** more details. ** ** You should have received a copy of the GNU General Public License along ** with Supermodel. If not, see . **/ /* * ppc.cpp * * PowerPC emulator main module. Written by Ville Linde for the original * Supermodel project. */ /* IBM/Motorola PowerPC 4xx/6xx Emulator */ #include // memset() #include "Supermodel.h" #include "ppc.h" // Typedefs that Supermodel no longer provides typedef unsigned int UINT; // C++ should allow this... #define INLINE inline // Model 3 context provides read/write handlers static class IBus *Bus = NULL; // pointer to Model 3 bus object (for access handlers) #ifdef SUPERMODEL_DEBUGGER // Pointer to current PPC debugger (if any) static class Debugger::CPPCDebug *PPCDebug = NULL; #endif void ppc603_exception(int exception); static void ppc603_check_interrupts(void); #define RD ((op >> 21) & 0x1F) #define RT ((op >> 21) & 0x1f) #define RS ((op >> 21) & 0x1f) #define RA ((op >> 16) & 0x1f) #define RB ((op >> 11) & 0x1f) #define RC ((op >> 6) & 0x1f) #define MB ((op >> 6) & 0x1f) #define ME ((op >> 1) & 0x1f) #define SH ((op >> 11) & 0x1f) #define BO ((op >> 21) & 0x1f) #define BI ((op >> 16) & 0x1f) #define CRFD ((op >> 23) & 0x7) #define CRFA ((op >> 18) & 0x7) #define FXM ((op >> 12) & 0xff) #define SPR (((op >> 16) & 0x1f) | ((op >> 6) & 0x3e0)) #define SIMM16 (INT32)(INT16)(op & 0xffff) #define UIMM16 (UINT32)(op & 0xffff) #define RCBIT (op & 0x1) #define OEBIT (op & 0x400) #define AABIT (op & 0x2) #define LKBIT (op & 0x1) #define REG(x) (ppc.r[x]) #define LR (ppc.lr) #define CTR (ppc.ctr) #define XER (ppc.xer) #define CR(x) (ppc.cr[x]) #define MSR (ppc.msr) #define SRR0 (ppc.srr0) #define SRR1 (ppc.srr1) #define SRR2 (ppc.srr2) #define SRR3 (ppc.srr3) #define EVPR (ppc.evpr) #define EXIER (ppc.exier) #define EXISR (ppc.exisr) #define DEC (ppc.dec) // Stuff added for the 6xx #define FPR(x) (ppc.fpr[x]) #define FM ((op >> 17) & 0xFF) #define SPRF (((op >> 6) & 0x3E0) | ((op >> 16) & 0x1F)) #define CHECK_SUPERVISOR() \ if((ppc.msr & 0x4000) != 0){ \ } #define CHECK_FPU_AVAILABLE() \ if((ppc.msr & 0x2000) == 0){ \ } static UINT32 ppc_field_xlat[256]; #define FPSCR_FX 0x80000000 #define FPSCR_FEX 0x40000000 #define FPSCR_VX 0x20000000 #define FPSCR_OX 0x10000000 #define FPSCR_UX 0x08000000 #define FPSCR_ZX 0x04000000 #define FPSCR_XX 0x02000000 #define BITMASK_0(n) (UINT32)(((UINT64)1 << n) - 1) #define CRBIT(x) ((ppc.cr[x / 4] & (1 << (3 - (x % 4)))) ? 1 : 0) #define _BIT(n) (1 << (n)) #define GET_ROTATE_MASK(mb,me) (ppc_rotate_mask[mb][me]) #define ADD_CA(r,a,b) ((UINT32)r < (UINT32)a) #define SUB_CA(r,a,b) (!((UINT32)a < (UINT32)b)) #define ADD_OV(r,a,b) ((~((a) ^ (b)) & ((a) ^ (r))) & 0x80000000) #define SUB_OV(r,a,b) (( ((a) ^ (b)) & ((a) ^ (r))) & 0x80000000) #define XER_SO 0x80000000 #define XER_OV 0x40000000 #define XER_CA 0x20000000 #define MSR_POW 0x00040000 /* Power Management Enable */ #define MSR_WE 0x00040000 #define MSR_CE 0x00020000 #define MSR_ILE 0x00010000 /* Interrupt Little Endian Mode */ #define MSR_EE 0x00008000 /* External Interrupt Enable */ #define MSR_PR 0x00004000 /* Problem State */ #define MSR_FP 0x00002000 /* Floating Point Available */ #define MSR_ME 0x00001000 /* Machine Check Enable */ #define MSR_FE0 0x00000800 #define MSR_SE 0x00000400 /* Single Step Trace Enable */ #define MSR_BE 0x00000200 /* Branch Trace Enable */ #define MSR_DE 0x00000200 #define MSR_FE1 0x00000100 #define MSR_IP 0x00000040 /* Interrupt Prefix */ #define MSR_IR 0x00000020 /* Instruction Relocate */ #define MSR_DR 0x00000010 /* Data Relocate */ #define MSR_PE 0x00000008 #define MSR_PX 0x00000004 #define MSR_RI 0x00000002 /* Recoverable Interrupt Enable */ #define MSR_LE 0x00000001 #define TSR_ENW 0x80000000 #define TSR_WIS 0x40000000 #define BYTE_REVERSE16(x) (((x >> 8) | (x << 8)) & 0xFFFF) #define BYTE_REVERSE32(x) ((x >> 24) | ((x << 8) & 0x00FF0000) | ((x >> 8) & 0x0000FF00) | (x << 24)) typedef union { UINT64 id; double fd; } FPR; typedef union { UINT32 i; float f; } FPR32; typedef struct { UINT32 u; UINT32 l; } BATENT; typedef struct { bool fatalError; // if true, halt PowerPC until hard reset UINT32 r[32]; UINT32 pc; UINT32 npc; UINT32 *op; UINT32 lr; UINT32 ctr; UINT32 xer; UINT32 msr; UINT8 cr[8]; UINT32 pvr; UINT32 srr0; UINT32 srr1; UINT32 srr2; UINT32 srr3; UINT32 hid0; UINT32 hid1; UINT32 hid2; UINT32 sdr1; UINT32 sprg[4]; UINT32 dsisr; UINT32 dar; UINT32 ear; UINT32 dmiss; UINT32 dcmp; UINT32 hash1; UINT32 hash2; UINT32 imiss; UINT32 icmp; UINT32 rpa; BATENT ibat[4]; BATENT dbat[4]; UINT32 evpr; UINT32 exier; UINT32 exisr; UINT32 bear; UINT32 besr; UINT32 iocr; UINT32 br[8]; UINT32 iabr; UINT32 esr; UINT32 iccr; UINT32 dccr; UINT32 pit; UINT32 pit_counter; UINT32 pit_int_enable; UINT32 tsr; UINT32 dbsr; UINT32 sgr; UINT32 pid; int reserved; UINT32 reserved_address; int interrupt_pending; int external_int; UINT64 tb; /* 56-bit timebase register */ int (*irq_callback)(int irqline); PPC_FETCH_REGION cur_fetch; PPC_FETCH_REGION * fetch; // STUFF added for the 6xx series UINT32 dec; UINT32 fpscr; FPR fpr[32]; UINT32 sr[16]; // Timing related int timer_ratio; UINT32 timer_frac; int tb_base_icount; int dec_base_icount; int dec_trigger_cycle; // Cycle related UINT64 total_cycles; int icount; int cur_cycles; int bus_freq_multiplier; int cycles_per_second; #if HAS_PPC603 int is603; #endif #if HAS_PPC602 int is602; #endif } PPC_REGS; typedef struct { int code; int subcode; void (* handler)(UINT32); } PPC_OPCODE; static PPC_REGS ppc; static UINT32 ppc_rotate_mask[32][32]; static void ppc_change_pc(UINT32 newpc) { UINT i; if (ppc.cur_fetch.start <= newpc && newpc <= ppc.cur_fetch.end) { ppc.op = &ppc.cur_fetch.ptr[(newpc-ppc.cur_fetch.start)/4]; // ppc.op = (UINT32 *)((void *)ppc.cur_fetch.ptr + (UINT32)(newpc - ppc.cur_fetch.start)); return; } for(i = 0; ppc.fetch[i].ptr != NULL; i++) { if (ppc.fetch[i].start <= newpc && newpc <= ppc.fetch[i].end) { ppc.cur_fetch.start = ppc.fetch[i].start; ppc.cur_fetch.end = ppc.fetch[i].end; ppc.cur_fetch.ptr = ppc.fetch[i].ptr; // ppc.op = (UINT32 *)((UINT32)ppc.cur_fetch.ptr + (UINT32)(newpc - ppc.cur_fetch.start)); ppc.op = &ppc.cur_fetch.ptr[(newpc-ppc.cur_fetch.start)/4]; return; } } DebugLog("Invalid PC %08X, previous PC %08X\n", newpc, ppc.pc); ErrorLog("PowerPC is out of bounds. Halting emulation until reset."); ppc.fatalError = true; } INLINE UINT8 READ8(UINT32 address) { return Bus->Read8(address); } INLINE UINT16 READ16(UINT32 address) { return Bus->Read16(address); } INLINE UINT32 READ32(UINT32 address) { return Bus->Read32(address); } INLINE UINT64 READ64(UINT32 address) { return Bus->Read64(address); } INLINE void WRITE8(UINT32 address, UINT8 data) { Bus->Write8(address,data); } INLINE void WRITE16(UINT32 address, UINT16 data) { Bus->Write16(address,data); } INLINE void WRITE32(UINT32 address, UINT32 data) { Bus->Write32(address,data); } INLINE void WRITE64(UINT32 address, UINT64 data) { Bus->Write64(address,data); } /*********************************************************************/ INLINE void SET_CR0(INT32 rd) { if( rd < 0 ) { CR(0) = 0x8; } else if( rd > 0 ) { CR(0) = 0x4; } else { CR(0) = 0x2; } if( XER & XER_SO ) CR(0) |= 0x1; } INLINE void SET_CR1(void) { CR(1) = (ppc.fpscr >> 28) & 0xf; } INLINE void SET_ADD_OV(UINT32 rd, UINT32 ra, UINT32 rb) { if( ADD_OV(rd, ra, rb) ) XER |= XER_SO | XER_OV; else XER &= ~XER_OV; } INLINE void SET_SUB_OV(UINT32 rd, UINT32 ra, UINT32 rb) { if( SUB_OV(rd, ra, rb) ) XER |= XER_SO | XER_OV; else XER &= ~XER_OV; } INLINE void SET_ADD_CA(UINT32 rd, UINT32 ra, UINT32 rb) { if( ADD_CA(rd, ra, rb) ) XER |= XER_CA; else XER &= ~XER_CA; } INLINE void SET_SUB_CA(UINT32 rd, UINT32 ra, UINT32 rb) { if( SUB_CA(rd, ra, rb) ) XER |= XER_CA; else XER &= ~XER_CA; } INLINE UINT32 check_condition_code(UINT32 bo, UINT32 bi) { UINT32 ctr_ok; UINT32 condition_ok; UINT32 bo0 = (bo & 0x10) ? 1 : 0; UINT32 bo1 = (bo & 0x08) ? 1 : 0; UINT32 bo2 = (bo & 0x04) ? 1 : 0; UINT32 bo3 = (bo & 0x02) ? 1 : 0; if( bo2 == 0 ) --CTR; ctr_ok = bo2 | ((CTR != 0) ^ bo3); condition_ok = bo0 | (CRBIT(bi) ^ (~bo1 & 0x1)); return ctr_ok && condition_ok; } INLINE UINT64 ppc_read_timebase(void) { int cycles = ppc.tb_base_icount - ppc.icount; // Timebase is incremented according to timer ratio, so adjust value accordingly return ppc.tb + (cycles / ppc.timer_ratio); } INLINE void ppc_write_timebase_l(UINT32 tbl) { UINT64 tb = ppc_read_timebase(); ppc.tb_base_icount = ppc.icount + ((ppc.tb_base_icount - ppc.icount) % ppc.timer_ratio); ppc.tb = (tb&~0xffffffff)|tbl; } INLINE void ppc_write_timebase_h(UINT32 tbh) { UINT64 tb = ppc_read_timebase(); ppc.tb_base_icount = ppc.icount + ((ppc.tb_base_icount - ppc.icount) % ppc.timer_ratio); ppc.tb = (tb&0xffffffff)|((UINT64)(tbh) << 32); } INLINE UINT32 read_decrementer(void) { int cycles = ppc.dec_base_icount - ppc.icount; // Decrementer is decremented at same rate as timebase, so adjust value accordingly return DEC - (cycles / ppc.timer_ratio); } INLINE void write_decrementer(UINT32 value) { if (((value&0x80000000) && !(read_decrementer()&0x80000000))) { /* trigger interrupt */ ppc.interrupt_pending |= 0x2; ppc603_check_interrupts(); } ppc.dec_base_icount = ppc.icount + ((ppc.dec_base_icount - ppc.icount) % ppc.timer_ratio); DEC = value; // Check if decrementer exception occurs during execution (exception occurs after decrementer // has passed through zero) if ((UINT32)(ppc.dec_base_icount / ppc.timer_ratio) > DEC) ppc.dec_trigger_cycle = ppc.dec_base_icount - ((1 + DEC) * ppc.timer_ratio); else ppc.dec_trigger_cycle = 0x7fffffff; } /*********************************************************************/ INLINE void ppc_set_spr(int spr, UINT32 value) { switch (spr) { case SPR_LR: LR = value; return; case SPR_CTR: CTR = value; return; case SPR_XER: XER = value; return; case SPR_SRR0: ppc.srr0 = value; return; case SPR_SRR1: ppc.srr1 = value; return; case SPR_SPRG0: ppc.sprg[0] = value; return; case SPR_SPRG1: ppc.sprg[1] = value; return; case SPR_SPRG2: ppc.sprg[2] = value; return; case SPR_SPRG3: ppc.sprg[3] = value; return; case SPR_PVR: return; case SPR603E_DEC: write_decrementer(value); return; case SPR603E_TBL_W: case SPR603E_TBL_R: // special 603e case ppc_write_timebase_l(value); return; case SPR603E_TBU_R: case SPR603E_TBU_W: // special 603e case ppc_write_timebase_h(value); return; case SPR603E_HID0: ppc.hid0 = value; return; case SPR603E_HID1: ppc.hid1 = value; return; case SPR603E_HID2: ppc.hid2 = value; return; case SPR603E_DSISR: ppc.dsisr = value; return; case SPR603E_DAR: ppc.dar = value; return; case SPR603E_EAR: ppc.ear = value; return; case SPR603E_DMISS: ppc.dmiss = value; return; case SPR603E_DCMP: ppc.dcmp = value; return; case SPR603E_HASH1: ppc.hash1 = value; return; case SPR603E_HASH2: ppc.hash2 = value; return; case SPR603E_IMISS: ppc.imiss = value; return; case SPR603E_ICMP: ppc.icmp = value; return; case SPR603E_RPA: ppc.rpa = value; return; case SPR603E_IBAT0L: ppc.ibat[0].l = value; return; case SPR603E_IBAT0U: ppc.ibat[0].u = value; return; case SPR603E_IBAT1L: ppc.ibat[1].l = value; return; case SPR603E_IBAT1U: ppc.ibat[1].u = value; return; case SPR603E_IBAT2L: ppc.ibat[2].l = value; return; case SPR603E_IBAT2U: ppc.ibat[2].u = value; return; case SPR603E_IBAT3L: ppc.ibat[3].l = value; return; case SPR603E_IBAT3U: ppc.ibat[3].u = value; return; case SPR603E_DBAT0L: ppc.dbat[0].l = value; return; case SPR603E_DBAT0U: ppc.dbat[0].u = value; return; case SPR603E_DBAT1L: ppc.dbat[1].l = value; return; case SPR603E_DBAT1U: ppc.dbat[1].u = value; return; case SPR603E_DBAT2L: ppc.dbat[2].l = value; return; case SPR603E_DBAT2U: ppc.dbat[2].u = value; return; case SPR603E_DBAT3L: ppc.dbat[3].l = value; return; case SPR603E_DBAT3U: ppc.dbat[3].u = value; return; case SPR603E_SDR1: ppc.sdr1 = value; return; case SPR603E_IABR: ppc.iabr = value; return; } ErrorLog("PowerPC wrote to an invalid register. Halting emulation until reset."); DebugLog("ppc: set_spr: unknown spr %d (%03X) !\n", spr, spr); ppc.fatalError = true; } INLINE UINT32 ppc_get_spr(int spr) { switch(spr) { case SPR_LR: return LR; case SPR_CTR: return CTR; case SPR_XER: return XER; case SPR_SRR0: return ppc.srr0; case SPR_SRR1: return ppc.srr1; case SPR_SPRG0: return ppc.sprg[0]; case SPR_SPRG1: return ppc.sprg[1]; case SPR_SPRG2: return ppc.sprg[2]; case SPR_SPRG3: return ppc.sprg[3]; case SPR_PVR: return ppc.pvr; case SPR603E_TBL_R: DebugLog("ppc: get_spr: TBL_R\n"); break; case SPR603E_TBU_R: DebugLog("ppc: get_spr: TBU_R\n"); break; case SPR603E_TBL_W: return (UINT32)(ppc_read_timebase()); case SPR603E_TBU_W: return (UINT32)(ppc_read_timebase() >> 32); case SPR603E_HID0: return ppc.hid0; case SPR603E_HID1: return ppc.hid1; case SPR603E_HID2: return ppc.hid2; case SPR603E_DEC: return read_decrementer(); case SPR603E_SDR1: return ppc.sdr1; case SPR603E_DSISR: return ppc.dsisr; case SPR603E_DAR: return ppc.dar; case SPR603E_EAR: return ppc.ear; case SPR603E_DMISS: return ppc.dmiss; case SPR603E_DCMP: return ppc.dcmp; case SPR603E_HASH1: return ppc.hash1; case SPR603E_HASH2: return ppc.hash2; case SPR603E_IMISS: return ppc.imiss; case SPR603E_ICMP: return ppc.icmp; case SPR603E_RPA: return ppc.rpa; case SPR603E_IBAT0L: return ppc.ibat[0].l; case SPR603E_IBAT0U: return ppc.ibat[0].u; case SPR603E_IBAT1L: return ppc.ibat[1].l; case SPR603E_IBAT1U: return ppc.ibat[1].u; case SPR603E_IBAT2L: return ppc.ibat[2].l; case SPR603E_IBAT2U: return ppc.ibat[2].u; case SPR603E_IBAT3L: return ppc.ibat[3].l; case SPR603E_IBAT3U: return ppc.ibat[3].u; case SPR603E_DBAT0L: return ppc.dbat[0].l; case SPR603E_DBAT0U: return ppc.dbat[0].u; case SPR603E_DBAT1L: return ppc.dbat[1].l; case SPR603E_DBAT1U: return ppc.dbat[1].u; case SPR603E_DBAT2L: return ppc.dbat[2].l; case SPR603E_DBAT2U: return ppc.dbat[2].u; case SPR603E_DBAT3L: return ppc.dbat[3].l; case SPR603E_DBAT3U: return ppc.dbat[3].u; } ErrorLog("PowerPC read from an invalid register. Halting emulation until reset."); DebugLog("ppc: get_spr: unknown spr %d (%03X) !\n", spr, spr); ppc.fatalError = true; return 0; } INLINE void ppc_set_msr(UINT32 value) { if( value & (MSR_ILE | MSR_LE) ) { ErrorLog("PowerPC entered an unemulated mode. Halting emulation until reset."); DebugLog("ppc: set_msr: little_endian mode not supported !\n"); ppc.fatalError = true; } MSR = value; ppc603_check_interrupts(); } INLINE UINT32 ppc_get_msr(void) { return MSR; } INLINE void ppc_set_cr(UINT32 value) { CR(0) = (value >> 28) & 0xf; CR(1) = (value >> 24) & 0xf; CR(2) = (value >> 20) & 0xf; CR(3) = (value >> 16) & 0xf; CR(4) = (value >> 12) & 0xf; CR(5) = (value >> 8) & 0xf; CR(6) = (value >> 4) & 0xf; CR(7) = (value >> 0) & 0xf; } INLINE UINT32 ppc_get_cr(void) { return CR(0) << 28 | CR(1) << 24 | CR(2) << 20 | CR(3) << 16 | CR(4) << 12 | CR(5) << 8 | CR(6) << 4 | CR(7); } /***********************************************************************/ static void (* optable19[1024])(UINT32); static void (* optable31[1024])(UINT32); static void (* optable59[1024])(UINT32); static void (* optable63[1024])(UINT32); static void (* optable[64])(UINT32); #include "ppc603.c" /********************************************************************/ #include "ppc_ops.c" #include "ppc_ops.h" /* Initialization and shutdown */ void ppc_base_init(void) { int i,j; memset(&ppc, 0, sizeof(ppc)); for( i=0; i < 64; i++ ) { optable[i] = ppc_invalid; } for( i=0; i < 1024; i++ ) { optable19[i] = ppc_invalid; optable31[i] = ppc_invalid; optable59[i] = ppc_invalid; optable63[i] = ppc_invalid; } /* Fill the opcode tables */ for( i=0; i < (sizeof(ppc_opcode_common) / sizeof(PPC_OPCODE)); i++ ) { switch(ppc_opcode_common[i].code) { case 19: optable19[ppc_opcode_common[i].subcode] = ppc_opcode_common[i].handler; break; case 31: optable31[ppc_opcode_common[i].subcode] = ppc_opcode_common[i].handler; break; case 59: case 63: break; default: optable[ppc_opcode_common[i].code] = ppc_opcode_common[i].handler; } } /* Calculate rotate mask table */ for( i=0; i < 32; i++ ) { for( j=0; j < 32; j++ ) { UINT32 mask; int mb = i; int me = j; mask = ((UINT32)0xFFFFFFFF >> mb) ^ ((me >= 31) ? 0 : ((UINT32)0xFFFFFFFF >> (me + 1))); if( mb > me ) mask = ~mask; ppc_rotate_mask[i][j] = mask; } } } void ppc_init(const PPC_CONFIG *config) { int pll_config = 0; float multiplier; int i ; ppc_base_init() ; optable[48] = ppc_lfs; optable[49] = ppc_lfsu; optable[50] = ppc_lfd; optable[51] = ppc_lfdu; optable[52] = ppc_stfs; optable[53] = ppc_stfsu; optable[54] = ppc_stfd; optable[55] = ppc_stfdu; optable31[631] = ppc_lfdux; optable31[599] = ppc_lfdx; optable31[567] = ppc_lfsux; optable31[535] = ppc_lfsx; optable31[595] = ppc_mfsr; optable31[659] = ppc_mfsrin; optable31[371] = ppc_mftb; optable31[210] = ppc_mtsr; optable31[242] = ppc_mtsrin; optable31[758] = ppc_dcba; optable31[759] = ppc_stfdux; optable31[727] = ppc_stfdx; optable31[983] = ppc_stfiwx; optable31[695] = ppc_stfsux; optable31[663] = ppc_stfsx; optable31[370] = ppc_tlbia; optable31[306] = ppc_tlbie; optable31[566] = ppc_tlbsync; optable31[310] = ppc_eciwx; optable31[438] = ppc_ecowx; optable63[264] = ppc_fabsx; optable63[21] = ppc_faddx; optable63[32] = ppc_fcmpo; optable63[0] = ppc_fcmpu; optable63[14] = ppc_fctiwx; optable63[15] = ppc_fctiwzx; optable63[18] = ppc_fdivx; optable63[72] = ppc_fmrx; optable63[136] = ppc_fnabsx; optable63[40] = ppc_fnegx; optable63[12] = ppc_frspx; optable63[26] = ppc_frsqrtex; optable63[22] = ppc_fsqrtx; optable63[20] = ppc_fsubx; optable63[583] = ppc_mffsx; optable63[70] = ppc_mtfsb0x; optable63[38] = ppc_mtfsb1x; optable63[711] = ppc_mtfsfx; optable63[134] = ppc_mtfsfix; optable63[64] = ppc_mcrfs; optable59[21] = ppc_faddsx; optable59[18] = ppc_fdivsx; optable59[24] = ppc_fresx; optable59[22] = ppc_fsqrtsx; optable59[20] = ppc_fsubsx; for(i = 0; i < 32; i++) { optable63[i * 32 | 29] = ppc_fmaddx; optable63[i * 32 | 28] = ppc_fmsubx; optable63[i * 32 | 25] = ppc_fmulx; optable63[i * 32 | 31] = ppc_fnmaddx; optable63[i * 32 | 30] = ppc_fnmsubx; optable63[i * 32 | 23] = ppc_fselx; optable59[i * 32 | 29] = ppc_fmaddsx; optable59[i * 32 | 28] = ppc_fmsubsx; optable59[i * 32 | 25] = ppc_fmulsx; optable59[i * 32 | 31] = ppc_fnmaddsx; optable59[i * 32 | 30] = ppc_fnmsubsx; } for(i = 0; i < 256; i++) { ppc_field_xlat[i] = ((i & 0x80) ? 0xF0000000 : 0) | ((i & 0x40) ? 0x0F000000 : 0) | ((i & 0x20) ? 0x00F00000 : 0) | ((i & 0x10) ? 0x000F0000 : 0) | ((i & 0x08) ? 0x0000F000 : 0) | ((i & 0x04) ? 0x00000F00 : 0) | ((i & 0x02) ? 0x000000F0 : 0) | ((i & 0x01) ? 0x0000000F : 0); } ppc.pvr = config->pvr; multiplier = (float)((config->bus_frequency_multiplier >> 4) & 0xf) + (float)(config->bus_frequency_multiplier & 0xf) / 10.0f; ppc.bus_freq_multiplier = (int)(multiplier * 2); // tb and dec are incremented every four bus cycles, so calculate default timer ratio ppc.timer_ratio = 2 * ppc.bus_freq_multiplier; switch (config->bus_frequency) { case BUS_FREQUENCY_16MHZ: ppc.cycles_per_second = multiplier * 16000000; break; case BUS_FREQUENCY_20MHZ: ppc.cycles_per_second = multiplier * 20000000; break; case BUS_FREQUENCY_25MHZ: ppc.cycles_per_second = multiplier * 25000000; break; case BUS_FREQUENCY_33MHZ: ppc.cycles_per_second = multiplier * 33000000; break; case BUS_FREQUENCY_40MHZ: ppc.cycles_per_second = multiplier * 40000000; break; case BUS_FREQUENCY_50MHZ: ppc.cycles_per_second = multiplier * 50000000; break; case BUS_FREQUENCY_60MHZ: ppc.cycles_per_second = multiplier * 60000000; break; case BUS_FREQUENCY_66MHZ: ppc.cycles_per_second = multiplier * 66000000; break; case BUS_FREQUENCY_75MHZ: ppc.cycles_per_second = multiplier * 75000000; break; } switch(config->pvr) { case PPC_MODEL_603E: pll_config = mpc603e_pll_config[ppc.bus_freq_multiplier-1][config->bus_frequency]; break; case PPC_MODEL_603EV: pll_config = mpc603ev_pll_config[ppc.bus_freq_multiplier-1][config->bus_frequency]; break; case PPC_MODEL_603R: pll_config = mpc603r_pll_config[ppc.bus_freq_multiplier-1][config->bus_frequency]; break; default: break; } if (pll_config == -1) { //ErrorLog("PPC: Invalid bus/multiplier combination (bus frequency = %d, multiplier = %1.1f)", config->bus_frequency, multiplier); } ppc.hid1 = pll_config << 28; } void ppc_shutdown(void) { } void ppc_set_irq_line(int irqline) { ppc.interrupt_pending |= 0x1; ppc603_check_interrupts(); } UINT32 ppc_get_pc(void) { return ppc.pc; } void ppc_set_fetch(PPC_FETCH_REGION * fetch) { ppc.fetch = fetch; } UINT64 ppc_total_cycles(void) { return ppc.total_cycles + (UINT64)(ppc.cur_cycles - ppc.icount); } int ppc_get_cycles_per_sec() { return ppc.cycles_per_second; } int ppc_get_bus_freq_multipler() { return ppc.bus_freq_multiplier; } void ppc_set_timer_ratio(int ratio) { ppc.timer_ratio = ratio; } int ppc_get_timer_ratio() { return ppc.timer_ratio; } /****************************************************************************** Supermodel Interface ******************************************************************************/ void ppc_attach_bus(IBus *BusPtr) { Bus = BusPtr; } void ppc_save_state(CBlockFile *SaveState) { SaveState->NewBlock("PowerPC", __FILE__); // Cycle counting SaveState->Write(&ppc.icount, sizeof(ppc.icount)); SaveState->Write(&ppc.cur_cycles, sizeof(ppc.cur_cycles)); SaveState->Write(&ppc.total_cycles, sizeof(ppc.total_cycles)); // Registers SaveState->Write(ppc.r, sizeof(ppc.r)); SaveState->Write(&ppc.pc, sizeof(ppc.pc)); SaveState->Write(&ppc.npc, sizeof(ppc.npc)); SaveState->Write(&ppc.lr, sizeof(ppc.lr)); SaveState->Write(&ppc.ctr, sizeof(ppc.ctr)); SaveState->Write(&ppc.xer, sizeof(ppc.xer)); SaveState->Write(&ppc.msr, sizeof(ppc.msr)); SaveState->Write(ppc.cr, sizeof(ppc.cr)); SaveState->Write(&ppc.pvr, sizeof(ppc.pvr)); SaveState->Write(&ppc.srr0, sizeof(ppc.srr0)); SaveState->Write(&ppc.srr1, sizeof(ppc.srr1)); SaveState->Write(&ppc.srr2, sizeof(ppc.srr2)); SaveState->Write(&ppc.srr3, sizeof(ppc.srr3)); SaveState->Write(&ppc.hid0, sizeof(ppc.hid0)); SaveState->Write(&ppc.hid1, sizeof(ppc.hid1)); SaveState->Write(&ppc.hid2, sizeof(ppc.hid2)); SaveState->Write(&ppc.sdr1, sizeof(ppc.sdr1)); SaveState->Write(ppc.sprg, sizeof(ppc.sprg)); SaveState->Write(&ppc.dsisr, sizeof(ppc.dsisr)); SaveState->Write(&ppc.dar, sizeof(ppc.dar)); SaveState->Write(&ppc.ear, sizeof(ppc.ear)); SaveState->Write(&ppc.dmiss, sizeof(ppc.dmiss)); SaveState->Write(&ppc.dcmp, sizeof(ppc.dcmp)); SaveState->Write(&ppc.hash1, sizeof(ppc.hash1)); SaveState->Write(&ppc.hash2, sizeof(ppc.hash2)); SaveState->Write(&ppc.imiss, sizeof(ppc.imiss)); SaveState->Write(&ppc.icmp, sizeof(ppc.icmp)); SaveState->Write(&ppc.rpa, sizeof(ppc.rpa)); SaveState->Write(ppc.ibat, sizeof(ppc.ibat)); SaveState->Write(ppc.dbat, sizeof(ppc.dbat)); // These are probably PPC 4xx registers, but who cares, save 'em anyway! SaveState->Write(&ppc.evpr, sizeof(ppc.evpr)); SaveState->Write(&ppc.exier, sizeof(ppc.exier)); SaveState->Write(&ppc.exisr, sizeof(ppc.exisr)); SaveState->Write(&ppc.bear, sizeof(ppc.bear)); SaveState->Write(&ppc.besr, sizeof(ppc.besr)); SaveState->Write(&ppc.iocr, sizeof(ppc.iocr)); SaveState->Write(ppc.br, sizeof(ppc.br)); SaveState->Write(&ppc.iabr, sizeof(ppc.iabr)); SaveState->Write(&ppc.esr, sizeof(ppc.esr)); SaveState->Write(&ppc.iccr, sizeof(ppc.iccr)); SaveState->Write(&ppc.dccr, sizeof(ppc.dccr)); SaveState->Write(&ppc.pit, sizeof(ppc.pit)); SaveState->Write(&ppc.pit_counter, sizeof(ppc.pit_counter)); SaveState->Write(&ppc.pit_int_enable, sizeof(ppc.pit_int_enable)); SaveState->Write(&ppc.tsr, sizeof(ppc.tsr)); SaveState->Write(&ppc.dbsr, sizeof(ppc.dbsr)); SaveState->Write(&ppc.sgr, sizeof(ppc.sgr)); SaveState->Write(&ppc.pid, sizeof(ppc.pid)); SaveState->Write(&ppc.reserved, sizeof(ppc.reserved)); SaveState->Write(&ppc.reserved_address, sizeof(ppc.reserved_address)); SaveState->Write(&ppc.external_int, sizeof(ppc.external_int)); SaveState->Write(&ppc.tb, sizeof(ppc.tb)); SaveState->Write(&ppc.dec, sizeof(ppc.dec)); SaveState->Write(&ppc.timer_frac, sizeof(ppc.timer_frac)); SaveState->Write(&ppc.fpscr, sizeof(ppc.fpscr)); SaveState->Write(ppc.fpr, sizeof(ppc.fpr)); SaveState->Write(ppc.sr, sizeof(ppc.sr)); } void ppc_load_state(CBlockFile *SaveState) { if (OKAY != SaveState->FindBlock("PowerPC")) { ErrorLog("Unable to load PowerPC state. Save state file is corrupt."); return; } // Timer and decrementer SaveState->Read(&ppc.icount, sizeof(ppc.icount)); SaveState->Read(&ppc.cur_cycles, sizeof(ppc.cur_cycles)); SaveState->Read(&ppc.total_cycles, sizeof(ppc.total_cycles)); // Registers SaveState->Read(ppc.r, sizeof(ppc.r)); SaveState->Read(&ppc.pc, sizeof(ppc.pc)); SaveState->Read(&ppc.npc, sizeof(ppc.npc)); ppc_change_pc(ppc.npc); SaveState->Read(&ppc.lr, sizeof(ppc.lr)); SaveState->Read(&ppc.ctr, sizeof(ppc.ctr)); SaveState->Read(&ppc.xer, sizeof(ppc.xer)); SaveState->Read(&ppc.msr, sizeof(ppc.msr)); SaveState->Read(ppc.cr, sizeof(ppc.cr)); SaveState->Read(&ppc.pvr, sizeof(ppc.pvr)); SaveState->Read(&ppc.srr0, sizeof(ppc.srr0)); SaveState->Read(&ppc.srr1, sizeof(ppc.srr1)); SaveState->Read(&ppc.srr2, sizeof(ppc.srr2)); SaveState->Read(&ppc.srr3, sizeof(ppc.srr3)); SaveState->Read(&ppc.hid0, sizeof(ppc.hid0)); SaveState->Read(&ppc.hid1, sizeof(ppc.hid1)); SaveState->Read(&ppc.hid2, sizeof(ppc.hid2)); SaveState->Read(&ppc.sdr1, sizeof(ppc.sdr1)); SaveState->Read(ppc.sprg, sizeof(ppc.sprg)); SaveState->Read(&ppc.dsisr, sizeof(ppc.dsisr)); SaveState->Read(&ppc.dar, sizeof(ppc.dar)); SaveState->Read(&ppc.ear, sizeof(ppc.ear)); SaveState->Read(&ppc.dmiss, sizeof(ppc.dmiss)); SaveState->Read(&ppc.dcmp, sizeof(ppc.dcmp)); SaveState->Read(&ppc.hash1, sizeof(ppc.hash1)); SaveState->Read(&ppc.hash2, sizeof(ppc.hash2)); SaveState->Read(&ppc.imiss, sizeof(ppc.imiss)); SaveState->Read(&ppc.icmp, sizeof(ppc.icmp)); SaveState->Read(&ppc.rpa, sizeof(ppc.rpa)); SaveState->Read(ppc.ibat, sizeof(ppc.ibat)); SaveState->Read(ppc.dbat, sizeof(ppc.dbat)); SaveState->Read(&ppc.evpr, sizeof(ppc.evpr)); SaveState->Read(&ppc.exier, sizeof(ppc.exier)); SaveState->Read(&ppc.exisr, sizeof(ppc.exisr)); SaveState->Read(&ppc.bear, sizeof(ppc.bear)); SaveState->Read(&ppc.besr, sizeof(ppc.besr)); SaveState->Read(&ppc.iocr, sizeof(ppc.iocr)); SaveState->Read(ppc.br, sizeof(ppc.br)); SaveState->Read(&ppc.iabr, sizeof(ppc.iabr)); SaveState->Read(&ppc.esr, sizeof(ppc.esr)); SaveState->Read(&ppc.iccr, sizeof(ppc.iccr)); SaveState->Read(&ppc.dccr, sizeof(ppc.dccr)); SaveState->Read(&ppc.pit, sizeof(ppc.pit)); SaveState->Read(&ppc.pit_counter, sizeof(ppc.pit_counter)); SaveState->Read(&ppc.pit_int_enable, sizeof(ppc.pit_int_enable)); SaveState->Read(&ppc.tsr, sizeof(ppc.tsr)); SaveState->Read(&ppc.dbsr, sizeof(ppc.dbsr)); SaveState->Read(&ppc.sgr, sizeof(ppc.sgr)); SaveState->Read(&ppc.pid, sizeof(ppc.pid)); SaveState->Read(&ppc.reserved, sizeof(ppc.reserved)); SaveState->Read(&ppc.reserved_address, sizeof(ppc.reserved_address)); SaveState->Read(&ppc.external_int, sizeof(ppc.external_int)); SaveState->Read(&ppc.tb, sizeof(ppc.tb)); SaveState->Read(&ppc.dec, sizeof(ppc.dec)); SaveState->Read(&ppc.timer_frac, sizeof(ppc.timer_frac)); SaveState->Read(&ppc.fpscr, sizeof(ppc.fpscr)); SaveState->Read(ppc.fpr, sizeof(ppc.fpr)); SaveState->Read(ppc.sr, sizeof(ppc.sr)); } UINT32 ppc_get_gpr(unsigned num) { return ppc.r[num&31]; } double ppc_get_fpr(unsigned num) { return ppc.fpr[num&31].fd; } UINT32 ppc_get_lr(void) { return ppc.lr; } UINT32 ppc_read_spr(unsigned spr) { return ppc_get_spr(spr); } UINT32 ppc_read_sr(unsigned num) { return ppc.sr[num&15]; } /****************************************************************************** Debugger Interface ******************************************************************************/ #ifdef SUPERMODEL_DEBUGGER void ppc_attach_debugger(Debugger::CPPCDebug *PPCDebugPtr) { if (PPCDebug != NULL) ppc_detach_debugger(); PPCDebug = PPCDebugPtr; Bus = PPCDebug->AttachBus(Bus); } void ppc_detach_debugger() { if (PPCDebug == NULL) return; Bus = PPCDebug->DetachBus(); PPCDebug = NULL; } void ppc_break() { if (PPCDebug != NULL) PPCDebug->ForceBreak(true); } #else // SUPERMODEL_DEBUGGER void ppc_break() { // } #endif // SUPERMODEL_DEBUGGER void ppc_set_pc(UINT32 pc) { ppc.pc = pc; ppc_change_pc(pc); ppc.npc = pc + 4; } UINT8 ppc_get_cr(unsigned num) { return ppc.cr[num&7]; } void ppc_set_cr(unsigned num, UINT8 val) { ppc.cr[num&7] = val; } void ppc_set_gpr(unsigned num, UINT32 val) { ppc.r[num&31] = val; } void ppc_set_fpr(unsigned num, double val) { ppc.fpr[num&31].fd = val; } void ppc_write_spr(unsigned spr, UINT32 val) { ppc_set_spr(spr, val); } void ppc_write_sr(unsigned num, UINT32 val) { ppc.sr[num&15] = val; } UINT32 ppc_read_msr() { return ppc_get_msr(); }