summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
authorGravatarGravatar Ville Linde <villelin@mamedev.org>2012-09-12 18:59:17 +0000
committerGravatarGravatar Ville Linde <villelin@mamedev.org>2012-09-12 18:59:17 +0000
commit087fd08912440de21dbb03ca18cb2ba39237af16 (patch)
tree5cbc0f603358ac4e366d8767b03221fb22bd3796 /src
parentb60c2477b539b57b300c4f05df2805faa8dea395 (diff)
sharc: Rewrote DMA handling to use timers.
Diffstat (limited to 'src')
-rw-r--r--src/emu/cpu/sharc/sharc.c113
-rw-r--r--src/emu/cpu/sharc/sharcdma.c117
2 files changed, 124 insertions, 106 deletions
diff --git a/src/emu/cpu/sharc/sharc.c b/src/emu/cpu/sharc/sharc.c
index ccab03aacb6..161ecc411ce 100644
--- a/src/emu/cpu/sharc/sharc.c
+++ b/src/emu/cpu/sharc/sharc.c
@@ -73,6 +73,21 @@ typedef struct
UINT32 loop_type;
} LADDR;
+typedef struct
+{
+ UINT32 src;
+ UINT32 dst;
+ UINT32 chain_ptr;
+ INT32 src_modifier;
+ INT32 dst_modifier;
+ INT32 src_count;
+ INT32 dst_count;
+ INT32 pmode;
+ INT32 chained_direction;
+ emu_timer *timer;
+ bool active;
+} DMA_OP;
+
typedef struct _SHARC_REGS SHARC_REGS;
struct _SHARC_REGS
{
@@ -147,17 +162,8 @@ struct _SHARC_REGS
SHARC_BOOT_MODE boot_mode;
- UINT32 dmaop_src;
- UINT32 dmaop_dst;
- UINT32 dmaop_chain_ptr;
- INT32 dmaop_src_modifier;
- INT32 dmaop_dst_modifier;
- INT32 dmaop_src_count;
- INT32 dmaop_dst_count;
- INT32 dmaop_pmode;
- INT32 dmaop_cycles;
- INT32 dmaop_channel;
- INT32 dmaop_chained_direction;
+ DMA_OP dma_op[12];
+ UINT32 dma_status;
INT32 interrupt_active;
@@ -260,12 +266,7 @@ static UINT32 sharc_iop_r(SHARC_REGS *cpustate, UINT32 address)
case 0x37: // DMA status
{
- UINT32 r = 0;
- if (cpustate->dmaop_cycles > 0)
- {
- r |= 1 << cpustate->dmaop_channel;
- }
- return r;
+ return cpustate->dma_status;
}
default: fatalerror("sharc_iop_r: Unimplemented IOP reg %02X at %08X\n", address, cpustate->pc);
}
@@ -292,7 +293,6 @@ static void sharc_iop_w(SHARC_REGS *cpustate, UINT32 address, UINT32 data)
case 0x1c:
{
cpustate->dma[6].control = data;
- //add_iop_write_latency_effect(cpustate, 0x1c, data, 1);
sharc_iop_delayed_w(cpustate, 0x1c, data, 1);
break;
}
@@ -312,7 +312,6 @@ static void sharc_iop_w(SHARC_REGS *cpustate, UINT32 address, UINT32 data)
case 0x1d:
{
cpustate->dma[7].control = data;
- //add_iop_write_latency_effect(cpustate, 0x1d, data, 30);
sharc_iop_delayed_w(cpustate, 0x1d, data, 30);
break;
}
@@ -438,6 +437,12 @@ static CPU_INIT( sharc )
cpustate->delayed_iop_timer = device->machine().scheduler().timer_alloc(FUNC(sharc_iop_delayed_write_callback), cpustate);
+ for (int i=0; i < 12; i++)
+ {
+ cpustate->dma_op[i].active = false;
+ cpustate->dma_op[i].timer = device->machine().scheduler().timer_alloc(FUNC(sharc_dma_callback), cpustate);
+ }
+
device->save_item(NAME(cpustate->pc));
device->save_pointer(NAME(&cpustate->r[0].r), ARRAY_LENGTH(cpustate->r));
device->save_pointer(NAME(&cpustate->reg_alt[0].r), ARRAY_LENGTH(cpustate->reg_alt));
@@ -523,17 +528,21 @@ static CPU_INIT( sharc )
device->save_item(NAME(cpustate->irq_active));
device->save_item(NAME(cpustate->active_irq_num));
- device->save_item(NAME(cpustate->dmaop_src));
- device->save_item(NAME(cpustate->dmaop_dst));
- device->save_item(NAME(cpustate->dmaop_chain_ptr));
- device->save_item(NAME(cpustate->dmaop_src_modifier));
- device->save_item(NAME(cpustate->dmaop_dst_modifier));
- device->save_item(NAME(cpustate->dmaop_src_count));
- device->save_item(NAME(cpustate->dmaop_dst_count));
- device->save_item(NAME(cpustate->dmaop_pmode));
- device->save_item(NAME(cpustate->dmaop_cycles));
- device->save_item(NAME(cpustate->dmaop_channel));
- device->save_item(NAME(cpustate->dmaop_chained_direction));
+ for (saveindex = 0; saveindex < ARRAY_LENGTH(cpustate->dma_op); saveindex++)
+ {
+ device->save_item(NAME(cpustate->dma_op[saveindex].src), saveindex);
+ device->save_item(NAME(cpustate->dma_op[saveindex].dst), saveindex);
+ device->save_item(NAME(cpustate->dma_op[saveindex].chain_ptr), saveindex);
+ device->save_item(NAME(cpustate->dma_op[saveindex].src_modifier), saveindex);
+ device->save_item(NAME(cpustate->dma_op[saveindex].dst_modifier), saveindex);
+ device->save_item(NAME(cpustate->dma_op[saveindex].src_count), saveindex);
+ device->save_item(NAME(cpustate->dma_op[saveindex].dst_count), saveindex);
+ device->save_item(NAME(cpustate->dma_op[saveindex].pmode), saveindex);
+ device->save_item(NAME(cpustate->dma_op[saveindex].chained_direction), saveindex);
+ device->save_item(NAME(cpustate->dma_op[saveindex].active), saveindex);
+ }
+
+ device->save_item(NAME(cpustate->dma_status));
device->save_item(NAME(cpustate->interrupt_active));
@@ -571,10 +580,9 @@ static CPU_RESET( sharc )
cpustate->dma[6].control = 0x2a1;
sharc_dma_exec(cpustate, 6);
- dma_op(cpustate, cpustate->dmaop_src, cpustate->dmaop_dst, cpustate->dmaop_src_modifier, cpustate->dmaop_dst_modifier,
- cpustate->dmaop_src_count, cpustate->dmaop_dst_count, cpustate->dmaop_pmode);
- cpustate->dmaop_cycles = 0;
-
+ dma_op(cpustate, 6);
+
+ cpustate->dma_op[6].timer->adjust(attotime::never, 0);
break;
}
@@ -679,21 +687,6 @@ static CPU_EXECUTE( sharc )
if (cpustate->idle && cpustate->irq_active == 0)
{
- // handle pending DMA transfers
- if (cpustate->dmaop_cycles > 0)
- {
- cpustate->dmaop_cycles -= cpustate->icount;
- if (cpustate->dmaop_cycles <= 0)
- {
- cpustate->dmaop_cycles = 0;
- dma_op(cpustate, cpustate->dmaop_src, cpustate->dmaop_dst, cpustate->dmaop_src_modifier, cpustate->dmaop_dst_modifier, cpustate->dmaop_src_count, cpustate->dmaop_dst_count, cpustate->dmaop_pmode);
- if (cpustate->dmaop_chain_ptr != 0)
- {
- schedule_chained_dma_op(cpustate, cpustate->dmaop_channel, cpustate->dmaop_chain_ptr, cpustate->dmaop_chained_direction);
- }
- }
- }
-
cpustate->icount = 0;
debugger_instruction_hook(device, cpustate->daddr);
}
@@ -790,28 +783,6 @@ static CPU_EXECUTE( sharc )
}
}
- // DMA transfer
- if (cpustate->dmaop_cycles > 0)
- {
- --cpustate->dmaop_cycles;
- if (cpustate->dmaop_cycles <= 0)
- {
- 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);
- }
-
- dma_op(cpustate, cpustate->dmaop_src, cpustate->dmaop_dst, cpustate->dmaop_src_modifier, cpustate->dmaop_dst_modifier, cpustate->dmaop_src_count, cpustate->dmaop_dst_count, cpustate->dmaop_pmode);
- if (cpustate->dmaop_chain_ptr != 0)
- {
- schedule_chained_dma_op(cpustate, cpustate->dmaop_channel, cpustate->dmaop_chain_ptr, cpustate->dmaop_chained_direction);
- }
- }
- }
-
--cpustate->icount;
};
}
diff --git a/src/emu/cpu/sharc/sharcdma.c b/src/emu/cpu/sharc/sharcdma.c
index 5def70d801f..8f6abf1964c 100644
--- a/src/emu/cpu/sharc/sharcdma.c
+++ b/src/emu/cpu/sharc/sharcdma.c
@@ -19,59 +19,79 @@ static void schedule_chained_dma_op(SHARC_REGS *cpustate, int channel, UINT32 dm
UINT32 ext_modifier = dm_read32(cpustate, op_ptr - 6);
UINT32 ext_count = dm_read32(cpustate, op_ptr - 7);
- if (cpustate->dmaop_cycles > 0)
+ if (cpustate->dma_op[channel].active)
{
fatalerror("schedule_chained_dma_op: DMA operation already scheduled at %08X!\n", 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;
+ cpustate->dma_op[channel].dst = ext_index;
+ cpustate->dma_op[channel].dst_modifier = ext_modifier;
+ cpustate->dma_op[channel].dst_count = ext_count;
+ cpustate->dma_op[channel].src = int_index;
+ cpustate->dma_op[channel].src_modifier = int_modifier;
+ cpustate->dma_op[channel].src_count = int_count;
}
- else // Receive from external
+ 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->dma_op[channel].src = ext_index;
+ cpustate->dma_op[channel].src_modifier = ext_modifier;
+ cpustate->dma_op[channel].src_count = ext_count;
+ cpustate->dma_op[channel].dst = int_index;
+ cpustate->dma_op[channel].dst_modifier = int_modifier;
+ cpustate->dma_op[channel].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;
+ cpustate->dma_op[channel].pmode = 0;
+ cpustate->dma_op[channel].chain_ptr = chain_ptr;
+ cpustate->dma_op[channel].chained_direction = chained_direction;
+
+ cpustate->dma_op[channel].active = true;
+
+ int cycles = cpustate->dma_op[channel].src_count / 4;
+ cpustate->dma_op[channel].timer->adjust(cpustate->device->cycles_to_attotime(cycles), channel);
+
+ // enable busy flag
+ cpustate->dma_status |= (1 << channel);
}
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)
+ if (cpustate->dma_op[channel].active)
{
fatalerror("schedule_dma_op: DMA operation already scheduled at %08X!\n", 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;
+ cpustate->dma_op[channel].src = src;
+ cpustate->dma_op[channel].dst = dst;
+ cpustate->dma_op[channel].src_modifier = src_modifier;
+ cpustate->dma_op[channel].dst_modifier = dst_modifier;
+ cpustate->dma_op[channel].src_count = src_count;
+ cpustate->dma_op[channel].dst_count = dst_count;
+ cpustate->dma_op[channel].pmode = pmode;
+ cpustate->dma_op[channel].chain_ptr = 0;
+
+ cpustate->dma_op[channel].active = true;
+
+ int cycles = src_count / 4;
+ cpustate->dma_op[channel].timer->adjust(cpustate->device->cycles_to_attotime(cycles), channel);
+
+ // enable busy flag
+ cpustate->dma_status |= (1 << channel);
}
-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)
+static void dma_op(SHARC_REGS *cpustate, int channel)
{
int i;
+ UINT32 src = cpustate->dma_op[channel].src;
+ UINT32 dst = cpustate->dma_op[channel].dst;
+ int src_modifier = cpustate->dma_op[channel].src_modifier;
+ int dst_modifier = cpustate->dma_op[channel].dst_modifier;
+ int src_count = cpustate->dma_op[channel].src_count;
+ //int dst_count = cpustate->dma_op[channel].dst_count;
+ int pmode = cpustate->dma_op[channel].pmode;
+
//printf("dma_op: %08X, %08X, %08X, %08X, %08X, %08X, %d\n", src, dst, src_modifier, dst_modifier, src_count, dst_count, pmode);
switch (pmode)
@@ -124,16 +144,21 @@ static void dma_op(SHARC_REGS *cpustate, UINT32 src, UINT32 dst, int src_modifie
}
}
- if (cpustate->dmaop_channel == 6)
+ if (channel == 6)
{
- cpustate->irptl |= (1 << (cpustate->dmaop_channel+10));
+ cpustate->irptl |= (1 << (channel+10));
/* DMA interrupt */
- if (cpustate->imask & (1 << (cpustate->dmaop_channel+10)))
+ if (cpustate->imask & (1 << (channel+10)))
{
- cpustate->irq_active |= 1 << (cpustate->dmaop_channel+10);
+ cpustate->irq_active |= 1 << (channel+10);
}
}
+
+ // clear busy flag
+ cpustate->dma_status &= ~(1 << channel);
+
+ cpustate->dma_op[channel].active = false;
}
static void sharc_dma_exec(SHARC_REGS *cpustate, int channel)
@@ -202,3 +227,25 @@ static void sharc_dma_exec(SHARC_REGS *cpustate, int channel)
schedule_dma_op(cpustate, channel, src, dst, src_modifier, dst_modifier, src_count, dst_count, pmode);
}
}
+
+static TIMER_CALLBACK(sharc_dma_callback)
+{
+ SHARC_REGS *cpustate = (SHARC_REGS *)ptr;
+ int channel = param;
+
+ cpustate->dma_op[channel].timer->adjust(attotime::never, 0);
+
+ cpustate->irptl |= (1 << (channel+10));
+
+ // DMA interrupt
+ if (cpustate->imask & (1 << (channel+10)))
+ {
+ cpustate->irq_active |= 1 << (channel+10);
+ }
+
+ dma_op(cpustate, channel);
+ if (cpustate->dma_op[channel].chain_ptr != 0)
+ {
+ schedule_chained_dma_op(cpustate, channel, cpustate->dma_op[channel].chain_ptr, cpustate->dma_op[channel].chained_direction);
+ }
+}