diff options
Diffstat (limited to 'src/emu/cpu/powerpc/ppc602.c')
-rw-r--r-- | src/emu/cpu/powerpc/ppc602.c | 293 |
1 files changed, 293 insertions, 0 deletions
diff --git a/src/emu/cpu/powerpc/ppc602.c b/src/emu/cpu/powerpc/ppc602.c new file mode 100644 index 00000000000..a53b08850af --- /dev/null +++ b/src/emu/cpu/powerpc/ppc602.c @@ -0,0 +1,293 @@ +static void ppc_dsa(UINT32 op) +{ + UINT32 msr = ppc_get_msr(); + + msr &= ~(MSR_SA | MSR_EE | MSR_PR | MSR_AP); + if (ppc.esasrr & 0x8) msr |= MSR_PR; + if (ppc.esasrr & 0x4) msr |= MSR_AP; + if (ppc.esasrr & 0x2) msr |= MSR_SA; + if (ppc.esasrr & 0x1) msr |= MSR_EE; + + ppc_set_msr(msr); +} + +static void ppc_esa(UINT32 op) +{ + int sa, ee, pr, ap; + UINT32 msr = ppc_get_msr(); + + sa = (msr & MSR_SA) ? 1 : 0; + ee = (msr & MSR_EE) ? 1 : 0; + pr = (msr & MSR_PR) ? 1 : 0; + ap = (msr & MSR_AP) ? 1 : 0; + + ppc.esasrr = (pr << 3) | (ap << 2) | (sa << 1) | (ee); + + msr &= ~(MSR_EE | MSR_PR | MSR_AP); + msr |= MSR_SA; + + ppc_set_msr(msr); +} + +#ifndef PPC_DRC +static void ppc_tlbli(UINT32 op) +{ + +} + +static void ppc_tlbld(UINT32 op) +{ + +} +#endif + +#ifndef PPC_DRC +void ppc602_exception(int exception) +{ + switch( exception ) + { + case EXCEPTION_IRQ: /* External Interrupt */ + if( ppc_get_msr() & MSR_EE ) { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.npc; + SRR1 = msr & 0xff73; + + msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI); + if( msr & MSR_ILE ) + msr |= MSR_LE; + else + msr &= ~MSR_LE; + ppc_set_msr(msr); + + if( msr & MSR_IP ) + ppc.npc = 0xfff00000 | 0x0500; + else + ppc.npc = ppc.ibr | 0x0500; + + ppc.interrupt_pending &= ~0x1; + change_pc(ppc.npc); + } + break; + + case EXCEPTION_DECREMENTER: /* Decrementer overflow exception */ + if( ppc_get_msr() & MSR_EE ) { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.npc; + SRR1 = msr & 0xff73; + + msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI); + if( msr & MSR_ILE ) + msr |= MSR_LE; + else + msr &= ~MSR_LE; + ppc_set_msr(msr); + + if( msr & MSR_IP ) + ppc.npc = 0xfff00000 | 0x0900; + else + ppc.npc = ppc.ibr | 0x0900; + + ppc.interrupt_pending &= ~0x2; + change_pc(ppc.npc); + } + break; + + case EXCEPTION_TRAP: /* Program exception / Trap */ + { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.pc; + SRR1 = (msr & 0xff73) | 0x20000; /* 0x20000 = TRAP bit */ + + msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI); + if( msr & MSR_ILE ) + msr |= MSR_LE; + else + msr &= ~MSR_LE; + + if( msr & MSR_IP ) + ppc.npc = 0xfff00000 | 0x0700; + else + ppc.npc = ppc.ibr | 0x0700; + change_pc(ppc.npc); + } + break; + + case EXCEPTION_SYSTEM_CALL: /* System call */ + { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.npc; + SRR1 = (msr & 0xff73); + + msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI); + if( msr & MSR_ILE ) + msr |= MSR_LE; + else + msr &= ~MSR_LE; + + if( msr & MSR_IP ) + ppc.npc = 0xfff00000 | 0x0c00; + else + ppc.npc = ppc.ibr | 0x0c00; + change_pc(ppc.npc); + } + break; + + case EXCEPTION_SMI: + if( ppc_get_msr() & MSR_EE ) { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.npc; + SRR1 = msr & 0xff73; + + msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI); + if( msr & MSR_ILE ) + msr |= MSR_LE; + else + msr &= ~MSR_LE; + ppc_set_msr(msr); + + if( msr & MSR_IP ) + ppc.npc = 0xfff00000 | 0x1400; + else + ppc.npc = ppc.ibr | 0x1400; + + ppc.interrupt_pending &= ~0x4; + change_pc(ppc.npc); + } + break; + + + default: + fatalerror("ppc: Unhandled exception %d", exception); + break; + } +} + +static void ppc602_set_irq_line(int irqline, int state) +{ + if( state ) { + ppc.interrupt_pending |= 0x1; + if (ppc.irq_callback) + { + ppc.irq_callback(irqline); + } + } +} + +static void ppc602_set_smi_line(int state) +{ + if( state ) { + ppc.interrupt_pending |= 0x4; + } +} + +INLINE void ppc602_check_interrupts(void) +{ + if (MSR & MSR_EE) + { + if (ppc.interrupt_pending != 0) + { + if (ppc.interrupt_pending & 0x1) + { + ppc602_exception(EXCEPTION_IRQ); + } + else if (ppc.interrupt_pending & 0x2) + { + ppc602_exception(EXCEPTION_DECREMENTER); + } + else if (ppc.interrupt_pending & 0x4) + { + ppc602_exception(EXCEPTION_SMI); + } + } + } +} + +static void ppc602_reset(void) +{ + ppc.pc = ppc.npc = 0xfff00100; + + ppc_set_msr(0x40); + change_pc(ppc.pc); + + ppc.hid0 = 1; + + ppc.interrupt_pending = 0; +} + +static int ppc602_execute(int cycles) +{ + int exception_type; + UINT32 opcode; + ppc_icount = cycles; + ppc_tb_base_icount = cycles; + ppc_dec_base_icount = cycles; + + // check if decrementer exception occurs during execution + if ((UINT32)(DEC - ppc_icount) > (UINT32)(DEC)) + { + ppc_dec_trigger_cycle = ppc_icount - DEC; + } + else + { + ppc_dec_trigger_cycle = 0x7fffffff; + } + + change_pc(ppc.npc); + +#ifdef __GNUC__ + // MinGW's optimizer kills setjmp()/longjmp() + (void)__builtin_return_address(1); +#endif + + exception_type = setjmp(ppc.exception_jmpbuf); + if (exception_type) + { + ppc.npc = ppc.pc; + ppc602_exception(exception_type); + } + + while( ppc_icount > 0 ) + { + ppc.pc = ppc.npc; + CALL_MAME_DEBUG; + + if (MSR & MSR_IR) + opcode = ppc_readop_translated(ppc.pc); + else + opcode = ROPCODE64(ppc.pc); + + ppc.npc = ppc.pc + 4; + switch(opcode >> 26) + { + case 19: optable19[(opcode >> 1) & 0x3ff](opcode); break; + case 31: optable31[(opcode >> 1) & 0x3ff](opcode); break; + case 59: optable59[(opcode >> 1) & 0x3ff](opcode); break; + case 63: optable63[(opcode >> 1) & 0x3ff](opcode); break; + default: optable[opcode >> 26](opcode); break; + } + + ppc_icount--; + + if(ppc_icount == ppc_dec_trigger_cycle) { + ppc.interrupt_pending |= 0x2; + } + + ppc602_check_interrupts(); + } + + // update timebase + // timebase is incremented once every four core clock cycles, so adjust the cycles accordingly + ppc.tb += ((ppc_tb_base_icount - ppc_icount) / 4); + + // update decrementer + DEC -= ((ppc_dec_base_icount - ppc_icount) / (bus_freq_multiplier * 2)); + + + return cycles - ppc_icount; +} +#endif // PPC_DRC |