From 992f1f73841490a635e8fc75f03aed18cdc7e097 Mon Sep 17 00:00:00 2001 From: Angelo Salese Date: Sun, 26 Sep 2010 22:55:28 +0000 Subject: [PATCH] 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...)" --- src/emu/cpu/sh2/sh2.c | 11 +- src/emu/cpu/sh2/sh2.h | 1 + src/emu/cpu/sh2/sh2comn.c | 356 +++++++++++++++++++++++++----------- src/emu/cpu/sh2/sh2comn.h | 10 +- src/emu/cpu/sh2/sh2drc.c | 8 +- src/mame/drivers/megadriv.c | 161 +++++++++++++++- 6 files changed, 424 insertions(+), 123 deletions(-) diff --git a/src/emu/cpu/sh2/sh2.c b/src/emu/cpu/sh2/sh2.c index 1a60aa88332..56241aaa1d7 100644 --- a/src/emu/cpu/sh2/sh2.c +++ b/src/emu/cpu/sh2/sh2.c @@ -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); diff --git a/src/emu/cpu/sh2/sh2.h b/src/emu/cpu/sh2/sh2.h index fd93257fec3..c437a8e8e02 100644 --- a/src/emu/cpu/sh2/sh2.h +++ b/src/emu/cpu/sh2/sh2.h @@ -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); diff --git a/src/emu/cpu/sh2/sh2comn.c b/src/emu/cpu/sh2/sh2comn.c index 8f2d692d047..c590249d056 100644 --- a/src/emu/cpu/sh2/sh2comn.c +++ b/src/emu/cpu/sh2/sh2comn.c @@ -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; diff --git a/src/emu/cpu/sh2/sh2comn.h b/src/emu/cpu/sh2/sh2comn.h index 300d9f6e874..de891b5c480 100644 --- a/src/emu/cpu/sh2/sh2comn.h +++ b/src/emu/cpu/sh2/sh2comn.h @@ -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); diff --git a/src/emu/cpu/sh2/sh2drc.c b/src/emu/cpu/sh2/sh2drc.c index 77f33b9a1ac..4b8d2a96864 100644 --- a/src/emu/cpu/sh2/sh2drc.c +++ b/src/emu/cpu/sh2/sh2drc.c @@ -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); diff --git a/src/mame/drivers/megadriv.c b/src/mame/drivers/megadriv.c index 6eb00c24b1e..3ea25c8dc49 100644 --- a/src/mame/drivers/megadriv.c +++ b/src/mame/drivers/megadriv.c @@ -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