diff options
author | 2012-07-30 22:20:30 +0000 | |
---|---|---|
committer | 2012-07-30 22:20:30 +0000 | |
commit | 6c8cba3503cb4f22816a43e4679cafc64e62b441 (patch) | |
tree | 71d5b67dff4c51434769597c3d72a4910e81c4bd /src/emu | |
parent | 9eaa7414e71a2ba6824b4bfbda4e9df94fc62905 (diff) |
ppc: Added callbacks for buffered external DMAs. [Ville Linde]
Diffstat (limited to 'src/emu')
-rw-r--r-- | src/emu/cpu/powerpc/ppc.h | 4 | ||||
-rw-r--r-- | src/emu/cpu/powerpc/ppccom.c | 119 | ||||
-rw-r--r-- | src/emu/cpu/powerpc/ppccom.h | 3 |
3 files changed, 125 insertions, 1 deletions
diff --git a/src/emu/cpu/powerpc/ppc.h b/src/emu/cpu/powerpc/ppc.h index 50f9612f203..d4e3257b029 100644 --- a/src/emu/cpu/powerpc/ppc.h +++ b/src/emu/cpu/powerpc/ppc.h @@ -173,6 +173,8 @@ struct _powerpc_config }; typedef void (*ppc_dcstore_handler)(device_t *device, UINT32 address); +typedef UINT32 (*ppc4xx_dma_read_handler)(device_t *device, int width); +typedef void (*ppc4xx_dma_write_handler)(device_t *device, int width, UINT32 data); /*************************************************************************** @@ -187,6 +189,8 @@ void ppc4xx_spu_set_tx_handler(device_t *device, ppc4xx_spu_tx_handler handler); void ppc4xx_spu_receive_byte(device_t *device, UINT8 byteval); void ppc_set_dcstore_callback(device_t *device, ppc_dcstore_handler handler); +void ppc4xx_set_dma_read_handler(device_t *device, int channel, ppc4xx_dma_read_handler handler); +void ppc4xx_set_dma_write_handler(device_t *device, int channel, ppc4xx_dma_write_handler handler); DECLARE_LEGACY_CPU_DEVICE(PPC403GA, ppc403ga); diff --git a/src/emu/cpu/powerpc/ppccom.c b/src/emu/cpu/powerpc/ppccom.c index 4fcf36bca33..bcf132910da 100644 --- a/src/emu/cpu/powerpc/ppccom.c +++ b/src/emu/cpu/powerpc/ppccom.c @@ -1856,7 +1856,102 @@ static void ppc4xx_dma_exec(powerpc_state *ppc, int dmachan) { /* buffered mode DMA */ case 0: - /* nothing to do; this happens asynchronously and is driven by the SPU */ + if (((dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_PL) >> 28) == 0) + { + /* buffered DMA with external peripheral */ + + width = dma_transfer_width[(dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_PW_MASK) >> 26]; + destinc = (dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_DAI) ? width : 0; + + if (dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_TD) + { + /* peripheral to memory */ + + switch (width) + { + /* byte transfer */ + case 1: + do + { + UINT8 data = 0; + if (ppc->ext_dma_read_handler[dmachan] != NULL) + data = (*ppc->ext_dma_read_handler[dmachan])(ppc->device, 1); + ppc->program->write_byte(dmaregs[DCR4XX_DMADA0], data); + dmaregs[DCR4XX_DMADA0] += destinc; + } while (!ppc4xx_dma_decrement_count(ppc, dmachan)); + break; + + /* word transfer */ + case 2: + do + { + UINT16 data = 0; + if (ppc->ext_dma_read_handler[dmachan] != NULL) + data = (*ppc->ext_dma_read_handler[dmachan])(ppc->device, 2); + ppc->program->write_word(dmaregs[DCR4XX_DMADA0], data); + dmaregs[DCR4XX_DMADA0] += destinc; + } while (!ppc4xx_dma_decrement_count(ppc, dmachan)); + break; + + /* dword transfer */ + case 4: + do + { + UINT32 data = 0; + if (ppc->ext_dma_read_handler[dmachan] != NULL) + data = (*ppc->ext_dma_read_handler[dmachan])(ppc->device, 4); + ppc->program->write_dword(dmaregs[DCR4XX_DMADA0], data); + dmaregs[DCR4XX_DMADA0] += destinc; + } while (!ppc4xx_dma_decrement_count(ppc, dmachan)); + break; + } + } + else + { + /* memory to peripheral */ + + // data is read from destination address! + switch (width) + { + /* byte transfer */ + case 1: + do + { + UINT8 data = ppc->program->read_byte(dmaregs[DCR4XX_DMADA0]); + if (ppc->ext_dma_write_handler[dmachan] != NULL) + (*ppc->ext_dma_write_handler[dmachan])(ppc->device, 1, data); + dmaregs[DCR4XX_DMADA0] += destinc; + } while (!ppc4xx_dma_decrement_count(ppc, dmachan)); + break; + + /* word transfer */ + case 2: + do + { + UINT16 data = ppc->program->read_word(dmaregs[DCR4XX_DMADA0]); + if (ppc->ext_dma_write_handler[dmachan] != NULL) + (*ppc->ext_dma_write_handler[dmachan])(ppc->device, 2, data); + dmaregs[DCR4XX_DMADA0] += destinc; + } while (!ppc4xx_dma_decrement_count(ppc, dmachan)); + break; + + /* dword transfer */ + case 4: + do + { + UINT32 data = ppc->program->read_dword(dmaregs[DCR4XX_DMADA0]); + if (ppc->ext_dma_write_handler[dmachan] != NULL) + (*ppc->ext_dma_write_handler[dmachan])(ppc->device, 4, data); + dmaregs[DCR4XX_DMADA0] += destinc; + } while (!ppc4xx_dma_decrement_count(ppc, dmachan)); + break; + } + } + } + else /* buffered DMA with internal peripheral (SPU) */ + { + /* nothing to do; this happens asynchronously and is driven by the SPU */ + } break; /* fly-by mode DMA */ @@ -2260,6 +2355,28 @@ void ppc4xx_spu_receive_byte(device_t *device, UINT8 byteval) ppc4xx_spu_rx_data(ppc, byteval); } +/*------------------------------------------------- + ppc4xx_set_dma_read_handler - PowerPC 4XX- + specific external DMA read handler configuration +-------------------------------------------------*/ + +void ppc4xx_set_dma_read_handler(device_t *device, int channel, ppc4xx_dma_read_handler handler) +{ + powerpc_state *ppc = *(powerpc_state **)downcast<legacy_cpu_device *>(device)->token(); + ppc->ext_dma_read_handler[channel] = handler; +} + +/*------------------------------------------------- + ppc4xx_set_dma_write_handler - PowerPC 4XX- + specific external DMA write handler configuration +-------------------------------------------------*/ + +void ppc4xx_set_dma_write_handler(device_t *device, int channel, ppc4xx_dma_write_handler handler) +{ + powerpc_state *ppc = *(powerpc_state **)downcast<legacy_cpu_device *>(device)->token(); + ppc->ext_dma_write_handler[channel] = handler; +} + /*------------------------------------------------- ppc4xx_set_info - PowerPC 4XX-specific diff --git a/src/emu/cpu/powerpc/ppccom.h b/src/emu/cpu/powerpc/ppccom.h index c72a5f48cb1..fa42265bc27 100644 --- a/src/emu/cpu/powerpc/ppccom.h +++ b/src/emu/cpu/powerpc/ppccom.h @@ -571,6 +571,9 @@ struct _powerpc_state write32_device_func dcr_write_func; ppc_dcstore_handler dcstore_handler; + + ppc4xx_dma_read_handler ext_dma_read_handler[4]; + ppc4xx_dma_write_handler ext_dma_write_handler[4]; }; |