diff options
Diffstat (limited to 'src/emu/cpu/powerpc/ppc403.c')
-rw-r--r-- | src/emu/cpu/powerpc/ppc403.c | 964 |
1 files changed, 964 insertions, 0 deletions
diff --git a/src/emu/cpu/powerpc/ppc403.c b/src/emu/cpu/powerpc/ppc403.c new file mode 100644 index 00000000000..d4370e9fdeb --- /dev/null +++ b/src/emu/cpu/powerpc/ppc403.c @@ -0,0 +1,964 @@ +/* PowerPC 403 specific functions */ + +static void ppc403_dma_exec(int ch); + +#define DMA_CE 0x80000000 +#define DMA_CIE 0x40000000 +#define DMA_TD 0x20000000 +#define DMA_PL 0x10000000 +#define DMA_DAI 0x02000000 +#define DMA_SAI 0x01000000 +#define DMA_CP 0x00800000 +#define DMA_ETD 0x00000200 +#define DMA_TCE 0x00000100 +#define DMA_CH 0x00000080 +#define DMA_BME 0x00000040 +#define DMA_ECE 0x00000020 +#define DMA_TCD 0x00000010 +#define DMA_PCE 0x00000008 + +static SPU_RX_HANDLER spu_rx_handler; +static SPU_TX_HANDLER spu_tx_handler; +static TIMER_CALLBACK( ppc403_spu_rx_callback ); +static TIMER_CALLBACK( ppc403_spu_tx_callback ); + +static PPC_DMA_HANDLER spu_rx_dma_handler; +static PPC_DMA_HANDLER spu_tx_dma_handler; +static UINT8 *spu_rx_dma_ptr; +static UINT8 *spu_tx_dma_ptr; + +static PPC_DMA_HANDLER dma_read_handler[4]; +static PPC_DMA_HANDLER dma_write_handler[4]; +static UINT8 *dma_read_ptr[4]; +static UINT8 *dma_write_ptr[4]; + +INLINE void ppc_set_dcr(int dcr, UINT32 value) +{ + switch(dcr) + { + case DCR_BEAR: ppc.bear = value; break; + case DCR_BESR: ppc.besr = value; break; + case DCR_BR0: ppc.br[0] = value; break; + case DCR_BR1: ppc.br[1] = value; break; + case DCR_BR2: ppc.br[2] = value; break; + case DCR_BR3: ppc.br[3] = value; break; + case DCR_BR4: ppc.br[4] = value; break; + case DCR_BR5: ppc.br[5] = value; break; + case DCR_BR6: ppc.br[6] = value; break; + case DCR_BR7: ppc.br[7] = value; break; + + case DCR_EXISR: ppc.exisr &= ~value; break; + case DCR_EXIER: EXIER = value; ppc.exisr &= EXIER; break; + case DCR_IOCR: ppc.iocr = value; break; + case DCR_DMASR: break; /* TODO */ + case DCR_DMADA0: ppc.dma[0].da = value; break; + case DCR_DMADA1: ppc.dma[1].da = value; break; + case DCR_DMADA2: ppc.dma[2].da = value; break; + case DCR_DMADA3: ppc.dma[3].da = value; break; + case DCR_DMASA0: ppc.dma[0].sa = value; break; + case DCR_DMASA1: ppc.dma[1].sa = value; break; + case DCR_DMASA2: ppc.dma[2].sa = value; break; + case DCR_DMASA3: ppc.dma[3].sa = value; break; + case DCR_DMACT0: ppc.dma[0].ct = value; break; + case DCR_DMACT1: ppc.dma[1].ct = value; break; + case DCR_DMACT2: ppc.dma[2].ct = value; break; + case DCR_DMACT3: ppc.dma[3].ct = value; break; + case DCR_DMACR0: ppc.dma[0].cr = value; ppc403_dma_exec(0); break; + case DCR_DMACR1: ppc.dma[1].cr = value; ppc403_dma_exec(1); break; + case DCR_DMACR2: ppc.dma[2].cr = value; ppc403_dma_exec(2); break; + case DCR_DMACR3: ppc.dma[3].cr = value; ppc403_dma_exec(3); break; + + default: + fatalerror("ppc: set_dcr: Unimplemented DCR %X", dcr); + break; + } +} + +INLINE UINT32 ppc_get_dcr(int dcr) +{ + switch(dcr) + { + case DCR_BEAR: return ppc.bear; + case DCR_BESR: return ppc.besr; + case DCR_BR0: return ppc.br[0]; + case DCR_BR1: return ppc.br[1]; + case DCR_BR2: return ppc.br[2]; + case DCR_BR3: return ppc.br[3]; + case DCR_BR4: return ppc.br[4]; + case DCR_BR5: return ppc.br[5]; + case DCR_BR6: return ppc.br[6]; + case DCR_BR7: return ppc.br[7]; + case DCR_EXISR: return EXISR; + case DCR_EXIER: return EXIER; + case DCR_IOCR: return ppc.iocr; + case DCR_DMASR: return ppc.dmasr; + case DCR_DMADA0: return ppc.dma[0].da; + case DCR_DMADA1: return ppc.dma[1].da; + case DCR_DMADA2: return ppc.dma[2].da; + case DCR_DMADA3: return ppc.dma[3].da; + case DCR_DMASA0: return ppc.dma[0].sa; + case DCR_DMASA1: return ppc.dma[1].sa; + case DCR_DMASA2: return ppc.dma[2].sa; + case DCR_DMASA3: return ppc.dma[3].sa; + case DCR_DMACT0: return ppc.dma[0].ct; + case DCR_DMACT1: return ppc.dma[1].ct; + case DCR_DMACT2: return ppc.dma[2].ct; + case DCR_DMACT3: return ppc.dma[3].ct; + case DCR_DMACR0: return ppc.dma[0].cr; + case DCR_DMACR1: return ppc.dma[1].cr; + case DCR_DMACR2: return ppc.dma[2].cr; + case DCR_DMACR3: return ppc.dma[3].cr; + + default: + fatalerror("ppc: get_dcr: Unimplemented DCR %X", dcr); + break; + } +} + + + +#ifndef PPC_DRC +INLINE void ppc403_check_interrupts(void) +{ + if (MSR & MSR_EE) + { + if (ppc.interrupt_pending != 0) + { + if (ppc.interrupt_pending & 0x1) + { + ppc403_exception(EXCEPTION_IRQ); + } + else if (ppc.interrupt_pending & 0x2) + { + ppc403_exception(EXCEPTION_PROGRAMMABLE_INTERVAL_TIMER); + } + else if (ppc.interrupt_pending & 0x4) + { + ppc403_exception(EXCEPTION_FIXED_INTERVAL_TIMER); + } + } + } +} + +static void ppc403_reset(void) +{ + ppc.pc = ppc.npc = 0xfffffffc; + + ppc_set_msr(0); + change_pc(ppc.pc); +} + +static int ppc403_execute(int cycles) +{ + UINT32 fit_trigger_cycle; + ppc_icount = cycles; + ppc_tb_base_icount = cycles; + change_pc(ppc.npc); + + fit_trigger_cycle = 0x7fffffff; + + if (ppc.fit_int_enable) + { + UINT32 tb = (UINT32)ppc.tb; + UINT32 fit_cycles = 0; + + if (ppc.tb & ppc.fit_bit) + { + fit_cycles += ppc.fit_bit; + tb += fit_cycles; + } + + fit_cycles += ppc.fit_bit - (tb & (ppc.fit_bit-1)); + + fit_trigger_cycle = ppc_icount - fit_cycles; + } + + while( ppc_icount > 0 ) + { + UINT32 opcode; + + CALL_MAME_DEBUG; + ppc.pc = ppc.npc; + ppc.npc += 4; + opcode = ROPCODE(ppc.pc); + + 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--; + + /* Programmable Interval Timer (PIT) */ + if (ppc.pit_counter > 0) + { + ppc.pit_counter--; + if (ppc.pit_counter == 0) + { + if (ppc.pit_int_enable) { + ppc.interrupt_pending |= 0x2; + } + if (ppc.tcr & 0x00400000) // Automatic reload + { + ppc.pit_counter = ppc.pit; + } + } + } + + /* Fixed Interval Timer */ + if (fit_trigger_cycle != 0x7fffffff) + { + if (ppc_icount == fit_trigger_cycle) + { + if (ppc.fit_int_enable) + { + fit_trigger_cycle -= ppc.fit_bit; + ppc.interrupt_pending |= 0x4; + } + } + } + +#if 0 + /* Watchdog Timer */ + if (((UINT32)(ppc.tb) & ppc.wdt_bit) && (tblo & ppc.wdt_bit) == 0) { + switch((ppc.tsr >> 28) & 0x3) + { + case 0: ppc.tsr |= TSR_ENW; break; + case 1: ppc.tsr |= TSR_ENW; break; + case 2: + if (ppc.wdt_int_enable && (ppc.msr & MSR_CE)) { + ppc403_exception(EXCEPTION_WATCHDOG_TIMER); + } + break; + case 3: + fatalerror("PPC: Watchdog Timer caused reset"); + break; + } + } +#endif + + ppc403_check_interrupts(); + } + + // update timebase + ppc.tb += (ppc_tb_base_icount - ppc_icount); + + return cycles - ppc_icount; +} + +void ppc403_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; + + msr &= ~(MSR_WE | MSR_PR | MSR_EE | MSR_PE); // Clear WE, PR, EE, PR + if( msr & MSR_LE ) + msr |= MSR_ILE; + else + msr &= ~MSR_ILE; + ppc_set_msr(msr); + + ppc.npc = EVPR | 0x0500; + change_pc(ppc.npc); + + ppc.interrupt_pending &= ~0x1; + } + break; + } + + case EXCEPTION_TRAP: /* Program exception / Trap */ + { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.pc; + SRR1 = msr; + + msr &= ~(MSR_WE | MSR_PR | MSR_EE | MSR_PE); // Clear WE, PR, EE, PR + if( msr & MSR_ILE ) + msr |= MSR_LE; + else + msr &= ~MSR_LE; + ppc_set_msr(msr); + + if( msr & MSR_IP ) + ppc.npc = 0xfff00000 | 0x0700; + else + ppc.npc = EVPR | 0x0700; + change_pc(ppc.npc); + break; + } + + case EXCEPTION_SYSTEM_CALL: /* System call */ + { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.npc; + SRR1 = msr; + + msr &= ~(MSR_WE | MSR_PR | MSR_EE | MSR_PE); // Clear WE, PR, EE, PR + if( msr & MSR_ILE ) + msr |= MSR_LE; + else + msr &= ~MSR_LE; + ppc_set_msr(msr); + + if( msr & MSR_IP ) + ppc.npc = 0xfff00000 | 0x0c00; + else + ppc.npc = EVPR | 0x0c00; + change_pc(ppc.npc); + break; + } + + case EXCEPTION_PROGRAMMABLE_INTERVAL_TIMER: + { + if( ppc_get_msr() & MSR_EE ) { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.npc; + SRR1 = msr; + + msr &= ~(MSR_WE | MSR_PR | MSR_EE | MSR_PE); // Clear WE, PR, EE, PR + if( msr & MSR_LE ) + msr |= MSR_ILE; + else + msr &= ~MSR_ILE; + ppc_set_msr(msr); + + ppc.npc = EVPR | 0x1000; + change_pc(ppc.npc); + + ppc.tsr |= 0x08000000; // PIT interrupt + ppc.interrupt_pending &= ~0x2; + } + break; + } + + case EXCEPTION_FIXED_INTERVAL_TIMER: /* Fixed Interval Timer */ + { + if( ppc_get_msr() & MSR_EE ) { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.npc; + SRR1 = msr; + + msr &= ~(MSR_WE | MSR_PR | MSR_EE | MSR_PE); // Clear WE, PR, EE, PR + if( msr & MSR_LE ) + msr |= MSR_ILE; + else + msr &= ~MSR_ILE; + ppc_set_msr(msr); + + ppc.npc = EVPR | 0x1010; + change_pc(ppc.npc); + ppc.interrupt_pending &= ~0x4; + } + break; + } + + case EXCEPTION_WATCHDOG_TIMER: /* Watchdog Timer */ + { + UINT32 msr = ppc_get_msr(); + + SRR2 = ppc.npc; + SRR3 = msr; + + msr &= ~(MSR_WE | MSR_PR | MSR_CE | MSR_EE | MSR_DE | MSR_PE | MSR_DR | MSR_IR); + if (msr & MSR_LE) + msr |= MSR_ILE; + else + msr &= ~MSR_ILE; + ppc_set_msr(msr); + + ppc.npc = EVPR | 0x1020; + change_pc(ppc.npc); + break; + } + + case EXCEPTION_CRITICAL_INTERRUPT: + { + UINT32 msr = ppc_get_msr(); + + SRR2 = ppc.npc; + SRR3 = msr; + + msr &= ~(MSR_WE | MSR_PR | MSR_CE | MSR_EE | MSR_DE | MSR_PE | MSR_DR | MSR_IR); + if (msr & MSR_LE) + msr |= MSR_ILE; + else + msr &= ~MSR_ILE; + ppc_set_msr(msr); + + EXISR |= 0x80000000; + ppc.npc = EVPR | 0x100; + change_pc(ppc.npc); + break; + } + + default: + fatalerror("ppc: Unhandled exception %d", exception); + break; + } +} + +static void ppc403_set_irq_line(int irqline, int state) +{ + if (irqline >= INPUT_LINE_IRQ0 && irqline <= INPUT_LINE_IRQ4) + { + UINT32 mask = (1 << (4 - irqline)); + if( state == ASSERT_LINE) { + if( EXIER & mask ) { + ppc.exisr |= mask; + ppc.interrupt_pending |= 0x1; + + if (ppc.irq_callback) + { + ppc.irq_callback(irqline); + } + } + } + // clear line is used to clear the interrupt when the interrupts are level-sensitive + else if (state == CLEAR_LINE) + { + ppc.exisr &= ~mask; + } + } + else if (irqline == PPC403_SPU_RX) + { + UINT32 mask = 0x08000000; + if (state) { + if( EXIER & mask ) { + ppc.exisr |= mask; + ppc.interrupt_pending |= 0x1; + } + } + } + else if (irqline == PPC403_SPU_TX) + { + UINT32 mask = 0x04000000; + if (state) { + if( EXIER & mask ) { + ppc.exisr |= mask; + ppc.interrupt_pending |= 0x1; + } + } + } + else if (irqline == PPC403_CRITICAL_IRQ) + { + if (state) { + if (EXIER & 0x80000000) { + ppc403_exception(EXCEPTION_CRITICAL_INTERRUPT); + } + } + } + else + { + fatalerror("PPC: Unknown IRQ line %d", irqline); + } +} + +static void ppc403_dma_set_irq_line(int dma, int state) +{ + UINT32 mask = (1 << (3 - dma)) << 20; + if( state ) { + if( EXIER & mask ) { + ppc.exisr |= mask; + ppc.interrupt_pending |= 0x1; + } + } +} +#endif + +#ifdef PPC_DRC +static void ppc403_dma_set_irq_line(int dma, int state) +{ + UINT32 mask = (1 << (3 - dma)) << 20; + if( state ) { + if( EXIER & mask ) { + ppc.exisr |= mask; + ppc.exception_pending |= 0x1; + } + } +} +#endif + + + + + + +#ifndef PPC_DRC +static void ppc_dccci(UINT32 op) +{ + +} + +static void ppc_dcread(UINT32 op) +{ + +} + +static void ppc_icbt(UINT32 op) +{ + +} + +static void ppc_iccci(UINT32 op) +{ + +} + +static void ppc_icread(UINT32 op) +{ + +} + +static void ppc_rfci(UINT32 op) +{ + UINT32 msr; + ppc.npc = ppc.srr2; + msr = ppc.srr3; + ppc_set_msr( msr ); + + change_pc(ppc.npc); +} +#endif + +static void ppc_mfdcr(UINT32 op) +{ + REG(RT) = ppc_get_dcr(SPR); +} + +static void ppc_mtdcr(UINT32 op) +{ + ppc_set_dcr(SPR, REG(RS)); +} + +static void ppc_wrtee(UINT32 op) +{ + if( REG(RS) & 0x8000 ) + ppc_set_msr( ppc_get_msr() | MSR_EE); + else + ppc_set_msr( ppc_get_msr() & ~MSR_EE); +} + +static void ppc_wrteei(UINT32 op) +{ + if( op & 0x8000 ) + ppc_set_msr( ppc_get_msr() | MSR_EE); + else + ppc_set_msr( ppc_get_msr() & ~MSR_EE); +} + + + +/**************************************************************************/ +/* PPC403 Serial Port */ + +UINT8 ppc403_spu_r(UINT32 a) +{ + switch(a & 0xf) + { + case 0x0: return ppc.spu.spls | 0x6; /* transmit buffer is always empty */ + case 0x2: return ppc.spu.sphs; + case 0x4: return (ppc.spu.brd >> 8) & 0xf; + case 0x5: return (ppc.spu.brd & 0xff); + case 0x6: return ppc.spu.spctl; + case 0x7: return ppc.spu.sprc; + case 0x8: return ppc.spu.sptc; + case 0x9: return ppc.spu.sprb; + default: fatalerror("ppc: spu_r: %02X", a & 0xf); + } +} + +void ppc403_spu_w(UINT32 a, UINT8 d) +{ + switch(a & 0xf) + { + case 0x0: + if( d & 0x80 ) ppc.spu.spls &= ~0x80; + if( d & 0x40 ) ppc.spu.spls &= ~0x40; + if( d & 0x20 ) ppc.spu.spls &= ~0x20; + if( d & 0x10 ) ppc.spu.spls &= ~0x10; + if( d & 0x08 ) ppc.spu.spls &= ~0x08; + break; + + case 0x2: + ppc.spu.sphs = d; + break; + + case 0x4: + ppc.spu.brd &= 0xff; + ppc.spu.brd |= (d << 8); + break; + + case 0x5: + ppc.spu.brd &= 0xff00; + ppc.spu.brd |= d; + if (ppc.iocr & 0x2) { + mame_printf_debug("ppc: SPU Baud rate: %d\n", (3686400 / (ppc.spu.brd + 1)) / 16); + } else { + mame_printf_debug("ppc: SPU Baud rate: %d\n", (33333333 / (ppc.spu.brd + 1)) / 16); + } + break; + + case 0x6: + ppc.spu.spctl = d; + break; + + case 0x7: + ppc.spu.sprc = d; + if (ppc.spu.sprc & 0x80) /* enable RX */ + { + int baud_rate; + if (ppc.iocr & 0x2) { + baud_rate = (3686400 / (ppc.spu.brd + 1)) / 16; + } else { + baud_rate = (33333333 / (ppc.spu.brd + 1)) / 16; + } + + /* check if serial port is hooked to a DMA channel */ + /* if so, do a DMA operation */ + if( ((((ppc.spu.sprc >> 5) & 0x3) == 2) && (ppc.dma[2].cr & DMA_CE)) || + ((((ppc.spu.sprc >> 5) & 0x3) == 3) && (ppc.dma[3].cr & DMA_CE)) ) + { + int i; + int ch = (ppc.spu.sprc >> 5) & 0x3; + // mame_printf_debug("ppc: DMA from serial port on channel %d (DA: %08X)\n", ch, ppc.dma[ch].da); + + if (spu_rx_dma_handler) + { + int length = ppc.dma[ch].ct; + + spu_rx_dma_handler(length); + + for (i=0; i < length; i++) + { + program_write_byte_32be(ppc.dma[ch].da++, spu_rx_dma_ptr[i]); + } + } + + ppc.dmasr |= (1 << (27 - ch)); + + /* generate interrupts */ + if( ppc.dma[ch].cr & DMA_CIE ) + { + ppc403_dma_set_irq_line( ch, PULSE_LINE ); + } + + /* set receive buffer full */ + ppc.spu.spls = 0x80; + +#ifndef PPC_DRC + ppc403_set_irq_line(PPC403_SPU_RX, ASSERT_LINE); +#else + ppcdrc403_set_irq_line(PPC403_SPU_RX, ASSERT_LINE); +#endif + } + } + else /* disable RX */ + { + } + break; + + case 0x8: + ppc.spu.sptc = d; + break; + + case 0x9: + ppc.spu.sptb = d; + ppc403_spu_tx_callback(Machine, cpu_getactivecpu()); + break; + + default: + fatalerror("ppc: spu_w: %02X, %02X", a & 0xf, d); + break; + } + //mame_printf_debug("spu_w: %02X, %02X at %08X\n", a & 0xf, d, ppc.pc); +} + +void ppc403_spu_rx(UINT8 data) +{ + ppc.spu.sprb = data; + + /* set receive buffer full */ + ppc.spu.spls = 0x80; + + /* generate interrupt if DMA is disabled and RBR interrupt is enabled */ + if (((ppc.spu.sprc >> 5) & 0x3) == 0x01) { +#ifndef PPC_DRC + ppc403_set_irq_line(PPC403_SPU_RX, ASSERT_LINE); +#else + ppcdrc403_set_irq_line(PPC403_SPU_RX, ASSERT_LINE); +#endif + } +} + +static TIMER_CALLBACK( ppc403_spu_rx_callback ) +{ + if (spu_rx_handler != NULL) + { + ppc403_spu_rx(spu_rx_handler()); + } +} + +static TIMER_CALLBACK( ppc403_spu_tx_callback ) +{ + if (spu_tx_handler != NULL) + { + spu_tx_handler(ppc.spu.sptb); + + /* generate interrupt if DMA is disabled and TBR interrupt is enabled */ + if (((ppc.spu.sptc >> 5) & 0x3) == 0x01) { +#ifndef PPC_DRC + ppc403_set_irq_line(PPC403_SPU_TX, ASSERT_LINE); +#else + ppcdrc403_set_irq_line(PPC403_SPU_TX, ASSERT_LINE); +#endif + } + } +} + +void ppc403_install_spu_rx_handler(SPU_RX_HANDLER rx_handler) +{ + spu_rx_handler = rx_handler; +} + +void ppc403_install_spu_tx_handler(SPU_TX_HANDLER tx_handler) +{ + spu_tx_handler = tx_handler; +} + + +void ppc403_spu_rx_dma(UINT8 *data, int length) +{ + +} + +void ppc403_install_spu_rx_dma_handler(PPC_DMA_HANDLER rx_dma_handler, UINT8 *buffer) +{ + spu_rx_dma_handler = rx_dma_handler; + spu_rx_dma_ptr = buffer; +} + +void ppc403_install_spu_tx_dma_handler(PPC_DMA_HANDLER tx_dma_handler, UINT8 *buffer) +{ + spu_tx_dma_handler = tx_dma_handler; + spu_tx_dma_ptr = buffer; +} + +/*********************************************************************************/ + +/* PPC 403 DMA */ + +static const int dma_transfer_width[4] = { 1, 2, 4, 16 }; + +void ppc403_install_dma_read_handler(int ch, PPC_DMA_HANDLER dma_handler, UINT8 *buffer) +{ + dma_read_handler[ch] = dma_handler; + dma_read_ptr[ch] = buffer; +} + +void ppc403_install_dma_write_handler(int ch, PPC_DMA_HANDLER dma_handler, UINT8 *buffer) +{ + dma_write_handler[ch] = dma_handler; + dma_write_ptr[ch] = buffer; +} + +static void ppc403_dma_exec(int ch) +{ + int i; + int dai, sai, width; + + /* Is the DMA channel enabled ? */ + if( ppc.dma[ch].cr & DMA_CE ) + { + /* transfer width */ + width = dma_transfer_width[(ppc.dma[ch].cr >> 26) & 0x3]; + + if( ppc.dma[ch].cr & DMA_DAI ) + dai = width; + else + dai = 0; /* DA not incremented */ + + if( ppc.dma[ch].cr & DMA_SAI ) + sai = width; + else + sai = 0; /* SA not incremented */ + + + /* transfer mode */ + switch( (ppc.dma[ch].cr >> 21) & 0x3 ) + { + case 0: /* buffered DMA */ + if( ppc.dma[ch].cr & DMA_TD ) /* peripheral to mem */ + { + // nothing to do for now */ + } + else /* mem to peripheral */ + { + + /* check if the serial port is hooked to channel 2 or 3 */ + if( (ch == 2 && ((ppc.spu.sptc >> 5) & 0x3) == 2) || + (ch == 3 && ((ppc.spu.sptc >> 5) & 0x3) == 3) ) + { + mame_printf_debug("ppc: dma_exec: DMA to serial port on channel %d (DA: %08X)\n", ch, ppc.dma[ch].da); + + if (spu_tx_dma_handler) + { + int length = ppc.dma[ch].ct; + + for( i=0; i < length; i++ ) { + spu_tx_dma_ptr[i] = program_read_byte_32be(ppc.dma[ch].da++); + } + spu_tx_dma_handler(length); + } + +#ifndef PPC_DRC + ppc403_set_irq_line(PPC403_SPU_TX, ASSERT_LINE); +#else + ppcdrc403_set_irq_line(PPC403_SPU_TX, ASSERT_LINE); +#endif + } + else { + fatalerror("ppc: dma_exec: buffered DMA to unknown peripheral ! (channel %d)", ch); + } + + } + break; + + case 1: /* fly-by DMA */ + fatalerror("ppc: dma_exec: fly-by DMA not implemented"); + break; + + case 2: /* software initiated mem-to-mem DMA */ + //mame_printf_debug("ppc: DMA (%d, SW mem-to-mem): SA = %08X, DA = %08X, CT = %08X\n", ch, ppc.dma[ch].sa, ppc.dma[ch].da, ppc.dma[ch].ct); + + switch(width) + { + case 1: /* Byte transfer */ + for (i=0; i < ppc.dma[ch].ct; i++) + { + UINT8 b = READ8(ppc.dma[ch].sa); + WRITE8(ppc.dma[ch].da, b); + ppc.dma[ch].sa += sai; + ppc.dma[ch].da += dai; + } + break; + case 2: /* Word transfer */ + for (i=0; i < ppc.dma[ch].ct; i++) + { + UINT16 w = READ16(ppc.dma[ch].sa); + WRITE16(ppc.dma[ch].da, w); + ppc.dma[ch].sa += sai; + ppc.dma[ch].da += dai; + } + break; + case 4: /* Double word transfer */ + for (i=0; i < ppc.dma[ch].ct; i++) + { + UINT32 d = READ32(ppc.dma[ch].sa); + WRITE32(ppc.dma[ch].da, d); + ppc.dma[ch].sa += sai; + ppc.dma[ch].da += dai; + } + break; + case 16: /* 16-byte transfer */ + for (i=0; i < ppc.dma[ch].ct; i++) + { + UINT32 d1 = READ32(ppc.dma[ch].sa+0); + UINT32 d2 = READ32(ppc.dma[ch].sa+4); + UINT32 d3 = READ32(ppc.dma[ch].sa+8); + UINT32 d4 = READ32(ppc.dma[ch].sa+12); + WRITE32(ppc.dma[ch].da+0, d1); + WRITE32(ppc.dma[ch].da+4, d2); + WRITE32(ppc.dma[ch].da+8, d3); + WRITE32(ppc.dma[ch].da+12, d4); + ppc.dma[ch].sa += 16; + ppc.dma[ch].da += 16; + } + break; + default: + fatalerror("dma: dma_exec: SW mem-to-mem DMA, width = %d", width); + } + break; + + case 3: /* hardware initiated mem-to-mem DMA */ + fatalerror("ppc: dma_exec: HW mem-to-mem DMA not implemented"); + break; + } + + ppc.dmasr |= (1 << (27 - ch)); + + /* DEBUG: check for not yet supported features */ + if( (ppc.dma[ch].cr & DMA_TCE) == 0 ) + fatalerror("ppc: dma_exec: DMA_TCE == 0"); + + if( ppc.dma[ch].cr & DMA_CH ) + fatalerror("ppc: dma_exec: DMA chaining not implemented"); + + /* generate interrupts */ + if( ppc.dma[ch].cr & DMA_CIE ) + ppc403_dma_set_irq_line( ch, PULSE_LINE ); + + } +} + +/*********************************************************************************/ + +static UINT8 ppc403_read8(UINT32 a) +{ + if(a >= 0x40000000 && a <= 0x4000000f) /* Serial Port */ + return ppc403_spu_r(a); + return program_read_byte_32be(a); +} + +#define ppc403_read16 program_read_word_32be +#define ppc403_read32 program_read_dword_32be + +static void ppc403_write8(UINT32 a, UINT8 d) +{ + if( a >= 0x40000000 && a <= 0x4000000f ) /* Serial Port */ + { + ppc403_spu_w(a, d); + return; + } + program_write_byte_32be(a, d); +} + +#define ppc403_write16 program_write_word_32be +#define ppc403_write32 program_write_dword_32be + +static UINT16 ppc403_read16_unaligned(UINT32 a) +{ + fatalerror("ppc: Unaligned read16 %08X at %08X", a, ppc.pc); + return 0; +} + +static UINT32 ppc403_read32_unaligned(UINT32 a) +{ + fatalerror("ppc: Unaligned read32 %08X at %08X", a, ppc.pc); + return 0; +} + +static void ppc403_write16_unaligned(UINT32 a, UINT16 d) +{ + fatalerror("ppc: Unaligned write16 %08X, %04X at %08X", a, d, ppc.pc); +} + +static void ppc403_write32_unaligned(UINT32 a, UINT32 d) +{ + fatalerror("ppc: Unaligned write32 %08X, %08X at %08X", a, d, ppc.pc); +} + |