diff options
Diffstat (limited to 'trunk/src/emu/cpu/sharc/sharcdma.c')
-rw-r--r-- | trunk/src/emu/cpu/sharc/sharcdma.c | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/trunk/src/emu/cpu/sharc/sharcdma.c b/trunk/src/emu/cpu/sharc/sharcdma.c new file mode 100644 index 00000000000..740f68bda14 --- /dev/null +++ b/trunk/src/emu/cpu/sharc/sharcdma.c @@ -0,0 +1,204 @@ +/* SHARC DMA operations */ + +#define DMA_PMODE_NO_PACKING 0 +#define DMA_PMODE_16_32 1 +#define DMA_PMODE_16_48 2 +#define DMA_PMODE_32_48 3 +#define DMA_PMODE_8_48 4 + +static void schedule_chained_dma_op(SHARC_REGS *cpustate, int channel, UINT32 dma_chain_ptr, int chained_direction) +{ + UINT32 op_ptr = 0x20000 + dma_chain_ptr; + + UINT32 int_index = dm_read32(cpustate, op_ptr - 0); + UINT32 int_modifier = dm_read32(cpustate, op_ptr - 1); + UINT32 int_count = dm_read32(cpustate, op_ptr - 2); + UINT32 chain_ptr = dm_read32(cpustate, op_ptr - 3); + //UINT32 gen_purpose = dm_read32(cpustate, op_ptr - 4); + UINT32 ext_index = dm_read32(cpustate, op_ptr - 5); + UINT32 ext_modifier = dm_read32(cpustate, op_ptr - 6); + UINT32 ext_count = dm_read32(cpustate, op_ptr - 7); + + if (cpustate->dmaop_cycles > 0) + { + fatalerror("schedule_chained_dma_op: DMA operation already scheduled at %08X!", cpustate->pc); + } + + if (chained_direction) // Transmit to external + { + cpustate->dmaop_dst = ext_index; + cpustate->dmaop_dst_modifier = ext_modifier; + cpustate->dmaop_dst_count = ext_count; + cpustate->dmaop_src = int_index; + cpustate->dmaop_src_modifier = int_modifier; + cpustate->dmaop_src_count = int_count; + } + else // Receive from external + { + cpustate->dmaop_src = ext_index; + cpustate->dmaop_src_modifier = ext_modifier; + cpustate->dmaop_src_count = ext_count; + cpustate->dmaop_dst = int_index; + cpustate->dmaop_dst_modifier = int_modifier; + cpustate->dmaop_dst_count = int_count; + } + + cpustate->dmaop_pmode = 0; + cpustate->dmaop_channel = channel; + cpustate->dmaop_cycles = cpustate->dmaop_src_count / 4; + cpustate->dmaop_chain_ptr = chain_ptr; + cpustate->dmaop_chained_direction = chained_direction; +} + +static void schedule_dma_op(SHARC_REGS *cpustate, int channel, UINT32 src, UINT32 dst, int src_modifier, int dst_modifier, int src_count, int dst_count, int pmode) +{ + if (cpustate->dmaop_cycles > 0) + { + fatalerror("schedule_dma_op: DMA operation already scheduled at %08X!", cpustate->pc); + } + + cpustate->dmaop_channel = channel; + cpustate->dmaop_src = src; + cpustate->dmaop_dst = dst; + cpustate->dmaop_src_modifier = src_modifier; + cpustate->dmaop_dst_modifier = dst_modifier; + cpustate->dmaop_src_count = src_count; + cpustate->dmaop_dst_count = dst_count; + cpustate->dmaop_pmode = pmode; + cpustate->dmaop_chain_ptr = 0; + cpustate->dmaop_cycles = src_count / 4; +} + +static void dma_op(SHARC_REGS *cpustate, UINT32 src, UINT32 dst, int src_modifier, int dst_modifier, int src_count, int dst_count, int pmode) +{ + int i; + //printf("dma_op: %08X, %08X, %08X, %08X, %08X, %08X, %d\n", src, dst, src_modifier, dst_modifier, src_count, dst_count, pmode); + + switch (pmode) + { + case DMA_PMODE_NO_PACKING: + { + for (i=0; i < src_count; i++) + { + UINT32 data = dm_read32(cpustate, src); + dm_write32(cpustate, dst, data); + src += src_modifier; + dst += dst_modifier; + } + break; + } + case DMA_PMODE_16_32: + { + int length = src_count/2; + for (i=0; i < length; i++) + { + UINT32 data = ((dm_read32(cpustate, src+0) & 0xffff) << 16) | (dm_read32(cpustate, src+1) & 0xffff); + + dm_write32(cpustate, dst, data); + src += src_modifier * 2; + dst += dst_modifier; + } + break; + } + case DMA_PMODE_8_48: + { + int length = src_count/6; + for (i=0; i < length; i++) + { + UINT64 data = ((UINT64)(dm_read32(cpustate, src+0) & 0xff) << 0) | + ((UINT64)(dm_read32(cpustate, src+1) & 0xff) << 8) | + ((UINT64)(dm_read32(cpustate, src+2) & 0xff) << 16) | + ((UINT64)(dm_read32(cpustate, src+3) & 0xff) << 24) | + ((UINT64)(dm_read32(cpustate, src+4) & 0xff) << 32) | + ((UINT64)(dm_read32(cpustate, src+5) & 0xff) << 40); + + pm_write48(cpustate, dst, data); + src += src_modifier * 6; + dst += dst_modifier; + } + break; + } + default: + { + fatalerror("SHARC: dma_op: unimplemented packing mode %d\n", pmode); + } + } + + if (cpustate->dmaop_channel == 6) + { + cpustate->irptl |= (1 << (cpustate->dmaop_channel+10)); + + /* DMA interrupt */ + if (cpustate->imask & (1 << (cpustate->dmaop_channel+10))) + { + cpustate->irq_active |= 1 << (cpustate->dmaop_channel+10); + } + } +} + +static void sharc_dma_exec(SHARC_REGS *cpustate, int channel) +{ + UINT32 src, dst; + UINT32 src_count, dst_count; + UINT32 src_modifier, dst_modifier; + int chen, tran, dtype, pmode, /*mswf, master,*/ ishake, intio/*, ext, flsh*/; + + chen = (cpustate->dma[channel].control >> 1) & 0x1; + tran = (cpustate->dma[channel].control >> 2) & 0x1; + dtype = (cpustate->dma[channel].control >> 5) & 0x1; + pmode = (cpustate->dma[channel].control >> 6) & 0x3; + //mswf = (cpustate->dma[channel].control >> 8) & 0x1; + //master = (cpustate->dma[channel].control >> 9) & 0x1; + ishake = (cpustate->dma[channel].control >> 10) & 0x1; + intio = (cpustate->dma[channel].control >> 11) & 0x1; + //ext = (cpustate->dma[channel].control >> 12) & 0x1; + //flsh = (cpustate->dma[channel].control >> 13) & 0x1; + + if (ishake) + fatalerror("SHARC: dma_exec: handshake not supported"); + if (intio) + fatalerror("SHARC: dma_exec: single-word interrupt enable not supported"); + + + + if (chen) // Chained DMA + { + UINT32 dma_chain_ptr = cpustate->dma[channel].chain_ptr & 0x1ffff; + + schedule_chained_dma_op(cpustate, channel, dma_chain_ptr, tran); + } + else + { + if (tran) // Transmit to external + { + dst = cpustate->dma[channel].ext_index; + dst_modifier = cpustate->dma[channel].ext_modifier; + dst_count = cpustate->dma[channel].ext_count; + src = cpustate->dma[channel].int_index; + src_modifier = cpustate->dma[channel].int_modifier; + src_count = cpustate->dma[channel].int_count; + } + else // Receive from external + { + src = cpustate->dma[channel].ext_index; + src_modifier = cpustate->dma[channel].ext_modifier; + src_count = cpustate->dma[channel].ext_count; + dst = cpustate->dma[channel].int_index; + dst_modifier = cpustate->dma[channel].int_modifier; + dst_count = cpustate->dma[channel].int_count; + + if (dst < 0x20000) + { + dst |= 0x20000; + } + } + + if (dtype) + //if (src_count != dst_count) + { + pmode = DMA_PMODE_8_48; + } + + schedule_dma_op(cpustate, channel, src, dst, src_modifier, dst_modifier, src_count, dst_count, pmode); + } +} |