mirror of
https://github.com/holub/mame
synced 2025-07-02 16:49:22 +03:00
ppc: Implemented PPC403 DMA chaining [Ville Linde]
This commit is contained in:
parent
a963c7c3ee
commit
bf39088b47
@ -189,8 +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 ppc4xx_spu_receive_byte(device_t *device, UINT8 byteval);
|
||||||
|
|
||||||
void ppc_set_dcstore_callback(device_t *device, ppc_dcstore_handler handler);
|
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_read_handler(device_t *device, int channel, ppc4xx_dma_read_handler handler, int rate);
|
||||||
void ppc4xx_set_dma_write_handler(device_t *device, int channel, ppc4xx_dma_write_handler handler);
|
void ppc4xx_set_dma_write_handler(device_t *device, int channel, ppc4xx_dma_write_handler handler, int rate);
|
||||||
|
|
||||||
|
|
||||||
DECLARE_LEGACY_CPU_DEVICE(PPC403GA, ppc403ga);
|
DECLARE_LEGACY_CPU_DEVICE(PPC403GA, ppc403ga);
|
||||||
|
@ -39,6 +39,8 @@ static TIMER_CALLBACK( ppc4xx_pit_callback );
|
|||||||
static TIMER_CALLBACK( ppc4xx_spu_callback );
|
static TIMER_CALLBACK( ppc4xx_spu_callback );
|
||||||
static TIMER_CALLBACK( decrementer_int_callback );
|
static TIMER_CALLBACK( decrementer_int_callback );
|
||||||
|
|
||||||
|
static TIMER_CALLBACK( ppc4xx_buffered_dma_callback );
|
||||||
|
|
||||||
static void ppc4xx_set_irq_line(powerpc_state *ppc, UINT32 bitmask, int state);
|
static void ppc4xx_set_irq_line(powerpc_state *ppc, UINT32 bitmask, int state);
|
||||||
|
|
||||||
static void ppc4xx_dma_update_irq_states(powerpc_state *ppc);
|
static void ppc4xx_dma_update_irq_states(powerpc_state *ppc);
|
||||||
@ -341,6 +343,19 @@ void ppccom_init(powerpc_state *ppc, powerpc_flavor flavor, UINT32 cap, int tb_d
|
|||||||
ppc->spu.timer = device->machine().scheduler().timer_alloc(FUNC(ppc4xx_spu_callback), ppc);
|
ppc->spu.timer = device->machine().scheduler().timer_alloc(FUNC(ppc4xx_spu_callback), ppc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cap & PPCCAP_4XX)
|
||||||
|
{
|
||||||
|
ppc->buffered_dma_timer[0] = device->machine().scheduler().timer_alloc(FUNC(ppc4xx_buffered_dma_callback), ppc);
|
||||||
|
ppc->buffered_dma_timer[1] = device->machine().scheduler().timer_alloc(FUNC(ppc4xx_buffered_dma_callback), ppc);
|
||||||
|
ppc->buffered_dma_timer[2] = device->machine().scheduler().timer_alloc(FUNC(ppc4xx_buffered_dma_callback), ppc);
|
||||||
|
ppc->buffered_dma_timer[3] = device->machine().scheduler().timer_alloc(FUNC(ppc4xx_buffered_dma_callback), ppc);
|
||||||
|
|
||||||
|
ppc->buffered_dma_rate[0] = 10000;
|
||||||
|
ppc->buffered_dma_rate[1] = 10000;
|
||||||
|
ppc->buffered_dma_rate[2] = 10000;
|
||||||
|
ppc->buffered_dma_rate[3] = 10000;
|
||||||
|
}
|
||||||
|
|
||||||
/* register for save states */
|
/* register for save states */
|
||||||
device->save_item(NAME(ppc->pc));
|
device->save_item(NAME(ppc->pc));
|
||||||
device->save_item(NAME(ppc->r));
|
device->save_item(NAME(ppc->r));
|
||||||
@ -1749,10 +1764,32 @@ static void ppc4xx_dma_update_irq_states(powerpc_state *ppc)
|
|||||||
|
|
||||||
/* update the IRQ state for each DMA channel */
|
/* update the IRQ state for each DMA channel */
|
||||||
for (dmachan = 0; dmachan < 4; dmachan++)
|
for (dmachan = 0; dmachan < 4; dmachan++)
|
||||||
|
{
|
||||||
if ((ppc->dcr[DCR4XX_DMACR0 + 8 * dmachan] & PPC4XX_DMACR_CIE) && (ppc->dcr[DCR4XX_DMASR] & (0x11 << (27 - dmachan))))
|
if ((ppc->dcr[DCR4XX_DMACR0 + 8 * dmachan] & PPC4XX_DMACR_CIE) && (ppc->dcr[DCR4XX_DMASR] & (0x11 << (27 - dmachan))))
|
||||||
ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_DMA(dmachan), ASSERT_LINE);
|
ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_DMA(dmachan), ASSERT_LINE);
|
||||||
else
|
else
|
||||||
ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_DMA(dmachan), CLEAR_LINE);
|
ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_DMA(dmachan), CLEAR_LINE);
|
||||||
|
|
||||||
|
// DMA chaining interrupts
|
||||||
|
switch (dmachan)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
if ((ppc->dcr[DCR4XX_DMACR0 + 8 * dmachan] & PPC4XX_DMACR_CIE) && (ppc->dcr[DCR4XX_DMASR] & 0x80000))
|
||||||
|
ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_DMA(dmachan), ASSERT_LINE);
|
||||||
|
else
|
||||||
|
ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_DMA(dmachan), CLEAR_LINE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
if ((ppc->dcr[DCR4XX_DMACR0 + 8 * dmachan] & PPC4XX_DMACR_CIE) && (ppc->dcr[DCR4XX_DMASR] & (1 << (7 - dmachan))))
|
||||||
|
ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_DMA(dmachan), ASSERT_LINE);
|
||||||
|
else
|
||||||
|
ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_DMA(dmachan), CLEAR_LINE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1773,93 +1810,64 @@ static int ppc4xx_dma_decrement_count(powerpc_state *ppc, int dmachan)
|
|||||||
if ((dmaregs[DCR4XX_DMACT0] & 0xffff) != 0)
|
if ((dmaregs[DCR4XX_DMACT0] & 0xffff) != 0)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
// if chained mode
|
||||||
|
if (dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_CH)
|
||||||
|
{
|
||||||
|
dmaregs[DCR4XX_DMADA0] = dmaregs[DCR4XX_DMASA0];
|
||||||
|
dmaregs[DCR4XX_DMACT0] = dmaregs[DCR4XX_DMACC0];
|
||||||
|
dmaregs[DCR4XX_DMACR0] &= ~PPC4XX_DMACR_CH;
|
||||||
|
|
||||||
|
switch (dmachan)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
ppc->dcr[DCR4XX_DMASR] |= 0x00080000;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
ppc->dcr[DCR4XX_DMASR] |= 1 << (7 - dmachan);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ppc4xx_dma_update_irq_states(ppc);
|
||||||
|
|
||||||
|
INT64 numdata = dmaregs[DCR4XX_DMACT0];
|
||||||
|
if (numdata == 0)
|
||||||
|
numdata = 65536;
|
||||||
|
|
||||||
|
INT64 time = (numdata * 1000000) / ppc->buffered_dma_rate[dmachan];
|
||||||
|
|
||||||
|
ppc->buffered_dma_timer[dmachan]->adjust(attotime::from_usec(time), dmachan);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* set the complete bit and handle interrupts */
|
/* set the complete bit and handle interrupts */
|
||||||
ppc->dcr[DCR4XX_DMASR] |= 1 << (31 - dmachan);
|
ppc->dcr[DCR4XX_DMASR] |= 1 << (31 - dmachan);
|
||||||
// ppc->dcr[DCR4XX_DMASR] |= 1 << (27 - dmachan);
|
// ppc->dcr[DCR4XX_DMASR] |= 1 << (27 - dmachan);
|
||||||
ppc4xx_dma_update_irq_states(ppc);
|
ppc4xx_dma_update_irq_states(ppc);
|
||||||
|
|
||||||
|
ppc->buffered_dma_timer[dmachan]->adjust(attotime::never, FALSE);
|
||||||
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------
|
/*-------------------------------------------------
|
||||||
ppc4xx_dma_fetch_transmit_byte - fetch a byte
|
buffered_dma_callback - callback that fires
|
||||||
to send to a peripheral
|
when buffered DMA transfer is ready
|
||||||
-------------------------------------------------*/
|
-------------------------------------------------*/
|
||||||
|
|
||||||
static int ppc4xx_dma_fetch_transmit_byte(powerpc_state *ppc, int dmachan, UINT8 *byte)
|
static TIMER_CALLBACK( ppc4xx_buffered_dma_callback )
|
||||||
{
|
{
|
||||||
UINT32 *dmaregs = &ppc->dcr[8 * dmachan];
|
powerpc_state *ppc = (powerpc_state *)ptr;
|
||||||
|
int dmachan = param;
|
||||||
|
|
||||||
/* if the channel is not enabled, fail */
|
|
||||||
if (!(dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_CE))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
/* if no transfers remaining, fail */
|
|
||||||
if ((dmaregs[DCR4XX_DMACT0] & 0xffff) == 0)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
/* fetch the data */
|
|
||||||
*byte = ppc->program->read_byte(dmaregs[DCR4XX_DMADA0]++);
|
|
||||||
ppc4xx_dma_decrement_count(ppc, dmachan);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------
|
|
||||||
ppc4xx_dma_handle_receive_byte - receive a byte
|
|
||||||
transmitted by a peripheral
|
|
||||||
-------------------------------------------------*/
|
|
||||||
|
|
||||||
static int ppc4xx_dma_handle_receive_byte(powerpc_state *ppc, int dmachan, UINT8 byte)
|
|
||||||
{
|
|
||||||
UINT32 *dmaregs = &ppc->dcr[8 * dmachan];
|
|
||||||
|
|
||||||
/* if the channel is not enabled, fail */
|
|
||||||
if (!(dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_CE))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
/* if no transfers remaining, fail */
|
|
||||||
if ((dmaregs[DCR4XX_DMACT0] & 0xffff) == 0)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
/* store the data */
|
|
||||||
ppc->program->write_byte(dmaregs[DCR4XX_DMADA0]++, byte);
|
|
||||||
ppc4xx_dma_decrement_count(ppc, dmachan);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------
|
|
||||||
ppc4xx_dma_execute - execute a DMA operation
|
|
||||||
if one is pending
|
|
||||||
-------------------------------------------------*/
|
|
||||||
|
|
||||||
static void ppc4xx_dma_exec(powerpc_state *ppc, int dmachan)
|
|
||||||
{
|
|
||||||
static const UINT8 dma_transfer_width[4] = { 1, 2, 4, 16 };
|
static const UINT8 dma_transfer_width[4] = { 1, 2, 4, 16 };
|
||||||
UINT32 *dmaregs = &ppc->dcr[8 * dmachan];
|
UINT32 *dmaregs = &ppc->dcr[8 * dmachan];
|
||||||
INT32 destinc, srcinc;
|
INT32 destinc;
|
||||||
UINT8 width;
|
UINT8 width;
|
||||||
|
|
||||||
/* skip if not enabled */
|
|
||||||
if (!(dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_CE))
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* check for unsupported features */
|
|
||||||
if (!(dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_TCE))
|
|
||||||
fatalerror("ppc4xx_dma_exec: DMA_TCE == 0");
|
|
||||||
if (dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_CH)
|
|
||||||
fatalerror("ppc4xx_dma_exec: DMA chaining not implemented");
|
|
||||||
|
|
||||||
/* transfer mode */
|
|
||||||
switch ((dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_TM_MASK) >> 21)
|
|
||||||
{
|
|
||||||
/* buffered mode DMA */
|
|
||||||
case 0:
|
|
||||||
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];
|
width = dma_transfer_width[(dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_PW_MASK) >> 26];
|
||||||
destinc = (dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_DAI) ? width : 0;
|
destinc = (dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_DAI) ? width : 0;
|
||||||
|
|
||||||
@ -1947,6 +1955,101 @@ static void ppc4xx_dma_exec(powerpc_state *ppc, int dmachan)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
ppc4xx_dma_fetch_transmit_byte - fetch a byte
|
||||||
|
to send to a peripheral
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
static int ppc4xx_dma_fetch_transmit_byte(powerpc_state *ppc, int dmachan, UINT8 *byte)
|
||||||
|
{
|
||||||
|
UINT32 *dmaregs = &ppc->dcr[8 * dmachan];
|
||||||
|
|
||||||
|
/* if the channel is not enabled, fail */
|
||||||
|
if (!(dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_CE))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* if no transfers remaining, fail */
|
||||||
|
if ((dmaregs[DCR4XX_DMACT0] & 0xffff) == 0)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* fetch the data */
|
||||||
|
*byte = ppc->program->read_byte(dmaregs[DCR4XX_DMADA0]++);
|
||||||
|
ppc4xx_dma_decrement_count(ppc, dmachan);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
ppc4xx_dma_handle_receive_byte - receive a byte
|
||||||
|
transmitted by a peripheral
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
static int ppc4xx_dma_handle_receive_byte(powerpc_state *ppc, int dmachan, UINT8 byte)
|
||||||
|
{
|
||||||
|
UINT32 *dmaregs = &ppc->dcr[8 * dmachan];
|
||||||
|
|
||||||
|
/* if the channel is not enabled, fail */
|
||||||
|
if (!(dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_CE))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* if no transfers remaining, fail */
|
||||||
|
if ((dmaregs[DCR4XX_DMACT0] & 0xffff) == 0)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* store the data */
|
||||||
|
ppc->program->write_byte(dmaregs[DCR4XX_DMADA0]++, byte);
|
||||||
|
ppc4xx_dma_decrement_count(ppc, dmachan);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
ppc4xx_dma_execute - execute a DMA operation
|
||||||
|
if one is pending
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
|
static void ppc4xx_dma_exec(powerpc_state *ppc, int dmachan)
|
||||||
|
{
|
||||||
|
static const UINT8 dma_transfer_width[4] = { 1, 2, 4, 16 };
|
||||||
|
UINT32 *dmaregs = &ppc->dcr[8 * dmachan];
|
||||||
|
INT32 destinc, srcinc;
|
||||||
|
UINT8 width;
|
||||||
|
|
||||||
|
/* skip if not enabled */
|
||||||
|
if (!(dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_CE))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* check for unsupported features */
|
||||||
|
if (!(dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_TCE))
|
||||||
|
fatalerror("ppc4xx_dma_exec: DMA_TCE == 0");
|
||||||
|
|
||||||
|
/* transfer mode */
|
||||||
|
switch ((dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_TM_MASK) >> 21)
|
||||||
|
{
|
||||||
|
/* buffered mode DMA */
|
||||||
|
case 0:
|
||||||
|
if (((dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_PL) >> 28) == 0)
|
||||||
|
{
|
||||||
|
/* buffered DMA with external peripheral */
|
||||||
|
|
||||||
|
INT64 numdata = dmaregs[DCR4XX_DMACT0];
|
||||||
|
if (numdata == 0)
|
||||||
|
numdata = 65536;
|
||||||
|
|
||||||
|
INT64 time;
|
||||||
|
if (numdata > 100)
|
||||||
|
{
|
||||||
|
time = (numdata * 1000000) / ppc->buffered_dma_rate[dmachan];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
time = 0; // let very short transfers occur instantly
|
||||||
|
}
|
||||||
|
|
||||||
|
ppc->buffered_dma_timer[dmachan]->adjust(attotime::from_usec(time), dmachan);
|
||||||
}
|
}
|
||||||
else /* buffered DMA with internal peripheral (SPU) */
|
else /* buffered DMA with internal peripheral (SPU) */
|
||||||
{
|
{
|
||||||
@ -2360,10 +2463,11 @@ void ppc4xx_spu_receive_byte(device_t *device, UINT8 byteval)
|
|||||||
specific external DMA read handler configuration
|
specific external DMA read handler configuration
|
||||||
-------------------------------------------------*/
|
-------------------------------------------------*/
|
||||||
|
|
||||||
void ppc4xx_set_dma_read_handler(device_t *device, int channel, ppc4xx_dma_read_handler handler)
|
void ppc4xx_set_dma_read_handler(device_t *device, int channel, ppc4xx_dma_read_handler handler, int rate)
|
||||||
{
|
{
|
||||||
powerpc_state *ppc = *(powerpc_state **)downcast<legacy_cpu_device *>(device)->token();
|
powerpc_state *ppc = *(powerpc_state **)downcast<legacy_cpu_device *>(device)->token();
|
||||||
ppc->ext_dma_read_handler[channel] = handler;
|
ppc->ext_dma_read_handler[channel] = handler;
|
||||||
|
ppc->buffered_dma_rate[channel] = rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------
|
/*-------------------------------------------------
|
||||||
@ -2371,10 +2475,11 @@ void ppc4xx_set_dma_read_handler(device_t *device, int channel, ppc4xx_dma_read_
|
|||||||
specific external DMA write handler configuration
|
specific external DMA write handler configuration
|
||||||
-------------------------------------------------*/
|
-------------------------------------------------*/
|
||||||
|
|
||||||
void ppc4xx_set_dma_write_handler(device_t *device, int channel, ppc4xx_dma_write_handler handler)
|
void ppc4xx_set_dma_write_handler(device_t *device, int channel, ppc4xx_dma_write_handler handler, int rate)
|
||||||
{
|
{
|
||||||
powerpc_state *ppc = *(powerpc_state **)downcast<legacy_cpu_device *>(device)->token();
|
powerpc_state *ppc = *(powerpc_state **)downcast<legacy_cpu_device *>(device)->token();
|
||||||
ppc->ext_dma_write_handler[channel] = handler;
|
ppc->ext_dma_write_handler[channel] = handler;
|
||||||
|
ppc->buffered_dma_rate[channel] = rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -545,6 +545,8 @@ struct _powerpc_state
|
|||||||
emu_timer * wdog_timer;
|
emu_timer * wdog_timer;
|
||||||
UINT32 pit_reload;
|
UINT32 pit_reload;
|
||||||
UINT32 irqstate;
|
UINT32 irqstate;
|
||||||
|
emu_timer * buffered_dma_timer[4];
|
||||||
|
int buffered_dma_rate[4];
|
||||||
|
|
||||||
/* PowerPC 603-specific state */
|
/* PowerPC 603-specific state */
|
||||||
UINT32 mmu603_cmp;
|
UINT32 mmu603_cmp;
|
||||||
|
Loading…
Reference in New Issue
Block a user