mirror of
https://github.com/holub/mame
synced 2025-05-22 05:38:52 +03:00
Put the SH2 DMA on a timer. This is needed because Knuckles Chaotix on the 32X can't be done with 'Instant DMA' due the SH2 DMA is used to read from a FIFO port which is being filled by the 68k during the transfer. [David Haywood]
Haze: "I need to review save state support in the core again, a few extra things probably need saving now. It might be possible to avoid the high frequency timer if it causes too many performance issues by moving the update of the DMA to the EXECUTE loop instead. (I want to experiment with this before updating the save state support, however if somebody else wants to fix savestates in the meantime they're welcome, as long as they don't get offended if their code gets changed...)"
This commit is contained in:
parent
8c8e75b948
commit
992f1f7384
@ -2148,6 +2148,7 @@ static CPU_RESET( sh2 )
|
||||
emu_timer *tsave, *tsaved0, *tsaved1;
|
||||
UINT32 *m;
|
||||
int (*dma_callback_kludge)(UINT32 src, UINT32 dst, UINT32 data, int size);
|
||||
int (*dma_callback_fifo_data_available)(UINT32 src, UINT32 dst, UINT32 data, int size);
|
||||
int save_is_slave;
|
||||
|
||||
void (*f)(UINT32 data);
|
||||
@ -2155,13 +2156,14 @@ static CPU_RESET( sh2 )
|
||||
|
||||
m = sh2->m;
|
||||
tsave = sh2->timer;
|
||||
tsaved0 = sh2->dma_timer[0];
|
||||
tsaved1 = sh2->dma_timer[1];
|
||||
tsaved0 = sh2->dma_current_active_timer[0];
|
||||
tsaved1 = sh2->dma_current_active_timer[1];
|
||||
|
||||
f = sh2->ftcsr_read_callback;
|
||||
save_irqcallback = sh2->irq_callback;
|
||||
save_is_slave = sh2->is_slave;
|
||||
dma_callback_kludge = sh2->dma_callback_kludge;
|
||||
dma_callback_fifo_data_available = sh2->dma_callback_fifo_data_available;
|
||||
|
||||
sh2->ppc = sh2->pc = sh2->pr = sh2->sr = sh2->gbr = sh2->vbr = sh2->mach = sh2->macl = 0;
|
||||
sh2->evec = sh2->irqsr = 0;
|
||||
@ -2176,14 +2178,15 @@ static CPU_RESET( sh2 )
|
||||
sh2->dma_timer_active[0] = sh2->dma_timer_active[1] = 0;
|
||||
|
||||
sh2->dma_callback_kludge = dma_callback_kludge;
|
||||
sh2->dma_callback_fifo_data_available = dma_callback_fifo_data_available;
|
||||
sh2->is_slave = save_is_slave;
|
||||
sh2->ftcsr_read_callback = f;
|
||||
sh2->irq_callback = save_irqcallback;
|
||||
sh2->device = device;
|
||||
|
||||
sh2->timer = tsave;
|
||||
sh2->dma_timer[0] = tsaved0;
|
||||
sh2->dma_timer[1] = tsaved1;
|
||||
sh2->dma_current_active_timer[0] = tsaved0;
|
||||
sh2->dma_current_active_timer[1] = tsaved1;
|
||||
sh2->m = m;
|
||||
memset(sh2->m, 0, 0x200);
|
||||
|
||||
|
@ -62,6 +62,7 @@ struct _sh2_cpu_core
|
||||
{
|
||||
int is_slave;
|
||||
int (*dma_callback_kludge)(UINT32 src, UINT32 dst, UINT32 data, int size);
|
||||
int (*dma_callback_fifo_data_available)(UINT32 src, UINT32 dst, UINT32 data, int size);
|
||||
};
|
||||
|
||||
DECLARE_LEGACY_CPU_DEVICE(SH1, sh1);
|
||||
|
@ -133,142 +133,271 @@ static TIMER_CALLBACK( sh2_timer_callback )
|
||||
sh2_timer_activate(sh2);
|
||||
}
|
||||
|
||||
static TIMER_CALLBACK( sh2_dmac_callback )
|
||||
|
||||
|
||||
/*
|
||||
We have to do DMA on a timer (or at least, in chunks) due to the way some systems use it.
|
||||
The 32x is a difficult case, they set the SOURCE of the DMA to a FIFO buffer, which at most
|
||||
can have 8 words in it. Attempting to do an 'instant DMA' in this scenario is impossible
|
||||
because the game is expecting the 68k of the system to feed data into the FIFO at the same
|
||||
time as the SH2 is transfering it out via DMA
|
||||
|
||||
It might be possible to avoid the timer (which causes a performance hit) by calling this
|
||||
from the CPU_EXECUTE loop instead when there is active DMA
|
||||
*/
|
||||
|
||||
static void sh2_do_dma(sh2_state *sh2, int dma)
|
||||
{
|
||||
UINT32 dmadata;
|
||||
|
||||
UINT32 tempsrc, tempdst;
|
||||
|
||||
if (sh2->active_dma_count[dma] > 0)
|
||||
{
|
||||
// schedule next DMA callback
|
||||
timer_adjust_oneshot(sh2->dma_current_active_timer[dma], sh2->device->cycles_to_attotime(2), dma);
|
||||
|
||||
// process current DMA
|
||||
switch(sh2->active_dma_size[dma])
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
// we need to know the src / dest ahead of time without changing them
|
||||
// to allow for the callback to check if we can process the DMA at this
|
||||
// time (we need to know where we're reading / writing to/from)
|
||||
|
||||
if(sh2->active_dma_incs[dma] == 2)
|
||||
tempsrc = sh2->active_dma_src[dma] - 1;
|
||||
else
|
||||
tempsrc = sh2->active_dma_src[dma];
|
||||
|
||||
if(sh2->active_dma_incd[dma] == 2)
|
||||
tempdst = sh2->active_dma_dst[dma] - 1;
|
||||
else
|
||||
tempdst = sh2->active_dma_dst[dma];
|
||||
|
||||
if (sh2->dma_callback_fifo_data_available)
|
||||
{
|
||||
int available = sh2->dma_callback_fifo_data_available(tempsrc, tempdst, 0, sh2->active_dma_size[dma]);
|
||||
|
||||
if (!available)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
dmadata = sh2->program->read_byte(tempsrc);
|
||||
if (sh2->dma_callback_kludge) dmadata = sh2->dma_callback_kludge(tempsrc, tempdst, dmadata, sh2->active_dma_size[dma]);
|
||||
sh2->program->write_byte(tempdst, dmadata);
|
||||
|
||||
if(sh2->active_dma_incs[dma] == 2)
|
||||
sh2->active_dma_src[dma] --;
|
||||
if(sh2->active_dma_incd[dma] == 2)
|
||||
sh2->active_dma_dst[dma] --;
|
||||
|
||||
|
||||
if(sh2->active_dma_incs[dma] == 1)
|
||||
sh2->active_dma_src[dma] ++;
|
||||
if(sh2->active_dma_incd[dma] == 1)
|
||||
sh2->active_dma_dst[dma] ++;
|
||||
|
||||
sh2->active_dma_count[dma] --;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
{
|
||||
if(sh2->active_dma_incs[dma] == 2)
|
||||
tempsrc = sh2->active_dma_src[dma] - 2;
|
||||
else
|
||||
tempsrc = sh2->active_dma_src[dma];
|
||||
|
||||
if(sh2->active_dma_incd[dma] == 2)
|
||||
tempdst = sh2->active_dma_dst[dma] - 2;
|
||||
else
|
||||
tempdst = sh2->active_dma_dst[dma];
|
||||
|
||||
if (sh2->dma_callback_fifo_data_available)
|
||||
{
|
||||
int available = sh2->dma_callback_fifo_data_available(tempsrc, tempdst, 0, sh2->active_dma_size[dma]);
|
||||
|
||||
if (!available)
|
||||
return;
|
||||
}
|
||||
|
||||
// check: should this really be using read_word_32 / write_word_32?
|
||||
dmadata = sh2->program->read_word(tempsrc);
|
||||
if (sh2->dma_callback_kludge) dmadata = sh2->dma_callback_kludge(tempsrc, tempdst, dmadata, sh2->active_dma_size[dma]);
|
||||
sh2->program->write_word(tempdst, dmadata);
|
||||
|
||||
if(sh2->active_dma_incs[dma] == 2)
|
||||
sh2->active_dma_src[dma] -= 2;
|
||||
if(sh2->active_dma_incd[dma] == 2)
|
||||
sh2->active_dma_dst[dma] -= 2;
|
||||
|
||||
if(sh2->active_dma_incs[dma] == 1)
|
||||
sh2->active_dma_src[dma] += 2;
|
||||
if(sh2->active_dma_incd[dma] == 1)
|
||||
sh2->active_dma_dst[dma] += 2;
|
||||
|
||||
sh2->active_dma_count[dma] --;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
if(sh2->active_dma_incs[dma] == 2)
|
||||
tempsrc = sh2->active_dma_src[dma] - 4;
|
||||
else
|
||||
tempsrc = sh2->active_dma_src[dma];
|
||||
|
||||
if(sh2->active_dma_incd[dma] == 2)
|
||||
tempdst = sh2->active_dma_dst[dma] - 4;
|
||||
else
|
||||
tempdst = sh2->active_dma_dst[dma];
|
||||
|
||||
if (sh2->dma_callback_fifo_data_available)
|
||||
{
|
||||
int available = sh2->dma_callback_fifo_data_available(tempsrc, tempdst, 0, sh2->active_dma_size[dma]);
|
||||
|
||||
if (!available)
|
||||
return;
|
||||
}
|
||||
|
||||
dmadata = sh2->program->read_dword(tempsrc);
|
||||
if (sh2->dma_callback_kludge) dmadata = sh2->dma_callback_kludge(tempsrc, tempdst, dmadata, sh2->active_dma_size[dma]);
|
||||
sh2->program->write_dword(tempdst, dmadata);
|
||||
|
||||
if(sh2->active_dma_incs[dma] == 2)
|
||||
sh2->active_dma_src[dma] -= 4;
|
||||
if(sh2->active_dma_incd[dma] == 2)
|
||||
sh2->active_dma_dst[dma] -= 4;
|
||||
|
||||
if(sh2->active_dma_incs[dma] == 1)
|
||||
sh2->active_dma_src[dma] += 4;
|
||||
if(sh2->active_dma_incd[dma] == 1)
|
||||
sh2->active_dma_dst[dma] += 4;
|
||||
|
||||
sh2->active_dma_count[dma] --;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
{
|
||||
// shouldn't this really be 4 calls here instead?
|
||||
|
||||
tempsrc = sh2->active_dma_src[dma];
|
||||
|
||||
if(sh2->active_dma_incd[dma] == 2)
|
||||
tempdst = sh2->active_dma_dst[dma] - 16;
|
||||
else
|
||||
tempdst = sh2->active_dma_dst[dma];
|
||||
|
||||
if (sh2->dma_callback_fifo_data_available)
|
||||
{
|
||||
int available = sh2->dma_callback_fifo_data_available(tempsrc, tempdst, 0, sh2->active_dma_size[dma]);
|
||||
|
||||
if (!available)
|
||||
fatalerror("SH2 dma_callback_fifo_data_available == 0 in unsupported mode");
|
||||
}
|
||||
|
||||
dmadata = sh2->program->read_dword(tempsrc);
|
||||
if (sh2->dma_callback_kludge) dmadata = sh2->dma_callback_kludge(tempsrc, tempdst, dmadata, sh2->active_dma_size[dma]);
|
||||
sh2->program->write_dword(tempdst, dmadata);
|
||||
|
||||
dmadata = sh2->program->read_dword(tempsrc+4);
|
||||
if (sh2->dma_callback_kludge) dmadata = sh2->dma_callback_kludge(tempsrc, tempdst, dmadata, sh2->active_dma_size[dma]);
|
||||
sh2->program->write_dword(tempdst+4, dmadata);
|
||||
|
||||
dmadata = sh2->program->read_dword(tempsrc+8);
|
||||
if (sh2->dma_callback_kludge) dmadata = sh2->dma_callback_kludge(tempsrc, tempdst, dmadata, sh2->active_dma_size[dma]);
|
||||
sh2->program->write_dword(tempdst+8, dmadata);
|
||||
|
||||
dmadata = sh2->program->read_dword(tempsrc+12);
|
||||
if (sh2->dma_callback_kludge) dmadata = sh2->dma_callback_kludge(tempsrc, tempdst, dmadata, sh2->active_dma_size[dma]);
|
||||
sh2->program->write_dword(tempdst+12, dmadata);
|
||||
|
||||
if(sh2->active_dma_incd[dma] == 2)
|
||||
sh2->active_dma_dst[dma] -= 16;
|
||||
|
||||
sh2->active_dma_src[dma] += 16;
|
||||
if(sh2->active_dma_incd[dma] == 1)
|
||||
sh2->active_dma_dst[dma] += 16;
|
||||
|
||||
sh2->active_dma_count[dma]-=4;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else // the dma is complete
|
||||
{
|
||||
// int dma = param & 1;
|
||||
// sh2_state *sh2 = (sh2_state *)ptr;
|
||||
|
||||
LOG(("SH2.%s: DMA %d complete\n", sh2->device->tag(), dma));
|
||||
sh2->m[0x63+4*dma] |= 2;
|
||||
sh2->dma_timer_active[dma] = 0;
|
||||
sh2_recalc_irq(sh2);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static TIMER_CALLBACK( sh2_dma_current_active_callback )
|
||||
{
|
||||
int dma = param & 1;
|
||||
sh2_state *sh2 = (sh2_state *)ptr;
|
||||
|
||||
LOG(("SH2.%s: DMA %d complete\n", sh2->device->tag(), dma));
|
||||
sh2->m[0x63+4*dma] |= 2;
|
||||
sh2->dma_timer_active[dma] = 0;
|
||||
sh2_recalc_irq(sh2);
|
||||
sh2_do_dma(sh2, dma);
|
||||
}
|
||||
|
||||
|
||||
static void sh2_dmac_check(sh2_state *sh2, int dma)
|
||||
{
|
||||
if(sh2->m[0x63+4*dma] & sh2->m[0x6c] & 1)
|
||||
{
|
||||
if(!sh2->dma_timer_active[dma] && !(sh2->m[0x63+4*dma] & 2))
|
||||
{
|
||||
int incs, incd, size;
|
||||
UINT32 src, dst, count;
|
||||
UINT32 dmadata;
|
||||
incd = (sh2->m[0x63+4*dma] >> 14) & 3;
|
||||
incs = (sh2->m[0x63+4*dma] >> 12) & 3;
|
||||
size = (sh2->m[0x63+4*dma] >> 10) & 3;
|
||||
if(incd == 3 || incs == 3)
|
||||
|
||||
sh2->active_dma_incd[dma] = (sh2->m[0x63+4*dma] >> 14) & 3;
|
||||
sh2->active_dma_incs[dma] = (sh2->m[0x63+4*dma] >> 12) & 3;
|
||||
sh2->active_dma_size[dma] = (sh2->m[0x63+4*dma] >> 10) & 3;
|
||||
if(sh2->active_dma_incd[dma] == 3 || sh2->active_dma_incs[dma] == 3)
|
||||
{
|
||||
logerror("SH2: DMA: bad increment values (%d, %d, %d, %04x)\n", incd, incs, size, sh2->m[0x63+4*dma]);
|
||||
logerror("SH2: DMA: bad increment values (%d, %d, %d, %04x)\n", sh2->active_dma_incd[dma], sh2->active_dma_incs[dma], sh2->active_dma_size[dma], sh2->m[0x63+4*dma]);
|
||||
return;
|
||||
}
|
||||
src = sh2->m[0x60+4*dma];
|
||||
dst = sh2->m[0x61+4*dma];
|
||||
count = sh2->m[0x62+4*dma];
|
||||
if(!count)
|
||||
count = 0x1000000;
|
||||
sh2->active_dma_src[dma] = sh2->m[0x60+4*dma];
|
||||
sh2->active_dma_dst[dma] = sh2->m[0x61+4*dma];
|
||||
sh2->active_dma_count[dma] = sh2->m[0x62+4*dma];
|
||||
if(!sh2->active_dma_count[dma])
|
||||
sh2->active_dma_count[dma] = 0x1000000;
|
||||
|
||||
LOG(("SH2: DMA %d start %x, %x, %x, %04x, %d, %d, %d\n", dma, src, dst, count, sh2->m[0x63+4*dma], incs, incd, size));
|
||||
LOG(("SH2: DMA %d start %x, %x, %x, %04x, %d, %d, %d\n", dma, sh2->active_dma_src[dma], sh2->active_dma_dst[dma], sh2->active_dma_count[dma], sh2->m[0x63+4*dma], sh2->active_dma_incs[dma], sh2->active_dma_incd[dma], sh2->active_dma_size[dma]));
|
||||
|
||||
sh2->dma_timer_active[dma] = 1;
|
||||
timer_adjust_oneshot(sh2->dma_timer[dma], sh2->device->cycles_to_attotime(2*count+1), dma);
|
||||
|
||||
src &= AM;
|
||||
dst &= AM;
|
||||
sh2->active_dma_src[dma] &= AM;
|
||||
sh2->active_dma_dst[dma] &= AM;
|
||||
|
||||
switch(size)
|
||||
switch(sh2->active_dma_size[dma])
|
||||
{
|
||||
case 0:
|
||||
for(;count > 0; count --)
|
||||
{
|
||||
if(incs == 2)
|
||||
src --;
|
||||
if(incd == 2)
|
||||
dst --;
|
||||
|
||||
dmadata = sh2->program->read_byte(src);
|
||||
if (sh2->dma_callback_kludge) dmadata = sh2->dma_callback_kludge(src, dst, dmadata, size);
|
||||
sh2->program->write_byte(dst, dmadata);
|
||||
|
||||
if(incs == 1)
|
||||
src ++;
|
||||
if(incd == 1)
|
||||
dst ++;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
src &= ~1;
|
||||
dst &= ~1;
|
||||
for(;count > 0; count --)
|
||||
{
|
||||
|
||||
if(incs == 2)
|
||||
src -= 2;
|
||||
if(incd == 2)
|
||||
dst -= 2;
|
||||
|
||||
// check: should this really be using read_word_32 / write_word_32?
|
||||
dmadata = sh2->program->read_word(src);
|
||||
if (sh2->dma_callback_kludge) dmadata = sh2->dma_callback_kludge(src, dst, dmadata, size);
|
||||
sh2->program->write_word(dst, dmadata);
|
||||
|
||||
if(incs == 1)
|
||||
src += 2;
|
||||
if(incd == 1)
|
||||
dst += 2;
|
||||
}
|
||||
sh2->active_dma_src[dma] &= ~1;
|
||||
sh2->active_dma_dst[dma] &= ~1;
|
||||
break;
|
||||
case 2:
|
||||
src &= ~3;
|
||||
dst &= ~3;
|
||||
for(;count > 0; count --)
|
||||
{
|
||||
if(incs == 2)
|
||||
src -= 4;
|
||||
if(incd == 2)
|
||||
dst -= 4;
|
||||
|
||||
dmadata = sh2->program->read_dword(src);
|
||||
if (sh2->dma_callback_kludge) dmadata = sh2->dma_callback_kludge(src, dst, dmadata, size);
|
||||
sh2->program->write_dword(dst, dmadata);
|
||||
|
||||
if(incs == 1)
|
||||
src += 4;
|
||||
if(incd == 1)
|
||||
dst += 4;
|
||||
|
||||
}
|
||||
sh2->active_dma_src[dma] &= ~3;
|
||||
sh2->active_dma_dst[dma] &= ~3;
|
||||
break;
|
||||
case 3:
|
||||
src &= ~3;
|
||||
dst &= ~3;
|
||||
count &= ~3;
|
||||
for(;count > 0; count -= 4)
|
||||
{
|
||||
if(incd == 2)
|
||||
dst -= 16;
|
||||
|
||||
dmadata = sh2->program->read_dword(src);
|
||||
if (sh2->dma_callback_kludge) dmadata = sh2->dma_callback_kludge(src, dst, dmadata, size);
|
||||
sh2->program->write_dword(dst, dmadata);
|
||||
|
||||
dmadata = sh2->program->read_dword(src+4);
|
||||
if (sh2->dma_callback_kludge) dmadata = sh2->dma_callback_kludge(src, dst, dmadata, size);
|
||||
sh2->program->write_dword(dst+4, dmadata);
|
||||
|
||||
dmadata = sh2->program->read_dword(src+8);
|
||||
if (sh2->dma_callback_kludge) dmadata = sh2->dma_callback_kludge(src, dst, dmadata, size);
|
||||
sh2->program->write_dword(dst+8, dmadata);
|
||||
|
||||
dmadata = sh2->program->read_dword(src+12);
|
||||
if (sh2->dma_callback_kludge) dmadata = sh2->dma_callback_kludge(src, dst, dmadata, size);
|
||||
sh2->program->write_dword(dst+12, dmadata);
|
||||
|
||||
src += 16;
|
||||
if(incd == 1)
|
||||
dst += 16;
|
||||
}
|
||||
sh2->active_dma_src[dma] &= ~3;
|
||||
sh2->active_dma_dst[dma] &= ~3;
|
||||
sh2->active_dma_count[dma] &= ~3;
|
||||
break;
|
||||
}
|
||||
|
||||
// start DMA timer
|
||||
timer_adjust_oneshot(sh2->dma_current_active_timer[dma], sh2->device->cycles_to_attotime(2), dma);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -276,7 +405,9 @@ static void sh2_dmac_check(sh2_state *sh2, int dma)
|
||||
if(sh2->dma_timer_active[dma])
|
||||
{
|
||||
logerror("SH2: DMA %d cancelled in-flight\n", dma);
|
||||
timer_adjust_oneshot(sh2->dma_timer[dma], attotime_never, 0);
|
||||
//timer_adjust_oneshot(sh2->dma_complete_timer[dma], attotime_never, 0);
|
||||
timer_adjust_oneshot(sh2->dma_current_active_timer[dma], attotime_never, 0);
|
||||
|
||||
sh2->dma_timer_active[dma] = 0;
|
||||
}
|
||||
}
|
||||
@ -707,11 +838,12 @@ void sh2_common_init(sh2_state *sh2, legacy_cpu_device *device, device_irq_callb
|
||||
sh2->timer = timer_alloc(device->machine, sh2_timer_callback, sh2);
|
||||
timer_adjust_oneshot(sh2->timer, attotime_never, 0);
|
||||
|
||||
sh2->dma_timer[0] = timer_alloc(device->machine, sh2_dmac_callback, sh2);
|
||||
timer_adjust_oneshot(sh2->dma_timer[0], attotime_never, 0);
|
||||
sh2->dma_current_active_timer[0] = timer_alloc(device->machine, sh2_dma_current_active_callback, sh2);
|
||||
timer_adjust_oneshot(sh2->dma_current_active_timer[0], attotime_never, 0);
|
||||
|
||||
sh2->dma_current_active_timer[1] = timer_alloc(device->machine, sh2_dma_current_active_callback, sh2);
|
||||
timer_adjust_oneshot(sh2->dma_current_active_timer[1], attotime_never, 0);
|
||||
|
||||
sh2->dma_timer[1] = timer_alloc(device->machine, sh2_dmac_callback, sh2);
|
||||
timer_adjust_oneshot(sh2->dma_timer[1], attotime_never, 0);
|
||||
|
||||
sh2->m = auto_alloc_array(device->machine, UINT32, 0x200/4);
|
||||
|
||||
@ -719,11 +851,13 @@ void sh2_common_init(sh2_state *sh2, legacy_cpu_device *device, device_irq_callb
|
||||
{
|
||||
sh2->is_slave = conf->is_slave;
|
||||
sh2->dma_callback_kludge = conf->dma_callback_kludge;
|
||||
sh2->dma_callback_fifo_data_available = conf->dma_callback_fifo_data_available;
|
||||
}
|
||||
else
|
||||
{
|
||||
sh2->is_slave = 0;
|
||||
sh2->dma_callback_kludge = NULL;
|
||||
sh2->dma_callback_fifo_data_available = NULL;
|
||||
|
||||
}
|
||||
sh2->irq_callback = irqcallback;
|
||||
|
@ -132,11 +132,19 @@ typedef struct
|
||||
int icount;
|
||||
|
||||
emu_timer *timer;
|
||||
emu_timer *dma_timer[2];
|
||||
emu_timer *dma_current_active_timer[2];
|
||||
int dma_timer_active[2];
|
||||
|
||||
int active_dma_incs[2];
|
||||
int active_dma_incd[2];
|
||||
int active_dma_size[2];
|
||||
UINT32 active_dma_src[2];
|
||||
UINT32 active_dma_dst[2];
|
||||
UINT32 active_dma_count[2];
|
||||
|
||||
int is_slave, cpu_type;
|
||||
int (*dma_callback_kludge)(UINT32 src, UINT32 dst, UINT32 data, int size);
|
||||
int (*dma_callback_fifo_data_available)(UINT32 src, UINT32 dst, UINT32 data, int size);
|
||||
|
||||
void (*ftcsr_read_callback)(UINT32 data);
|
||||
|
||||
|
@ -799,8 +799,8 @@ static CPU_RESET( sh2 )
|
||||
|
||||
m = sh2->m;
|
||||
tsave = sh2->timer;
|
||||
tsaved0 = sh2->dma_timer[0];
|
||||
tsaved1 = sh2->dma_timer[1];
|
||||
tsaved0 = sh2->dma_current_active_timer[0];
|
||||
tsaved1 = sh2->dma_current_active_timer[1];
|
||||
|
||||
f = sh2->ftcsr_read_callback;
|
||||
save_irqcallback = sh2->irq_callback;
|
||||
@ -822,8 +822,8 @@ static CPU_RESET( sh2 )
|
||||
sh2->device = device;
|
||||
|
||||
sh2->timer = tsave;
|
||||
sh2->dma_timer[0] = tsaved0;
|
||||
sh2->dma_timer[1] = tsaved1;
|
||||
sh2->dma_current_active_timer[0] = tsaved0;
|
||||
sh2->dma_current_active_timer[1] = tsaved1;
|
||||
sh2->m = m;
|
||||
memset(sh2->m, 0, 0x200);
|
||||
|
||||
|
@ -2343,6 +2343,72 @@ static WRITE16_HANDLER( _32x_68k_dram_overwrite_w )
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************************************/
|
||||
// 68k side a15112
|
||||
// FIFO
|
||||
/**********************************************************************************************/
|
||||
|
||||
static UINT16 fifo_block_a[4];
|
||||
static UINT16 fifo_block_b[4];
|
||||
static UINT16* current_fifo_block;
|
||||
static UINT16* current_fifo_readblock;
|
||||
int current_fifo_write_pos;
|
||||
int current_fifo_read_pos;
|
||||
int fifo_block_a_full;
|
||||
int fifo_block_b_full;
|
||||
|
||||
static READ16_HANDLER( _32x_68k_a15112_r)
|
||||
{
|
||||
printf("read write-only FIFO register\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static WRITE16_HANDLER( _32x_68k_a15112_w )
|
||||
{
|
||||
//printf("write to FIFO %04x!\n", data);
|
||||
|
||||
if (current_fifo_block==fifo_block_a && fifo_block_a_full)
|
||||
{
|
||||
printf("attempt to write to Full Fifo block a!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (current_fifo_block==fifo_block_b && fifo_block_b_full)
|
||||
{
|
||||
printf("attempt to write to Full Fifo block b!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
current_fifo_block[current_fifo_write_pos] = data;
|
||||
current_fifo_write_pos++;
|
||||
|
||||
if (current_fifo_write_pos==4)
|
||||
{
|
||||
if (current_fifo_block==fifo_block_a)
|
||||
{
|
||||
fifo_block_a_full = 1;
|
||||
if (!fifo_block_b_full)
|
||||
{
|
||||
current_fifo_block = fifo_block_b;
|
||||
current_fifo_readblock = fifo_block_a;
|
||||
}
|
||||
current_fifo_write_pos = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
fifo_block_b_full = 1;
|
||||
|
||||
if (!fifo_block_a_full)
|
||||
{
|
||||
current_fifo_block = fifo_block_a;
|
||||
current_fifo_readblock = fifo_block_b;
|
||||
}
|
||||
|
||||
current_fifo_write_pos = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
@ -2367,7 +2433,7 @@ static READ16_HANDLER( _32x_68k_a15106_r)
|
||||
|
||||
retval = a15106_reg;
|
||||
|
||||
//if (fifo_full) retval |= 0x0080;
|
||||
if (fifo_block_a_full && fifo_block_b_full) retval |= 0x8080;
|
||||
|
||||
return retval;
|
||||
}
|
||||
@ -2409,6 +2475,7 @@ static READ16_HANDLER( _32x_68k_MARS_r )
|
||||
return 0x0000;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************************************/
|
||||
// 68k side a15100
|
||||
// control register - used to enable 32x etc.
|
||||
@ -2910,11 +2977,65 @@ static WRITE16_HANDLER( _32x_sh2_common_4002_w )
|
||||
// 68k To SH2 DReq Length Register
|
||||
/**********************************************************************************************/
|
||||
|
||||
static READ16_HANDLER( _32x_sh2_common_4010_r )
|
||||
{
|
||||
// printf("reading DReq Length!\n");
|
||||
return 0x0000;
|
||||
}
|
||||
|
||||
/**********************************************************************************************/
|
||||
// SH2 side 4012
|
||||
// FIFO Register (read)
|
||||
/**********************************************************************************************/
|
||||
|
||||
static READ16_HANDLER( _32x_sh2_common_4012_r )
|
||||
{
|
||||
UINT16 retdat = current_fifo_readblock[current_fifo_read_pos];
|
||||
|
||||
current_fifo_read_pos++;
|
||||
|
||||
// printf("reading FIFO!\n");
|
||||
|
||||
if (current_fifo_readblock == fifo_block_a && !fifo_block_a_full)
|
||||
printf("Fifo block a isn't filled!\n");
|
||||
|
||||
if (current_fifo_readblock == fifo_block_b && !fifo_block_b_full)
|
||||
printf("Fifo block b isn't filled!\n");
|
||||
|
||||
|
||||
if (current_fifo_read_pos==4)
|
||||
{
|
||||
if (current_fifo_readblock == fifo_block_a)
|
||||
{
|
||||
fifo_block_a_full = 0;
|
||||
|
||||
if (fifo_block_b_full)
|
||||
{
|
||||
current_fifo_readblock = fifo_block_b;
|
||||
current_fifo_block = fifo_block_a;
|
||||
}
|
||||
|
||||
current_fifo_read_pos = 0;
|
||||
}
|
||||
else if (current_fifo_readblock == fifo_block_b)
|
||||
{
|
||||
fifo_block_b_full = 0;
|
||||
|
||||
if (fifo_block_a_full)
|
||||
{
|
||||
current_fifo_readblock = fifo_block_a;
|
||||
current_fifo_block = fifo_block_b;
|
||||
}
|
||||
|
||||
current_fifo_read_pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return retdat;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**********************************************************************************************/
|
||||
// SH2 side 4014
|
||||
// VRES (md reset button interrupt) clear
|
||||
@ -3184,9 +3305,12 @@ _32X_MAP_WRITEHANDLERS(slave_401c,slave_401e) // _32x_sh2_slave_401c_slave_401e_
|
||||
_32X_MAP_RAM_READHANDLERS(commsram) // _32x_sh2_commsram_r
|
||||
_32X_MAP_RAM_WRITEHANDLERS(commsram) // _32x_sh2_commsram_w
|
||||
|
||||
_32X_MAP_READHANDLERS(common_4010,common_4012)
|
||||
|
||||
_32X_MAP_READHANDLERS(common_4100,common_4102) // _32x_sh2_common_4100_common_4102_r
|
||||
_32X_MAP_WRITEHANDLERS(common_4100,common_4102) // _32x_sh2_common_4100_common_4102_w
|
||||
|
||||
|
||||
_32X_MAP_READHANDLERS(common_4104,common_4106) // _32x_sh2_common_4104_common_4106_r
|
||||
_32X_MAP_WRITEHANDLERS(common_4104,common_4106) // _32x_sh2_common_4104_common_4106_w
|
||||
|
||||
@ -3213,6 +3337,8 @@ static ADDRESS_MAP_START( sh2_main_map, ADDRESS_SPACE_PROGRAM, 32 )
|
||||
|
||||
AM_RANGE(0x00004000, 0x00004003) AM_READWRITE( _32x_sh2_master_4000_common_4002_r, _32x_sh2_master_4000_common_4002_w )
|
||||
|
||||
AM_RANGE(0x00004010, 0x00004013) AM_READ( _32x_sh2_common_4010_common_4012_r )
|
||||
|
||||
AM_RANGE(0x00004014, 0x00004017) AM_WRITE( _32x_sh2_master_4014_master_4016_w ) // IRQ clear
|
||||
AM_RANGE(0x00004018, 0x0000401b) AM_WRITE( _32x_sh2_master_4018_master_401a_w ) // IRQ clear
|
||||
AM_RANGE(0x0000401c, 0x0000401f) AM_WRITE( _32x_sh2_master_401c_master_401e_w ) // IRQ clear
|
||||
@ -3237,6 +3363,8 @@ static ADDRESS_MAP_START( sh2_slave_map, ADDRESS_SPACE_PROGRAM, 32 )
|
||||
|
||||
AM_RANGE(0x00004000, 0x00004003) AM_READWRITE( _32x_sh2_slave_4000_common_4002_r, _32x_sh2_slave_4000_common_4002_w )
|
||||
|
||||
AM_RANGE(0x00004010, 0x00004013) AM_READ( _32x_sh2_common_4010_common_4012_r )
|
||||
|
||||
AM_RANGE(0x00004014, 0x00004017) AM_WRITE( _32x_sh2_slave_4014_slave_4016_w ) // IRQ clear
|
||||
AM_RANGE(0x00004018, 0x0000401b) AM_WRITE( _32x_sh2_slave_4018_slave_401a_w ) // IRQ clear
|
||||
AM_RANGE(0x0000401c, 0x0000401f) AM_WRITE( _32x_sh2_slave_401c_slave_401e_w ) // IRQ clear
|
||||
@ -5804,6 +5932,13 @@ MACHINE_RESET( megadriv )
|
||||
cpu_set_input_line(_segacd_68k_cpu, INPUT_LINE_HALT, ASSERT_LINE);
|
||||
}
|
||||
|
||||
current_fifo_block = fifo_block_a;
|
||||
current_fifo_readblock = fifo_block_b;
|
||||
current_fifo_write_pos = 0;
|
||||
current_fifo_read_pos = 0;
|
||||
fifo_block_a_full = 0;
|
||||
fifo_block_b_full = 0;
|
||||
|
||||
}
|
||||
|
||||
void megadriv_stop_scanline_timer(void)
|
||||
@ -6063,8 +6198,25 @@ MACHINE_CONFIG_END
|
||||
|
||||
|
||||
|
||||
static const sh2_cpu_core sh2_conf_master = { 0, NULL };
|
||||
static const sh2_cpu_core sh2_conf_slave = { 1, NULL };
|
||||
static int _32x_fifo_available_callback(UINT32 src, UINT32 dst, UINT32 data, int size)
|
||||
{
|
||||
if (src==0x4012)
|
||||
{
|
||||
if (current_fifo_readblock==fifo_block_a && fifo_block_a_full)
|
||||
return 1;
|
||||
|
||||
if (current_fifo_readblock==fifo_block_b && fifo_block_b_full)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static const sh2_cpu_core sh2_conf_master = { 0, NULL, _32x_fifo_available_callback };
|
||||
static const sh2_cpu_core sh2_conf_slave = { 1, NULL, _32x_fifo_available_callback };
|
||||
|
||||
MACHINE_CONFIG_DERIVED( genesis_32x, megadriv )
|
||||
|
||||
@ -6378,6 +6530,9 @@ DRIVER_INIT( _32x )
|
||||
memory_install_readwrite16_handler(cputag_get_address_space(machine, "maincpu", ADDRESS_SPACE_PROGRAM), 0xa15104, 0xa15105, 0, 0, _32x_68k_a15104_r, _32x_68k_a15104_w); // 68k BANK rom set
|
||||
memory_install_readwrite16_handler(cputag_get_address_space(machine, "maincpu", ADDRESS_SPACE_PROGRAM), 0xa15106, 0xa15107, 0, 0, _32x_68k_a15106_r, _32x_68k_a15106_w); // dreq stuff
|
||||
|
||||
memory_install_readwrite16_handler(cputag_get_address_space(machine, "maincpu", ADDRESS_SPACE_PROGRAM), 0xa15112, 0xa15113, 0, 0, _32x_68k_a15112_r, _32x_68k_a15112_w); // fifo
|
||||
|
||||
|
||||
memory_install_readwrite16_handler(cputag_get_address_space(machine, "maincpu", ADDRESS_SPACE_PROGRAM), 0xa15120, 0xa1512f, 0, 0, _32x_68k_commsram_r, _32x_68k_commsram_w); // comms reg 0-7
|
||||
|
||||
memory_install_read16_handler(cputag_get_address_space(machine, "maincpu", ADDRESS_SPACE_PROGRAM), 0x0a130ec, 0x0a130ef, 0, 0, _32x_68k_MARS_r); // system ID
|
||||
|
Loading…
Reference in New Issue
Block a user