summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/cpu/sharc/sharcdma.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/cpu/sharc/sharcdma.c')
-rw-r--r--src/emu/cpu/sharc/sharcdma.c204
1 files changed, 204 insertions, 0 deletions
diff --git a/src/emu/cpu/sharc/sharcdma.c b/src/emu/cpu/sharc/sharcdma.c
new file mode 100644
index 00000000000..720bd9538c0
--- /dev/null
+++ b/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(int channel, UINT32 dma_chain_ptr, int chained_direction)
+{
+ UINT32 op_ptr = 0x20000 + dma_chain_ptr;
+
+ UINT32 int_index = dm_read32(op_ptr - 0);
+ UINT32 int_modifier = dm_read32(op_ptr - 1);
+ UINT32 int_count = dm_read32(op_ptr - 2);
+ UINT32 chain_ptr = dm_read32(op_ptr - 3);
+ //UINT32 gen_purpose = dm_read32(op_ptr - 4);
+ UINT32 ext_index = dm_read32(op_ptr - 5);
+ UINT32 ext_modifier = dm_read32(op_ptr - 6);
+ UINT32 ext_count = dm_read32(op_ptr - 7);
+
+ if (sharc.dmaop_cycles > 0)
+ {
+ fatalerror("schedule_chained_dma_op: DMA operation already scheduled at %08X!", sharc.pc);
+ }
+
+ if (chained_direction) // Transmit to external
+ {
+ sharc.dmaop_dst = ext_index;
+ sharc.dmaop_dst_modifier = ext_modifier;
+ sharc.dmaop_dst_count = ext_count;
+ sharc.dmaop_src = int_index;
+ sharc.dmaop_src_modifier = int_modifier;
+ sharc.dmaop_src_count = int_count;
+ }
+ else // Receive from external
+ {
+ sharc.dmaop_src = ext_index;
+ sharc.dmaop_src_modifier = ext_modifier;
+ sharc.dmaop_src_count = ext_count;
+ sharc.dmaop_dst = int_index;
+ sharc.dmaop_dst_modifier = int_modifier;
+ sharc.dmaop_dst_count = int_count;
+ }
+
+ sharc.dmaop_pmode = 0;
+ sharc.dmaop_channel = channel;
+ sharc.dmaop_cycles = sharc.dmaop_src_count / 4;
+ sharc.dmaop_chain_ptr = chain_ptr;
+ sharc.dmaop_chained_direction = chained_direction;
+}
+
+static void schedule_dma_op(int channel, UINT32 src, UINT32 dst, int src_modifier, int dst_modifier, int src_count, int dst_count, int pmode)
+{
+ if (sharc.dmaop_cycles > 0)
+ {
+ fatalerror("schedule_dma_op: DMA operation already scheduled at %08X!", sharc.pc);
+ }
+
+ sharc.dmaop_channel = channel;
+ sharc.dmaop_src = src;
+ sharc.dmaop_dst = dst;
+ sharc.dmaop_src_modifier = src_modifier;
+ sharc.dmaop_dst_modifier = dst_modifier;
+ sharc.dmaop_src_count = src_count;
+ sharc.dmaop_dst_count = dst_count;
+ sharc.dmaop_pmode = pmode;
+ sharc.dmaop_chain_ptr = 0;
+ sharc.dmaop_cycles = src_count / 4;
+}
+
+static void dma_op(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(src);
+ dm_write32(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(src+0) & 0xffff) << 16) | (dm_read32(src+1) & 0xffff);
+
+ dm_write32(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(src+0) & 0xff) << 0) |
+ ((UINT64)(dm_read32(src+1) & 0xff) << 8) |
+ ((UINT64)(dm_read32(src+2) & 0xff) << 16) |
+ ((UINT64)(dm_read32(src+3) & 0xff) << 24) |
+ ((UINT64)(dm_read32(src+4) & 0xff) << 32) |
+ ((UINT64)(dm_read32(src+5) & 0xff) << 40);
+
+ pm_write48(dst, data);
+ src += src_modifier * 6;
+ dst += dst_modifier;
+ }
+ break;
+ }
+ default:
+ {
+ fatalerror("SHARC: dma_op: unimplemented packing mode %d\n", pmode);
+ }
+ }
+
+ if (sharc.dmaop_channel == 6)
+ {
+ sharc.irptl |= (1 << (sharc.dmaop_channel+10));
+
+ /* DMA interrupt */
+ if (sharc.imask & (1 << (sharc.dmaop_channel+10)))
+ {
+ sharc.irq_active |= 1 << (sharc.dmaop_channel+10);
+ }
+ }
+}
+
+static void sharc_dma_exec(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 = (sharc.dma[channel].control >> 1) & 0x1;
+ tran = (sharc.dma[channel].control >> 2) & 0x1;
+ dtype = (sharc.dma[channel].control >> 5) & 0x1;
+ pmode = (sharc.dma[channel].control >> 6) & 0x3;
+ mswf = (sharc.dma[channel].control >> 8) & 0x1;
+ master = (sharc.dma[channel].control >> 9) & 0x1;
+ ishake = (sharc.dma[channel].control >> 10) & 0x1;
+ intio = (sharc.dma[channel].control >> 11) & 0x1;
+ ext = (sharc.dma[channel].control >> 12) & 0x1;
+ flsh = (sharc.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 = sharc.dma[channel].chain_ptr & 0x1ffff;
+
+ schedule_chained_dma_op(channel, dma_chain_ptr, tran);
+ }
+ else
+ {
+ if (tran) // Transmit to external
+ {
+ dst = sharc.dma[channel].ext_index;
+ dst_modifier = sharc.dma[channel].ext_modifier;
+ dst_count = sharc.dma[channel].ext_count;
+ src = sharc.dma[channel].int_index;
+ src_modifier = sharc.dma[channel].int_modifier;
+ src_count = sharc.dma[channel].int_count;
+ }
+ else // Receive from external
+ {
+ src = sharc.dma[channel].ext_index;
+ src_modifier = sharc.dma[channel].ext_modifier;
+ src_count = sharc.dma[channel].ext_count;
+ dst = sharc.dma[channel].int_index;
+ dst_modifier = sharc.dma[channel].int_modifier;
+ dst_count = sharc.dma[channel].int_count;
+
+ if (dst < 0x20000)
+ {
+ dst |= 0x20000;
+ }
+ }
+
+ if (dtype)
+ //if (src_count != dst_count)
+ {
+ pmode = DMA_PMODE_8_48;
+ }
+
+ schedule_dma_op(channel, src, dst, src_modifier, dst_modifier, src_count, dst_count, pmode);
+ }
+}