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:
Angelo Salese 2010-09-26 22:55:28 +00:00
parent 8c8e75b948
commit 992f1f7384
6 changed files with 424 additions and 123 deletions

View File

@ -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);

View File

@ -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);

View File

@ -133,16 +133,219 @@ 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)
{
int dma = param & 1;
sh2_state *sh2 = (sh2_state *)ptr;
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;
sh2_do_dma(sh2, dma);
}
static void sh2_dmac_check(sh2_state *sh2, int dma)
{
@ -150,125 +353,51 @@ static void sh2_dmac_check(sh2_state *sh2, int dma)
{
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;

View File

@ -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);

View File

@ -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);

View File

@ -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